Not sure how I can mock a side-effect function with Vitest in Typescript Node.js project, Vitest 0.33.0. Consider this simplified example:
// dummy.ts
export function parent(): string {
return `foo${child()}`;
}
export function child(): string {
console.log('calling actual child');
return 'bar';
}
// dummy.test.ts
describe('parent', () => {
it('should return foobar', () => {
const spy = vi.spyOn(dummy, 'child').mockReturnValueOnce('baz'); // also tried mockImplementationOnce
expect(dummy.parent()).eq('foobaz'); // fails, got foobar
expect(spy).toHaveBeenCalled(); // fails, actual child function is called
});
});
In this simplified example, actual child() function is called instead of the spy.
The following did not work either:
vi.mock('./dummy.js', async () => {
const actual = await vi.importActual<typeof import('./dummy.js')>('./dummy.js');
return {
...actual,
child: () => 'baz',
};
});
describe('parent', () => {
it('should return foobar', () => {
expect(dummy.parent()).eq('foobaz'); // fails, got foobar
});
});
Internal references inside the dummy.ts module cannot mocked.
A simple alternative would be to move your child function into a different module and mock that module separately.
// dummy-parent.ts
import { child } from './dummy-child';
export function parent(): string {
return `foo${child()}`;
}
// dummy-child.ts
export function child(): string {
console.log('calling actual child');
return 'bar';
}
import { dummy } from './dummy-parent';
vi.mock('./dummy-child', () => {
return {
child: () => 'baz',
};
});
describe('parent', () => {
it('should return foobar', () => {
expect(dummy.parent()).eq('foobaz');
});
});