Files
cloudflare__vinext/pnpm-workspace.yaml
T
James Anderson d03c5aa045 test(msw): introduce MSW infrastructure and migrate font-google-build (#1444)
* 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.
2026-05-22 13:03:08 +00:00

134 lines
3.3 KiB
YAML

autoInstallPeers: false
frozenLockfile: true
preferFrozenLockfile: true
saveExact: true
blockExoticSubdeps: true
minimumReleaseAge: 1440
packages:
- apps/*
- packages/*
- examples/*
- tests/fixtures/*
- tests/fixtures/ecosystem/*
- benchmarks/vinext
catalog:
"@cloudflare/kumo": ^2.2.0
"@cloudflare/vite-plugin": ^1.31.0
"@cloudflare/workers-types": ^4.0.0
"@heroicons/react": 2.2.0
"@mdx-js/loader": 3.1.0
"@mdx-js/react": ^3.1.1
"@mdx-js/rollup": ^3.1.1
"@phosphor-icons/react": ^2.1.10
"@playwright/test": ^1.58.2
"@radix-ui/react-dialog": ^1.1.14
"@radix-ui/react-dropdown-menu": ^2.1.15
"@radix-ui/react-slot": ^1.2.3
"@tailwindcss/forms": 0.5.10
"@tailwindcss/postcss": 4.1.4
"@tailwindcss/typography": 0.5.16
"@tailwindcss/vite": ^4.1.0
"@takumi-rs/image-response": ^0.72.0
"@types/mdx": 2.0.13
"@types/ms": 2.1.0
"@types/node": ^25.2.3
"@types/react": ^19.2.14
"@types/react-dom": ^19.2.3
"@typescript/native-preview": ^7.0.0-dev.20260213.1
"@unpic/react": ^1.0.2
"@vercel/og": ^0.8.6
"@vitejs/plugin-react": ^6.0.1
"@next/mdx": 16.2.6
recma-codehike: 0.0.1
remark-codehike: 0.0.1
"@vitejs/plugin-rsc": ^0.5.26
"@vitest/coverage-istanbul": 4.1.6
better-auth: ^1.5.6
better-sqlite3: ^12.0.0
class-variance-authority: ^0.7.1
clsx: ^2.1.1
codehike: 1.0.7
date-fns: 4.1.0
drizzle-kit: ^0.31.10
drizzle-orm: ^0.45.2
sanitize-html: ^2.17.3
fumadocs-core: 16.7.9
fumadocs-mdx: 14.2.10
fumadocs-ui: 16.7.9
image-size: 2.0.2
ipaddr.js: ^2.1.0
lucide-react: ^0.577.0
magic-string: ^0.30.21
"@mswjs/interceptors": ^0.41.3
msw: ^2.14.6
ms: 3.0.0-canary.1
next: 16.2.6
next-intl: ^4.9.2
next-themes: ^0.4.6
next-view-transitions: ^0.3.5
nitro: npm:nitro-nightly@latest
nuqs: ^2.8.8
playwright: ^1.52.0
postcss: 8.5.10
react: ^19.2.6
react-dom: ^19.2.6
react-server-dom-webpack: ^19.2.6
server-only: ^0.0.1
swr: ^2.0.0
tailwind-merge: ^3.3.0
tailwindcss: 4.1.4
typescript: ^5.7.0
use-count-up: 3.0.1
validator: ^13.15.26
vite: npm:@voidzero-dev/vite-plus-core@0.1.22
vite-plugin-commonjs: ^0.10.4
vite-plus: 0.1.22
vite-tsconfig-paths: ^6.1.1
vitest: npm:@voidzero-dev/vite-plus-test@0.1.22
web-vitals: ^4.2.4
wrangler: ^4.80.0
zod: 3.24.3
knip: ^6.6.2
overrides:
vite: "catalog:"
vitest: "catalog:"
picomatch: ">=2.3.2"
srvx: ">=0.11.13"
peerDependencyRules:
allowAny:
- vite
- vitest
allowedVersions:
vite: "*"
vitest: "*"
ignoreMissing:
- next
- webpack
- rollup
packageExtensions:
# codehike@1.0.7 lists zod only as a devDependency, so pnpm doesn't nest zod
# next to it. TS then resolves `zod` from inside codehike's .d.ts files to
# whichever zod happens to be hoisted (zod@4.3.6 in this monorepo, pulled in
# by better-auth/fumadocs), which is incompatible with codehike's zod v3
# types. Declare zod as a peerDependency on codehike so pnpm pulls the
# correct version (zod@3.24.3 from the catalog) into codehike's scope.
codehike@1.0.7:
peerDependencies:
zod: 3.24.3
allowBuilds:
better-sqlite3: true
esbuild: true
sharp: true
workerd: true
"@parcel/watcher": true
"@swc/core": true
unrs-resolver: false
# MSW's postinstall only copies a service worker into ./public for browser
# mocking. We exclusively use msw/node, so the postinstall is unnecessary.
msw: false