ebiv
ebiv

Reputation: 325

Jest test the resolve reject callback

I have this function which calls an util function for api calls. The util function resolves or rejects based on the api result.

Now, I need to unit test the callback functions which has the following structure.

`theClassMethod : () => {
    return utilMethod().then(
    result => { this.functionOne() //Test this function is called }, 
    error => { this.functionTwo() //Test this function is called }
    )
}`

The util method returns a promise like below:

utilFunc = (data :string) :Promise<ResultData[]> => {
    return new Promise(async (resolve, reject) => {
        try{
            resolve(data)
        }catch{
            reject(error)
        }
    }) 
}

https://codesandbox.io/s/vjnwy1zw75?fontsize=14

What I tried:

  1. Mocked the util method to resolve/reject. Call the class method and do assertions. It doesn't work and the test always passes as a false positive.

I have spend much time looking for a similar problem. Most questions here are to test the code like:

theClassMethod : () => { utilMethod.then().catch()}

The problem I am trying to solve is to test the resolve, reject callbacks in the then block then(function1, function2). That the code block inside function1 has to be tested that it calls some intended functions.

Upvotes: 2

Views: 4427

Answers (1)

Brian Adams
Brian Adams

Reputation: 45810

The approach you are describing (mocking utilMethod to resolve/reject) is a good approach.

Here is a simple working example to get you started:

Note: I implemented functionOne as a class method and functionTwo as an instance property to show how to spy on both types of functions:

util.js

export const utilMethod = async () => 'original';

code.js

import { utilMethod } from './util';

export class MyClass {
  functionOne() { }  // <= class method
  functionTwo = () => { }  // <= instance property
  theClassMethod() {
    return utilMethod().then(
      result => { this.functionOne() },
      error => { this.functionTwo() }
    );
  }
}

code.test.js

import { MyClass } from './code';
import * as util from './util';

test('theClassMethod', async () => {
  const mock = jest.spyOn(util, 'utilMethod');

  const instance = new MyClass();

  const functionOneSpy = jest.spyOn(MyClass.prototype, 'functionOne');  // <= class method
  const functionTwoSpy = jest.spyOn(instance, 'functionTwo');  // <= instance property

  mock.mockResolvedValue('mocked value');  // <= mock it to resolve
  await instance.theClassMethod();
  expect(functionOneSpy).toHaveBeenCalled();  // Success!

  mock.mockRejectedValue(new Error('something bad happened'));  // <= mock it to reject
  await instance.theClassMethod();
  expect(functionTwoSpy).toHaveBeenCalled();  // Success!
});

Upvotes: 3

Related Questions