Anand
Anand

Reputation: 408

Jest Enzyme - Code Coverage for a callback function from third party Library

I have a React application, and I am using Jest and Enzyme for unit testing the application. I am using a third-party library that returns a callback function. I am struggling to complete code coverage for the code inside the callback function. I tried mocking and spyOn but couldn’t use it to my use case. Can I get any suggestions on how to approach this?

I have created a sample code for reference

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 - as of now

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

Upvotes: 0

Views: 2112

Answers (1)

Lin Du
Lin Du

Reputation: 102457

Use jest.spyOn(object, methodName) to overwrite the original someLib.getUserContext() method, you can use jest.spyOn(object, methodName).mockImplementation(() => customImplementation).

So that you can get the callback function in customImplementation function. Invoke this callback function with mocked data.

E.g.

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

test result:

 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

Upvotes: 3

Related Questions