`vi.mock()` doesn't work if module is already imported
Describe the bug
When I run a test using the following mock code:
import { vi } from "vitest";
vi.mock("./random", () => {
return {
randomString: () => "__MOCK__",
};
});
Vitest in browser mode isn't functioning properly.
I found a section in the documentation discussing Spying on browser mode, but I'm still unsure how to resolve my use case after reading it.
Reproduction
Git repo: https://github.com/issueset/vitest-mock-browser-mode
Reproduction steps:
❯ git clone https://github.com/issueset/vitest-mock-browser-mode
❯ cd vitest-mock-browser-mode
❯ pnpm install
❯ pnpm run test
> @vitest/example-test@ test /private/tmp/vitest-mock-browser-mode
> vitest run
RUN v3.2.4 /private/tmp/vitest-mock-browser-mode
✓ src/without-mock.test.ts (1 test) 1ms
✓ src/with-mock.test.ts (1 test) 1ms
❯ pnpm run test:browser
> @vitest/example-test@ test:browser /private/tmp/vitest-mock-browser-mode
> vitest run --config=vitest.browser.config.ts
RUN v3.2.4 /private/tmp/vitest-mock-browser-mode
Port 63315 is in use, trying another one...
❯ chromium src/with-mock.test.ts (1 test | 1 failed) 3ms
× randomString 2ms
→ expected '43587017925835303' to be '__MOCK__' // Object.is equality
✓ chromium src/without-mock.test.ts (1 test) 0ms
FAIL chromium src/with-mock.test.ts > randomString
AssertionError: expected '43587017925835303' to be '__MOCK__' // Object.is equality
System Info
System:
OS: macOS 15.5
CPU: (8) arm64 Apple M2
Memory: 66.75 MB / 24.00 GB
Shell: 5.9 - /bin/zsh
Binaries:
Node: 20.19.3 - /opt/homebrew/opt/node@20/bin/node
Yarn: 1.22.22 - /opt/homebrew/bin/yarn
npm: 10.8.2 - /opt/homebrew/opt/node@20/bin/npm
pnpm: 10.11.0 - /opt/homebrew/bin/pnpm
bun: 1.2.15 - /opt/homebrew/bin/bun
Browsers:
Chrome: 137.0.7151.122
Safari: 18.5
Safari Technology Preview: 26.0
npmPackages:
@vitest/browser: ^3.2.4 => 3.2.4
playwright: ^1.53.2 => 1.53.2
vite: ^7.0.0 => 7.0.0
vitest: ^3.2.4 => 3.2.4
Used Package Manager
npm
Validations
- [x] Follow our Code of Conduct
- [x] Read the Contributing Guidelines.
- [x] Read the docs.
- [x] Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.
- [x] Check that this is a concrete bug. For Q&A open a GitHub Discussion or join our Discord Chat Server.
- [x] The provided reproduction is a minimal reproducible example of the bug.
Does it work if you move the vi.mock inside the test file?
- import "./random.mock";
import { randomString } from "./random";
- import { test, expect } from "vitest";
+ import { vi, test, expect } from "vitest";
+ vi.mock("./random", () => {
+ return {
+ randomString: () => "__MOCK__",
+ };
+ });
test("randomString", () => {
expect(randomString()).toBe("__MOCK__");
});
Does it work if you move the
vi.mockinside the test file?
Yes, it works! I'm not quite sure why, though. Is this the expected behavior?
Does it work if you move the
vi.mockinside the test file?Yes, it works! I'm not quite sure why, though. Is this the expected behavior?
Yes, the mock needs to be registered before the browser starts fetching modules. If you only have static imports, the browser will always fetch them in parallel. vi.mock on the other hand makes it so every import becomes dynamic and we load files one by one.
If you only have static imports, the browser will always fetch them in parallel.
vi.mockon the other hand makes it so every import becomes dynamic and we load files one by one. Thanks for your response! If I change my imports to dynamic imports, as shown below, then the browser mode works perfectly!
-import "./random.mock";
-import { randomString } from "./random";
import { test, expect } from "vitest";
+await import("./random.mock");
+const { randomString } = await import("./random");
test("randomString", () => {
expect(randomString()).toBe("__MOCK__");
});
Do you think it's reasonable to convert all imports to dynamic in a test file when using browser mode, even if the test file doesn't directly include vi.mock?
Do you think it's reasonable to convert all imports to dynamic in a test file when using browser mode, even if the test file doesn't directly include
vi.mock?
Vitest does this automatically if there is vi.mock or vi.hoisted in the file. I don't think it's very ergonomic to do it manually.
I'm running into the same issue. I want to mock a module for all tests, so adding the mock to every test file and also forcing every other developer in the team to do that is not a feasible solution. Is there another option?
I'm running into the same issue. I want to mock a module for all tests, so adding the mock to every test file and also forcing every other developer in the team to do that is not a feasible solution. Is there another option?
Just add vi.mock to your setup file
I'm running into the same issue. I want to mock a module for all tests, so adding the mock to every test file and also forcing every other developer in the team to do that is not a feasible solution. Is there another option?
Just add
vi.mockto your setup file
That's what I did but it seems it only works for some of the tests. Adding the vi.mock directly to the other tests does seem to help but like I said, that's not a very maintainable solution.