Покрытие кода фермента Jest для функции обратного вызова из сторонней библиотеки

#reactjs #unit-testing #jestjs #enzyme

Вопрос:

У меня есть приложение React, и я использую Jest и Enzyme для модульного тестирования приложения. Я использую стороннюю библиотеку, которая возвращает функцию обратного вызова. Я изо всех сил пытаюсь завершить покрытие кода для кода внутри функции обратного вызова. Я пробовал издеваться и шпионить, но не смог использовать это в своем случае. Могу ли я получить какие-либо предложения о том, как подойти к этому?

Я создал образец кода для справки

https://codesandbox.io/s/xenodochial-kilby-obnmt

someLibrary.js

 export function getUserContext(callback) {
  var context = {
    userName: "TestUser",
    locale: "en-us"
  };
  callback(context);
}

 

MyApp.js

 
componentDidMount() {
    someLib.getUserContext((context) => {
      //want to cover these below lines
      //and some other codes inside this callback function
      this.setState({
        userName: context.userName,
        locale: context.locale
      });
      //some other code to cover
    });
  }

 

App.test.js — на данный момент

 describe("App Component", () => {
  const wrapper = shallow(<App />);
  //const layout = wrapper.instance();
  it("renders the component", () => {
    expect(wrapper.exists()).toBe(true);
  });
  it("sets the user context", () => {
    //not sure what to write here inorder to cover
  });
});
 

Ответ №1:

Используйте jest.spyOn(объект, имя метода), чтобы перезаписать исходный someLib.getUserContext() метод, который вы можете использовать jest.spyOn(object, methodName).mockImplementation(() => customImplementation) .

Так что вы можете получить функцию обратного customImplementation вызова в функции. Вызовите эту функцию обратного вызова с помощью поддельных данных.

Напр.

MyApp.jsx :

 import React, { Component } from 'react';
import * as someLib from './someLibrary';

export default class MyApp extends Component {
  constructor() {
    super();
    this.state = {
      userName: '',
      locale: '',
    };
  }
  componentDidMount() {
    someLib.getUserContext((context) => {
      this.setState({
        userName: context.userName,
        locale: context.locale,
      });
    });
  }

  render() {
    const { userName } = this.state;
    return <div>{userName}</div>;
  }
}
 

MyApp.test.jsx :

 import React from 'react';
import { shallow } from 'enzyme';
import App from './MyApp';
import * as someLib from './someLibrary';

describe('App Component', () => {
  it('renders the component', () => {
    const wrapper = shallow(<App />);
    expect(wrapper.exists()).toBe(true);
  });

  it('sets the user context', () => {
    const getUserContextSpy = jest.spyOn(someLib, 'getUserContext').mockImplementation((callback) => {
      callback({ userName: 'mocked user name', locale: 'zh_CN' });
    });
    const wrapper = shallow(<App />);
    expect(wrapper.text()).toEqual('mocked user name');
    expect(getUserContextSpy).toBeCalledWith(expect.any(Function));
  });
});
 

результат теста:

  PASS  examples/68102090/MyApp.test.jsx (12.251 s)
  App Component
    ✓ renders the component (6 ms)
    ✓ sets the user context (2 ms)

----------------|---------|----------|---------|---------|-------------------
File            | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------------|---------|----------|---------|---------|-------------------
All files       |     100 |      100 |     100 |     100 |                   
 MyApp.jsx      |     100 |      100 |     100 |     100 |                   
 someLibrary.js |     100 |      100 |     100 |     100 |                   
----------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        14.305 s