Jest (Pleasant Testing Framework)
1 What is Jest
Jest is Facebook’s open source JavaScript testing framework that automatically integrates assertions, JSDom, coverage reports, and all the other testing tools that developers need. It is a near-zero configuration testing framework.
2 the installation
Use YARN to install Jest
yarn add --dev jest
Copy the code
Or NPM:
npm install --save-dev jest
Copy the code
3 Simple Trial
Let’s write our first summation function, sum.js
function sum(a, b){
return a + b;
}
module.exports = sum;
Copy the code
Next create the test case:
const sum = require('./sum');
test('adds 1 + 2 to equal 3', () => {
expect(sum(1, 2)).toBe(3);
})
Copy the code
Configure the test startup script in package.json:
{
"scripts": {
"test": "jest"}}Copy the code
Finally, by running yarn test or NPM run test,Jest will print the following message:
PASS./sum.test.js adds 1 + 2 to equal 3 (5ms)Copy the code
4 verifier
Ordinary matching apparatus
The simplest test is to compare an exact match
test(`two plus tow is four`, () => {
expect(2 + 2).toBe(4);
})
Copy the code
Truthiness
In testing, sometimes you need to accurately distinguish between undefined, null, and false, and sometimes you don’t. Jest satisfies all of them.
- ToBeNull only matches null
- ToBeUndefined only matches undefined
- ToBeDefined is the opposite of toBeUndefined
- ToBeTruthy matches any if statement that is true
- ToBeFalsy matches any if statement that is false
test('null', () => {
const n = null;
expect(n).toBeNull();
expect(n).toBeDefined();
expect(n).not.toBeUndefined();
expect(n).not.toBeTruthy();
expect(n).toBeFalsy();
});
test('zero', () => {
const z = 0;
expect(z).not.toBeNull();
expect(z).toBeDefined();
expect(z).not.toBeUndefined();
expect(z).not.toBeTruthy();
expect(z).toBeFalsy();
});
Copy the code
digital
Most comparison numbers have equivalent matchers.
test('two plus two', () => { const value = 2 + 2; expect(value).toBeGreaterThan(3); Expect (value). ToBeGreaterThanOrEqual (3.5); expect(value).toBeLessThan(5); Expect (value). ToBeLessThanOrEqual (4.5); // toBe and toEqual are equivalentfor numbers
expect(value).toBe(4);
expect(value).toEqual(4);
});
Copy the code
For comparing floating point numbers for equality, use toBeCloseTo instead of toEqual, because you don’t want the test to depend on a small rounding error.
test('Add two floating point numbers'() => {const value = 0.1 + 0.2; / / expect (value). Place (0.3); ToBeCloseTo (0.3); toBeCloseTo(0.3); toBeCloseTo(0.3); // This will work});Copy the code
string
ToMatch regular expression string:
test('there is no I in team', () => {
expect('team').not.toMatch(/I/);
});
test('but there is a "stop" in Christoph', () => {
expect('Christoph').toMatch(/stop/);
});
Copy the code
Arrays and iterables
ToContain You can check whether an array or an iterable contains a particular item with toContain:
const shoppingList = [
'diapers'.'kleenex'.'trash bags'.'paper towels'.'beer',];test('the shopping list has beer on it', () => {
expect(shoppingList).toContain('beer');
expect(new Set(shoppingList)).toContain('beer');
});
Copy the code
exception
The particular function under test throws an error, and when it is called, use toThrow.
function compileAndroidCode() {
throw new ConfigError('you are using the wrong JDK');
}
test('compiling android goes as expected', () => {
expect(compileAndroidCode).toThrow();
expect(compileAndroidCode).toThrow(ConfigError);
// You can also use the exact error message or a regexp
expect(compileAndroidCode).toThrow('you are using the wrong JDK');
expect(compileAndroidCode).toThrow(/JDK/);
});
Copy the code
Test asynchronous code
The callback
test('the data is peanut butter'.done= > {function callback(data) {
expect(data).toBe('peanut butter');
done(a); } fetchData(callback); });Copy the code
Promises
test('the data is peanut butter', () = > {return fetchData().then(data => {
expect(data).toBe('peanut butter');
});
});
Copy the code
.resloves/.rejects
test('the data is peanut butter', () = > {return expect(fetchData()).resolves.toBe('peanut butter');
});
Copy the code
test('the fetch fails with an error', () = > {return expect(fetchData()).rejects.toMatch('error');
});
Copy the code
Async/Await
test('the data is peanut butter', async () => {
const data = await fetchData();
expect(data).toBe('peanut butter');
});
test('the fetch fails with an error', async () => {
expect.assertions(1);
try {
await fetchData();
} catch (e) {
expect(e).toMatch('error'); }});Copy the code
6 Mounting and Unmounting (Setup and Teardown)
It is used for the preparation that needs to be done before the tests are run when you write them, and for the cleanup that needs to be done after the tests are run.
Repeat the Settings for multiple tests
beforeEach(() => {
initializeCityDatabase();
});
afterEach(() => {
clearCityDatabase();
});
test('city database has Vienna', () => {
expect(isCity('Vienna')).toBeTruthy();
});
test('city database has San Juan', () => {
expect(isCity('San Juan')).toBeTruthy();
});
Copy the code
One-time setting
beforeAll(() => {
return initializeCityDatabase();
});
afterAll(() => {
return clearCityDatabase();
});
test('city database has Vienna', () => {
expect(isCity('Vienna')).toBeTruthy();
});
test('city database has San Juan', () => {
expect(isCity('San Juan')).toBeTruthy();
});
Copy the code
scope
By default, before and after blocks can be applied to each test in the file. In addition, tests can be grouped using describe blocks. When the before and after blocks are inside a Describe block, they are only applicable to tests within that describe block.
// Applies to all tests in this file
beforeEach(() => {
return initializeCityDatabase();
});
test('city database has Vienna', () => {
expect(isCity('Vienna')).toBeTruthy();
});
test('city database has San Juan', () => {
expect(isCity('San Juan')).toBeTruthy();
});
describe('matching cities to foods', () => {
// Applies only to tests in this describe block
beforeEach(() => {
return initializeFoodDatabase();
});
test('Vienna <3 sausage', () => {
expect(isValidCityFoodPair('Vienna'.'Wiener Schnitzel')).toBe(true);
});
test('San Juan <3 plantains', () => {
expect(isValidCityFoodPair('San Juan'.'Mofongo')).toBe(true);
});
});
Copy the code
MockFunction test (mockFunction)
Using mocks
function forEach(items, callback) {
for (let index = 0; index < items.length; index++) {
callback(items[index]);
}
}
const mockCallback = jest.fn(x => 42 + x);
forEach([0, 1], mockCallback);
// The mock function is called twice
expect(mockCallback.mock.calls.length).toBe(2);
// The first argument of the first call to the function was 0
expect(mockCallback.mock.calls[0][0]).toBe(0);
// The first argument of the second call to the function was 1
expect(mockCallback.mock.calls[1][0]).toBe(1);
// The return value of the first call to the function was 42
expect(mockCallback.mock.results[0].value).toBe(42);
Copy the code
Return value of the mock
const myMock = jest.fn();
console.log(myMock());
// > undefined
myMock
.mockReturnValueOnce(10)
.mockReturnValueOnce('x')
.mockReturnValue(true); console.log(myMock(), myMock(), myMock(), myMock()); / / > 10,'x'.true.true
Copy the code
7 Snapshot
You can use the snapshot function to create snapshots for components for comparison after adjustment
Use React’s Test Renderer and Jest’s snapshot feature to interact with components to get render results and generate snapshot files:
import React from 'react';
import Link from '.. /Link.react';
import renderer from 'react-test-renderer';
test('Link changes the class when hovered', () => {
const component = renderer.create(
<Link page="http://www.facebook.com">Facebook</Link>,
);
let tree = component.toJSON();
expect(tree).toMatchSnapshot();
// manually trigger the callback
tree.props.onMouseEnter();
// re-rendering
tree = component.toJSON();
expect(tree).toMatchSnapshot();
// manually trigger the callback
tree.props.onMouseLeave();
// re-rendering
tree = component.toJSON();
expect(tree).toMatchSnapshot();
});
Copy the code