Skip to content
Advertisement

How to mock functions in the same module using Jest?

What’s the best way to correctly mock the following example?

The problem is that after import time, foo keeps the reference to the original unmocked bar.

module.js:

export function bar () {
    return 'bar';
}

export function foo () {
    return `I am foo. bar is ${bar()}`;
}

module.test.js:

import * as module from '../src/module';

describe('module', () => {
    let barSpy;

    beforeEach(() => {
        barSpy = jest.spyOn(
            module,
            'bar'
        ).mockImplementation(jest.fn());
    });


    afterEach(() => {
        barSpy.mockRestore();
    });

    it('foo', () => {
        console.log(jest.isMockFunction(module.bar)); // outputs true

        module.bar.mockReturnValue('fake bar');

        console.log(module.bar()); // outputs 'fake bar';

        expect(module.foo()).toEqual('I am foo. bar is fake bar');
        /**
         * does not work! we get the following:
         *
         *  Expected value to equal:
         *    "I am foo. bar is fake bar"
         *  Received:
         *    "I am foo. bar is bar"
         */
    });
});

I could change:

export function foo () {
    return `I am foo. bar is ${bar()}`;
}

to:

export function foo () {
    return `I am foo. bar is ${exports.bar()}`;
}

but this is pretty ugly in my opinion to do everywhere.

Advertisement

Answer

fwiw, the solution I settled on was to use dependency injection, by setting a default argument.

So I would change

export function bar () {
    return 'bar';
}

export function foo () {
    return `I am foo. bar is ${bar()}`;
}

to

export function bar () {
    return 'bar';
}

export function foo (_bar = bar) {
    return `I am foo. bar is ${_bar()}`;
}

This is not a breaking change to the API of my component, and I can easily override bar in my test by doing the following

import { foo, bar } from '../src/module';

describe('module', () => {
    it('foo', () => {
        const dummyBar = jest.fn().mockReturnValue('fake bar');
        expect(foo(dummyBar)).toEqual('I am foo. bar is fake bar');
    });
});

This has the benefit of leading to slightly nicer test code too 🙂

User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement