mirror of
https://github.com/cloudflare/vinext.git
synced 2026-09-14 19:04:59 +08:00
373e8264a1
* fix(use-cache): support nested cache functions passed as props
* fix(use-cache): use inline registerServerReference instead of broken forward-reference module-level code
The previous approach used `noExport: true` and appended module-level
`const ${name}_$$vcf` declarations at the end of the transformed file,
then referenced them via forward reference at the call-site. This caused
a temporal dead zone (TDZ) error because `const` bindings are not
hoisted — the call-site assignment evaluated before the TLA const was
initialized, crashing all RSC files that contain function-level "use
cache" (HTTP 500 for use-cache pages, route handlers, etc.).
Fix: keep the existing hoisting/export behaviour (`noExport` stays
false) and instead wrap `registerCachedFunction(...)` with
`registerServerReference(...)` inline at call-site in the RSC
environment. This adds the RSC serialisation metadata ($$typeof, $$id)
so cached functions can be passed as props to client components
(useActionState / formAction), while not disturbing the existing
exported binding that loadServerAction relies on.
* fix(use-cache): use correct normalised id and register in manifest for nested function props
The previous approach passed the raw absolute file path as the $$id to
registerServerReference. @vitejs/plugin-rsc resolves server references by a
normalised key (sha256(toRelativeId) in build; URL-path in dev), so production
would throw "server reference not found" for any cached function passed as a
client-component prop.
Also, the module was never added to the virtual:vite-rsc/server-references
manifest because only the plugin's own "use server" transform writes to
manager.serverReferenceMetaMap. Without a manifest entry, the production
serverReferences lookup has no entry for the module at all.
Fix:
- Capture the plugin-rsc manager via the rsc:minimal plugin API in
configResolved so we can write to serverReferenceMetaMap directly.
- Compute normalizedRefKey to match vitePluginUseServer's getNormalizedId():
build → sha256(toRelativeId(id)).hex.slice(0,12)
dev → id.slice(root.length) (Vite URL path)
- After transformHoistInlineDirective succeeds, register the hoisted export
names in manager.serverReferenceMetaMap[id] so the manifest is populated.
- Pass normalizedRefKey (not raw id) to registerServerReference.
Add unit tests verifying the hash formula matches plugin-rsc's own logic.
* fix(use-cache): wrap hoisted exports as cached server references and register manifest after rsc:use-server
- Derive the build-mode reference key via plugin-rsc's own
manager.toRelativeId() instead of a string slice, so the hash input is
byte-for-byte identical to the plugin's hashString(toRelativeId(id)).
- Reassign each hoisted inline 'use cache' export at module level to
registerServerReference(registerCachedFunction(fn)) so the module
export itself is the cached wrapper (Next.js parity: direct action
invocation goes through the cache) and call sites/manifest imports all
observe the same wrapped function.
- Register serverReferenceMetaMap entries from a new
vinext:use-cache-server-references plugin placed after the plugin-rsc
plugins: rsc:use-server deletes metaMap entries for modules without
'use server', which wiped the entries written during the use-cache
transform (prod actions 404'd with 'server reference not found').
- Deduplicate the RSC/non-RSC transform branches into a single
transformHoistInlineDirective call and hoist the
@vitejs/plugin-rsc/react/rsc resolution out of the per-module path.
- Replace the self-referential key-formula unit test with the ported
Next.js fixture (use-cache-with-server-function-props/nested-cache), a
dev-mode Playwright round-trip test, and a production-server
integration test that resolves the serialized references via action
POSTs and asserts cached-invoke semantics.
* docs(use-cache): document dev-key normalisation scope for inline cache server references
* fix(use-cache): throw instead of emitting unresolvable inline cache server references when the plugin-rsc manager is missing
When the @vitejs/plugin-rsc manager is unavailable in the rsc environment,
the inline 'use cache' transform previously fell back to a locally computed
reference key and still wrapped the hoisted exports — but the manifest
registration plugin bails without the manager, so the emitted reference
would serialize into the RSC payload yet never resolve (silent 404 on
action POST in production). Fail loudly at transform time instead; the
manager is a structural invariant whenever the rsc environment exists.
Adds transform-level unit tests for the fail-loud path (build + dev), the
non-rsc no-manager control, and build reference-key parity with plugin-rsc.
* test(use-cache): pin unencrypted closure-captured bound args and document the divergence
Extends the nested-fn-props fixture with a cached function that closes over
a value from the cached component's scope, exercising the .bind(null, ...)
bound-arg path end to end: the production round-trip test asserts the
captured value appears in plaintext in the flight payload (pinning the
documented divergence from Next.js, which encrypts bound args by default)
and that invoking the bound reference observes the captured value; the
Playwright test covers the real flight-client encodeReply round-trip in
dev. A transform-level test pins that captures are emitted as plain bind
args. The divergence is now also documented in the README's Known
limitations section.
* refactor(use-cache): route registerServerReference through a vinext shim to decouple from plugin-rsc module-id normalisation
The inline 'use cache' prepend imported registerServerReference from a
file:// URL of @vitejs/plugin-rsc/react/rsc while the cache runtime
imports the same package via the bare specifier, relying on Vite
normalising both to a single module id. Re-export it instead from a new
vinext-owned cache-server-reference shim whose only react/rsc specifier
is the same bare one cache-runtime uses, resolved from the same importer
location — one module instance by construction. The transform unit test
now pins that the emitted import targets the shim and never a plugin-rsc
file URL.
* test(use-cache): pin cached-invoke semantics for the closure-bound getMessage path
Mirror the getDate cache assertion on the closure-bound path: the
fixture's getMessage now appends a Math.random() suffix so cache hits
are observable, and the production-server round-trip asserts that two
identical bound-arg invocations return the same cached value while a
different bound arg misses instead of reusing the entry. The Playwright
assertion matches the suffixed message via regex.
* fix(use-cache): encrypt closure-bound arguments
* refactor(use-cache): use plugin-rsc directive transforms
* test(use-cache): cover directive transforms across environments
* fix(cache): update RSC directive prerelease
* fix(cache): stabilize directive reference tests
* style(cache): format HMR test
* refactor(use-cache): move server function directives to user land
* refactor(use-cache): clarify generic directive plugin naming
* refactor(use-cache): own directive plugin types
* refactor(use-cache): use plugin-rsc metadata map directly
* refactor(use-cache): own server reference metadata lifecycle
* chore(use-cache): keep directive type internal
* refactor(use-cache): adopt server reference claims
* fix(init): install required plugin-rsc prerelease
* feat(rsc): harden use cache server functions
* feat(cache): adopt plugin-rsc transform primitives
* refactor(cache): rename callable plugin
* test(init): update plugin-rsc install expectations
* test(cache): avoid reloading during HMR retries
* test(cache): align callable references with plugin-rsc
* fix(cache): align mixed directives with plugin-rsc 0.5.34
* fix(cache): harden callable use cache transforms
* fix(cache): support manually configured RSC
* fix(cache): harden manual RSC ordering
469 lines
17 KiB
TypeScript
469 lines
17 KiB
TypeScript
import { defineConfig } from "@playwright/test";
|
|
|
|
const appRouterBrowserSpecificTests = "**/app-router/**/*.browser.spec.ts";
|
|
const appRouterServer = {
|
|
command: "npx vp dev --port 4174",
|
|
cwd: "./tests/fixtures/app-basic",
|
|
port: 4174,
|
|
reuseExistingServer: !process.env.CI,
|
|
timeout: 30_000,
|
|
};
|
|
|
|
// Dedicated server for BFCache/cacheComponents coverage. cacheComponents is an
|
|
// opt-in semantic mode that retains inactive route trees as hidden Activity DOM.
|
|
// Running it on the shared app-basic fixture would change the DOM contract for
|
|
// every unrelated app-router test, so it gets its own isolated fixture instead.
|
|
const appRouterBfcacheServer = {
|
|
command: "npx vp dev --port 4183",
|
|
cwd: "./tests/fixtures/app-bfcache",
|
|
port: 4183,
|
|
reuseExistingServer: !process.env.CI,
|
|
timeout: 30_000,
|
|
};
|
|
|
|
/**
|
|
* Each project maps to a single webServer. Some browser-specific projects share
|
|
* a server with the base project, and shared servers are de-duped by port.
|
|
* Browser-specific production tests may opt out with server: null when they own
|
|
* their build/server lifecycle inside the test fixture.
|
|
* When PLAYWRIGHT_PROJECT is set
|
|
* (e.g. in CI matrix jobs), only that project and its server are configured,
|
|
* so each CI runner only starts the one server it needs.
|
|
*/
|
|
const projectServers = {
|
|
"pages-router": {
|
|
testDir: "./tests/e2e/pages-router",
|
|
use: { baseURL: "http://localhost:4173" },
|
|
server: {
|
|
command: "npx vp run vinext#build && npx vp dev --port 4173",
|
|
cwd: "./tests/fixtures/pages-basic",
|
|
port: 4173,
|
|
reuseExistingServer: !process.env.CI,
|
|
timeout: 30_000,
|
|
},
|
|
},
|
|
"app-router": {
|
|
testDir: "./tests/e2e",
|
|
testMatch: ["**/app-router/**/*.spec.ts", "**/og-image.spec.ts"],
|
|
testIgnore: [
|
|
appRouterBrowserSpecificTests,
|
|
"**/app-router/nextjs-compat/client-cache.spec.ts",
|
|
"**/app-router/nextjs-compat/route-handler-draft-cache.spec.ts",
|
|
"**/app-router/nextjs-compat/segment-cache-client-params.spec.ts",
|
|
"**/app-router/isr.spec.ts",
|
|
],
|
|
use: { baseURL: "http://localhost:4174" },
|
|
server: appRouterServer,
|
|
},
|
|
"app-router-isr-prod": {
|
|
testDir: "./tests/e2e",
|
|
testMatch: ["app-router/isr.spec.ts", "app-router-prod/use-cache.spec.ts"],
|
|
use: { baseURL: "http://localhost:4198" },
|
|
server: {
|
|
command:
|
|
"npx vp run vinext#build && node ../../../packages/vinext/dist/cli.js build && node ../../../packages/vinext/dist/cli.js start --port 4198",
|
|
cwd: "./tests/fixtures/app-basic",
|
|
port: 4198,
|
|
reuseExistingServer: !process.env.CI,
|
|
timeout: 120_000,
|
|
},
|
|
},
|
|
"app-router-client-cache": {
|
|
testDir: "./tests/e2e/app-router/nextjs-compat",
|
|
testMatch: [
|
|
"client-cache.spec.ts",
|
|
"route-handler-draft-cache.spec.ts",
|
|
"segment-cache-client-params.spec.ts",
|
|
],
|
|
use: { baseURL: "http://localhost:4191" },
|
|
server: {
|
|
command:
|
|
"npx vp run vinext#build && node ../../../packages/vinext/dist/cli.js build && node ../../../packages/vinext/dist/cli.js start --port 4191",
|
|
cwd: "./tests/fixtures/app-basic",
|
|
port: 4191,
|
|
reuseExistingServer: !process.env.CI,
|
|
timeout: 120_000,
|
|
},
|
|
},
|
|
"app-router-chrome-browser-specific": {
|
|
testDir: "./tests/e2e",
|
|
testMatch: [appRouterBrowserSpecificTests],
|
|
use: {
|
|
browserName: "chromium" as const,
|
|
channel: "chrome" as const,
|
|
},
|
|
server: null,
|
|
},
|
|
"app-router-webkit-browser-specific": {
|
|
testDir: "./tests/e2e",
|
|
testMatch: [appRouterBrowserSpecificTests],
|
|
use: { browserName: "webkit" as const },
|
|
server: null,
|
|
},
|
|
"app-router-bfcache": {
|
|
testDir: "./tests/e2e/app-router-bfcache",
|
|
use: { baseURL: "http://localhost:4183" },
|
|
server: appRouterBfcacheServer,
|
|
},
|
|
"catch-error": {
|
|
testDir: "./tests/e2e/catch-error",
|
|
use: { baseURL: "http://localhost:4185" },
|
|
server: {
|
|
command:
|
|
"npx vp run vinext#build && node ../../../packages/vinext/dist/cli.js build && node ../../../packages/vinext/dist/cli.js start --port 4185",
|
|
cwd: "./tests/fixtures/global-not-found-basic",
|
|
port: 4185,
|
|
reuseExistingServer: false,
|
|
timeout: 60_000,
|
|
},
|
|
},
|
|
"cloudflare-pages-router": {
|
|
testDir: "./tests/e2e",
|
|
testMatch: [
|
|
"**/cloudflare-pages-router/**/*.spec.ts",
|
|
"**/pages-router/instrumentation-startup.spec.ts",
|
|
],
|
|
use: { baseURL: "http://localhost:4177" },
|
|
server: {
|
|
command: "VINEXT_E2E_REVALIDATION_PROXY=1 npx vp build && npx wrangler dev --port 4177",
|
|
cwd: "./examples/pages-router-cloudflare",
|
|
port: 4177,
|
|
reuseExistingServer: !process.env.CI,
|
|
timeout: 30_000,
|
|
},
|
|
},
|
|
"pages-router-prod": {
|
|
testDir: "./tests/e2e/pages-router-prod",
|
|
server: {
|
|
// Use node to invoke the CLI directly — npx vinext may not be on PATH
|
|
// in fixture subdirectories since vinext is a workspace dependency.
|
|
command:
|
|
"npx vp run vinext#build && node ../../../packages/vinext/dist/cli.js build && node ../../../packages/vinext/dist/cli.js start --port 4175",
|
|
cwd: "./tests/fixtures/pages-basic",
|
|
port: 4175,
|
|
reuseExistingServer: !process.env.CI,
|
|
timeout: 60_000,
|
|
env: { NEXT_DEPLOYMENT_ID: "pages-production-deployment" },
|
|
},
|
|
},
|
|
"pages-scroll-restoration": {
|
|
testDir: "./tests/e2e/pages-scroll-restoration",
|
|
use: { baseURL: "http://localhost:4185" },
|
|
server: {
|
|
command:
|
|
"npx vp run vinext#build && node ../../../packages/vinext/dist/cli.js build && node ../../../packages/vinext/dist/cli.js start --port 4185",
|
|
cwd: "./tests/fixtures/pages-scroll-restoration",
|
|
port: 4185,
|
|
reuseExistingServer: !process.env.CI,
|
|
timeout: 60_000,
|
|
},
|
|
},
|
|
"cloudflare-workers": {
|
|
testDir: "./tests/e2e",
|
|
testMatch: [
|
|
"**/cloudflare-workers/**/*.spec.ts",
|
|
"**/app-router/instrumentation.spec.ts",
|
|
"**/og-image.spec.ts",
|
|
],
|
|
use: { baseURL: "http://localhost:4176" },
|
|
server: {
|
|
// Build app-router-cloudflare with Vite, then serve with wrangler dev (miniflare)
|
|
command: "npx vp build && npx wrangler dev --config dist/server/wrangler.json --port 4176",
|
|
cwd: "./examples/app-router-cloudflare",
|
|
port: 4176,
|
|
reuseExistingServer: !process.env.CI,
|
|
timeout: 60_000,
|
|
},
|
|
},
|
|
"cloudflare-sentry-app": {
|
|
testDir: "./tests/e2e",
|
|
testMatch: ["**/cloudflare-sentry-app/**/*.spec.ts"],
|
|
use: { baseURL: "http://localhost:4193" },
|
|
server: {
|
|
command:
|
|
"NEXT_PUBLIC_VINEXT_TEST_SENTRY_DSN=http://public@localhost:4193/1 npx vp build && npx wrangler dev --port 4193",
|
|
cwd: "./tests/fixtures/cf-sentry-app",
|
|
port: 4193,
|
|
reuseExistingServer: !process.env.CI,
|
|
timeout: 60_000,
|
|
},
|
|
},
|
|
"cloudflare-sentry-pages": {
|
|
testDir: "./tests/e2e",
|
|
testMatch: ["**/cloudflare-sentry-pages/**/*.spec.ts"],
|
|
use: { baseURL: "http://localhost:4194" },
|
|
server: {
|
|
command:
|
|
"NEXT_PUBLIC_VINEXT_TEST_SENTRY_DSN=http://public@localhost:4194/1 npx vp build && npx wrangler dev --port 4194",
|
|
cwd: "./tests/fixtures/cf-sentry-pages",
|
|
port: 4194,
|
|
reuseExistingServer: !process.env.CI,
|
|
timeout: 60_000,
|
|
},
|
|
},
|
|
"cloudflare-dev": {
|
|
testDir: "./tests/e2e",
|
|
testMatch: [
|
|
"**/cloudflare-dev/**/*.spec.ts",
|
|
"**/app-router/instrumentation.spec.ts",
|
|
"**/og-image.spec.ts",
|
|
],
|
|
use: { baseURL: "http://localhost:4178" },
|
|
server: {
|
|
// Run vite dev (not wrangler) against the cloudflare example so that
|
|
// configureServer() is exercised with @cloudflare/vite-plugin loaded.
|
|
command: "npx vp dev --port 4178",
|
|
cwd: "./examples/app-router-cloudflare",
|
|
port: 4178,
|
|
reuseExistingServer: !process.env.CI,
|
|
timeout: 30_000,
|
|
},
|
|
},
|
|
"cloudflare-pages-router-dev": {
|
|
testDir: "./tests/e2e",
|
|
testMatch: [
|
|
"**/cloudflare-pages-router-dev/**/*.spec.ts",
|
|
"**/pages-router/instrumentation-startup.spec.ts",
|
|
],
|
|
use: { baseURL: "http://localhost:4179" },
|
|
server: {
|
|
command: "npx vp dev --port 4179",
|
|
cwd: "./examples/pages-router-cloudflare",
|
|
port: 4179,
|
|
reuseExistingServer: !process.env.CI,
|
|
timeout: 30_000,
|
|
},
|
|
},
|
|
"static-export": {
|
|
testDir: "./tests/e2e/static-export",
|
|
use: { baseURL: "http://localhost:4180" },
|
|
server: {
|
|
// Build the static export fixture, then serve the output with a
|
|
// lightweight static file server. No vinext runtime is needed —
|
|
// the output is pure pre-rendered HTML files.
|
|
command:
|
|
"npx vp run vinext#build && node ../../../packages/vinext/dist/cli.js build && node ../../../tests/e2e/static-export/serve-static.mjs dist/client 4180",
|
|
cwd: "./tests/fixtures/static-export",
|
|
port: 4180,
|
|
reuseExistingServer: !process.env.CI,
|
|
timeout: 60_000,
|
|
},
|
|
},
|
|
"app-with-src": {
|
|
testDir: "./tests/e2e/app-with-src",
|
|
use: { baseURL: "http://localhost:4181" },
|
|
server: {
|
|
command: "npx vp dev --port 4181",
|
|
cwd: "./tests/fixtures/app-with-src",
|
|
port: 4181,
|
|
reuseExistingServer: !process.env.CI,
|
|
timeout: 30_000,
|
|
},
|
|
},
|
|
"standalone-output": {
|
|
testDir: "./tests/e2e/standalone-output",
|
|
use: { baseURL: "http://localhost:4182" },
|
|
server: {
|
|
// Build vinext CLI, then build the fixture, then start the standalone
|
|
// server from an isolated temp directory. Moving it outside the repo
|
|
// prevents Node from resolving missing externals from workspace
|
|
// node_modules and verifies the standalone package is self-contained.
|
|
command:
|
|
'npx vp run vinext#build && node ../../../packages/vinext/dist/cli.js build && standalone_dir="$(mktemp -d)" && cp -R dist/standalone/. "$standalone_dir" && PORT=4182 node "$standalone_dir/server.js"',
|
|
cwd: "./tests/fixtures/standalone-output",
|
|
port: 4182,
|
|
reuseExistingServer: !process.env.CI,
|
|
timeout: 60_000,
|
|
},
|
|
},
|
|
"root-layout-redirect": {
|
|
testDir: "./tests/e2e/root-layout-redirect",
|
|
use: { baseURL: "http://localhost:4184" },
|
|
server: {
|
|
// Build vinext CLI, then build the fixture, then start the production
|
|
// server. This exercises prodOnCaughtError (the fixed code path) rather
|
|
// than devOnCaughtError, which already filtered navigation-signal errors
|
|
// before this PR.
|
|
command:
|
|
"npx vp run vinext#build && node ../../../packages/vinext/dist/cli.js build && node ../../../packages/vinext/dist/cli.js start --port 4184",
|
|
cwd: "./tests/fixtures/root-layout-redirect",
|
|
port: 4184,
|
|
reuseExistingServer: !process.env.CI,
|
|
timeout: 60_000,
|
|
},
|
|
},
|
|
"use-params-app-pages": {
|
|
testDir: "./tests/e2e/use-params-app-pages",
|
|
use: { baseURL: "http://localhost:4186" },
|
|
server: {
|
|
command:
|
|
"cd ../../.. && npx vp run vinext#build && cd tests/fixtures/use-params-app-pages && node ../../../packages/vinext/dist/cli.js build && node ../../../packages/vinext/dist/cli.js start --port 4186",
|
|
cwd: "./tests/fixtures/use-params-app-pages",
|
|
port: 4186,
|
|
reuseExistingServer: !process.env.CI,
|
|
timeout: 60_000,
|
|
},
|
|
},
|
|
"ppr-impact-demo": {
|
|
testDir: "./tests/e2e/ppr-impact-demo",
|
|
use: { baseURL: "http://localhost:4187" },
|
|
server: {
|
|
command:
|
|
"npx vp run vinext#build && node ../../../packages/vinext/dist/cli.js build && node ../../../packages/vinext/dist/cli.js start --port 4187",
|
|
cwd: "./tests/fixtures/ppr-impact-demo",
|
|
port: 4187,
|
|
reuseExistingServer: !process.env.CI,
|
|
timeout: 90_000,
|
|
},
|
|
},
|
|
"app-front-redirect-issue": {
|
|
testDir: "./tests/e2e/app-front-redirect-issue",
|
|
use: { baseURL: "http://localhost:4188" },
|
|
server: {
|
|
command:
|
|
"(test -e node_modules || test -L node_modules || ln -s ../../../fixtures/app-basic/node_modules node_modules) && npx vp run vinext#build && NEXT_DEPLOYMENT_ID=vinext-front-redirect-e2e node ../../../../packages/vinext/dist/cli.js build && NEXT_DEPLOYMENT_ID=vinext-front-redirect-e2e node ../../../../packages/vinext/dist/cli.js start --port 4188",
|
|
cwd: "./tests/e2e/app-front-redirect-issue/fixture",
|
|
port: 4188,
|
|
reuseExistingServer: !process.env.CI,
|
|
timeout: 60_000,
|
|
},
|
|
},
|
|
"pages-router-basepath-dev": {
|
|
testDir: "./tests/e2e/pages-router-basepath-dev",
|
|
use: { baseURL: "http://localhost:4189" },
|
|
server: {
|
|
command:
|
|
"(test -e node_modules || test -L node_modules || ln -s ../pages-basic/node_modules node_modules) && npx vp dev --port 4189",
|
|
cwd: "./tests/fixtures/pages-basepath-dev",
|
|
port: 4189,
|
|
reuseExistingServer: !process.env.CI,
|
|
timeout: 30_000,
|
|
},
|
|
},
|
|
"pages-router-basepath": {
|
|
// basePath + trailingSlash. Runs in PROD mode (build + start) because
|
|
// vinext's dev server has a Vite html-proxy / basePath incompatibility
|
|
// in inline hydration imports — unrelated to the navigation pipeline
|
|
// under test. Prod skips html-proxy entirely (it uses pre-built
|
|
// `__VINEXT_PAGE_LOADERS__`), so we exercise the same Pages Router
|
|
// navigation code paths users hit in production.
|
|
testDir: "./tests/e2e/pages-router-basepath",
|
|
use: { baseURL: "http://localhost:4190" },
|
|
server: {
|
|
command:
|
|
"(test -e node_modules || test -L node_modules || ln -s ../pages-basic/node_modules node_modules) && npx vp run vinext#build && node ../../../packages/vinext/dist/cli.js build && node ../../../packages/vinext/dist/cli.js start --port 4190",
|
|
cwd: "./tests/fixtures/pages-basepath-trailing-slash",
|
|
port: 4190,
|
|
reuseExistingServer: !process.env.CI,
|
|
timeout: 120_000,
|
|
},
|
|
},
|
|
"app-router-prefetch-searchparams": {
|
|
testDir: "./tests/e2e/app-router-prefetch-searchparams",
|
|
use: { baseURL: "http://localhost:4191" },
|
|
server: {
|
|
command:
|
|
"npx vp run vinext#build && node ../../../packages/vinext/dist/cli.js build && node ../../../packages/vinext/dist/cli.js start --port 4191",
|
|
cwd: "./tests/fixtures/app-basic",
|
|
port: 4191,
|
|
reuseExistingServer: !process.env.CI,
|
|
timeout: 120_000,
|
|
},
|
|
},
|
|
"app-router-encoded-basepath-i18n": {
|
|
testDir: "./tests/e2e/app-router-encoded-basepath-i18n",
|
|
use: { baseURL: "http://localhost:4196" },
|
|
server: {
|
|
command:
|
|
"VINEXT_ENCODED_PATH_BASEPATH_I18N=1 npx vp run vinext#build && VINEXT_ENCODED_PATH_BASEPATH_I18N=1 node ../../../packages/vinext/dist/cli.js build && VINEXT_ENCODED_PATH_BASEPATH_I18N=1 node ../../../packages/vinext/dist/cli.js start --port 4196",
|
|
cwd: "./tests/fixtures/app-basic",
|
|
port: 4196,
|
|
reuseExistingServer: !process.env.CI,
|
|
timeout: 120_000,
|
|
},
|
|
},
|
|
"pages-router-complex": {
|
|
// Compatibility target exercising the convoluted patterns of large,
|
|
// long-lived Pages Router apps (examples/pages-router-complex). The specs
|
|
// document behaviour verified against real Next.js (`pnpm dev:next` in
|
|
// the example). Known vinext gaps are marked test.fixme so the passing
|
|
// compatibility surface remains enforced in CI. Run it with:
|
|
// PLAYWRIGHT_PROJECT=pages-router-complex pnpm run test:e2e
|
|
testDir: "./tests/e2e/pages-router-complex",
|
|
use: { baseURL: "http://localhost:4199" },
|
|
server: {
|
|
command: "npx vp dev --port 4199",
|
|
cwd: "./examples/pages-router-complex",
|
|
port: 4199,
|
|
reuseExistingServer: !process.env.CI,
|
|
timeout: 30_000,
|
|
env: {
|
|
ATLAS_PURGE_BEARER: "e2e-purge-token",
|
|
// Parity gap: vinext invokes generateBuildId at dev startup; Next.js
|
|
// only calls it at build time.
|
|
RELEASE_TAG: "e2e",
|
|
},
|
|
},
|
|
},
|
|
"cloudflare-encoded-paths": {
|
|
testDir: "./tests/e2e/cloudflare-encoded-paths",
|
|
use: { baseURL: "http://localhost:4197" },
|
|
server: {
|
|
command: "npx vp build && npx wrangler dev --config dist/server/wrangler.json --port 4197",
|
|
cwd: "./tests/fixtures/cf-app-basic",
|
|
port: 4197,
|
|
reuseExistingServer: !process.env.CI,
|
|
timeout: 60_000,
|
|
},
|
|
},
|
|
};
|
|
|
|
type ProjectName = keyof typeof projectServers;
|
|
|
|
const selected = process.env.PLAYWRIGHT_PROJECT;
|
|
|
|
if (selected && !(selected in projectServers)) {
|
|
throw new Error(
|
|
`Unknown PLAYWRIGHT_PROJECT: "${selected}". ` +
|
|
`Valid: ${Object.keys(projectServers).join(", ")}`,
|
|
);
|
|
}
|
|
|
|
const activeProjects: ProjectName[] = selected
|
|
? [selected as ProjectName]
|
|
: (Object.keys(projectServers) as ProjectName[]);
|
|
|
|
export default defineConfig({
|
|
testDir: "./tests/e2e",
|
|
timeout: 30_000,
|
|
retries: 1,
|
|
// GitHub reporter adds inline failure annotations in PR diffs.
|
|
reporter: process.env.CI ? [["list"], ["github"]] : [["list"]],
|
|
use: {
|
|
headless: true,
|
|
// Most projects use Chromium by default. Browser-specific projects override this.
|
|
browserName: "chromium",
|
|
},
|
|
projects: activeProjects.map((name) => {
|
|
const p = projectServers[name];
|
|
return {
|
|
name,
|
|
testDir: p.testDir,
|
|
...("testMatch" in p ? { testMatch: p.testMatch } : {}),
|
|
...("testIgnore" in p ? { testIgnore: p.testIgnore } : {}),
|
|
...("use" in p ? { use: p.use } : {}),
|
|
};
|
|
}),
|
|
webServer: [
|
|
...new Map(
|
|
activeProjects
|
|
.map((name) => projectServers[name].server)
|
|
.filter(
|
|
(server): server is NonNullable<(typeof projectServers)[ProjectName]["server"]> =>
|
|
server !== null,
|
|
)
|
|
.map((server) => [server.port, server]),
|
|
).values(),
|
|
],
|
|
});
|