vue jest unit test

1. Rendering: mount and shallowMount

1.1 mount and shallowMount

vue-test-utils provides two ways to render, or mount, a component — mount and shallowMount. A component that uses either of these two methods will return a wrapper, which is an object containing the Vue component, supplemented by some methods useful for testing.

1.2 The difference between mount and shallowMount

  • mount: will render subcomponents
  • shallowMount: The subcomponent will be loaded, and the component will not be affected by the behavior properties of the subcomponent

Two, beforeEach and beforeAll

2.1 Repeat setup for multiple tests

If you have some work that you want to repeat setup for multiple tests, you can use beforeEach and afterEach.
There is such a requirement that we need to call the method initializeCityDatabase() before each test, and call the method clearCityDatabase() after each test

beforeEach(() => {
  initializeCityDatabase();
});

afterEach(() => {
  clearCityDatabase();
});

test('city database has Vienna', () => {
  expect(isCity('Vienna')).toBeTruthy();
});

test('city database has San Juan', () => {
  expect(isCity('San Juan')).toBeTruthy();
});

2.2 One-time setup

In some cases, you only need to do the setting once at the beginning of the file. While this setup behaves asynchronously, you're unlikely to handle it in one line. Jest provides beforeAll and afterAll to handle this situation.

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();
});

2.3 Scope

By default, before and after blocks apply to every test in the file. In addition, a certain block in the test can be grouped by the describe block. When the before and after blocks are inside the describe block, it is only applicable to the test inside the describe block.

3. Matcher

3.1 Matcher Basics

  • toBe: determine whether it is equal
  • toBeNull: determine whether it is null
  • toBeUndefined: determine whether it is undefined
  • toBeDefined: the opposite of the above
  • toBeNaN: determine whether it is NaN
  • toBeTruthy: determine whether it is true
  • toBeFalsy: determine whether it is false
  • toContain: for arrays, check whether it contains
  • toHaveLength: for arrays, to detect the length of the array
  • toEqual: for objects, to check whether they are equal
  • toStrictEqual: the function is similar to toEqual, but more strict
  • toThrow: exception match
  • toBeCalled: Whether the function is called
  • toHaveBeenCalledTimes: how many times the function was called
  • expect.assertions(n): Indicates that the expect code must be executed n times before execution is complete

3.2 Use of matchers

describe('Test', () => {
  // Judging whether it is equal
  expect(2 + 2).toBe(4);
  // Determine whether it is null
  expect(null).toBeNull();
  // Determine whether it is undefined
  expect(undefined).toBeUndefined();
  let a = 1;
  // Determine if it is not undefined
  expect(a).toBeDefined();
  a = 'ada';
  // Determine whether it is NaN
  expect(a).toBeNaN();
  a = true;
  // Determine whether it is true
  expect(a).toBeTruthy();
  a = false;
  // Determine whether it is false
  expect(a).toBeFalsy();
  a = [1, 2, 3];
  // For arrays, check whether it contains
  expect(a).toContain(2);
  // For arrays, check the length of the array
  expect(a).toHaveLength(3);
  a = { a: 1 };
  // For objects, check for equality
  expect(a).toEqual({ a: 1 });
  // Functionally similar to toEqual, but stricter
  expect(a).toStrictEqual({ a: 1 });
  a = () => 1;
  // Whether the function is called
  expect(a).toBeCalled();
  // How many times the function is called
  expect(a).toHaveBeenCalledTimes(1);
});

3.3 The difference between toStrictEqual and toEqual

toStrictEqual functions similarly to toEqual, but is stricter. mainly reflects in:

  • Even if two objects have the same members but different prototype chains they are different.
  • undefined is not compatible with undefined.

3.4 expect.assertions(number)

Verify that a certain number of assertions are called during the test, this is often useful when testing asynchronous code, in order to ensure that assertions in callbacks are actually called.
Suppose we have a function doAsync which receives two callbacks callback1 and callback2 which will be called asynchronously in an unknown order.

test('doAsync calls both callbacks', () => {
  expect.assertions(2);
  function callback1(data) {
    expect(data).toBeTruthy();
  }
  function callback2(data) {
    expect(data).toBeTruthy();
  }
 
  doAsync(callback1, callback2);
});

4. Wrapper

  • Wrapper: A Wrapper is a method that includes a mounted component or vnode, and a method for testing that component or vnode.
  • Wrapper.vm: This is the Vue instance. You can access all methods and properties of an instance through wrapper.vm.
  • Wrapper.classes: returns whether to have the dom of the class or an array of class names.
  • Wrapper.find: Returns the first dom that meets the condition.
  • Wrapper.findAll: Returns all dom s that meet the conditions.
  • Wrapper.html: returns the html string.
  • Wrapper.text: returns the content string.
  • Wrapper.setData: Set the initial data of the component.
  • Wrapper.setProps: Set the initial props data of the component.
  • Wrapper.trigger: used to trigger events.

