Please refer to:Github.com/antgod/reac…

Test the framework Jest

1. Start fast

Install the jest

npm install --save-dev jestCopy the code

Let’s start by writing a test function that takes two numeric arguments to add. First, create the sum.js file

function sum(a, b) {
  return a + b
}
module.exports = sumCopy the code

Then, create create sum.test.js, which contains our current test code.

const sum = require('./sum');

test('adds 1 + 2 to equal 3', () => {
  expect(sum(1, 2)).toBe(3);
});Copy the code

Then add the fragment to package.json

{
  "scripts": {
    "test": "jest"
  }
}Copy the code

Finally, run NPM test and type jest as follows

PASS./sum. Test. Js ✓ Adds 1 + 2 to equal 3 (5ms)Copy the code

You’ve just successfully written a JEST test!

This test case uses Expect and toBe for two tests with the same value. To learn more about jEST testing, see Using Matchers

Run from the command line

You can also do this directly from the command line by typing some empty arguments (NPM install jest -g).

Here’s how to run Jest on files matching my-test, using config.json as a configuration file and display a native OS notification after the run:

jest my-test --notify --config=config.jsonCopy the code

If you want to learn more about command-line execution, please refer to Jest CLI Options

Additional configuration

Using Babel: Install the babel-jest and regenerator-Runtime packages:

npm install --save-dev babel-jest regenerator-runtimeCopy the code

Note: if you are using NPM 3 or NPM 4, you do not need to specify the installationregenerator-runtime.

Add a. Babelrc file to your project root directory, for example, if you are using ES6 or react.js you need to use babel-preth-ES2015 and babel-preth-react:

{
  "presets": ["es2015", "react"]
}Copy the code

This way you’ll use all the syntax specified for ES6 and React.

Note: If you are using more Babel compilation configurations, please usebabel's env option, remember that Jest will automatically define node_env as a test.

Using webpack

Jest can be used to manage your assets, styles and edits within the project using Webpack. Webpack provides some special features compared to other tools. For more information, see the Webpack Guide

2. Use matches

Ordinary match

Jest uses Matchers to let you test values in different ways. You need to memorize a lot of different matchers. Only the most commonly used matchers are introduced here.

The simplest test for equality is exact equality:

test('two plus two is four', () => {
  expect(2 + 2).toBe(4);
});Copy the code

In the previous code, Expect (2 + 2) returns an “expect” object. Other than calling matchers, you don’t need to do much about expecting objects. In this code,.tobe (4) is a matcher. When jEST runs, it keeps track of all failed matchers, so it can print error messages precisely.

ToBe uses the === exact equals test. If you want to deeply test objects for equality, use toEqual instead.

test('object assignment', () => {
  const data = {one: 1};
  data['two'] = 2;
  expect(data).toEqual({one: 1, two: 2});
});Copy the code

ToEqual recursively finds whether each field comparison is equal.

You can use not to test the opposite of Matcher:

test('adding positive numbers is not zero', () => { for (let a = 1; a < 10; a++) { for (let b = 1; b < 10; b++) { expect(a + b).not.toBe(0); }}});Copy the code

Type judgment

Sometimes you need to distinguish between undefined,null, and false, but sometimes you don’t need to distinguish between them. Jest includes tools to clearly distinguish between them.

  • toBeNull matches only null
  • toBeUndefined matches only undefined
  • toBeDefined is the opposite of toBeUndefined
  • toBeTruthy matches anything that an if statement treats as true
  • toBeFalsy matches anything that an if statement treats as false

Here’s an example:

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

You can use these matchers to make exact matches.

digital

There are many ways to compare numbers

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 equivalent for numbers expect(value).toBe(4); expect(value).toEqual(4); });Copy the code

You can use toBeCloseTo for floating-point comparisons

