preface

In recent years, front-end development is fast, which means that the demand for front-end engineering will be higher and higher. Front-end automation testing, as a part of code quality assurance, is also a category of front-end engineering. At present, many open source frameworks or libraries use front-end automation testing, such as Ant Design, Element UI, etc. So we need to learn about front-end automation testing.

Jest is a facebook testing framework that integrates Mocha, Chai, Jsdom, Sinon, and more. So its powerful function is worth our learning.

Simple configuration of JEST

Jest runs in the Node environment and does not support es6’s Es Module, but our test code usually runs in the browser, so it is necessary to use Babel for code conversion. Here is the initialization of the project and a simple configuration of JEST:

run

npm init
Copy the code

The script command to initialize the project and configure the test in package.json:

"script": {
    "test": 'jset'
}
Copy the code

Install jest, @babel/core, @babel/preset-env

npm i jest @babel/core @babel/preset-env -D
Copy the code

When the installation is complete, run

npx jest --init
Copy the code

The jest configuration is initialized. After initialization, there is another jest.config.js configuration file in the directory.

Then create.babelrc to configure Babel:

// .babelrc
{
    "presets": [["@babel/preset-env", {
            "target": {
                "node": "current"}}}]]Copy the code

After this configuration, we can use the Es Module in jest’s test file. When using JEST for testing, we need to follow certain file naming rules for testing modules:

moduleName.test.js
Copy the code

For example, if we need to test the button.js file module, we create a test file named button.test.js.

First, the principle of front – end automated testing

Jest has a number of apis for testing a variety of development scenarios, with expect() and Test () at its core, which are integral to every test case.

The test() function is used primarily to describe a test case, and the expect() function is used to indicate what we expect. Expect () and test() are clever and uncomplicated, and here’s how they work:

