Hello, I’m Luo Zhu from @Daning

This article was first published on luozhu’s official website

This article has authorized the exclusive use of the public account of the Developer community, including but not limited to editing, marking the original rights and other rights.

What is a unit test 🧐

Unit tests are used to test the correctness of a module, a function, or a class. A program unit is the smallest testable part of an application. In React programming, the smallest unit is usually a component, a function. If you’re familiar with “test-driven Development” (TDD), unit testing is also familiar, narrowly defined as single Test Driven Development.

In general, programmers perform at least one unit test every time they modify a program, and most likely multiple times before and after the program is written to verify that the program meets the requirements of the software specification and is free of errors. In TDD, even unit tests are written against the design and then the code is written against the unit tests.

Great oaks grow from little acorns, and unit testing, like documentation, is an important part of ensuring the minimum unit quality of a program. Imagine that a brick can be mass-produced without a manual, but the consequences of putting a brick into use without quality testing can be terrifying. From this perspective, single testing may be a more important presence than documentation. Of course, we don’t advocate single testing for single testing’s sake, single testing is a precaution.

Other tests

Common testing types of front-end testing include Unit testing, Integration testing, and E2E testing. Generally, the testing resources we invest are sorted as follows:

Integration testing is based on unit testing, integrating multiple modules for testing, to ensure that the interaction between modules is correct. Sometimes a single module passes the unit tests completely and is fine on its own, but when used in conjunction with other modules, problems may arise. Here is an example of a failed integration test:

End-to-end testing is testing from the user’s point of view (one end) to the real environment (the other end). Generally, we use tools such as Cypress and Puppeteer for automated testing instead of human testing. Here is an example of a failed end-to-end test:

Test coverage

When we test, we often care about whether all of our code is tested, and what code is not. The Istanbul Test Coverage tool is built into JEST. We can see code test coverage in four dimensions:

  • Statements (STMTS) : Expression coverage, is every expression executed?
  • Branches (Branch) : Branch coverage. Is every if block executed?
  • Functions (Funcs) : Function coverage, is every function called?
  • Lines (Lines) : Line coverage, is every line executed?

Here is the command line output after jest –coverage is executed:

Here is a nice test coverage report generated:

Click app.js to see the test coverage of a single file:

Click on each and you’ll see a colorful page. Don’t worry, these colors have a clear meaning:

  • Code in pink: statement or function that has not been executed
  • Code in yellow: Not covered branch
  • I: the if for if-else was not executed

  • E: if for if-else is not executed

  • Nx: Represents the number of times a code block has been executed, and can be used as a reference for code performance

Install dependencies

$ yarn add jest -D
# babel
$ yarn add babel-jest -D
# enzyme
$ yarn add enzyme jest-enzyme enzyme-adapter-react-16 enzyme-to-json -D
# react-native-mock-render
$ yarn add react-native-mock-render -D
# types
$ yarn add @types/enzyme @types/jest @types/react @types/react-native -D
Copy the code

Tool Introduction:

  • Jest: JEST is a delightful JavaScript testing framework that focuses on simplicity.
  • Enzyme: Enzyme is a JavaScript test utility for React that makes it easier to test the output of the React component. You can also work on the output given, traversing and simulating the runtime in some way.
  • Jest-enzyme: the Jest assertion against enzyme
  • Hrk-adapter-react-16: Bridge required for react Native testing
  • Faith-to-json: Converts the enzyme wrappers into a JSON format that matches the Jest snapshot test.
  • react-native-mock-render: A fully mocked and test-friendly version of react native

configuration

jest.config.js

module.exports = {
  preset: 'react-native'.verbose: true.collectCoverage: true.moduleNameMapper: {
    // for https://github.com/facebook/jest/issues/919
    '^image! [a-zA-Z0-9$_-]+$': 'GlobalImageStub'.'^[@./a-zA-Z0-9$_-]+\\.(png|gif)$': 'RelativeImageStub',},setupFilesAfterEnv: ['<rootDir>/jest.setup.js'].snapshotSerializers: ['enzyme-to-json/serializer']};Copy the code
  • CollectCoverage: Generate test coverage reports
  • SetupFilesAfterEnv: Run the installation file using Jest to configure the enzymes and adapters (see belowjest.setup.js), beforesetupTestFrameworkScriptFile, can also be usedsetupFiles
  • SnapshotSerializers: The serializer is recommendedenzyme-to-json, it is simple to install and use, and allows you to write concise snapshot tests.

Note: Jest can only use setupFilesAfterEnv after 24.1.0

jest.setup.js

import 'react-native';
import 'react-native-mock-render/mock';
import 'react-native/Libraries/Animated/src/bezier'; // for https://github.com/facebook/jest/issues/4710
import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';

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