Test ('adding floating point numbers', () => {const value = 0.1 + 0.2; Expect (value). Not. Place (0.3); // Float numbers are not directly equal expect(value).tobecloseto (0.3); // Float number comparison using closeTo method});Copy the code

string

You can use toMatch to test regular expressions to validate string strings

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

An array of

You can verify that the array contains a particular item

const shoppingList = [
  'diapers',
  'kleenex',
  'trash bags',
  'paper towels',
  'beer',
];

test('the shopping list has beer on it', () => {
  expect(shoppingList).toContain('beer');
});Copy the code

expression

You can use toThrow to check whether a function throws an exception

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

More and more

This is a just try, view the full list of Matchers renerence docs.

Once you have a working matcher, the next recommended step is to learn how jEST validates asynchronous code

3. Test asynchronous code

It is common for JS to run asynchronous code. Jest needs to know when the code test is complete before it can move to the next test. Jest can be handled in several ways.

Callbacks

The most common asynchrony is through callback functions.

For example, if you call fetchData(callback) to pull asynchronous data and call callback(data) at the end. The data you’re testing equals peanut buter.

By default, Jest completes the test as soon as it walks through the test code. This means the test cannot be carried out on schedule.

// Don't do this!
test('the data is peanut butter', () => {
  function callback(data) {
    expect(data).toBe('peanut butter');
  }

  fetchData(callback);
});Copy the code

The problem is that the test will end when fetchData ends, before the callback function.

To solve this problem, this is another form. Use the argument done instead of the no-parameter function. Jest will delay the test until the done callback completes.

test('the data is peanut butter', done => {
  function callback(data) {
    expect(data).toBe('peanut butter');
    done();
  }

  fetchData(callback);
});Copy the code

If done is never called, the test will fail.

Promises

If you use Promises, there is an easy way to handle asynchronous testing. Jest returns a Promise in your test code and waits for the Promise to resolve. If the Promise is Rejected, the test automatically fails.

For example, fetchData again, this time using a callback, returns a promise assuming reslove a string peanut butter. The test code is as follows:

test('the data is peanut butter', () => {
  return fetchData().then(data => {
    expect(data).toBe('peanut butter');
  });
});Copy the code

Make sure to return a Promise- if you omit the return, your test code will end before fetchData.

You can also use the trans-dominant keyword behind your Expect code, then Jest will convert the wait state to resolve. If the Promise is rejected, the test automatically fails.

test('the data is peanut butter', () => {
  return expect(fetchData()).resolves.toBe('peanut butter');
});Copy the code

Async/Await

If you use async/await, you can embed tests perfectly. Write an async test that passes just by using the async keyword in front of your matchers function. For example, fetchData, again, can be written as a test scheme

test('the data is peanut butter', async () => {
  await expect(fetchData()).resolves.toBe('peanut butter');
});Copy the code

In this case async/await is just a logical grammar candy for promises examples that are valid.

These forms are great, and you can mix them up in your code base or in a single file, and it just makes your testing easier.

Installation and Uninstallation

When you write a test, before you run the test, you need to do some initialization, before you do something that needs to be tested, and you need to do some closure, to do something that needs to be tested. Jest provides helper functions to handle these tasks.

Repeat initialization for multiple tests

If you have a lot of tests that have repetitive work, you can use beforeEach with afterEach.

For example, many of your tests need to call initializeCityDatabase() before they run and clearCityDatabase() after they finish. Here’s what you can do:

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

Similarly, if your initializeCityDatabase function returns a promise, you can use return to return the function.

beforeEach(() => {
  return initializeCityDatabase();
});Copy the code

One-time setting

If you have many tests that have repetitive work in common, and the repetitive work is run only once at the start and end of the test, you can use beforeAll vs. beforeAll.

Say you have a test that calls initializeCityDatabase() before it starts and clearCityDatabase() after it ends. Here’s what you can do:

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

The scope of

By default,before and after apply to each test of a file. If you only want certain tests to work, you can use the Describe block. Before and after only run inside the declaration block.

For example, we need to initialize not only the city, but also the food, and we can do different initializations for different tests.

// 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

advice

If you just want to test a test case, or cross over a test case, you can use Fit and Xit.

fit('this will be the only test that runs', () => {
  expect(true).toBe(false);
});

xit('this will be the only test that runs', () => {
  expect(true).toBe(false);
});

test('this test will not run', () => {
  expect('A').toBe('A');
});Copy the code