function expect (result) {
    return {
        toBe: function (actual) {
            if(result ! == actual) {throw new Error(' expected value is not the actual value, expected value is${actual}, the actual value is${result}`); }}}}function test (desc, callback) {
    try {
        callback();
        console.info(`${desc}Pass the test '); } catch(e) { console.info(`${desc}Failed the test:${e}`); }}Copy the code

In this code, expact(result) returns the expected result. Normally, we just call expact(result), which can be a function with a return value, or an expression. The following toBe is a matcher. When Jest runs, it records the details of all failed matchers and outputs them to the user, so that the maintainer can clearly know the reason for the failure.

Jest API

2.1. Matchers

Matchers are an important concept in Jest. They provide a variety of ways for you to verify the return values you are testing. Matchers are popularly known as equal operations.

2.1.1 equal match Matchers

  • toBe()

ToBe () tests whether expect’s expected value is exactly equal to the result value. ToBe () is equivalent to js ===, object.is ().

test('1 + 2 = 3',() => {
  expect(1 + 2).toBe(3);
});
Copy the code
  • toEqual()

ToEqual (), as opposed to full equality of toBe(), matches content equality and is generally used to test the content equality of objects or arrays.

test('Test object contents equal', () = > {let a = { a: 1 };
  expect(a).toEqual({ a: 1 });
});
Copy the code

2.1.2 Judge match Matchers

ToBeTruthy () tests whether expect’s expected value is true; ToBeFalsy () tests whether expect’s expected value is false; ToBeUndefined () tests whether expect’s expected value is undefined; ToBeNull () tests whether expect’s expected value is null;

test('Judge match Matchers',() => {
  expect(true).toBeTruthy();
  expect(false).toBeFalsy();
  expect().toBeUndefined();
  expect(null).toBeNull();
});
Copy the code

2.1.3. Numbers match Matchers

ToBeGreaterThan () tests whether expect’s expected value is greater than the parameter passed in; ToBeLessThan () tests whether expect’s expected value is less than the parameter passed in; ToBeGreaterThanOrEqual () tests whether expect’s expected value is greater than or equal to the parameter passed in; ToBeLessThanOrEqual () tests whether expect’s expected value is less than or equal to the parameter passed in;

test('Judge match Matchers',() => {
  expect(2).toBeGreaterThan(1);
  expect(2).toBeLessThan(3);
  expect(2).toBeGreaterThanOrEqual(2);
  expect(2).toBeLessThanOrEqual(2);
});
Copy the code

2.1.4 Other commonly used match Matchers

ToMatch () tests whether Expect’s expected value matches the regular expression rules passed in; ToContain () tests whether expect’s expected contains the parameters passed in; ToThrow () tests whether Expect’s expected value throws a particular exception;

test('Other commonly used matches Matchers',() => {
  expect(/2/).toMatch(2);
  expect('Other Matchers').toContain('Matchers');
  expect(() => { throw new Error('error'); }).toThrow('error');
});
Copy the code

There are many jest matchers, but we don’t have to remember all of them. We can use various matchers flexibly to achieve similar effects, such as toBe(True) similar to toBeTruthy.

Jest tests asynchronous code

Jest also takes this into account. Now let’s use Jest as an example to illustrate how to use Jest to test asynchronous code:

run

npm i axios --save
Copy the code

3.1. Callback function asynchronous type test

Create the fetch. Js:

//fetch.js
import axios from 'axios'; / / assume that'https://juejin.im/editor'The returned data is {success:true }
export const fetchData = (callback) => {
    aixos.get('https://juejin.im/editor').then(res => {
        callback(res.data);
    });
}
Copy the code

Then create fetch. Test.js for the test:

//fetch.test.js
import { fetchData } from './fetchData.js';

test('Test returns {success: true}', (done) => {
    fetchData((data) => {
        expect(data).toEqual({ success: true });
        done();
    })
});
Copy the code

3.2. Return Promise asynchronous type tests

3.2.1. The Promise requests a successful test

Create the fetch. Js:

//fetch.js
import axios from 'axios'; / / assume that'https://juejin.im/editor'The returned data is {success:true }
export const fetchData = (callback) => {
   return aixos.get('https://juejin.im/editor');
}
Copy the code

Then create fetch. Test.js for the test:

//fetch.test.js
import { fetchData } from './fetchData.js';

test('Test returns {success: true}', () = > {return fetchData().then(res => {
        const { data } = res;
        expect(data).toEqual({ success: true}); })});Copy the code

3.2.2 The test that the Promise requests fails

Create the fetch. Js:

//fetch.js
import axios from 'axios'; / / assume that'https://juejin.im/editor/xxxx'No data returned, status 404export const fetchData = (callback) => {
   return aixos.get('https://juejin.im/editor/xxxx');
}
Copy the code

Then create fetch. Test.js for the test:

//fetch.test.js
import { fetchData } from './fetchData.js';

test('Test returns 404', () => {
    expect.assertions(1);
    return fetchData().catch(e => {
        expect(e.toString().indexOf('404') > -1).toBe(true); })});Copy the code

Jest hook function

Jest’s hook functions, similar to Vue’s lifecycle functions, automatically run a function at a specific point in the code’s execution. There are four core hook functions in Jest, beforeAll, beforeEach, afterEach, afterAll. All hook functions accept callback functions as arguments.

4.1 Execution sequence of Jest hook functions

As the name implies, Jest’s four core hook functions are executed beforeAll, beforeEach, afterEach, and afterAll in this order.

  • beforeAll:The hook function will be in theallThe test casePerform beforeExecution, usually used for initialization.
  • beforeEach:The hook function will be in theeachThe test casePerform beforeThe execution.
  • afterEach:The hook function will be in theeachThe test caseAfter performingThe execution.
  • afterAll:The hook function will be in theallThe test caseAfter performingThe execution.

Hook test.js hook functions are executed in sequence.

//hook.test.js

beforeAll(() => {
    console.info('beforeAll hook function execution ');
})

beforeEach(() => {
    console.info('beforeEach hook function execution ');
})

afterEach(() => {
    console.info('afterEach hook function execution ');
})

afterAll(() => {
    console.info('afterAll hook function execution ');
})

test('Testing hook functions in Jest', () => {
    console.info('Test Case Execution');
    expect(1).toBe(1);
});
Copy the code

run

npm run test
Copy the code

We will find the terminal and print out the following information:

'beforeAll hook function execution '
'beforeEach hook function execution '
'Test Case Execution'
'afterEach hook function execution '
'afterAll hook function execution '
Copy the code

This confirms the sequence of the hook functions described above.

4.2. Improve code maintainability with hook functions

The proper use of the hook function can make our test code easier to maintain. The following uses Calculator.js as an example to illustrate the use of the hook function:

Create a Calculator. Js:

//Calculator.js
class Calculator {
    constructor() {
        this.number = 0
    }
    add() {
        this.number += 1;
    }
    minus() { this.number -= 1; }}Copy the code

Then create calculator.test.js to test:

//Calculator.test.js
import Calculator from './Calculator.js';

letcalculator = null; //Jest recommends using hook functions for initialization beforeAll(() => {calculator = new calculator (); })test('Test add method in Calculator', () => {
    calculator.add();
    expect(calculator.number).toBe(1);
});

test('Test Calculator minus method', () => {// Calculator shares the same instance, coupling calculator.minus() with the previous code; expect(calculator.number).toBe(0); });Copy the code

run

npm run test
Copy the code

We’ll see that the test case passes without a hitch, but there’s a problem with the way the code is written in Calculator.test.js: The same Calculator instance was shared in each test case, causing each test function to be coupled to each other, which was not conducive to maintenance. To solve this problem, we could decouple with the beforeEach hook function of Jest.

To modify the Calculator. Test. Js:

//Calculator.test.js
import Calculator from './Calculator.js';

let calculator = null;

beforeEach(() => {
    calculator = new Calculator();
})

test('Test add method in Calculator', () => {
    calculator.add();
    expect(calculator.number).toBe(1);
});

test('Test Calculator minus method', () => {
    calculator.minus();
    expect(calculator.number).toBe(-1);
});
Copy the code

run

npm run test
Copy the code

We’ll see that the test cases pass smoothly. By using the beforeEach hook function, we re-create the calculator instance beforeEach test case execution so that there is no coupling between each test case and the code is easier to maintain.

Use describe to manage test case groups

We will meet in the process of development in a wide range of functional complex modules, for that we need to write a large number of test cases to test these modules, but if you simply write a test case for each function module and not classified, Jest test files will be confused and difficult to maintain, so we need to classify module function, Group management with Jest describe.

Calculator.js and calculator.test.js above are examples of how to use describe for group management:

To modify the Calculator. Js:

//Calculator.js
class Calculator {
    constructor() {
        this.number = 0
    }
    add() {
        this.number += 1;
    }
    minus() {
        this.number -= 1;
    }
    multiply() {
        this.number *= 2;
    }
    divide() { this.number /= 10; }}Copy the code

To modify the Calculator. Test. Js:

//Calculator.test.js
import Calculator from './Calculator.js';

describe('Test Calculator module all functions', () = > {let calculator = null;

    beforeEach(() => {
        calculator = new Calculator();
    });
    
    describe('Add quantity-dependent methods to the test Calculator', () = > {test('Test add method in Calculator', () => {
            calculator.add();
            expect(calculator.number).toBe(1);
        });
        test('Test multiply method in Calculator', () => {
            calculator.multiply();
            expect(calculator.number).toBe(0);
        });
    });
    
    describe('Methods to reduce quantitative correlation in test Calculator', () = > {test('Test Calculator minus method', () => {
            calculator.minus();
            expect(calculator.number).toBe(-1);
        });
        test('Test divide method in Calculator', () => {
            calculator.divide();
            expect(calculator.number).toBe(0);
        });
    });
})
Copy the code

run

npm run test
Copy the code

We will find that the terminal prints the following well-organized and readable test information:

'Test Calculator module all functions'
    'Add quantity-dependent methods to the test Calculator''Test add method in Calculator''Test multiply method in Calculator'
    'Methods to reduce quantitative correlation in test Calculator''Test Calculator minus method''Test divide method in Calculator'
Copy the code

We can see a significant improvement in the maintainability of our test code and the readability of the test run result information by categorizing module functionality and grouping it with Jest’s Describe.

Describe hook function execution rules

Each describe callback function has its own scope and can use Jest’s four core hook functions, and any describe hook function can work on all test cases in its callback function.

For scenarios where the describe callback functions nested describe, as in the calculator.test.js file above, the order of execution of the hook functions in each describe can be somewhat special.

The following changes are made to calculator.test.js to illustrate the order in which the describe callback nested the describe scenario’s hook functions are executed:

To modify the Calculator. Test. Js:

//Calculator.test.js
import Calculator from './Calculator.js';

describe('Test Calculator module all functions', () = > {let calculator = null;
    
    beforeAll(() => {
        console.info('beforeAll: parent beforeAll execution ');
    });
    
    beforeEach(() => {
        calculator = new Calculator();
        console.info('beforeEach: parent beforeEach execution ');
    });
    
    afterEach(() => {
        console.info('afterEach: Parent afterEach execution ');
    });
    
    describe('Add quantity-dependent methods to the test Calculator', () => {beforeAll(() => {console.info('beforeAll: first child beforeAll executes');
        });
        
        test('Test add method in Calculator', () => {
            console.info('Test add method in Calculator');
            calculator.add();
            expect(calculator.number).toBe(1);
        });
    });
    
    describe('Methods to reduce quantitative correlation in test Calculator', () => {beforeEach(() => {console.info('beforeEach: second child beforeEach executes');
        });
        
        test('Test Calculator minus method', () => {
            console.info('Test Calculator minus method');
            calculator.minus();
            expect(calculator.number).toBe(-1);
        });
    });
})
Copy the code

run

npm run test
Copy the code

We will find the terminal and print out the following information:

'beforeAll: parent beforeAll execution '
'beforeAll: first child beforeAll executes'
'beforeEach: parent beforeEach execution '
'Test add method in Calculator'
'afterEach: Parent afterEach execution '
'beforeEach: parent beforeEach execution '
'beforeEach: second child beforeEach executes'
'Test Calculator minus method'
'afterEach: Parent afterEach execution '
Copy the code

From this, we can see that in the describe callback nested describe scenario, the hook functions in Describe can be applied to all test cases in its callback function, and when each test case is run in the Describe scope, Hook functions of the same type are executed from parent to child and from outside to inside.

Mock in Jest

From the Angle of the test, I only care about the test method, the internal logic of itself, is not concerned with the current methods rely on implementation, so that we in some test certain dependence on the external interface of the implementation of the method, usually in a Mock implementation depends on the return of the interface, only test method of the internal logic and avoiding external dependence, based on this idea, Jest provides powerful Mock functions to make it easy for developers to Mock.

7.1, use,jest.fn()Function, capturing the call to the function

It is not uncommon for a function function to pass a callback as an argument during development. To test such a function function, we need to use Mock functions to capture the function call.

Use callback.js and callback.test.js as examples to illustrate Mock functions:

Create a callback. Js:

//callback.js
export const testCallback = (callback) => {
    callback();
}
Copy the code

Create a callback. Test. Js:

//callback.test.js
import { testCallback } from './callback.js';

test('Test the testCallback method', () => {
    const fn = jest.fn();
    testCallback(fn);
    expect(fn).toBeCalled();
})
Copy the code

run

npm run test
Copy the code

The above code mocks a FN function as a callback function of testCallback using jest.fn() to capture the fn call after toBeCalled to verify the test case. Note that only functions mock out by jest.fn() can be caught by toBeCalled.

Mock functions.mockattribute

The jest. Fn ()mock function has a.mock attribute, with which we can test functional modules in various ways.

To illustrate Mock functions, see callback.js and callback.test.js above:

Modify the callback. Test. Js:

//callback.test.js
import { testCallback } from './callback.js';

test('Test the testCallback method', () => {
    const fn = jest.fn();
    testCallback(fn);
    testCallback(fn);
    console.info(fn.mock);
    expect(fn).toBeCalled();
})
Copy the code

After running, we’ll find that the terminal prints out the following. Mock property information:

{
    calls: [ [], [] ],
    instances: [ undefined, undefined ],
    invocationCallOrder: [ 1, 2 ],
    results: [
        { type: 'return', value: undefined },
        { type: 'return', value: undefined }
    ]
}
Copy the code

7.2.1 mock objectcallsattribute

The calls property in fn.mock is a two-dimensional array whose entries represent the arguments to the function passed to jest. Fn ()mock, similar to the arguments property.

Callback callback callback callback callback callback callback callback callback callback callback callback callback callback callback callback callback callback callback callback callback callback callback callback

We can modify callback.js to pass the callback argument and see what happens to the calls:

//callback.js
export const testCallback = (callback) => {
    callback(1, 2, 3);
}
Copy the code

After running callback.test.js, we’ll see that the terminal prints the following. Mock property information:

{
    calls: [ [1, 2, 3], [1, 2, 3] ],
    instances: [ undefined, undefined ],
    invocationCallOrder: [ 1, 2 ],
    results: [
        { type: 'return', value: undefined },
        { type: 'return', value: undefined }
    ]
}
Copy the code

We can see that calls become [[1, 2, 3], [1, 2, 3], which means that the array element of calls is indeed an argument to the function passed to jest. Fn ()mock.

7.2.2 mock objectinvocationCallOrderattribute

The invocationCallOrder property in fn.mock is an array that indicates the order in which the functions derived from jest. Fn ()mock should be executed.

As you can see from callback.test.js above, fn is the function mock out by jest. Fn is called twice in testCallback, so the length of the invocationCallOrder array is 2.

7.2.3 mock objectresultsattribute

The results property in fn.mock is an array of objects that indicate the return value of the function jest. Fn ()mock returns, which is represented by the value property.

As you can see from callback.test.js, fn is the mock function from jest.fn(). Fn is called twice in testCallback and fn returns no value. The value attribute of the object is undefined.

We can modify callback. Test. js so that fn returns a value.

//callback.test.js
import { testCallback } from './callback.js';

test('Test the testCallback method', () => {
    const fn = jest.fn(() => {
        return 123;
    });
    testCallback(fn);
    testCallback(fn);
    console.info(fn.mock);
    expect(fn).toBeCalled();
})
Copy the code

After running callback.test.js, we’ll see that the terminal prints the following. Mock property information:

{
    calls: [ [1, 2, 3], [1, 2, 3] ],
    instances: [ undefined, undefined ],
    invocationCallOrder: [ 1, 2 ],
    results: [
        { type: 'return', value: 123 },
        { type: 'return', value: 123 }
    ]
}
Copy the code

We can see that the value of the results object is changed to the return value of fn 123, which means that the objects in the Results array do indicate the return value of the jest.fn()mock function, which is represented by the value property.

7.2.4 mock objectinstancesattribute

The Instances attribute in fn.mock is an array indicating that the jest. Fn ()mock function points to this. When a mock function is called as a normal function, this points to undefined; When the mock function is instantiated as a constructor by new, this points to mockConstructor{}.

Fn mock (jest. Fn); fn mock (jest. Fn); fn mock (jest. Fn); Array entries are undefined.

We can modify callback.js so that fn is called as a constructor.

Modify the callback. Js:

//callback.js
export const testCallback = (callback) => {
    callback();
};

export const testInstances = (callback) => {
    new callback();
}
Copy the code

Callback.test.js:

//callback.test.js
import { testCallback, testInstances } from './callback.js';

test('Test testInstances Method', () => {
    const fn = jest.fn();
    testInstances(fn);
    testInstances(fn);
    console.info(fn.mock);
    expect(fn).toBeCalled();
})
Copy the code

After running callback.test.js, we’ll see that the terminal prints the following. Mock property information:

{
    calls: [ [], [] ],
    instances: [ mockConstructor{}, mockConstructor{} ],
    invocationCallOrder: [ 1, 2 ],
    results: [
        { type: 'return', value: undefined },
        { type: 'return', value: undefined }
    ]
}
Copy the code

We can see that instances change to [mockConstructor{}, mockConstructor{}], that is, instances do indicate the this pointer to the jest.fn()mock function. When a mock function is called as a normal function, this points to undefined; When the mock function is instantiated as a constructor by new, this points to mockConstructor{}.

7.3, use,MockFunction to change the implementation of the inner function

When testing a functional module, we sometimes want to omit a certain execution step of the functional module and do not follow the code logic of the functional module. If we change the source code of the functional module, it is not desirable. We can use Mock functions to change the implementation of internal functions.

Suppose now that we

Create mockFetch. Js:

//mockFetch.js
import axios from 'axios';

export const fetchData = () => {
    return axios.get('https://juejin.im/editor').then(res => res.data);
}
Copy the code

Create mockFetch. Test. Js:

//mockFetch.test.js
import axios from 'axios';
import { fetchData } from './mockFetch.js';

jest.mock(axios);

test('Test the Mock function and change the implementation of the inner function', () => {
    axios.get.mockResolvedValue({ data: { success: true}});return fetchData().then(data => {
        expect(data).toEqual({ success: true}); })});Copy the code

run

npm run test
Copy the code

We will see that the test case passes smoothly. In the above code, we wrap axios with jest.mock() and define the data of the axios.get request as {data: {success: True}}, so that fetchData does not actually asynchronously request the ‘https://juejin.im/editor’ interface, but synchronously requests {data: {success: true} as the result of the data request.

With the help of jest. Mock () and mockResolvedValue, we can change the function implementation of the AXIos module itself so that it does not execute exactly as its own code logic.

7.4, create,__mocks__Folder, change the implementation of internal functions

In addition to changing the implementation of an inner function using the jest. Mock function as in section 7.3, we can also change the implementation of an inner function by creating a __mocks__ file.

Suppose we now continue with mockFetch. Js as an example and modify the file in section 7.3:

Create a __mocks__ folder in the mockFetch. Js sibling directory, and create mockFetch. Js in that folder as follows:

// mockFetch. Js in the __mocks__ folderexport const fetchData = () => {
   console.log('fetchData execution of mockFetch. Js in the __mocks__ folder');
   const data = { success: true };
   return Promise.resolve(data);
}
Copy the code

Modify mockFetch. Js:

//mockFetch.js
import axios from 'axios';

export const fetchData = () => {
   console.log('fetchData execution in mockFetch. Js');
   return axios.get('https://juejin.im/editor').then(res => res.data);
}
Copy the code

Modify mockFetch. Test. Js:

//mockFetch.test.js
jest.mock('./mockFetch.js');
import { fetchData } from './mockFetch.js';

test('Test creating a __mocks__ folder, changing the implementation of internal functions', () = > {return fetchData().then(data => {
        expect(data).toEqual({ success: true}); })});Copy the code

run

npm run test
Copy the code

We should see that the test case passed without any problems. Looking at the console, we can see the following information:

'fetchData execution of mockFetch. Js in the __mocks__ folder'
Copy the code

This shows that the test case executes fetchData from mockFetch. Js in the __mocks__ folder, because in the code above, Mock (‘./mockFetch. Js ‘) to mock./mockFetch. Js so that import {fetchData} from ‘./mockFetch. In./mockFetch. Js for the __mocks__ folder we created, we change the implementation of the internal function by creating the __mocks__ file and changing the reference to the file.

8. Snapshot test

During component development, we often need to create a default Props configuration for the component. During the component upgrade iteration, we may add or modify the configuration of the default Props. As a result, some configurations may be modified incorrectly but we are not aware of it, causing the modification and introducing bugs. With Snapshot, you can generate a Snapshot history of the file so that you can prompt the developer with each change and make them aware of the change.

Create generateProps. Js for Snapshot.

//generateProps.js
export const generateProps = () => {
    return {
        name: 'jest',
        time: '2020',
        onChange: () => {}
    }
}
Copy the code

Create generateProps. Test. Js:

//generateProps.test.js
import { generateProps } from './generateProps.js'

test('Snapshot test ', () => {
    expect(generateProps()).toMatchSnapshot();
})
Copy the code

For the first time to run

npm run test
Copy the code

The _snapshot_ folder is a snapshot of the return value of generateProps(). It is a snapshot of the result of the generateProps() execution. To be used as a reference for the next change.

Modify generateProps. Js:

//generateProps.js
export const generateProps = () => {
    return {
        name: 'jest',
        time: '2020',
        desc: 'test',
        onChange: () => {}
    }
}
Copy the code

run

npm run test
Copy the code

We will find the terminal console error:

1 snapshot failed
Copy the code

This is because the contents of the modified file do not match the snapshot. If we are sure that we need to update the snapshot, we need to enter the Jest command line mode at the console terminal and type U to confirm updating the snapshot.

Test the Timer

SetTimeout, setInterval() and other timers in the development process are asynchronous, if you want to test them, we can refer to the third, Jest test asynchronous code.

However, if the timer is set too long, we need to wait for the trigger of the timer to know the test result, which is obviously unreasonable, we do not need to waste time to wait, Jest also knows this, so, We can use jest. UseFakeTimers () and jest. AdvanceTimersByTime () to trigger timers immediately to improve development efficiency.

Create timer.js to show how to test the timer:

// timer.js
export const timer = (callback) => {
    setTimeout(() => {
        callback()
    }, 2000) ;
}
Copy the code

Create a timer. Test. Js:

// timer.test.js
import { timer } from './timer.js';

jest.useFakeTimers();

test('Test timer', () => {
    const fn = jest.fn();
    timer(fn);
    jest.advanceTimersByTime(2000);
    expect(fn).toHaveBeenCalledTimes(1);
});
Copy the code

run

npm run test
Copy the code

We can see that the test case passes without waiting for the timer to set. In this case, we use jest. UseFakeTimers () to start the fake timer and then use jest. AdvanceTimersByTime () to fast forward 2000 seconds, so that the timer has successfully triggered once, as expected in the test.

Test the DOM node

Jest runs in the node environment. Theoretically, Node does not have the concept of DOM. In order to facilitate developers to test DOM node operations, Jest has simulated a set of APIS in the Node environment, which we can call JSDOM. Using the JSDOM feature, we can also test DOM nodes using Jest.

Dom.js and jQuery are examples of how to use Jest to test dom nodes:

run

npm i jquery
Copy the code

Create dom. Js:

//dom.js
import $ from 'jquery';

export const createDiv = () => {
    $('body').append('<div/>')}Copy the code

Create dom. Test. Js:

//dom.test.js
import { createDiv }from './dom.js';

test('Test DOM node', () => {
    createDiv();
    let length = $('body').find('div').length;
    expect(length).toBe(1);
});
Copy the code

run

npm run test
Copy the code

We can see that the test case passes smoothly, that is, Jest supports testing DOM nodes.