This article is translated from the wanago. IO series of test tutorials with permission from the original author.

You’ve probably known the terms “unit testing” and “end-to-end testing” for a long time, but never actually put them into practice. In this series of practical tutorial, we will take you hand in hand to master Jest, Enzyme, Cypress and other test tools, to help us break out of the swamp of bugs, become an invincible advanced front-end developer!

The React project will teach you how to write the first test using Jest, and then use the Enzyme to render the React component. To facilitate fine-grained testing of components at different levels, you will have a good understanding of the basics of test writing and component testing after you follow this tutorial.

Introduction to Jest unit testing

Testing is code that examines code and can greatly enhance our confidence in the application. More importantly, testing prevents you from fixing one thing while breaking another, freeing us up to add features and massively refactor. You can test many aspects of an application, from a single function and its return value to a complex application running in a browser. Great oaks from little acorns grow, so let’s take a look at the tests.

Types of tests

Unit testing

The target of a unit test can be a function, a class, or a module. Unit tests should be isolated and independent. For a given input, the unit test checks the result. By catching problems early and preventing bugs from returning, it helps us ensure that all parts of the code work as expected.

Integration testing

Even if all the unit tests passed, our application could still crash. Integration testing is the process of testing across modular units/modules and is a good way to ensure that our code works as a whole.

End-to-end Testing (E2E)

Unlike other types of tests, E2E tests are always run in a browser (or browser-like) environment. It could be an actual browser that you can open and run tests in; It could also be a Headless browser environment, which is a browser with no user interface. E2E testing focuses on simulating real users in the application we are running (for example, simulating behaviors like scrolling, clicking, and typing) and checking that our application is performing well from the perspective of real users.

In this series of tutorials, we’ll start from scratch and walk you through everything from unit testing to end-to-end testing. We will practice the automated testing techniques we have learned in a React project. Create React App (CRA)

create-react-app javascript-test-series
Copy the code

Then we delete all the pre-created files in the SRC directory (you can also delete them manually) :

rm src/*
Copy the code

Everything is ready! Let’s get started.

Write your first unit test

Writing a unit test is actually a lot easier than you think. We’ll start by creating separate.js, where we’ll write an divide function:

// divide.js
function divide(a, b) {
  return a / b;
}

module.exports = divide;
Copy the code

Then create the test file separate.test.js as follows:

// divide.test.js
const divide = require('./divide');

test('dividing 6 by 3 equals 2'.() = > {
  expect(divide(6.3)).toBe(2);
});
Copy the code

As the first Jest test in this series, let’s take a closer look:

  • We import the units/modules that need to be tested first
  • testThe function defines oneThe test caseThe first parameter isUse case description“Is usually a complete description, such as the one abovedividing 6 by 3 equals 2; The second argument is one to be executedTest functions
  • The most important component of a test function isassertionsAssertion, as aboveexpect(divide(6, 3)).toBe(2)
  • The core of the assertion isexpectFunction, which takes an expression and can then call Matcher to test whether the expression meets the criteria, such as the one we use heretoBeThe Matcher. Jest also provides a number of matchers to help us write more concise and readable assertion statements for referenceExpect API

CRA has already configured Jest for us. Run the NPX Jest command directly to see the test results:

PASS. / divide. Test. Js ✓ dividing6 by 3 equals 2 (5ms)
Copy the code

prompt

CRA also configures the test command, but it provides more complex configurations (Watch mode, etc.) that may confuse you as a beginner of Jest. Therefore, it is recommended to use NPX JEST directly to perform tests.

Write the first set of tests

Each test file typically has multiple test cases. Jest allows us to group test cases through the Describe function, which creates a block that can combine multiple tests. Let’s run some tests on the global Math object (I hope browser engineers and Node project maintainers don’t beat me up) and create math.test.js with the following code:

// math.test.js
describe('in the math global object'.() = > {
  describe('the random function'.() = > {
    it('should return a number'.() = > {
      expect(typeof Math.random()).toEqual('number');
    });

    it('should return a number between 0 and 1'.() = > {
      const randomNumber = Math.random();
      expect(randomNumber).toBeGreaterThanOrEqual(0);
      expect(randomNumber).toBeLessThan(1);
    });
  });

  describe('the round function'.() = > {
    it('should return a rounded value of 4.5 being 5'.() = > {
      expect(Math.round(4.5)).toBe(5);
    });
  });
});
Copy the code

You may have noticed that we’re using the IT function instead of the test function, which is essentially the same thing.

Grouping tests this way makes our code clearer. As well as focusing on the code quality of the application, we should also ensure the quality of the test code, so that we have enough incentive to maintain the test code constantly to ensure that our projects remain robust.

In addition to making your code more readable, it helps provide better error messages when errors occur. If we change the first test case to expect(typeof Math.random()).toequal (‘string’), then we run NPX jest and get the following error message:

FAIL./math.test.js ● In the math global Object › The random function › should return a number expect(received).toEqual(expected) Expected value to equal: "string" Received: "number"Copy the code

Is it easy to see?

summary

In this section, we first looked at what types of tests there are. We then wrote a simple function in CRA scaffolding, wrote our first unit test for it, familiarizing ourselves with the key concepts of test cases, assertions, Matcher, and passed the test successfully. Next, we wrote a test file containing multiple use cases and organized the test cases using the Describe function.

Write the first React component test

Obviously, we’re not going to settle for testing simple functions like Divide. We’d like to be able to test a React component, but unlike a normal JavaScript function, testing a React component requires two key questions: 1) how to render the component under test; 2) how to test the rendered components.

Fortunately, Airbnb, as a pioneer in heavy use of React, has long proposed a special solution: Enzyme.

Install and configure the Enzyme

First install the Enzyme and corresponding React adapter:

npm install enzyme enzyme-adapter-react-16
Copy the code

We need to configure the Enzyme to use it in the Jest test file. Create SRC/setuptests.js with the following code:

// src/setupTests.js
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';

configure({ adapter: new Adapter() });
Copy the code

Shallow rendering

An important function provided by enzymes is the Shallow Rendering of components. It allows us to render only the parent component and not all its children when running the test. Shallow rendering is fast and therefore good for unit testing.

First let’s create a simple React component and create SRC/app.js with the following code:

// src/App.js
import React from 'react';

const App = () = > {
  return <h1>Hello world!</h1>;
};

export default App;
Copy the code

Compile the test file SRC/app.test.js corresponding to App components, the code is as follows:

// src/App.test.js
import React from 'react';
import { shallow } from 'enzyme';

import App from './App';

describe('app component'.() = > {
  it('contains a header with the "Hello world!" '.() = > {
    const app = shallow(<App />);
    expect(app.containsMatchingElement(<h1>Hello world!</h1>)).toEqual(true);
  });
});
Copy the code

As you can see, we shallow render the App component with its shallow function to get the App and call its containsMatchingElement to determine if the rendered App component contains

Hello World! < / h1 > element.

Enzyme shallow after rendering components include other test methods, reference enzymejs. Making. IO/Enzyme/docs… .

Using the NPM test command, we can see that the test passed:

PASS app/ app.test. js app component ✓ Contains a header with the "Hello world!" ✓Copy the code

Test more complex components

In real front-end development, our components are much more complex. In the spirit of step by step, let’s go a little further: write a component that accepts props and decide the render result based on the data.

Configuration jest – enzyme

As you may recall, we used Jest’s native Matcher (toEqual) in our test code. But in fact, the community offers a better alternative — a library of Matcher made specifically for enzymes: Enzyme – Matchers. These matchers make writing assertion statements easier and more readable.

We install jest-enzyme via NPM:

npm install jest-enzyme
Copy the code

Add the appropriate configuration to SRC/setuptests.js accordingly:

// src/setupTests.js
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import 'jest-enzyme';

configure({ adapter: new Adapter() });
Copy the code

Write the TodoList component

This time, we’ll write a familiar TodoList component. Create SRC/todolist.js with the following code:

// src/TodoList.js
import React from 'react';

const ToDoList = (props) = > {
  return (
    <ul>
      {props.tasks.map((taskName, index) => (
        <li key={index}>{taskName}</li>
      ))}
    </ul>
  );
};

export default ToDoList;
Copy the code

As you can see, this component takes an array of Tasks and renders it as a list.

Write TodoList component tests

First of all, what would you consider if you were to test the TodoList component above? It is not hard to think of two main cases:

  • The incomingtasksThe array is empty
  • The incomingtasksThe array is not empty

In both cases, we started writing tests. Create SRC/todolist.test.js with the following code:

// src/TodoList.test.js
import React from 'react';
import { shallow } from 'enzyme';

import ToDoList from './ToDoList';

describe('ToDoList component'.() = > {
  describe('when provided with an empty array of tasks'.() = > {
    it('contains an empty <ul> element'.() = > {
      const toDoList = shallow(<ToDoList tasks={} [] />);
      expect(toDoList).toContainReact(<ul />);
    });

    it('does not contain any <li> elements'.() = > {
      const toDoList = shallow(<ToDoList tasks={} [] />);
      expect(toDoList.find('li').length).toEqual(0);
    });
  });

  describe('when provided with an array of tasks'.() = > {
    it('contains a matching number of <li> elements'.() = > {
      const tasks = ['Wash the dishes'.'Make the bed'];
      const toDoList = shallow(<ToDoList tasks={tasks} />);
      expect(toDoList.find('li').length).toEqual(tasks.length);
    });
  });
});
Copy the code

As you can see, in our first test case, we used the toContainReact Matcher, which is pretty obvious; In the later test case, we use todolist.find (‘li’) to get an array of Li elements and determine if it is of the desired length.

prompt

You may find that we didn’t verify that every item of TodoList matches because we used the Enzyme shallow rendering, which means that all children are in an unrendered state, so of course we can’t verify that the content is correct. We will explain how to test our components more “in depth” in the next tutorial.

Run NPM test and check the test results.

PASS  app/App.test.js
PASS  app/components/ToDoList/ToDoList.test.js

Test Suites: 2 passed, 2 total
Tests:       4 passed, 4 total
Snapshots:   0 total
Time:        1.41s
Ran all test suites.
Copy the code

summary

In the last two sections, we learned, installed, and configured the Enzyme, touched the shallow rendering unit test tool, and tested the two React components step by step. But you should also notice that sometimes shallow rendering doesn’t quite meet our needs, and the Enzyme provides other rendering methods to test. In our next tutorial, we’ll cover new rendering methods, snapshot testing, and mock data. Be there!

❤️ Love triple punch

1. Please give me a “like” when you see this. Your “like” is the motivation for my creation.

2. Pay attention to the public account “Tuque community”, “gather wonderful free technical combat tutorial”!

3. This article has been included in the Tuq community Github github.com/tuture-dev/… Ask for a little Star, thank Star.