preface

React project Jest + enzyme solution Read the API and you should be able to write it in a couple of clicks, but there were some bumps along the way and some unexpected problems. Some are about the use method of enzyme, and some are not enough to understand the single test idea. Now sort out to give everyone reference ha ~

To prepare

Github allows you to install Jest and enzyme.

Jest: github.com/facebook/je…

Enzyme: github.com/enzymejs/en…

Remember, do unified configuration in Jest configuration according to enzyme instructions (github.com/enzymejs/en…) , there is no need for each single test file to write the application Adapter code.

Easy to use VSCode plug-in

VSCode has many useful plug-ins, Jest Runner plug-in can be installed to do Jest single test, execute use cases at any time, only execute a describe or even a certain it, very convenient, and even step by step debug:

If your Jest configuration file is not in the root directory of jest.config.js, you need to change it in the plugin Settings:

It is recommended to turn off the coverage switch (after all, you have a lot of single-test files and single-test cases and cannot use the same single-test coverage configuration).

Most useful API: Debug

Jest + enzyme start simple, look at the official demo to know how to write, each API to see the official document can be. But before you start writing single tests, seriously recommend the Enzyme Debug API. Usage:

const component = shallow(<Test />);
console.log(component.debug());
Copy the code

In conjunction with console.log, it allows the enzyme to render the React component’s DOM structure, as shown below. When you write a single measurement report wrong puzzled, print this out can find and solve most of the problems! It’s a must at home!

Shallow or mount

One thing I like about enzymes is that it provides shallow rendering, also known as shallow rendering. As the name suggests:

Mount: Renders the React component in its entirety, including each child component. The resulting structure looks like the familiar DOM structure.

Shallow: Only one layer is rendered. Treat child components as web Component nodes and leave them as they are. As shown in the preceding section.

One of the principles of single testing is to try to ensure the purity of the object being tested. Test one file and try not to introduce other files, test a function and try not to involve other functions. Similarly, test a React component without importing the logic of other components, which should be tested in their own use cases.

So, except for a few special cases, try to use only shallow. Special cases will be referred to below.

Mock, mock, mock!

As mentioned in the previous section, to ensure the purity of the object under test, if the test file A really needs the import file BCD to run, what can be done? Mock it all out and we’re done.

Jest provides a number of mock functions, most notably:

Jest. Fn: Mock a function, execute an empty function, do not execute the original function, return jest Mock Function. You can also pass arguments instead of executing the function you pass in;

Jest. SpyOn: similar to jest. Fn except that it executes the original function and returns the Jest Mock function;

Jest.fn ().mockImplementation: Mock a function with a prototype;

Jest. Mock: Mock the module.

Mock test uses toHaveBeenCalled, toHaveBeenCalledWith, and toHaveBeenCalledTimes. See the official documentation for the usage. However, in the process of use, there are many small skills.

1. The mock module has some holes

First of all, how do I write the path? Mock The first argument is the path of the package to mock. Is this path written relative to the single test file or referenced in the test file?

After test verification, the path here is relative to the single test file, as long as the single test file can be imported to the corresponding file through this path. Such as:

The paths of the single-test file and the tested file need not be the same, as long as the file system can correspond to the same file.

Next, don’t mock modules in describe. It doesn’t work. Jest promotes the Jest. Mock statement to the top of the code file, so there is no way to dynamically mock out different looks in the middle of the code.

Again, you cannot use external variables when you do a modular custom mock using the second argument to jest. Mock. The diagram below:

There is also no way to import objects from other files as a result of mocking:

This is also estimated because jest. Mock automatically promotes the feature at the top of the code file.

2. Mock web requests?

Mock out the package that makes the network request, such as Axios, and synchronously return the fabricated data.

At this time some students will ask, that I with the same request the same parameter call, hope to measure success, failure and other situations, how to do?

Use a few tricks:

3. What if I just need a dynamic mock module?

As mentioned earlier, do not use jest. Mock in describe, but what if you do mock a file repeatedly in real development? For example, to test file A, the uA. ts file is used. It will return the ua information of the current page. In single test, it is necessary to constantly switch UA to do different test cases.

There are two options to consider:

Scenario 1: Hack tricks, like the mock network request above, mock the module with a custom interface like setUa, and then call the switch parameter before each single test case. [Fixed] It’s a hack and may affect TS a little bit, but it works.

Option 2: Use the official interface jest. DoMock. This interface is not automatically promoted to the top of the code. Change to dynamic import and refer to the official documentation.

Both have their own advantages and disadvantages, according to the situation to choose ha.

4. Unified management of mock modules

The official example is to create a __mocks__ folder with the same name at the level of the file to mock, which is automatically matched using jest. Mock (‘ XXX ‘).

However, in our project, we want the single test files to be placed under

/test/unit and the single test mock files to be placed under

/test/unit/__mocks__. What should we do? Jest provides the configuration.

First change Jest configuration, add roots:

Then build directories and files layer by layer in the __mocks__ directory based on the path you wrote during the mock. For example, when jest. Mock (‘aa/bb’) is used, simply create __mocks_/aa/bb.ts to automatically match replacements.

One point in particular: When we do the above with the NPM package, Jest will automatically replace:

Mock (‘ XXX ‘), jest will replace all use case files and the test files they introduce as long as there is a file in the __mocks__ directory. In general this is fine, as external NPM packages tend to be stable. However, if lerNA was used in our project to manage the code, it would be different.

For example, student A will test the file using the lerna package @project/package1 of the project. He will put A mock file in the __mocks__ directory instead. BCDEF and other students’ use cases might not work because the source file they tested referenced that package and was automatically replaced with a mock file that didn’t meet the needs of their scenario and was GG. That is, the lerna package cannot be mocked by jest. Mock like a normal file of a project.

Mock the Lerna package carefully.

A few Tips

Tips1: How does the ref function trigger

It’s not surprising to write the React component using ref, especially in function form:

The ref function was not executed when the enzyme test was used. !

To execute the ref function, use the enzyme mount method to load the component. This is the special case I mentioned earlier.

Tips2: Be careful with setState

It is common to invoke setState for componentDidMount, event firing, and so on. The React setState method is asynchronous, but the enzyme mode handles setState differently.

In shallow rendering mode, calling setState updates the value of state synchronously:

If mount mode is used, however, calls to setState within the component will take effect asynchronously, forcing updates:

So, try to use shallow.

Tips3: Use pure functional components

Here’s an example of a function that returns a different React component depending on the argument passed in. Now do a single test on it:

The first use case succeeded, but the second failed? Console.log (component.debug()) shows that the Test component for button B is expanded. Shallow does not expand child components.

Shallow (
) deplores the first layer node, as shallow(
) deplores the CompA component, and the second Test component becomes the first layer component after executing the function. There is no way to test button A like this (the subcomponent will digest the name property elsewhere).

How to change? Wrap one more layer around the Test? It is better to use purely functional components:

conclusion

In general, Jest + enzyme is really good, this article is just some of my superficial experience, there must be more skills and useful tools to unlock, welcome everyone to leave a message to exchange ha ~