Unit Testing Components with Jest in React Native. Setup and Trouble Resolutions
Tags: reactnative, react, testing, tutorial
Published: 2023-04-07 06:22:16


# Setup

## 1. Jest configuration

*I removed properties not related to react-native (such as testMatch, testUrl, etc.)*

```json
"jest": {
    "preset": "react-native",
    "moduleNameMapper": {
        "styled-components": "styled-components/native"
    },
    "transform": {
        "^.+\\.js$": "<rootDir>/node_modules/react-native/jest/preprocessor.js"
    }
}
```

*Also, it could be jest.config.js (depends on your project organization)*

## 2. Mocking store

I used `redux-mock-store`.

1\. For decrease duplicate code [I put it into __mocks__.](https://jestjs.io/docs/manual-mocks)

*As an example of middleware, there is a thunk here. You could use any.*
```javascript
import configureStore from 'redux-mock-store';
import thunk from 'redux-thunk';

const middlewares = [thunk];
const mockStore = configureStore(middlewares);

export default mockStore;
```
<sup>Redux mock store located in __mocks__ folder</sup>

2\. I've created a separate render component function.
```
import { render } from 'react-native-testing-library';
import { Provider } from 'react-redux';
import * as React from 'react';

export function renderComponent(content, store) {
    return render(<Provider store={store}>{content}</Provider>);
}
```
<sup>Receives component to render as content and state of the store</sup>

3\. And just use it:
```javascript
import Catalog from './index';
import * as React from 'react';
import mockStore from 'redux-mock-store';
import state from '../../../dev/spec-helpers/state';
import { renderComponent } from '../../../dev/spec-helpers/render-component';

describe('Catalog', () => {
  const store = mockStore(state);

  it('should render component in init state', () => {
      const component = renderCatalog(store, { disabled: true });
      expect(component.toJSON()).toMatchSnapshot();
  });
});

function renderCatalog(store, extendedProps = {}) {
    const props = { ...extendedProps, resultId: 'P39' };
    return renderComponent(<Catalog {...props} />, store);
}
```
<sup>Fragment of some component testing</sup>

# 3\. Add more readable expect method "toBeFound"
```javascript
const expect = require('expect');

expect.extend({
    toBeFound(received) {
        if (received === null) {
            return {
                message: () => 'Target node doesn\'t exist',
                pass: false
            };
        }

        return { pass: true };
    }
});
```
<sup>Extension of expect-file</sup>

1.  Create a script config/jest/expect.js
2.  Add it to setupFiles in your jest config:
```javascript
it('should correctly render last-date laboratory result', () => {
      const {getByText} = renderHomeResult(store);
      expect(getByText('Urogenital swab')).toBeFound();
      expect(getByText('Inhibin B')).toBeFound();
  });
```

# Trouble resolutions:


## 1\. ES6 in node_modules

Error in using of es6+ libraries from `node_modules` such it:

> /Users/dsitdikov/Projects/experimentx-dx-app/node_modules/react-native/jest/mockComponent.js:20 static displayName = 'Component'; ^ SyntaxError: Unexpected token =

### Solution:

Use `transformIgnorePatterns` in jest config:
```javascript
{
    "transformIgnorePatterns": [
        "<rootDir>/node_modules/(?!react-navigation|react-native|rn-apple-healthkit|rn-fetch-blob)"
    ]
}
```
<sup>A fragment of the package.json > jest</sup>

By default, jest transformIgnorePatterns has `<rootDir>/node_modules` and ignores all node_modules. So that it transforms each file from es6+ to understandable es5 except `node_modules`. Some modules are not in es6, and we should say ignore all `node_modules` except `react-navigation`, `react-native`, `rn-apple-healthkit`, etc.

[You also can read about it in jest documentation.](https://jestjs.io/docs/en/configuration#transformignorepatterns-array-string)

## 2\. Modules don't work in jest.

Something like:

> TypeError: Cannot read property 'RNFSFileTypeRegular' of undefined | import RNFS from 'react-native-fs';

### Solution:

It's ok. Just:

1.  Create `mocks.js` in your project
2.  Add `setupFiles` in your jest configuration
```json
{
    "setupFiles": [
      "<rootDir>/config/jest/mocks.js"
    ]
}
```
<sup>Fragment of package.json > jest</sup>

3\. For each unnecessary and unworking module write the following:
```javascript
jest.mock('react-native-camera', () => {});
```
<sup>An example of a mock some module</sup>


## 3\. Error in using mocked default exported modules.

An error could be such this:

> TypeError: Cannot read property 'dirs' of undefined

### Solution:

Just add this to your mocks file.
```javascript
jest.mock(
    'rn-fetch-blob', 
    () => ({
        __esModule: true,
        default: {
           fs: {
           dirs: {
               DocumentDir: jest.fn()
           }
        }
    })
);
```
<sub>A fragment of mocks.js file</sup>