Skip to content

Commit 085a37a

Browse files
edmundhungCarmenPopoviciu
andauthoredFeb 25, 2025··
fix(vitest-pool-workers): reset module graphs to ensure module mock works in watch mode (#8182)
Co-authored-by: Carmen Popoviciu <cpopoviciu@cloudflare.com>
1 parent 6cae13a commit 085a37a

File tree

3 files changed

+111
-0
lines changed

3 files changed

+111
-0
lines changed
 

‎.changeset/quick-shoes-jump.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@cloudflare/vitest-pool-workers": patch
3+
---
4+
5+
fix mock modules not re-evaluated in watch mode

‎packages/vitest-pool-workers/src/worker/lib/cloudflare/test-runner.ts

+6
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
registerHandlerAndGlobalWaitUntil,
99
waitForGlobalWaitUntil,
1010
} from "cloudflare:test-internal";
11+
import { vi } from "vitest";
1112
import { VitestTestRunner } from "vitest/runners";
1213
import workerdUnsafe from "workerd:unsafe";
1314
import type { CancelReason, Suite, Test } from "@vitest/runner";
@@ -229,6 +230,11 @@ export default class WorkersTestRunner extends VitestTestRunner {
229230
await scheduler.wait(100);
230231
}
231232

233+
// Unlike the official threads and forks pool, we do not recycle the miniflare instances to maintain the module cache.
234+
// However, this creates a side effect where the module mock will not be re-evaluated on watch mode.
235+
// This fixes https://github.com/cloudflare/workers-sdk/issues/6844 by resetting the module graph.
236+
vi.resetModules();
237+
232238
// Ensure all `ctx.waitUntil()` calls complete before disposing the runtime
233239
// (if using `vitest run`) and aborting all objects. `ctx.waitUntil()`s may
234240
// contain storage calls (e.g. caching responses) that could try to access

‎packages/vitest-pool-workers/test/watch.test.ts

+100
Original file line numberDiff line numberDiff line change
@@ -106,3 +106,103 @@ test("automatically re-runs integration tests", async ({
106106
expect(result.stdout).toMatch("Tests 1 passed");
107107
});
108108
});
109+
110+
test("automatically reset module graph", async ({
111+
expect,
112+
seed,
113+
vitestDev,
114+
}) => {
115+
await seed({
116+
"vitest.config.mts": dedent`
117+
import { defineWorkersConfig } from "@cloudflare/vitest-pool-workers/config";
118+
export default defineWorkersConfig({
119+
test: {
120+
poolOptions: {
121+
workers: {
122+
main: "./index.ts",
123+
singleWorker: true,
124+
miniflare: {
125+
compatibilityDate: "2024-01-01",
126+
compatibilityFlags: ["nodejs_compat"],
127+
},
128+
},
129+
},
130+
}
131+
});
132+
`,
133+
"answer.ts": dedent`
134+
export function getAnswer() {
135+
return "wrong";
136+
}
137+
`,
138+
"index.ts": dedent`
139+
import { getAnswer } from "./answer";
140+
141+
export default {
142+
async fetch(request, env, ctx) {
143+
const answer = getAnswer();
144+
return new Response(answer);
145+
}
146+
}
147+
`,
148+
"index.test.ts": dedent`
149+
import { env, createExecutionContext, waitOnExecutionContext } from "cloudflare:test";
150+
import { it, expect, vi } from "vitest";
151+
import worker from "./index";
152+
import { getAnswer } from './answer';
153+
154+
vi.mock('./answer');
155+
156+
it("mocks module properly", async () => {
157+
vi.mocked(getAnswer).mockReturnValue("correct");
158+
159+
const request = new Request("https://example.com");
160+
const ctx = createExecutionContext();
161+
const response = await worker.fetch(request, env, ctx);
162+
await waitOnExecutionContext(ctx);
163+
expect(await response.text()).toBe("correct");
164+
});
165+
`,
166+
});
167+
const result = vitestDev();
168+
169+
await waitFor(() => {
170+
expect(result.stdout).toMatch("Tests 1 passed");
171+
});
172+
173+
// Trigger a re-run by updating the test file with an extra test.
174+
await seed({
175+
"index.test.ts": dedent`
176+
import { env, createExecutionContext, waitOnExecutionContext } from "cloudflare:test";
177+
import { it, expect, vi } from "vitest";
178+
import worker from "./index";
179+
import { getAnswer } from './answer';
180+
181+
vi.mock('./answer');
182+
183+
it("mocks module properly", async () => {
184+
vi.mocked(getAnswer).mockReturnValue("correct");
185+
186+
const request = new Request("https://example.com");
187+
const ctx = createExecutionContext();
188+
const response = await worker.fetch(request, env, ctx);
189+
await waitOnExecutionContext(ctx);
190+
expect(await response.text()).toBe("correct");
191+
});
192+
193+
it("mocks module properly when re-run in watch mode", async () => {
194+
vi.mocked(getAnswer).mockReturnValue("test");
195+
196+
const request = new Request("https://example.com");
197+
const ctx = createExecutionContext();
198+
const response = await worker.fetch(request, env, ctx);
199+
await waitOnExecutionContext(ctx);
200+
expect(await response.text()).toBe("test");
201+
});
202+
`,
203+
});
204+
205+
await waitFor(() => {
206+
expect(result.stdout).toMatch("Tests 2 passed");
207+
});
208+
});

0 commit comments

Comments
 (0)
Please sign in to comment.