Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spying on an imported function that calls another function in Jest

I'm trying to spy on a function that's called by another function, both of which reside in an external file and imported.

Funcs.spec.js:

import * as Funcs from './Funcs'
describe('funcA', () => {
    it('calls funcB', () => {
        jest.spyOn(Funcs, 'funcB')
        Funcs.funcA()
        expect(Funcs.funcB).toHaveBeenCalled()
    }
}

Funcs.js:

export const funcA = () => {
    funcB()
}
export const funcB = () => {}

For some reason the spy is not respected in scope of Funcs.js. What can I do to spy on funcB so I know funcA has called it?

like image 222
Dean James Avatar asked Jun 14 '18 09:06

Dean James


2 Answers

Only methods can be spied. There is no way to spy on funcB if it's called directly like funcB() within same module.

In order for exported function to be spied or mocked, funcA and funcB should reside in different modules.

This allows to spy on funcB in transpiled ES module (module object is read-only in native ESM):

import { funcB } from './b';

export const funcA = () => {
    funcB()
}

Due to that module imports are representations of modules, this is transpiled to:

var _b = require('./b');

var funcA = exports.funcA = function funcA() {
    (0, _b.funcB)();
};

Where funcB method is tied to _b module object, so it's possible to spy on it.

like image 180
Estus Flask Avatar answered Sep 28 '22 12:09

Estus Flask


The problem you describe is referenced on a jest issue.

A possible solution to your problem (if you want to keep the functions inside the same file) is to use CommonJS, consider the following example:

fns.js

exports.funcA = () => {
  exports.funcB();
};
exports.funcB = () => {};

fns.spec.js

const fns = require("./fns");

describe("funcA", () => {
  it("calls funcB", () => {
    fns.funcB = jest.fn();
    fns.funcA();
    expect(fns.funcB).toBeCalled();
  });
});
like image 24
a--m Avatar answered Sep 28 '22 13:09

a--m