Unit Tests in React
Contents
TDD in React
Installing Enzyme & Jest
npm i enzyme jest-cli@20.0.4 --save-dev
--save-dev only saves dependency in dev environment whereas --save saves dependency in production environment as well
to run tests
npm run tests
if it fails in the first time clear node_modules folder and run npm i then run the command above
npm i react-dom react-test-renderer --save-dev
We start with App.tests.js file
import React from 'react'; import { shallow } from 'enzyme'; import App from './App'; const app = shallow(<App />); it('renders correctly', () => { expect(app).toMatchSnapshot(); });
Enzyme
Shallow wrapper api reference
https://github.com/airbnb/enzyme/blob/master/docs/api/shallow.md
Full Rendering API (mount(...))
https://github.com/airbnb/enzyme/blob/master/docs/api/mount.md
Jest
Expect
https://jestjs.io/docs/en/expect#tomatchsnapshotpropertymatchers-snapshotname
Globals
Fast Dive
toMatchSnapshot
it takes a snapshot on the first run and saves it. Later when we run unit tests it compares saved snapshot with current snapshot.
it('renders correctly', () => { expect(app).toMatchSnapshot(); });
toEqual
it('initializes the `state` with an empty list of gifts', ()=> { expect(app.state().gifts).toEqual([]); });
to pass this
constructor(){ super(); this.state = { gifts: [] }; }
find & simulate
it('adds a new gift to `state` when clicking the `add gift` button', () => { app.find('.btn-add').simulate('click'); expect(app.state().gifts).toEqual([{id: 1 }]); });
to pass this
import { Button } from 'react-bootstrap'; ... addGift = () => { const { gifts } = this.state; const ids = this.state.gifts.map(gift => gift.id); const max_id = ids.length > 0 ? Math.max(...ids) : 0 ; gifts.push({ id: max_id + 1 }); this.setState({ gifts }); } ... <button className='btn-add' onClick={this.addGift}>Add Gift</Button>
children
expect(app.find('gift-list').children().length).toEqual(1);
Important: Enzyme Adapter
Please keep this in mind!
In order to use the most current version of React > 16, we now need to install "enzyme adapters" to provide full compatibility with React.
There's two options to take. The first is quicker, the second is recommended:
1. You can use the same versions for the node_modules libraries in the package.json files of the original repo:
Or you can:
2. Install the adapter for enzyme and react:
npm i enzyme-adapter-react-16 --save-dev
Next, add a src/tempPolyfills.js file to create the global request animation frame function that React now depends on.
src/tempPolyfills.js should contain the following contents:
const requestAnimationFrame = global.requestAnimationFrame = callback => { setTimeout(callback, 0); } export default requestAnimationFrame;
Finally, add a src/setupTests.js file to configure the enzmye adapter for our tests. The disableLifecyleMethods portion is needed to allow us to modify props through different tests.
src/setupTests.js should contain the following contents:
import requestAnimationFrame from './tempPolyfills'; import { configure } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; configure({ adapter: new Adapter(), disableLifecycleMethods: true });
Test Coverage
npm run test -- ---coverage
in package.json we can set up the coverage area
"jest":{ collectCoverageFrom: [ "src/**/*.js", "!src/index.js" ] }