jest testing tricks with react and mobx

First of all, i use a lot of jest with @testing-library/react. I think everyone heard about it and is already using it, if not, please give it a try :)

To get everything up and testing, we need to glue everything together with the jest config and the global test setup

setup hints

// jest.config.js

module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  setupFilesAfterEnv: ['./globalTestSetup.js']
};
// globalTestSetup.js

require('jest-styled-components')
require('@testing-library/jest-dom/extend-expect')
require('mobx-react-lite/batchingForReactDom')

mocking a mobx model from useContext

In my current default setup, i’m using mob-react-lite and the useContext hook to access the data store.

One chance to test it, is to write container components that are just the observers and set the mobx models as props. This is working fine, but in some cases, you might just want to mock a model and to test some behaviour

note: only variable names with “mock” prefix are usable with jest.mocks -> jest docs

const mockFn = jest.fn()

jest.mock('../../store/MyMobxModel.ts', () => {
  // return a constructor
  return jest.fn().mockImplementation(() => {
    // with a mock implementation
    return {
      data: ['overwritten initial value'],
      functionToTest(input: string): string {
        mockFn(input)
        return '???'
      },
    }
  })
})

beforeEach(() => {
  mockFn.mockReset()
})

testing a file upload

This is just a little utility script that simulates a file upload with react-testing-library

const simulateFileUpload = (inputEl: HTMLElement) => {
  const file = new File(['(⌐□_□)'], 'chucknorris.png', {
    type: 'image/png',
  })

  act(() => {
    Object.defineProperty(inputEl, 'files', {
      value: [file],
    })
    fireEvent.change(inputEl)
  })
}

and the a test using it

test('that file uploads are working', () => {)
  const mock = jest.fn()
  const { getByTestId } = render(<UploadComponent successCallback={mock} />)
  simulateFileUpload(getByTestId('fileuploadinput'))
  expect(mock).toBeCalledWith('chucknorris.png')
})

testing react router, with react router hooks

perhaps you noted some errors when testing components that needs to access useParams or some other hooks from react router. To get this test up and running, you need to provide some router context, and the easiest way is to use the MemoryRouter

import { MemoryRouter } from 'react-router-dom'

const { getByTestId } = render(<ComponentWithRoutingElements />, {
  wrapper: MemoryRouter,
})

or if some specific route params are needed, you can render it directly with initial entries and a matching route to provide it

const { getByTestId } = render(
  <MemoryRouter initialEntries={[`/route/Awesome`]} >
    <Route path="/route/:param" component={ComponentWithUseParamsHook} />
  </MemoryRouter>,
)

expect(getByTestId('headline')).toMatchSnapshot()

tests with a styled-components theme

the obvious solution ist just to wrap every test in a theme provider…

<ThemeProvider theme={Theme}>
  <ComponentUnderTest />
</ThemeProvider>

One alternative i used in small atom components, is just to set the Theme as default prop. The tests are just running, and everyone can use the atoms wihtout thinking about to wrap the test

MyStyledButton.defaultProps = {
  theme: Theme,
}

Last posts

Tags