bun
bun copied to clipboard
Restore mock.module using mock.restore not work as expect
What version of Bun is running?
1.0.20+09d51486e
What platform is your computer?
Linux 6.5.0-14-generic x86_64 x86_64
What steps can reproduce the bug?
I create test file with this code inside
import axios from "axios"
import { describe, expect, it, mock } from "bun:test"
describe("topic", () => {
it("test case 1", async () => {
// before mock
expect((await axios("https://google.com/", { method: "GET" })).status).toBe(200)
// mock
mock.module("axios", () => ({
default: () => {
return {
status: 500
}
}
}));
// after mock
expect((await axios("https://google.com/", { method: "GET" })).status).toBe(500)
// restore mock & test again
mock.restore()
expect((await axios("https://google.com/", { method: "GET" })).status).toBe(200)
})
})
What is the expected behavior?
I expect this test case must pass
What do you see instead?
// before mock expect((await axios("https://google.com/", { method: "GET" })).status).toBe(200) -> this pass
// after mock expect((await axios("https://google.com/", { method: "GET" })).status).toBe(500) -> this pass
// restore mock & test again expect((await axios("https://google.com/", { method: "GET" })).status).toBe(200) -> this fail (value is 500)
Additional information
This one work like what I expected but I think it is not good solution
import axios from "axios"
import path from "path"
import { describe, expect, it, mock } from "bun:test"
describe("topic", () => {
it("test case 1", async () => {
// before mock
expect((await axios("https://google.com/", { method: "GET" })).status).toBe(200)
// mock
const axiosBak = axios <-- add this
mock.module("axios", () => ({
default: () => {
return {
status: 500
}
}
}));
// after mock
expect((await axios("https://google.com/", { method: "GET" })).status).toBe(500)
// restore mock & test again
mock.restore()
mock.module("axios", () => axiosBak) <-- add this
expect((await axios("https://google.com/", { method: "GET" })).status).toBe(200)
})
})
Not only is the restore not working, modules that are mocked will conflict with other testfiles that also need to mock the given module. Not sure what the path forward is for this but its a major blocker
This is the workaround I have been using in the meantime:
import { mock } from "bun:test";
export type MockResult = {
clear: () => void;
};
/**
*
* @param modulePath - the path starting from this files' path.
* @param renderMocks - function to generate mocks (by their named or default exports)
* @returns an object
*/
export const mockModule = async (
modulePath,
renderMocks: () => Record<string, any>,
): Promise<MockResult> => {
let original = {
...(await import(modulePath)),
};
let mocks = renderMocks();
let result = {
...original,
...mocks,
};
mock.module(modulePath, () => result);
return {
clear: () => {
mock.module(modulePath, () => original);
},
};
};
Then for each test suite declare
let mocks: MockResult[] = [];
afterEach(() => {
mocks.forEach((mockResult) => mockResult.clear());
mocks = [];
});
Then finally for example in the test
mocks.push(
await mockModule("./utils/aws", () => ({
ensureAwsSsoSession: jest.fn(() => Promise.resolve()),
})),
);
I can't stress enough that this is a hacky unstable solution that I am only leveraging because our unit tests would be dead in the water otherwise. Hopefully this helps others until a permanent solution comes through 👍
As a temporary workaround, you can try jest.restoreAllMocks
import {jest} from 'bun:test';
jest.restoreAllMocks();
@Jarred-Sumner hmm unfortunately that didn't resolve it for me, or at the very least the way I used it wasn't working. I leveraged it as an afterEach
, i.e.
afterEach(() => jest.restoreAllMocks());
And using the standard mock.module
(example usage):
mock.module("./utils/aws", () => ({
ensureAwsSsoSession: jest.fn(() => Promise.resolve()),
}));
I'm facing the same issue with mock.module, I also tried mocking the module with require.resolve('path')
in order to see if that would create another mock for the same module but with no luck.
Ideally the mock.module should only be valid inside that test, other tests could mock the same module with other values like jest. Global mocks should be added in the preload file IMHO.
As a temporary workaround, you can try
jest.restoreAllMocks
import {jest} from 'bun:test'; jest.restoreAllMocks();
This doesn't work. Any other workarounds other than instantiating a new bun process for every test file?
Since #10210 is closed now, we really need the fix for mock.restore
or jest.restoreAllMocks
… Right now it’s really hard to use bun’s test runner on more or less big project with module mocking without spawning separate process for every test file.