Introduction to enzyme

Enzyme is Airbnb’s open source React test library, which provides a clean and powerful API and dom processing in a jquery style, making the development experience very user-friendly. It provides three testing methods.

shallow

Shallow returns a shallow rendering of the module, encapsulating the official Shallow Rendering. The light render effect is that it only renders to the virtual DOM and does not return real DOM nodes, which is a huge performance improvement. Shallow only renders the current component and can only make assertions about the current component

mount

The mount method is used to load the React component as a real DOM node. Mount renders the current component and all its children. In most cases, the Shallow method will suffice. The REF test is intended to be in mount mode.

render

Render is a third-party library Cheerio rendering, rendering results are ordinary HTML structure, for snapshot use render is more appropriate.

Component test

Component snapshot testing

Snapshot tests are a useful tool when it comes to making sure the UI doesn’t change unexpectedly. ToMatchSnapshot is done.

describe('Button Component'.() = > {
  it('basic render'.() = > {
    const component = renderer.create(<Button />).toJSON();
    expect(component).toMatchSnapshot();
  });
});
Copy the code

Life cycle testing

componentDidMount

By calling shallow and mount methods, you trigger the componentDidMount lifecycle:

import { shallow } from 'enzyme';

function setup(props = {}) {
  const wrapper = shallow(<CarouselComponent />);
  const instance = wrapper.instance();
  return { wrapper, instance };
}

describe('Carousel Component'.() = > {
  it('renders correctly'.() = > {
    setup();
  });
});
Copy the code

It can also be triggered using the wrapper.setstate method:

import { shallow } from 'enzyme';

function setup(props = {}) {
  const wrapper = shallow(<Component {. props} / >);
  const instance = wrapper.instance();
  return { wrapper, instance };
}

describe('Component'.() = > {
  it('renders correctly'.() = > {
    const { wrapper } = setup();
    wrapper.setState({
      enable: true}); }); });Copy the code

componentWillUnMont

The componentWillUnMont lifecycle can be triggered by calling wrapper.unmount() :

import { shallow } from 'enzyme';

function setup(props = {}) {
  const wrapper = shallow(<Component />);
  const instance = wrapper.instance();
  return { wrapper, instance };
}
describe('Carousel Component'.() = > {
  it('renders correctly'.() = > {
    const { wrapper } = setup();
    expect(wrapper).toMatchSnapshot();
    wrapper.unmount();
    expect(wrapper).toMatchSnapshot();
  });
});
Copy the code

componentWillReceiveProps

Can be triggered by using the wrapper.setprops method:

import { shallow } from 'enzyme';

function setup(props = {}) {
  const wrapper = shallow(<Component {. props} / >);
  const instance = wrapper.instance();
  return { wrapper, instance };
}

it('componentWillReceiveProps'.() = > {
  const { wrapper, instance } = setup({
    autoplay: true}); wrapper.setProps({autoplay: false });
});
Copy the code

Timer Mocks

Native timer features (i.e. SetTimeout, setInterval, clearTimeout, clearInterval) are not ideal for test environments because they rely on real-time time. Jest can replace timers with features that allow us to control our own time.

Here we enable the fake timer by calling jest.usefakeTimers (). And in need of executing jest runOnlyPendingTimers () to trigger the timer:

import { shallow } from 'enzyme';

jest.useFakeTimers();

it('autoplay methods with count(2) and os(ios)'.() = > {
  const { wrapper, instance } = setup({
    autoplay: true.loop: false}); wrapper.setState({isScrolling: true }, () = > {
    jest.runOnlyPendingTimers();
  });
});
Copy the code

FAQ

How do I ignore a piece of code

Just add a comment in the following format to the block you want to ignore:

/* istanbul ignore next */
Copy the code

Ignore React Native warnings when using mount

  • Remove warnings when rendering react-native components
describe('mounting'.() = > {
    const origConsole = console.error;
    beforeEach(() = > {
      console.error = () = > {};
    });
    afterEach(() = > {
      console.error = origConsole;
    });
    it ......
       mount....
});
Copy the code

Common issues

  • enzyme

    • Create Adapter for React Native & React 16
    • Can’t simulate press event in react-native
    • Shallow with New React Context API. Consumer not getting context
    • Enzyme is not finding component by props
  • jest

    • TypeError: Cannot read property ‘Object.’ of null
    • Jest – how to test if a component does not exist?
    • Refs not working in component being shallow rendered
    • ReferenceError: You are trying to import a file after the Jest environment has been torn down.
  • react-native

    • requiring image in react-native
    • Cannot find module ‘setupDevtools’ from ‘setup.js’
    • Unable to resolve module ./views/assets/back-icon.png