React technical principles and code development practice: from Jest to Enzyme

1. Background Introduction

React is a JavaScript library developed by Facebook for building user interfaces. Its original intention was to solve the problem of low view rendering efficiency in JavaScript single-page applications. Facebook is also using React internally for the development of internal projects. This article will introduce some knowledge points about React principles, component development, testing framework Jest, and unit testing to help readers master React-related technologies and better understand the role and working principle of React. As a software engineer, I have rich programming experience, strong hands-on and problem-solving abilities, and a high level of learning ability, able to accurately grasp technical elements and put what I have learned into practice. Therefore, I will focus on explaining the technical principles and code implementation of React, striving to be easy to understand and lead readers to appreciate the full picture of React, thereby further improving their technical literacy. In addition, due to my limited technical level, there will inevitably be omissions and errors in the article. I would like to ask colleagues to criticize and correct me. Thank you very much!

2. Core concepts and connections

2.1.React overview

React is a JavaScript library for building user interfaces, consisting of three main parts:

  • JSX (JavaScript XML): JSX is a syntax extension, similar to XML, that describes how to create elements. All functions of JavaScript can be used in JSX, such as conditional statements, loops, function calls, etc.
  • Components: are reusable components defined based on JSX syntax, which can be nested and combined to form complex pages.
  • Virtual DOM: It is a data structure used to simulate the real DOM. Whenever the data changes, a new virtual DOM will be regenerated, and then React will generate the real DOM based on this virtual DOM, and finally the changed content will be generated. Updates are on the page. The React ecosystem consists of three important parts:
  • ReactDOM: Used to manage and control component rendering throughout the application.
  • PropTypes: Used to check whether PropTypes are correct.
  • Redux/Flux: It is an architectural pattern that can manage the state changes of applications.

    2.2. Lifecycle Methods

    React provides a series of lifecycle methods that can help us perform specific tasks at different stages of the component. These methods are generally divided into three stages:

  • Mounting phase: Triggered when a component is added or inserted into the DOM tree.
  • Updating phase: Triggered when the component receives new properties or state.
  • Unmounting phase: triggered when the component is removed from the DOM.

    2.3. Data Flow and State Management

    React’s data flow is one-way, that is, the parent component can only pass props to the child component, and the child component cannot directly Modify the value of props. Therefore, state management is generally implemented through parent-child component communication. React provides two basic state management methods:

  • Local state: Use this.state to store local state. You need to manually call the setState method to update the state.
  • Flux/Redux: Provides a centralized state management solution, using a single store to manage all states of the application.

    2.4. Communication methods between components

    React provides a variety of communication methods between components, such as callback functions, event handlers, Context API, Redux et al. Among them, Context API and Redux are centralized state management solutions.

    React Router is a simple and flexible routing solution officially provided by React. It allows you to define routing rules declaratively, supports nested routing configurations, and also supports dynamic routing matching and animated transition effects.

    2.6. Packaging Release and Deployment

    React can be installed through npm, and there are many tools to package, compile, publish, and deploy React projects, such as Webpack, Babel, and Create React App, CRA templates, Browserify, Parcel, Gulp, Grunt, NPM Scripts, Yarn and more.

    3. Detailed explanation of core algorithm principles, specific operation steps and mathematical model formulas

    Jest

    3.1. Introduction

    Jest is a JavaScript testing framework for testing React applications. It is also a testing framework recommended by Facebook. Its characteristics are as follows:

  • Supports browser, JSDOM and Node environments.
  • Supports asynchronous testing.
  • Built-in automatic snapshot function to capture rendering output results.
  • Support covers a wide range of areas, including unit testing, end-to-end testing, simulation testing, etc.
  • Supports custom test runners and report generators.
  • Run test cases via the command line or integrated development environment (IDE).

    3.2. Getting Started

    Installation and Settings

    First, you need to install Jest. It can be installed globally or locally. We recommend installing Jest globally so that it can be used everywhere.

    npm install -g jest
    //or
    yarn global add jest

    Then, create a new directory, switch to the directory, and initialize a package.json file.

    mkdir my-app & amp; & amp; cd my-app
    npm init --yes

    Next, install react, react-dom and babel dependencies.

    npm install react react-dom babel-jest @babel/core @babel/preset-env @babel/preset-react --save-dev

    Configure Jest

    Jest’s configuration file is jest.config.js, which is placed in the root directory. The default configuration is as follows:

    module.exports = {
    verbose: true, // Whether to display the name of each test case
    collectCoverageFrom: ['src/**/*.{js,jsx,mjs}'], // Specify which files contain code that is included in the test coverage
    coveragePathIgnorePatterns: [
      '/node_modules/',
      '<rootDir>/coverage',
     'src/__tests__/helpers',
     'src/setupTests.js'
    ], // File names not included in test coverage
    testMatch: [
      '**/__tests__/*.test.(ts|tsx)|**/?(*.)(spec|test).[tj]s?(x)', // Matching rules for test files
      '**/__tests__/*.(ts|tsx)'
    ], // Test file matching rules
    transform: {
      '^. + \.[t|j]sx?$': './node_modules/@babel/transform-es2015/lib/index.js', // used to convert JSX files Default options
      '^. + \.css$': '<rootDir>/config/jest/cssTransform.js', // Default options for converting CSS files
      '^(?!.*\.(js|jsx|mjs|css|json)$)': './config/jest/fileTransform.js' // Used to convert non-JS/ Default options for JSX/CSS/JSON files
    },
    transformIgnorePatterns: ['[/\\]node_modules[/\\]. + \.(js|jsx|mjs|ts|tsx)$'] , // List of regular expressions used to ignore matching file or module paths
    moduleNameMapper: {}, // Object used to map module paths, or path replacement rules when importing modules in test files
    moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'] // List of supported file suffixes
    };

    The meanings of the above configuration items are as follows:

  • verbose: If set to true, the name of each test case will be displayed during the test; if set to false, only a summary report will be displayed.
  • collectCoverageFrom: Specifies which files contain code that is included in the test coverage. It supports glob syntax and can specify multiple values.
  • coveragePathIgnorePatterns: File names not included in test coverage, supports glob syntax, and can specify multiple values.
  • testMatch: Test file matching rules, supports glob syntax, and can specify multiple values.
  • transform: Configuration options for transforming source files, including JSX, CSS, and other file types.
  • transformIgnorePatterns: A list of regular expressions used to ignore matching file or module paths.
  • moduleNameMapper: An object used to map module paths, or path replacement rules when importing modules in test files.
  • moduleFileExtensions: List of supported file suffixes.

Create test file

By default, Jest searches for all files matching the “/tests/*.test.(ts|tsx)” rule. If not found, it will search for “/< strong>tests/*.(ts|tsx)” rule file. We need to create two files to write test cases. Named App.test.js and Button.test.js respectively.

App.test.js:

import React from'react';
import renderer from'react-test-renderer';
import App from '../src/App';

it('renders correctly', () => {
  const tree = renderer.create(<App />).toJSON();
  expect(tree).toMatchSnapshot();
});

Button.test.js:

import React from'react';
import renderer from'react-test-renderer';
import Button from '../src/components/Button';

it('renders correctly', () => {
  const tree = renderer.create(<Button>Hello World</Button>).toJSON();
  expect(tree).toMatchSnapshot();
});

Here, we introduce React, react-test-renderer and the components App and Button to be tested, and then use snapshot testing. That is, before each test, a snapshot will be generated and then the test case will be run. If the test is successful, the new snapshot will be saved to a file called .snap, otherwise, a difference will be generated. We can use git diff to view the differences.

Execute the command jest to see the test report.

Enzyme

3.3. Introduction

Enzyme is a React testing tool launched by Facebook. It uses the mock module provided by Jest to provide a complete set of APIs for assertions and event handler testing of component rendering results. It mainly provides the following five APIs:

  • shallow(): Only renders the current component and does not render its sub-components. It is suitable for testing small components.
  • mount(): Completely renders the component into a virtual DOM, suitable for testing large components and component interaction logic.
  • render(): Only renders the current component, not its subcomponents, and returns the html string of the current component.
  • simulate(): Trigger an event, such as click() or mouseover().
  • find(): Find components or component elements.

3.4. Getting Started

Installation and Setup

First, you need to install Enzyme. It can be installed globally or locally. We recommend installing Enzyme globally so you can use Enzyme everywhere.

npm install -g enzyme
//or
yarn global add enzyme

Then, create a new directory, switch to this directory, and initialize a package.json file.

mkdir my-app & amp; & amp; cd my-app
npm init --yes

Next, install react and enzyme dependencies.

npm install react enzyme chai --save-dev

chai is an assertion library.

Configure Enzyme

Enzyme’s configuration file is enzyme.config.js, which is placed in the root directory. The default configuration is as follows:

const path = require('path');

module.exports = {
  rootDir: process.cwd(),
  roots: ['<rootDir>/src'],
  setupFilesAfterEnv: [],
  snapshotSerializers: [],
  testEnvironment: 'jsdom',
  testURL: 'http://localhost',
  testRunner: 'jest-circus/runner',
  transform: {},
  transformIgnorePatterns: [],
  watchPlugins: []
};

Create test file

Enzyme requires us to create test files and add .spec.js or .test.js to the file name, such as App.spec.js. We create Component.test.js.

Component.test.js:

import React from'react';
import { shallow } from 'enzyme';
import Component from './Component';

describe('<Component />', () => {
  it('should do something...', () => {
    const wrapper = shallow(<Component />);

    // Assertions go here

    expect(wrapper).toMatchSnapshot();
  });
});

Here, we introduced React and enzyme, created a shallow renderer, and rendered our components. We can use the find() method to find the child elements of the component and then make assertions. Finally, use the toMatchSnapshot() method for snapshot testing.

Execute the command jest to see the test report.