5. Simulation function

5.1 Simulation functions

  • jest.fn(): Generate a mock function that can be used to replace the third-party function used in the source code
  • mockFn.mockImplementation(fn): accepts a function which should be used as the implementation for the mock
  • mockFn.mockImplementationOnce(fn): accepts a function that will be used as the mock implementation for one call to the mocked function
  • mockFn.mockReturnValue(value): Used to define the default value returned for each call of the specified function
  • mockFn.mockReturnValueOnce(value):
  • mockFn.mockResolvedValue(value): Used to define the default value returned for each call of the specified asynchronous function
  • mockFn.mockResolvedValueOnce(value):

5.2 mockImplementationOnce()

const myMockFn = jest.fn(() => 'default')
  .mockImplementationOnce(() => 'first call')
  .mockImplementationOnce(() => 'second call');

console.log(myMockFn(), myMockFn(), myMockFn(), myMockFn());
// 'first call', 'second call', 'default', 'default'

6. mock system

6.1 Commonly used mock methods

In unit testing, many times you don’t want to change the original code logic because you pass the test, or you just want to simply obtain a piece of data to test smoothly. At this time, you need to manually mock the data. Jest provides a powerful mock system. In the global Jest object, there are three commonly used mock methods:

  • jest.fn(implementation): returns a mock function, where implementation is optional and represents the mock implementation of the mock function.
  • jest.mock(moduleName, factory, options): used to mock some modules or files.
  • jest.spyOn(object, methodName): returns a mock function, which is similar to jest.fn, but can track the calling information of object[methodName]. If object[methodName] is not a function, an error will be reported.

6.2 jest.fn()

Jest.fn() is the easiest way to create a Mock function. If the internal implementation of the function is not defined, jest.fn() will return undefined as the return value.
The Mock function created by Jest.fn() can also set the return value, define the internal implementation or return the Promise object.

6.3 jest.mock()

6.3.1 Automatic mocking with jest.mock

jest.mock('./utils.ts') automatically returns a mock that can be used to monitor calls to the class constructor and all its methods.

6.3.2 jest.mock() mock module directly in the unit test

jest.mock(path, moduleFactory) accepts a module factory argument. A module factory is a function that returns a mock. In order to mock a constructor, a module factory must return a constructor. In other words, a module factory must be a function returning a function - a higher order function (HOF).

jest.mock('fs', () => ({
    readFileSync: jest.fn()
}))

6.3.3 Create a directory __mocks__ near the module directory that needs to be mocked

6.3.4 Examples

// utils.js
export default {
  add(a, b) {
    console.log('---------------util.js add----------');
    return a + b;
  }
};
// mock.js
import utils from './utils';
export default {
  test() {
    console.log('---------------mock.js test----------');
    return utils.add(1, 2);
  }
};
// mock.test.js
import m from './mock';
import utils from './utils';
jest.mock('./utils.js');
it('mock entire fetch.js module', () => {
  m.test();
  expect(utils.add).toBeCalledTimes(1);
});

6.4 jest.spyOn()

The jest.spyOn() method also creates a mock function, but the mock function can not only capture the calling of the function, but also execute the spyed function normally. In fact, jest.spyOn() is syntactic sugar for jest.fn(), which creates a mock function with the same internal code as the spyed function.

import m from './mock';
import utils from './utils';
it('mock entire fetch.js module', () => {
  const y = jest.spyOn(utils, 'add');
  m.test();
  expect(y).toBeCalledTimes(1);
});
  • The add method is not actually executed when jest.mock() is used, and add will be executed when jest.spyOn() is used

Seven, wrapper.emitted()

Each mounted wrapper will automatically log all fired events through the Vue instance behind it. You can retrieve these event records with the wrapper.emitted() method.

wrapper.vm.$emit('foo')
wrapper.vm.$emit('foo', 123)
/*
`wrapper.emitted()` returns the following objects:
{
  foo: [[], [123]]
}
*/

// Assert that the event has been triggered
expect(wrapper.emitted().foo).toBeTruthy()

// Number of Assertion Events
expect(wrapper.emitted().foo.length).toBe(2)

// Valid data for the assertion event
expect(wrapper.emitted().foo[1]).toEqual([123])

You can also call wrapper.emittedByOrder() to get an array of events sorted by firing order.

refer to

Tags: Javascript Vue.js unit testing

Posted by Attila on Thu, 22 Dec 2022 23:51:03 +0530