One year ago in an apartment not so far from this chair my React-Native journey began.
One of the great things about the platform is the great power of the Jest; being able to unit test your components without expensive test farms!
As we started publishing open source packages on NPM test coverage became even more important. So how to configure it? Start in jest.config.js. If you’re configuring Jest straight in package.json (don’t) syntax varies.
We use TypeScript for all JS development, because proper type checking and autocompletion rules.
Table of Contents
- Jest Collect Code Coverage
- Upload to Codecov and badge
- Jest React state manipulation
- Setting React state in Jest test
- Find React children in Jest test
- Read React state in Jest test
- React functions in Jest
- Jest call direct function in React Component
- Jest callback on React child function
- Async calls in Jest tests
- Mock module in single test
Jest Collect Code Coverage
When you now run Jest it will tell you your level of Jest mastery. This is from react-native-cross-cognito at the time of writing. Notice the “% Stmts” part. This is percent of test coverage. And looking at “Uncovered lines” will tell you exactly what lines your tests are missing!
Upload to Codecov and badge
It will also generate a /coverage folder containing the above report.
This can be turned into a cool Markdown badge (because badges are cool) for Codecov.io as seen below. Pretty neat right? Setup your codecov account and you’ll get one just as nice.
Simply upload the report using codecov cli, preferably in a CI build step:
Jest React state manipulation
Here’s the Jedi tricks you need to succeed. What I know is based on the excellent lessons of Russell Briggs right here on Medium. As seen, we’ve dropped Enzyme entirely in favour for the awesome react-native-test-renderer:
I will brake it down in slightly more concrete examples as seen in our library here. Also, if you’re in to AWS Cognito using Amplify, give it a go 🙂
Full source of tests in below examples:
Setting React state in Jest test
Our component CognitoLogin exposes it’s state object: ICognitoLoginState to the world. Say we want to simulate it’s state.formState being “Register”? Easy peasy. root.instance provides access to the real component instance.
Find React children in Jest test
A basic requirement is to identify children. While you could search by some props they happen to have, that’s pretty generic and unreliable. Each React component has a testID property, and you can add such to your custom components. This property makes it a breeze to identify the child in a test.
CognitoLogin.tsx contains this child:
<ForgotForm testID=’ForgotForm’ />
Which we can now look up in the test:
In this scenario findByType would have worked as well, but required us to import the child component.
Read React state in Jest test
When you’ve acted in the test and want to assert the result, reading the React component state becomes critical. Turns out, not so hard.
I’m using the excellent library Lodash, which no JS developer should live without, so the imports are included here for clarity. You could just do wrapper.root.instance.state and then read off any property in state.
React functions in Jest
Now that we can set and read state, let’s call our functions.
Jest call direct function in React Component
So you have a component with some functions (declared as arrow functions) and want to test those directly. No problemo! So assuming our component looks something like this:
We want to test onEmailChanged
Once again root.instance provides access and let us call any function within the component.
Jest callback on React child function
If you did the “Find React children” part then you have access to the child already. Now you can use the child instance props property to call any function on the child, such as button onSubmit or any custom function.
In this example CrossButton has a child of type FontAwesome.Button. Looks something like this:
So we create a callback handler for the onPress event in the test. After finding the React child we use it’s props to call the event. onCalled will update the called field.
Async calls in Jest tests
This is can be a little confusing sometimes. Why not just await your async function? Well you should, but you also have to tell Jest the test is done.
So the key parts are
- Decorate test function with async
- Add the done parameter to test function
- Call the done(); function before test exit.
Mock module in single test
In some cases you might need to mock a module in a single test.
There are two key parts involved here:
- Import the class you wish to mock (“Auth”) and create a spy using jest.spyOn
- After evaluation of result, call mockRestore() on the spy
Cool. Your mastering the Jest.