Skip to content

Jest Unit Testing function that calls a second one that returns a promise

Edited Question with vazsonyidl suggestions applied

I have to write unit tests for a function similar to this one:

import {External} from 'ExternalModule';

async functionA(){
    this.functionB().then((data) => {
        External.functionC(options);
        console.log("Reached1");

    }).catch((data) => {
        const { OnError = "" } = data || {}
        if(OnError) {
            External.functionC(anotherOptions);
            console.log("Reached2");
        }
    })
}

functionB() {
    return new Promise(() => {
    });
  }

As functionC belongs to another module, I placed a mock of it in the _mocks_folder:

//_mocks_/ExternalModule.ts

export var External: ExternalClass = {
  functionC(){}
}

class ExternalClass{
  constructor(){};
  functionC(){};
}

I have mocked functionB in two diferent ways for testing the then and the catch :

it("should test then block", () => {
        functionB = jest.fn(() => {return Promise.resolve()});

        const functionSpy = jest.spyOn(ExternalModule.External, 'functionC');
        void functionA().then(() => {
          expect(functionSpy).not.toHaveBeenCalled();
        });
    })

it("should test catch block", () => {
        const err = { OnError: "Error" };
        functionB = jest.fn(() => {return Promise.reject(err)});

        const functionSpy = jest.spyOn(ExternalModule.External, 'functionC');
        void functionA().then(() => {
          expect(functionSpy).not.toHaveBeenCalled();
        });
    })

What I am trying to do is expect that functionC was called and called with the correct params, but the test is always passing even if I test if functionC was not called.

What am I doing wrong?

Answer

Jest does not wait for the async code to complete before doing assertions.

You can use the following function:

const waitForPromises = () => new Promise(setImmediate);

to force Jest to wait for promises to complete before continuing like so:

it("does something", async () => {
  promiseCall();
  await waitForPromises();
  expect(something).toBe(something)
});