-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Restore mock.module using mock.restore not work as expect #7823
Comments
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:
Then for each test suite declare
Then finally for example in the test
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
|
@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
And using the standard
|
I'm facing the same issue with mock.module, I also tried mocking the module with 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. |
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 |
Any updates on this? When i mock a common module it just breaks everything on other tests. |
I am facing the same issue! Tests break once I mock a function A in a unit test and then use the same function A in an integration test. I have separate files for the unit and integration tests. Mocking a module mocks globally, not on describe() level. I used mock.restore() and jest.restoreAllMocks(), but still nothing. Are there any updates? |
Seems the conversation has shifted a bit towards cross-test module mocking, here's a related issue on that: #12823 |
I ended up using @jpasquers' solution, from this earlier comment. It's unfortunate that it doesn't work out of the box, but the benefits I get from testing outweigh the additional complexity. I tweaked the solution to use a class, so it's all encapsulated in one place. It looks like this: /**
* Due to an issue with Bun (https://github.com/oven-sh/bun/issues/7823), we need to manually restore mocked modules
* after we're done. We do this by setting the mocked value to the original module.
*
* When setting up a test that will mock a module, the block should add this:
* const moduleMocker = new ModuleMocker()
*
* afterEach(() => {
* moduleMocker.clear()
* })
*
* When a test mocks a module, it should do it this way:
*
* await moduleMocker.mock('@/services/token.ts', () => ({
* getBucketToken: mock(() => {
* throw new Error('Unexpected error')
* })
* }))
*
*/
export class ModuleMocker {
private mocks: MockResult[] = []
async mock(modulePath: string, renderMocks: () => Record<string, any>) {
let original = {
...(await import(modulePath))
}
let mocks = renderMocks()
let result = {
...original,
...mocks
}
mock.module(modulePath, () => result)
this.mocks.push({
clear: () => {
mock.module(modulePath, () => original)
}
})
}
clear() {
this.mocks.forEach(mockResult => mockResult.clear())
this.mocks = []
}
} |
@jstlaurent the main issue with this approach is that you’re still importing the original module. In many cases mocking is used for the whole module in order to not import it itself or its dependencies. So right now it’s not possible to restore the module mock in Bun without importing the original module. Since Bun seems to spawn processes quite fast, I’ve come to love this approach: find . -name \"*.test.ts\" | xargs -I {} sh -c 'bun test {} || exit 255' It runs each test file in its own process sequentially and therefore doesn’t come across issues related to module mocking not restoring. It also stops the execution if one of the test files failed. It’s also possible to increase test run speed by running |
Unfortunately, none of the workarounds mentioned above resolved this blocker for me. While the implementation is pending, perhaps the documentation for Module mocks with |
It's really weird, for me I'm using 1.1.39 in both environments |
I agree with the conversation, but I wanted to share my way of doing this which doesn't require you calling the .clear method. import { mock } from "bun:test";
/**
*
* @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: string,
renderMocks: () => Record<string, any>,
) => {
let original = {
...(await import(modulePath)),
};
let mocks = renderMocks();
let result = {
...original,
...mocks,
};
mock.module(modulePath, () => result);
return {
[Symbol.dispose]: () => {
mock.module(modulePath, () => original);
},
};
}; This takes advantage of the Typescript using parseAndRollMock = await mockModule('../commands/utils/parseAndRoll', () => ({
parseAndRoll: jest.fn().mockReturnValue({ total: 15, details: [15] }),
})); No need to call clear or use before/after hooks for this. As soon as it leaves scope, it will call the reset methods defined in Symbol.dispose - credit due to @jpasquers since I borrowed it from there and just expanded on it. |
@notsoluckycharm that's a pretty neat fix for now 🙌 How would you make assertions like |
The only quick ( and very very dirty ) way I got around this was to...
Hope this helps |
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
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
The text was updated successfully, but these errors were encountered: