Basic introduction

Hook function

  • Scope and the order in which hooks are executed under different scopes
  • Describe and test blocks execution order. Finish the describe layer code and then execute test
  • You can use test.only(“,()=>{}) to execute only one test case

Global setting

Jest contains globally-defined objects and functions that can be used directly.

  • test()
  • describe()
  • beforeEach()

matcher

  • toBe() toEqual() toStrictEqual()
test.only('object equal'.() = >{
  let obj1 = {
    name:'jack'.age:12.friends: ['rose']}let obj2 = {
    name:'jack'.age:12.friends: ['rose'].address:undefined
  }
  let obj3 = obj1
  expect(obj1).toEqual(obj2) // key-value compares key-value pairs
  expect(obj1).toStrictEqual(obj2) // Compare keys and values hasOwnProperty()
  expect(obj1).toBe(obj3)  Object. Is (obj1,obj2)
})
Copy the code

Timer simulation

jest.useFakeTimers(‘legacy’)

  • usetoHaveBeenLastCalledWithDetermines the incoming argument to the last call to setTimeout()
test('call'.() = >{
  let fn = jest.fn(() = >{})
  fn('foo')
  //fn('foo1')
  expect(fn).toHaveBeenLastCalledWith('foo') // The last call to fn takes an argument of foo
}) 
Copy the code
jest.useFakeTimers(); // fake timers
// The last call to timer is passed as an argument
expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), 1000);
Copy the code
  • expect.any(constructor)

As an instance of the constructor, can match any instance of the constructor.

test('call'.() = >{
  let a = 1
  expect(a).toEqual(expect.any(Number)) // true
}) 

test('call'.() = >{
  let fn = jest.fn(() = >{})
  fn(1)
  expect(fn).toBeCalledWith(expect.any(Number))})Copy the code
  • How can I tell if a function is executed instead of being usedexpect.any(Function)
const handle = timerGame(fn);
expect(setTimeout).toHaveBeenLastCalledWith(handle, 1000);
Copy the code
  • jest.advanceTimersByTime(1000)Fast forward
// The difference between the two is to pass a setTimeout parameter
expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), 1000);
// This is to determine whether the callback we passed is executed
expect(callback).toBeCalled();
Copy the code

jest.useFakeTimers(‘modern’)

Jest. UseFakeTimers (‘ modern ‘) and jest setSystemTime (number | Date), is used to simulate the Date

mock

A mock function

Why mock functions?

  • Capture function callstoHaveBeenCalledMock functions must be used
  • Sets the return value of the function
  • Change the internal implementation of a function
describe('mock function'.() = >{
  test.only('mock.fn'.() = >{
    let mockFn = jest.fn((arg) = >arg + ' is passed')
    let result = curry(mockFn)('foo')
    expect(mockFn).toBeCalled()
    expect(mockFn).toHaveBeenCalled();
    expect(mockFn).toHaveBeenCalledTimes(1);
    expect(mockFn).toHaveBeenCalledWith("foo");
    expect(result).toBe('foo is passed')})})Copy the code

The mock module

See WXB – manager/utils. Test. Js test commonUploadPictureOrFile method, rely on a lot of other configuration, and we care about it depends on the configuration, only consider the input leads to different output function.

Create a __mocks__ folder to place the manually emulated modules. The search priority is higher than node_modules

// __mocks__/axios
const get = url= > {
  return Promise.resolve({ data: { title: 'delectus aut autem'}}); };const post = url= >{
  if(url === 'https://wxb-manger/userinfo') {return Promise.resolve({
      data: {userInfo: {isAdmin:true.expired:false}})}}exports.get = get;
exports.post = post
Copy the code
// __mocks__/lodash
module.exports = {
  chunk(arr,len) {
    let length = arr.length 
    let i = 0
    let store = []
    while(i<length){
      store.push(arr.slice(i,i+len))
      i+=len
    }
    return store
  }
}
Copy the code

Asynchronous code testing

  test("callback was't called".() = >{
    const callback = data= >{
      expect(data).toBe('suc') // The assertion will not be executed
    }
    asyncHandle(callback)
  })
Copy the code
  1. Use the done() callback provided by test
  test('callback called'.(done) = >{
    const callback = data= >{
      expect(data).toBe('suc')
      done()
    }
    asyncHandle(callback)
  })
Copy the code
  1. Perform assertions on promise.then()
  test('called in promise.then'.() = >{
    asyncHandle().then(res= >{
      expect(res).toBe('suc')})})Copy the code
  1. Use async functions
  test('async'.async() = > {let res = await asyncHandle()
    expect(res).toBe('suc')})Copy the code

engineering

Babel configuration

If you need to be compatible with the previous Babel configuration in an existing project, Jest will set process.env.node_env to ‘test’ to determine whether the environment is compatible with the Babel configuration required by jest and the Babel configuration of the project.

// babel.config.js
module.exports = api= > {
  const isTest = api.env('test');
  const jestConfig = { / *... * /}
  const projectConfig = { / *... * /}
  return isTest ? jestConfig : projectConfig 
};
Copy the code

Jest configuration file

  1. jest --init
  2. Config jest
module.exports = {
  moduleFileExtensions: [
    "js"."ts"."json"."vue"].// Use the new function
  transform:  {
    "\\.ts$": ['ts-jest']."\\.js$": ['babel-jest', {rootMode: "upward"}].// Use 'vue-jest' to process '*. Vue' files
    ".*\\.(vue)$": "vue-jest"."^.+\\.tsx? $": "ts-jest"
  },
  transformIgnorePatterns: [ // Ignore file translation in this path
    "/node_modules/"."\\.pnp\\.[^\\/]+$"].testPathIgnorePatterns: [ // Ignore the test files in this path
    "/node_modules/"].clearMocks: true.// Each test clears the mock directly
  moduleNameMapper: {/ / map mapping
    "^ @ / (. *) $":"<rootDir>/src/$1"."^assets/(.*)$": [
      "<rootDir>/images/$1"."<rootDir>/photos/$1"."<rootDir>/recipes/$1"]}}Copy the code

jest CLI

  • jest --watchListening for file changes
  • jest -o async.test.js example.test.jsRun only the specified template

Debug

Configuration of Launch and Attach modes

Vscode debug configuration

Better Tests

  • TDD(Test Driven Development) defines the points we need to Test from the Test cases listed in QA before Development (the process of combing the requirements document).
  • Pay attention to the design of test granularity.
    • For modules that change frequently, we can write tests based on function points, so that the function does not change without internal implementation.
    • Functions and classes can test detailed function points.
  • Ensure the reliability of the test
    • Independent of external conditions, ensure that one input corresponds to one output.
    • Include fail and success.
    • Tests are not interdependent states.
    • Avoid mock methods, class private methods, and attributes.
  • Test maintainability
    • Extract the duplicate code into the preceding constructor

    • Use more matchers to improve readability

    • Keep the logic of your tests simple and granular. Avoid code changes that modify too many test cases

The complete code

The source code