Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vitest mock modules function in only one test and use the actual function in others

The following is an abstraction of my problem and thus does not make too much sense:

Given I have a simple utility callMethodIf that's returning the return of another imported method (blackbox).

~~/utils/call-method-if.js:

import { blackbox } from '~~/utils/blackbox';

export const callMethodIf = (condition) => {
    return blackbox(condition);
};

~~/utils/blackbox.js:

export const blackbox = (condition) => {
    return { called: condition };
};

How would I run one test case which calls the actual implementation of blackbox() and another one where I mock the return value of blackbox()?

I tried to do it that way:

import { describe, expect, it } from 'vitest';

import { callMethodIf } from '~~/utils/call-method-if';

describe('Call method if', () => {
    it('returns "called: true" if condition is true', () => {
        const result = callMethodIf(true);
        expect(result).toEqual({ called: true });
    });

    it('returns mocked blackbox return object', () => {
        vi.mock('~~/utils/blackbox', () => ({
            blackbox: vi.fn().mockReturnValue({ mock: true })
        }));
        const result = callMethodIf(false);
        expect(result).toEqual({ mock: true });
    });
});

Both tests work if I run only one of them, but they don't work when combined.

Running vi.clearAllMocks() or vi.resetAllMocks() don't help.

Defining a global mock and overwriting it in my first test doesn't work either:

import { describe, expect, it } from 'vitest';

import { callMethodIf } from '~~/utils/call-method-if';

vi.mock('~~/utils/blackbox', () => ({
    blackbox: vi.fn().mockReturnValue({ mock: true })
}));

describe('Call method if', () => {
    it('returns "called: true" if condition is true', () => {
        vi.mock('~~/utils/blackbox', async () => ({
            blackbox: (await vi.importActual('~~/utils/blackbox')).blackbox
        }));
        const result = callMethodIf(true);
        expect(result).toEqual({ called: true });
    });

    it('returns mocked blackbox return object', () => {
        const result = callMethodIf(false);
        expect(result).toEqual({ mock: true });
    });
});
like image 564
floriankapaun Avatar asked Dec 15 '25 04:12

floriankapaun


1 Answers

Okay, after lots of trial and error I finally got it to work. I can't really tell why my previous tries do not work tough.

Working solution:

import { describe, expect, it } from 'vitest';

import { callMethodIf } from '~~/utils/call-method-if';

vi.mock('~~/utils/blackbox');

describe('Call method if', () => {
    it('returns "called: true" if condition is true', async () => {
        const blackbox = await import('~~/utils/blackbox');
        blackbox.blackbox = (await vi.importActual('~~/utils/blackbox')).blackbox;
        const result = callMethodIf(true);
        expect(result).toEqual({ called: true });
    });

    it('returns mocked blackbox return object', async () => {
        const blackbox = await import('~~/utils/blackbox');
        blackbox.blackbox = vi.fn().mockReturnValue({ mock: true });
        const result = callMethodIf(false);
        expect(result).toEqual({ mock: true });
    });
});

When using TypeScript consider typing the importActual() return like that:

blackbox.blackbox = (await vi.importActual<typeof import('~~/utils/blackbox')>('~~/utils/blackbox')).blackbox;
like image 109
floriankapaun Avatar answered Dec 16 '25 20:12

floriankapaun



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!