mirror of
https://github.com/cloudflare/vinext.git
synced 2026-09-14 19:04:59 +08:00
d03c5aa045
* test(msw): introduce MSW infrastructure and migrate font-google-build
Replaces ad-hoc `globalThis.fetch` hijacking in tests with Mock Service
Worker. MSW intercepts both `globalThis.fetch` and `node:http`/`https`,
so it covers fetches issued by in-process Vite servers and fixture pages
without each test having to manage its own stub.
The setup file enables `onUnhandledRequest: 'error'` so any future test
that issues an unmocked external request fails loudly instead of
silently hitting the network. Loopback hostnames (localhost, 127.0.0.1,
::1) are bypassed because the integration project deliberately hits
in-process test servers via fetch.
What this PR contains:
- `tests/_msw/{handlers,server,setup}.ts` — shared infra
- `setupFiles` wired into both vitest projects (unit + integration)
- `msw` + `@mswjs/interceptors` added to the workspace catalog
- `msw` postinstall skipped via `allowBuilds` (it only copies a browser
service worker; we exclusively use `msw/node`)
- `tests/font-google-build.test.ts` migrated as the proof of pattern
Temporary handlers for `httpbin.org/uuid` and
`example.com/not-cacheable` keep the existing fixture pages
(`revalidate-tag-test`, `dynamic-error-fetch`) working under the new
guard. These are placeholders flagged with `TODO(msw-migration)` — a
follow-up will replace those live URLs with test-local endpoints.
This is PR 1 of 3:
- PR 2 will migrate `tests/fetch-cache.test.ts`
- PR 3 will migrate `tests/font-google.test.ts` and the font block in
`tests/app-router.test.ts`
* test(msw): restrict MSW to the unit project + use passthrough for loopback
Two fixes to the initial MSW wiring that surfaced when CI ran the full
suite:
1. The integration project is now excluded from MSW. Integration tests
spin up in-process HTTP servers and fixture dev servers and exercise
them via `fetch("http://127.0.0.1:<port>/...")`. Even with a loopback
`passthrough()` handler installed, the @mswjs/interceptors layer
interferes with that traffic in subtle ways:
- `tests/prerender.test.ts > errors without writing .rsc when the
middleware short-circuit fallback RSC request fails` timed out at
30s — the 5xx response body never reached the caller.
- `tests/ecosystem.test.ts > nuqs` hung in `beforeAll` waiting for
its fixture process to come up, because the readiness fetch
stalled inside the interceptor.
Integration tests already talk to real local servers, not the
internet, so the unhandled-request guard buys little there. The
value of MSW for this repo is mocking external HTTP for unit tests
of fetch wrappers (font-google, font-google-build, fetch-cache),
which is preserved.
2. The `onUnhandledRequest` callback in `setup.ts` that tried to
silently let loopback through wasn't sufficient — MSW's interceptor
still ran for those requests and could stall them. Replaced with a
default `http.all(LOOPBACK_URL_PATTERN, () => passthrough())`
handler in `handlers.ts` and a plain `onUnhandledRequest: "error"`
in `setup.ts`. Unit tests like the middleware-rewrite proxy in
`tests/shims.test.ts` and the JSX-in-JS suite need this to keep
their in-process HTTP servers reachable.
* test(msw): address BigBonk review notes
- Update PR description in the commit body to drop the stale mention of
TODO(msw-migration) handlers — they were removed when the integration
project was excluded from MSW; the fixture pages run there.
- Tighten the loopback IPv4 octet regex from `\d+` to `\d{1,3}` so it
doesn't match absurdly long octet strings. `URL.hostname` normalises
real addresses, so this is purely a readability fix.
* test(msw): address remaining BigBonk notes from the initial review
- Add `0.0.0.0` to the loopback passthrough pattern so test servers that
bind to the unspecified address keep working without per-test mocks.
- Add a `TODO(msw-3)` comment in `server.ts` flagging the
`SetupServerApi` deprecation in MSW 2.14.6 — the `FetchInterceptor`-only
construction will need to migrate to `defineNetwork`'s interceptor
config when we bump to MSW 3.
Both raised by BigBonk on the first review of this PR (the second review
focused on the stale description and the loose `\d+` octet bound, which
were addressed in the previous commit).
* test(msw): scope server.use() inside the try block in font-google-build
Minor structural fix from BigBonk's review: moves the `server.use()`
handler registration inside the `try` block so all setup and the
matching `fs.unlink` cleanup share the same try/finally scope.
No behaviour change — `server.use()` is synchronous and infallible, so
this is purely a structural tidy-up.
* test(msw): correct comment in font-google-build to match interceptor config
BigBonk caught that the comment described the default `setupServer()`
behaviour (which uses both `FetchInterceptor` and `ClientRequestInterceptor`),
but this project's `server.ts` deliberately constructs `SetupServerApi`
with only `FetchInterceptor`. Update the comment to reflect that — it
intercepts `globalThis.fetch`, not `node:http`/`node:https`.
No code change, comment only.
30 lines
1.6 KiB
TypeScript
30 lines
1.6 KiB
TypeScript
import { FetchInterceptor } from "@mswjs/interceptors/fetch";
|
|
import { SetupServerApi } from "msw/node";
|
|
import { handlers } from "./handlers.js";
|
|
|
|
/**
|
|
* The MSW server instance for this vitest worker.
|
|
*
|
|
* `setupFiles` runs once per worker before any test code, so each worker gets
|
|
* its own `server`. The vitest `integration` project runs file-serially, and
|
|
* the `unit` project's tests rely on `server.resetHandlers()` between tests
|
|
* (registered in `setup.ts`) to keep handler state isolated.
|
|
*
|
|
* We instantiate `SetupServerApi` directly with ONLY the `FetchInterceptor`,
|
|
* rather than calling `setupServer()` (which also installs the
|
|
* `ClientRequestInterceptor`). The latter monkey-patches `globalThis.Headers`
|
|
* and `globalThis.Request` to record raw headers on a hidden symbol, and that
|
|
* machinery leaks original-source headers across `new Request(req, { headers })`
|
|
* copy-construction — surfacing as e.g. `new Headers(req.headers)` returning
|
|
* headers that the new Request explicitly stripped. We only need
|
|
* `globalThis.fetch` interception in this suite (no `node:http` callers), so
|
|
* dropping the ClientRequestInterceptor avoids that side-effect entirely.
|
|
*
|
|
* TODO(msw-3): `SetupServerApi` is `@deprecated` in MSW 2.14.6 in favour of the
|
|
* `defineNetwork` API that MSW 3 standardises around. Migrate when we bump to
|
|
* MSW 3 — the FetchInterceptor-only customisation will need to be expressed
|
|
* through `defineNetwork`'s interceptor configuration instead of constructing
|
|
* `SetupServerApi` directly.
|
|
*/
|
|
export const server = new SetupServerApi(handlers, [new FetchInterceptor()]);
|