-
Notifications
You must be signed in to change notification settings - Fork 1.4k
[vitest-pool-workers] Adopt @msw/cloudflare and remove MSW workarounds #13830
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
Open
penalosa
wants to merge
8
commits into
main
Choose a base branch
from
penalosa/msw-cloudflare
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
d5f86af
[vitest-pool-workers] Adopt @msw/cloudflare and remove MSW workarounds
penalosa 8f04aba
[vitest-pool-workers] Fix hyperdrive fixture ProvidedContext augmenta…
penalosa 4df72df
[vitest-pool-workers] Pin msw catalog entry to exact version
penalosa 7daffc6
Merge remote-tracking branch 'origin/main' into penalosa/msw-cloudflare
penalosa a1d7fc4
Merge remote-tracking branch 'origin/main' into penalosa/msw-cloudflare
penalosa 8c25d4e
[vitest-pool-workers] Address request mocking review
penalosa a0d410c
[wrangler] Fix test harness MSW fixture type
penalosa 6a678d1
Merge remote-tracking branch 'origin/main' into penalosa/msw-cloudflare
penalosa File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| --- | ||
| "@cloudflare/vitest-pool-workers": minor | ||
| --- | ||
|
|
||
| Mocking requests with MSW in Worker tests now requires MSW >= 2.14 | ||
|
|
||
| `@cloudflare/vitest-pool-workers` previously shipped internal shims to make MSW work inside the workerd runtime. MSW 2.14 added that support natively, so those shims have been removed. | ||
|
|
||
| If you mock requests with MSW in your Worker tests, make sure you're on MSW `>= 2.14`; older versions will no longer intercept requests. You can keep using `setupServer()` from `msw/node`, or adopt the official [`@msw/cloudflare`](https://github.com/mswjs/cloudflare) integration via `setupNetwork()`. See the updated [`request-mocking` example fixture](https://github.com/cloudflare/workers-sdk/tree/main/fixtures/vitest-pool-workers-examples/request-mocking) for the recommended pattern. |
4 changes: 2 additions & 2 deletions
4
fixtures/create-test-harness-example/tests/playwright.test.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,7 @@ | ||
| import "vitest"; | ||
|
|
||
| declare module "vitest" { | ||
| interface ProvidedContext { | ||
| echoServerPort: number; | ||
| } | ||
| } | ||
|
|
||
| export {}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
13 changes: 8 additions & 5 deletions
13
fixtures/vitest-pool-workers-examples/request-mocking/README.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,11 @@ | ||
| # 🤹 request-mocking | ||
|
|
||
| This Worker rewrites the host of all incoming requests to `cloudflare.com` then forwards the request on. Tests demonstrate declarative mocking with [MSW (Mock Service Worker)](https://mswjs.io/), and imperative mocks of `globalThis.fetch()`. Note mocking WebSocket requests is only supported with imperative mocking. | ||
| This Worker rewrites the host of all incoming requests to `cloudflare.com` then forwards the request on, except for the `/echo-ws` path which opens an outbound WebSocket. Tests demonstrate declarative request mocking with [MSW (Mock Service Worker)](https://mswjs.io/) via the [`@msw/cloudflare`](https://github.com/mswjs/cloudflare) integration, including outbound WebSocket connections. | ||
|
|
||
| | Test | Overview | | ||
| | ----------------------------------------------- | ----------------------------------------------------------------------- | | ||
| | [declarative.test.ts](test/declarative.test.ts) | Integration tests with declarative request mocking using MSW | | ||
| | [imperative.test.ts](test/imperative.test.ts) | Integration tests with imperative request mocking, including WebSockets | | ||
| | Test | Worker invocation style | Overview | | ||
| | ------------------------------------------- | ----------------------------- | ------------------------------------------------------------------------------------ | | ||
| | [direct.test.ts](test/direct.test.ts) | `worker.fetch(req, env, ctx)` | Mocking HTTP requests with `http.get` / `http.post` handlers | | ||
| | [websocket.test.ts](test/websocket.test.ts) | `worker.fetch(req, env, ctx)` | Mocking outbound WebSocket connections (`new WebSocket(url)`) with the `ws.link` API | | ||
| | [exports.test.ts](test/exports.test.ts) | `exports.default.fetch(...)` | Mocking HTTP requests dispatched into a separate request I/O context | | ||
|
|
||
| `exports.test.ts` verifies that MSW handlers registered in the test runner also intercept requests dispatched through `exports.default.fetch(...)` into a separate request I/O context. |
32 changes: 30 additions & 2 deletions
32
fixtures/vitest-pool-workers-examples/request-mocking/src/index.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,11 +1,39 @@ | ||
| export default <ExportedHandler>{ | ||
| export default { | ||
| async fetch(request, env, ctx) { | ||
| const url = new URL(request.url); | ||
| url.host = "cloudflare.com"; | ||
|
|
||
| try { | ||
| // Special handler: open a WebSocket to the rewritten URL, send a | ||
| // message, then return the first reply as the response. | ||
| if (url.pathname === "/echo-ws") { | ||
| url.protocol = "wss:"; | ||
| const ws = new WebSocket(url.toString()); | ||
| try { | ||
| const messagePromise = new Promise<string>((resolve, reject) => { | ||
| const timeout = setTimeout( | ||
| () => reject(new Error("WebSocket connection timed out")), | ||
| 5_000 | ||
| ); | ||
| ws.addEventListener("message", (event) => { | ||
| clearTimeout(timeout); | ||
| resolve(String(event.data)); | ||
| }); | ||
| ws.addEventListener("error", () => { | ||
| clearTimeout(timeout); | ||
| reject(new Error("WebSocket connection errored")); | ||
| }); | ||
| }); | ||
| ws.addEventListener("open", () => ws.send("hello")); | ||
| return Response.json({ message: await messagePromise }); | ||
| } finally { | ||
| ws.close(); | ||
| } | ||
| } | ||
|
|
||
| return await fetch(url, request); | ||
| } catch (e) { | ||
| return new Response(String(e), { status: 500 }); | ||
| } | ||
| }, | ||
| }; | ||
| } satisfies ExportedHandler; |
65 changes: 0 additions & 65 deletions
65
fixtures/vitest-pool-workers-examples/request-mocking/test/declarative.test.ts
This file was deleted.
Oops, something went wrong.
89 changes: 89 additions & 0 deletions
89
fixtures/vitest-pool-workers-examples/request-mocking/test/direct.test.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| // Exercises the "direct-import" worker invocation pattern: | ||
| // `import worker from "../src/index"` followed by `worker.fetch(req, env, ctx)`. | ||
| // The worker's `fetch` handler runs in the same I/O context as the test | ||
| // runner where `setupNetwork()` was enabled. | ||
| // | ||
| // For the `exports.default.fetch(...)` counterpart (different request I/O | ||
| // context per call) see `exports.test.ts`. | ||
| import { | ||
| createExecutionContext, | ||
| waitOnExecutionContext, | ||
| } from "cloudflare:test"; | ||
| import { env } from "cloudflare:workers"; | ||
| import { http, HttpResponse } from "msw"; | ||
| import { it } from "vitest"; | ||
| import worker from "../src/index"; | ||
| import { network } from "./server"; | ||
|
|
||
| it("mocks GET requests", async ({ expect }) => { | ||
| network.use( | ||
| http.get( | ||
| "https://cloudflare.com/once", | ||
| () => { | ||
| return HttpResponse.text("😉"); | ||
| }, | ||
| { once: true } | ||
| ), | ||
| http.get("https://cloudflare.com/persistent", () => { | ||
| return HttpResponse.text("📌"); | ||
| }) | ||
| ); | ||
|
|
||
| // Host `example.com` will be rewritten to `cloudflare.com` by the Worker | ||
| let ctx = createExecutionContext(); | ||
| let response = await worker.fetch( | ||
| new Request("https://example.com/once"), | ||
| env, | ||
| ctx | ||
| ); | ||
| await waitOnExecutionContext(ctx); | ||
| expect(response.status).toBe(200); | ||
| expect(await response.text()).toBe("😉"); | ||
|
|
||
| // Persistent handlers match forever | ||
| for (let i = 0; i < 3; i++) { | ||
| ctx = createExecutionContext(); | ||
| response = await worker.fetch( | ||
| new Request("https://example.com/persistent"), | ||
| env, | ||
| ctx | ||
| ); | ||
| await waitOnExecutionContext(ctx); | ||
| expect(response.status).toBe(200); | ||
| expect(await response.text()).toBe("📌"); | ||
| } | ||
| }); | ||
|
|
||
| it("mocks POST requests", async ({ expect }) => { | ||
| network.use( | ||
| http.post("https://cloudflare.com/path", async ({ request }) => { | ||
| const text = await request.text(); | ||
| if (text !== "✨") { | ||
| return HttpResponse.text("Bad request body", { status: 400 }); | ||
| } | ||
| return HttpResponse.text("✅"); | ||
| }) | ||
| ); | ||
|
|
||
| // Sending a request without the expected body returns an error response... | ||
| let ctx = createExecutionContext(); | ||
| let response = await worker.fetch( | ||
| new Request("https://example.com/path", { method: "POST", body: "🙃" }), | ||
| env, | ||
| ctx | ||
| ); | ||
| await waitOnExecutionContext(ctx); | ||
| expect(response.status).toBe(400); | ||
| expect(await response.text()).toBe("Bad request body"); | ||
|
|
||
| // ...but the correct body should succeed | ||
| ctx = createExecutionContext(); | ||
| response = await worker.fetch( | ||
| new Request("https://example.com/path", { method: "POST", body: "✨" }), | ||
| env, | ||
| ctx | ||
| ); | ||
| await waitOnExecutionContext(ctx); | ||
| expect(response.status).toBe(200); | ||
| expect(await response.text()).toBe("✅"); | ||
| }); |
46 changes: 46 additions & 0 deletions
46
fixtures/vitest-pool-workers-examples/request-mocking/test/exports.test.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| // Exercises the "integration-self" worker invocation pattern: | ||
| // `exports.default.fetch(...)`, which dispatches each call into a fresh | ||
| // request I/O context separate from the runner DO context where | ||
| // `setupNetwork()` was enabled in `beforeAll`. | ||
| import { exports } from "cloudflare:workers"; | ||
| import { http, HttpResponse } from "msw"; | ||
| import { it } from "vitest"; | ||
| import { network } from "./server"; | ||
|
|
||
| it("mocks GET requests via exports.default.fetch", async ({ expect }) => { | ||
| network.use( | ||
| http.get("https://cloudflare.com/exports", () => { | ||
| return HttpResponse.text("🟢"); | ||
| }) | ||
| ); | ||
|
|
||
| const response = await exports.default.fetch("https://example.com/exports"); | ||
| expect(response.status).toBe(200); | ||
| expect(await response.text()).toBe("🟢"); | ||
| }); | ||
|
|
||
| it("mocks POST requests via exports.default.fetch", async ({ expect }) => { | ||
| network.use( | ||
| http.post("https://cloudflare.com/exports", async ({ request }) => { | ||
| const text = await request.text(); | ||
| if (text !== "✨") { | ||
| return HttpResponse.text("Bad request body", { status: 400 }); | ||
| } | ||
| return HttpResponse.text("✅"); | ||
| }) | ||
| ); | ||
|
|
||
| let response = await exports.default.fetch("https://example.com/exports", { | ||
| method: "POST", | ||
| body: "🙃", | ||
| }); | ||
| expect(response.status).toBe(400); | ||
| expect(await response.text()).toBe("Bad request body"); | ||
|
|
||
| response = await exports.default.fetch("https://example.com/exports", { | ||
| method: "POST", | ||
| body: "✨", | ||
| }); | ||
| expect(response.status).toBe(200); | ||
| expect(await response.text()).toBe("✅"); | ||
| }); | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.