Writing Effective Unit Tests with React and Enzyme

UNIT TESTING is a type of software testing where individual units or components of the software are tested. with this method of testing, both testers and developers can isolate each module, identity, and fix the system defects at the very early stage of the software development lifecycle(SDLC).

Unit test is solely performed by developers.

Why Unit Test for Frontend?

  • Front end  code changes more frequently than any other piece of code.you are probably going to introduce more bugs on the UI than anywhere else. That’s where unit testing come for the rescue
  •  One of the main benefits of unit testing is that it makes the coding process more agile
  •  Within unit tests environments, the individual modules of a product become isolated from one another and have their own area of responsibility. That means that the code is more reliable it’s been tested in a contained environment and therefore, reusable
  • The goal of unit testing is overall functionalities to ensure the presentation layer of web applications or software is defect-free with Successive updates.

How to perform unit testing in react?

  • In order to unit test in react we will use two libraries namely jest and enzyme       
  • Jest and enzyme are different tools that integrate well together to provide Flexible and creative testing abilities. We will briefly look at the differences between the two.  

Jest

  • Jest   is a javascript unit testing framework, used by facebook to test services and react application
  •  The primary way that Jest does this is through the use of snapshots. A Jest snapshot is a saved fragment of HTML generated by your application. 
  •  Developers generate these snapshots before writing tests by rendering components and saving their HTML using the jest snapshot
  • With snapshot testing, the output of the current test run is compared with the snapshot of the previous test run. If the output matches the snapshot, the test passes.

Enzyme

  • Enzyme is a JavaScript Testing utility for React that makes it easier to assert, manipulate, and traverse your React Components’ output.
  • Enzyme is not a unit testing framework. It does not have a test runner or an assertion library. It works with any test runner and assertion library. 
  • Enzyme renders the component in memory, then provides a series of APIs to examine the component’s properties 
  • Enzyme sends a shallow rendering api and full rendering api to examine the components properties.

Jest and Enzyme comparison

JestEnzyme
Jest is the test runner, assertion library, and mocking library The enzyme is not the test runner.it doesn’t have its own assertion library
Jest compares the snapshotEnzyme provides API to examine react components
Jest is more of a testing framework and can be used with non react applicationThe enzyme must be paired with another test runner if jest is not used 
Jest allows you to test the whole application with one test library The enzyme is a library that makes react components easier
Create-react-app comes bundled with jest it does not need to be installed separately It must be installed in addition to tools already bundled with Create-react-app

Steps to perform unit testing with jest and enzyme

Installation

  • let’s start by installing all the necessary libraries. Open the application console using yarn or npm to install Jest, Enzyme, and some additional plugins.
  • If you created your app with create-react-app you don’t have to install Jest, it’s already there.

Setting the files for testing 

  • Configure Jest

Add the following jest.config.js file to the root of your project:

module.exports = {
  "roots": [
    "<rootDir>/src"
  ],
  "transform": {
    "^.+\\.tsx?$": "ts-jest"
  },
  "testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$",
  "moduleFileExtensions": [
    "ts",
    "tsx",
    "js",
    "jsx",
    "json",
    "node"
  ],
}

Explanation:

  1. We always recommend having all TypeScript files in a src folder in your project. We assume this is true and specify this using the roots option.
  2. The transform config just tells Jest to use ts-jest for ts / tsx files.
  3. The testRegex tells Jest to look for tests in any __tests__ folder AND also any files anywhere that use the (.test|.spec).(ts|tsx) extension e.g. checkbox.test.tsx etc.
  4. The moduleFileExtensions tells Jest to recognize our file extensions. This is needed as we add ts/tsx into the defaults (js|jsx|json|node).

Run npx jest –watch (or ./node_modules/.bin/jest --watch) from your project root and Jest will execute any tests you have.

Optional: Add script target for npm scripts

Add this in package.json:

{
  "test": "jest --watch"
}
  • This allows you to run the tests in watch mode with a simple yarn test or npm t.

  1. Install Enzyme, types for Enzyme, a better snapshot serializer for Enzyme, enzyme-adapter-react for your React version:
yarn add enzyme @types/enzyme enzyme-to-json enzyme-adapter-react-16 --dev

# or if you are using NPM
npm i enzyme @types/enzyme enzyme-to-json enzyme-adapter-react-16 -D
  1. Add “snapshotSerializers” and “setupTestFrameworkScriptFile” to your jest.config.js:
module.exports = {
  // ... ... ... TRUNCATED. Other parts as before ... ... ...

  // Setup Enzyme
  "snapshotSerializers": ["enzyme-to-json/serializer"],
  "setupTestFrameworkScriptFile": "<rootDir>/src/setupEnzyme.ts",
}
  1. Open the setupTest.js file, where we will need to configure the adapter to use Enzyme in the Jest environment properly.
import { configure } from "enzyme";

import Adapter from "enzyme-adapter-react-16";
configure({ adapter: new Adapter() });


When that’s ready and saved, the next step will be to do the test cases

Execution

Now , its time to add our unit test case and run the test

Create a React component with checkbox. The checkbox state can be changed into on / off based on interactions.

import * as React from "react";

export class CheckboxWithLabel extends React.Component<{
  labelOn: string;
  labelOff: string;
}, {
  isChecked: boolean
}> {
  constructor(props) {
    super(props);
    this.state = { isChecked: false };
  }

  onChange = () => {
    this.setState({ isChecked: !this.state.isChecked });
  }

  render() {
    return (
      <label>
        <input
          type="checkbox"
          checked={this.state.isChecked}
          onChange={this.onChange}
        />
        {this.state.isChecked ? this.props.labelOn : this.props.labelOff}
      </label>
    );
  }
}


Create a file with Component name and it should end with .test.tsx or .test.js. In our case , use checkboxWithLabel.test.tsx

Jest will automatically pickup files ending with .test.tsx / js while running. Now , let’s start describing a jest test function with enzyme.

test('Checkbox With Label changes the text after click', () => {

    const checkbox = shallow(<CheckboxWithLabel labelOn='On' labelOff='Off' />);

    // Interaction demo
    expect(checkbox.text()).toEqual('Off');
    checkbox.find('input').simulate('change');
    expect(checkbox.text()).toEqual('On');

    // Snapshot demo
    expect(shallow).toMatchSnapshot();
});

Here in the example , Blue denotes jest code , red color denotes enzyme code.

In the default state, the checkbox value should be equal to Off and while clicking, it should have On.

We use Enzyme to simulate DOM actions via its APIs.

Let’s run the tests

Naveen:react-jest-enzyme-naveenraj$ yarn test 

Now, the tests will be successfully executed and a report will be shown like this.

I have attached the complete code in this GitHub repo.

Happy Coding!

Leave a comment

Your email address will not be published. Required fields are marked *