Snapshot Testing with Jest and Enzyme

Unit testing in React

/testing-react-components-with-enzyme-jest.jpg

What is Jest?

Jest is a popular Node.js unit testing framework, frequently used with React. Like React itself, Jest is used internally by Facebook as a primary development tool. Jest allows for tests to be run in parallel, greatly increasing efficiency.

Why use tests at all?

Even after you complete an app and get everything finally working, this is always the possibility of future modifications introducing new bugs. Unit testing simply makes it easier to guard against this scenario.

How do I install Jest?

Jest is included with React (and React Native). Otherwise, it can be installed using your package manager of choice

npm install --save-dev jest
yarn add --dev jest

Then add a test script to your package.json

scripts: {
    "test": "jest"
}

React-test-renderer

React-test-renderer is a library that creates virtual components which can be tested with assertions With the create method, these pure JavaScript virtual components can be mounted (virtually), which means that the real DOM is not used, but the pure JS representation of that component is still able to be tested.

Configure the Adapter for React Native

React Native requires an adapter to work with the DOM. (For React Native) create a Jest configuration file in the root directory.

// jest.config.json
{
  "preset": "react-native",
  "collectCoverage": true,
  "moduleDirectories": [
    "node_modules",
    "src"
  ],
  "transform": {
    "^.+\\.js$": "node_modules/react-native/jest/preprocessor.js"
  },
  "setupFiles": [
    "jest.setup.js"
  ],
  "transformIgnorePatterns": [
    "node_modules/(?!(jest-)?react-native)"
  ],
  "coveragePathIgnorePatterns": [
    "/node_modules/",
    "/jest"
  ]
}

Then create a jest.setup.js file for jest in your root directory

// jest.setup.js
import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';

Enzyme.configure({ adapter: new Adapter() });

Where do I put the tests?

Jest will scour your entire project directory for files ending in .test.js or .spec.js In addition, all files within any directory named tests will be automatically executed by Jest. This allows you to keep test files close to the project files they are working with, or otherwise keep them contained to specific directories. You are free to organize your tests however you see fit.

What does a test look like?

A typical test will bundle expect methods within it methods within a describe method. In this way, you can express the intent and function of your many tests in a coherent and organized way. Methods it and describe are used to group tests together. Expect is the sharp end of the stick - this is where your assertions are tested

describe('Test basic Javascript functionality', () => {
    it('appends strings correctly', () => {
        expect('foo' + 'bar').toEqual('foobar')
        expect('st'.concat('ring')).toEqual('string')
    })
    it('performs math correctly', () => {
        expect(3 * 4).toEqual(12)
        expect(2**2).toEqual(2*2)
    })
    it('operates on arrays correctly', () => {
        expect([1,2,3][1]).toEqual(2)
    })
})

As you can see here, it is not difficult to understand what is going on in these tests. The expect() part performs a function, and must return something that is equal to toEqual() in order for the test to pass.

When a test is run successfully, output should look like this:

/Screenshot_2019-08-22_14-00-08-jest-test.png

Only if tests fail will you see something like this

/Screenshot_2019-08-22_14-17-15-jest-failing-test.png

Matchers and Assertions

An assertion is a statement that must be true - in Jest, these are validated with matchers As seen here, the toEqual() is a matcher, and there are a variety of matcher types that jest makes available.

  • toContain()
  • toBeFalsy()
  • toMatch()
  • toThrow()

Using Enzyme to test React

Enzyme is a testing framework developed by Airbnb

Installation:

yarn add --dev enzyme enzyme-adapter-react-16 react-test-renderer
npm install --save-dev enzyme enzyme-adapter-react-16 react-test-renderer

the assertion method shallow() tests a component provided to it. This unit test is intended to test only one function. Conversely, testing functions that rely on other functions is referred to as an integration test A full rendering test takes the entire component tree and lifecycle methods for testing. The prototypical test looks like this:

import React from 'react';
import { shallow } from 'enzyme';
import App from './App';describe('First React component test with Enzyme', () => {
   it('renders without crashing', () => {
      shallow(<App />);
    });
});

Snapshot Testing

Snapshot testing is a way to test if a component renders correctly with specified props and state A component is rendered, a snapshot taken, and then that snapshot is compared to a reference image, which must match. This helps to prevent your components from changing in unanticipated ways.

Creating the Spec file

If you want to test a component, you can create a spec file to compare it against. This is called shallow comparison. Make sure to have your Enzyme adapter loaded, and create a file called MyComponent.spec.js This will tell us if anything deviates about the way the component renders. If we make an intentional change to our component’s rendering, we can update our snapshots manually.

Updating Snapshots

npm run test -- -u

Coverage Report

Running tests creates a log of the test output for us, in addition to the console output. You can inspect the coverage report at coverage/lcov-report/index.html