[next-playwright] Use unique cookie values for instant navigation testing lock (#91250)

Co-authored-by: Cursor Agent <[email protected]>
This commit is contained in:
Sebastian "Sebbie" Silbermann
2026-03-16 21:07:56 +00:00
committed by GitHub
co-authored by Cursor Agent
parent 63dff61bfc
commit 672b02b270
16 changed files with 154 additions and 111 deletions
+1 -1
View File
@@ -12,6 +12,6 @@
"devDependencies": {
"rimraf": "6.0.1",
"next": "workspace:*",
"playwright": "^1.40.0"
"playwright": "1.58.2"
}
}
+2 -2
View File
@@ -255,8 +255,8 @@
"octokit": "3.1.0",
"outdent": "0.8.0",
"pixrem": "5.0.0",
"playwright": "1.48.0",
"playwright-chromium": "1.48.0",
"playwright": "1.58.2",
"playwright-chromium": "1.58.2",
"postcss": "8.4.31",
"postcss-nested": "4.2.1",
"postcss-pseudoelements": "5.0.0",
+1
View File
@@ -26,6 +26,7 @@
}
},
"devDependencies": {
"@playwright/test": "1.58.2",
"typescript": "5.9.2"
}
}
+8 -5
View File
@@ -74,11 +74,14 @@ export async function instant<T>(
// navigation-testing-lock.ts, which acquires the in-memory navigation lock.
const { hostname } = new URL(resolveURL(page, options))
await step('Acquire Instant Lock', () =>
page
.context()
.addCookies([
{ name: INSTANT_COOKIE, value: '[0]', domain: hostname, path: '/' },
])
page.context().addCookies([
{
name: INSTANT_COOKIE,
value: JSON.stringify([0, `p${Math.random()}`]),
domain: hostname,
path: '/',
},
])
)
try {
return await fn()
+1 -1
View File
@@ -167,7 +167,7 @@
"@next/react-refresh-utils": "16.2.0-canary.100",
"@next/swc": "16.2.0-canary.100",
"@opentelemetry/api": "1.6.0",
"@playwright/test": "1.51.1",
"@playwright/test": "1.58.2",
"@rspack/core": "1.6.7",
"@storybook/addon-a11y": "8.6.0",
"@storybook/addon-essentials": "8.6.0",
@@ -5,11 +5,6 @@
* during instant navigation captures, and owns all cookie state
* transitions (pending → captured-MPA, pending → captured-SPA).
*
* The cookie value is a JSON array:
* [0] — pending (waiting to capture)
* [1, null] — captured MPA page load
* [1, { from, to }] — captured SPA navigation (from/to route trees)
*
* External actors (Playwright, devtools) set [0] to start a lock scope
* and delete the cookie to end one. Next.js writes captured values.
* The CookieStore handler distinguishes them by value: pending = external,
@@ -22,17 +17,30 @@ import { refreshOnInstantNavigationUnlock } from '../use-action-queue'
type InstantNavCookieState = 'pending' | 'mpa' | 'spa'
type InstantCookie =
// pending (waiting to capture)
| [captured: 0, id: string]
// captured MPA page load
| [captured: 1, id: string, state: null]
// captured SPA navigation (from/to route trees)
| [
captured: 1,
id: string,
state: { from: FlightRouterState; to: FlightRouterState | null },
]
function parseCookieValue(raw: string): InstantNavCookieState {
try {
const parsed = JSON.parse(raw)
if (Array.isArray(parsed) && parsed.length >= 2) {
return parsed[1] === null ? 'mpa' : 'spa'
if (Array.isArray(parsed) && parsed.length >= 3) {
const rawState = parsed[2]
return rawState === null ? 'mpa' : 'spa'
}
} catch {}
return 'pending'
}
function writeCookieValue(value: unknown[]): void {
function writeCookieValue(value: InstantCookie): void {
if (typeof cookieStore === 'undefined') {
return
}
@@ -101,7 +109,7 @@ export function startListeningForInstantNavigationCookie(): void {
})
}
writeCookieValue([1, null])
writeCookieValue([1, `c${Math.random()}`, null])
acquireLock()
}
@@ -151,7 +159,7 @@ export function transitionToCapturedSPA(
toTree: FlightRouterState | null
): void {
if (process.env.__NEXT_EXPOSE_TESTING_API) {
writeCookieValue([1, { from: fromTree, to: toTree }])
writeCookieValue([1, `c${Math.random()}`, { from: fromTree, to: toTree }])
}
}
@@ -164,7 +172,7 @@ export function updateCapturedSPAToTree(
toTree: FlightRouterState
): void {
if (process.env.__NEXT_EXPOSE_TESTING_API) {
writeCookieValue([1, { from: fromTree, to: toTree }])
writeCookieValue([1, `c${Math.random()}`, { from: fromTree, to: toTree }])
}
}
@@ -30,14 +30,15 @@ export type InstantNavCookieData =
function parseCookieValue(raw: string): InstantNavCookieData {
try {
const parsed = JSON.parse(raw)
if (Array.isArray(parsed) && parsed.length >= 2) {
if (parsed[1] === null) {
if (Array.isArray(parsed) && parsed.length >= 3) {
const rawState = parsed[2]
if (rawState === null) {
return { state: 'mpa' }
}
// SPA capture: parsed[1] is { from, to }
if (typeof parsed[1] === 'object' && parsed[1] !== null) {
const fromTree: FlightRouterState = parsed[1].from ?? ['', {}]
const toTree: FlightRouterState | null = parsed[1].to ?? null
// SPA capture: rawState is { from, to }
if (typeof rawState === 'object' && rawState !== null) {
const fromTree: FlightRouterState = rawState.from ?? ['', {}]
const toTree: FlightRouterState | null = rawState.to ?? null
return { state: 'spa', fromTree, toTree }
}
return { state: 'spa', fromTree: ['', {}], toTree: null }
@@ -44,7 +44,7 @@ export function InstantNavsPanel() {
if (typeof cookieStore !== 'undefined') {
cookieStore.set({
name: COOKIE_NAME,
value: '[0]',
value: JSON.stringify([0, `p${Math.random()}`]),
path: '/',
})
}
@@ -55,7 +55,7 @@ export function InstantNavsPanel() {
if (typeof cookieStore !== 'undefined') {
cookieStore.set({
name: COOKIE_NAME,
value: '[0]',
value: JSON.stringify([0, `p${Math.random()}`]),
path: '/',
})
}
+50 -62
View File
@@ -460,11 +460,11 @@ importers:
specifier: 5.0.0
version: 5.0.0
playwright:
specifier: 1.48.0
version: 1.48.0
specifier: 1.58.2
version: 1.58.2
playwright-chromium:
specifier: 1.48.0
version: 1.48.0
specifier: 1.58.2
version: 1.58.2
postcss:
specifier: 8.4.31
version: 8.4.31
@@ -668,7 +668,7 @@ importers:
version: 0.554.0([email protected])
next:
specifier: 16.0.8
version: 16.0.8(@babel/[email protected])(@opentelemetry/[email protected])(@playwright/[email protected]1.1)([email protected])([email protected])([email protected]([email protected]))([email protected])([email protected])
version: 16.0.8(@babel/[email protected])(@opentelemetry/[email protected])(@playwright/[email protected]8.2)([email protected])([email protected])([email protected]([email protected]))([email protected])([email protected])
next-themes:
specifier: ^0.4.6
version: 0.4.6([email protected]([email protected]))([email protected])
@@ -726,16 +726,16 @@ importers:
dependencies:
fumadocs-core:
specifier: 15.7.12
version: 15.7.12(@types/[email protected])([email protected](@babel/[email protected])(@opentelemetry/[email protected])(@playwright/[email protected]1.1)([email protected])([email protected])([email protected]([email protected]))([email protected])([email protected]))([email protected]([email protected]))([email protected])
version: 15.7.12(@types/[email protected])([email protected](@babel/[email protected])(@opentelemetry/[email protected])(@playwright/[email protected]8.2)([email protected])([email protected])([email protected]([email protected]))([email protected])([email protected]))([email protected]([email protected]))([email protected])
fumadocs-mdx:
specifier: 11.10.0
version: 11.10.0([email protected](@types/[email protected])([email protected](@babel/[email protected])(@opentelemetry/[email protected])(@playwright/[email protected]1.1)([email protected])([email protected])([email protected]([email protected]))([email protected])([email protected]))([email protected]([email protected]))([email protected]))([email protected](@babel/[email protected])(@opentelemetry/[email protected])(@playwright/[email protected]1.1)([email protected])([email protected])([email protected]([email protected]))([email protected])([email protected]))([email protected])
version: 11.10.0([email protected](@types/[email protected])([email protected](@babel/[email protected])(@opentelemetry/[email protected])(@playwright/[email protected]8.2)([email protected])([email protected])([email protected]([email protected]))([email protected])([email protected]))([email protected]([email protected]))([email protected]))([email protected](@babel/[email protected])(@opentelemetry/[email protected])(@playwright/[email protected]8.2)([email protected])([email protected])([email protected]([email protected]))([email protected])([email protected]))([email protected])
fumadocs-ui:
specifier: 15.7.12
version: 15.7.12(@types/[email protected](@types/[email protected]))(@types/[email protected])([email protected](@babel/[email protected])(@opentelemetry/[email protected])(@playwright/[email protected]1.1)([email protected])([email protected])([email protected]([email protected]))([email protected])([email protected]))([email protected]([email protected]))([email protected])([email protected])
version: 15.7.12(@types/[email protected](@types/[email protected]))(@types/[email protected])([email protected](@babel/[email protected])(@opentelemetry/[email protected])(@playwright/[email protected]8.2)([email protected])([email protected])([email protected]([email protected]))([email protected])([email protected]))([email protected]([email protected]))([email protected])([email protected])
next:
specifier: 15.5.8
version: 15.5.8(@babel/[email protected])(@opentelemetry/[email protected])(@playwright/[email protected]1.1)([email protected])([email protected])([email protected]([email protected]))([email protected])([email protected])
version: 15.5.8(@babel/[email protected])(@opentelemetry/[email protected])(@playwright/[email protected]8.2)([email protected])([email protected])([email protected]([email protected]))([email protected])([email protected])
react:
specifier: npm:[email protected]
version: 19.3.0-canary-5e9eedb5-20260312
@@ -831,8 +831,8 @@ importers:
specifier: workspace:*
version: link:../../packages/next
playwright:
specifier: ^1.40.0
version: 1.48.0
specifier: 1.58.2
version: 1.58.2
rimraf:
specifier: 6.0.1
version: 6.0.1
@@ -1237,8 +1237,8 @@ importers:
specifier: 1.6.0
version: 1.6.0
'@playwright/test':
specifier: 1.51.1
version: 1.51.1
specifier: 1.58.2
version: 1.58.2
'@rspack/core':
specifier: 1.6.7
version: 1.6.7(@swc/[email protected])
@@ -1412,7 +1412,7 @@ importers:
version: 3.0.0
axe-playwright:
specifier: 2.0.3
version: 2.0.3([email protected]1.1)
version: 2.0.3([email protected]8.2)
babel-loader:
specifier: 10.0.0
version: 10.0.0(@babel/[email protected])([email protected](@swc/[email protected](@swc/[email protected]))([email protected]))
@@ -1872,11 +1872,10 @@ importers:
version: 0.7.3
packages/next-playwright:
dependencies:
'@playwright/test':
specifier: '>=1.0.0'
version: 1.51.1
devDependencies:
'@playwright/test':
specifier: 1.58.2
version: 1.58.2
typescript:
specifier: 5.9.2
version: 5.9.2
@@ -2040,8 +2039,8 @@ importers:
specifier: ^2.0.5
version: 2.0.5
playwright-chromium:
specifier: 1.48.0
version: 1.48.0
specifier: 1.58.2
version: 1.58.2
split2:
specifier: ^4.2.0
version: 4.2.0
@@ -5032,8 +5031,8 @@ packages:
resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==}
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
'@playwright/[email protected]1.1':
resolution: {integrity: sha512-nM+kEaTSAoVlXmMPH10017vn3FSiFqr/bh4fKg9vmAdMfd9SDqRZNvPSiAHADc/itWak+qPvMPZQOPwCBW7k7Q==}
'@playwright/[email protected]8.2':
resolution: {integrity: sha512-akea+6bHYBBfA9uQqSYmlJXn61cTa+jbO87xVLCWbTqbWadRVmhxlXATaOjOgcBaWU4ePo0wB41KMFv3o35IXA==}
engines: {node: '>=18'}
hasBin: true
@@ -15032,13 +15031,8 @@ packages:
resolution: {integrity: sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==}
engines: {node: '>=8'}
playwright-chromium@1.48.0:
resolution: {integrity: sha512-jPFKhB4+zGEcAwc+h1mTLa8L08Rb+FwGKFqd/o7mWSGyxAtwBu5R4QxSG/a8KcHbewOj4DLBUVVK2N/uKrYmiQ==}
engines: {node: '>=18'}
hasBin: true
[email protected]:
resolution: {integrity: sha512-RBvzjM9rdpP7UUFrQzRwR8L/xR4HyC1QXMzGYTbf1vjw25/ya9NRAVnXi/0fvFopjebvyPzsmoK58xxeEOaVvA==}
playwright-chromium@1.58.2:
resolution: {integrity: sha512-SCoQ3hjBs7FfO46CoOtgAUg77BuYwCni1bzQgm47IUyLBTipnGkLxLnaUNRKXvPYO4hAyt8++Z6wVShVnhrzmw==}
engines: {node: '>=18'}
hasBin: true
@@ -15047,13 +15041,13 @@ packages:
engines: {node: '>=18'}
hasBin: true
playwright@1.48.0:
resolution: {integrity: sha512-qPqFaMEHuY/ug8o0uteYJSRfMGFikhUysk8ZvAtfKmUK3kc/6oNl/y3EczF8OFGYIi/Ex2HspMfzYArk6+XQSA==}
playwright-core@1.58.2:
resolution: {integrity: sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==}
engines: {node: '>=18'}
hasBin: true
[email protected]1.1:
resolution: {integrity: sha512-kkx+MB2KQRkyxjYPc3a0wLZZoDczmppyGJIvQ43l+aZihkaVvmu/21kiyaHeHjiFxjxNNFnUncKmcGIyOojsaw==}
[email protected]8.2:
resolution: {integrity: sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A==}
engines: {node: '>=18'}
hasBin: true
@@ -22595,9 +22589,9 @@ snapshots:
'@pkgr/[email protected]': {}
'@playwright/[email protected]1.1':
'@playwright/[email protected]8.2':
dependencies:
playwright: 1.51.1
playwright: 1.58.2
'@polka/[email protected]': {}
@@ -23949,7 +23943,7 @@ snapshots:
jest-serializer-html: 7.1.0
jest-watch-typeahead: 2.2.2([email protected](@types/[email protected](patch_hash=rvl3vkomen3tospgr67bzubfyu))([email protected]))
nyc: 15.1.0
playwright: 1.48.0
playwright: 1.58.2
storybook: 8.6.0([email protected])
transitivePeerDependencies:
- '@swc/helpers'
@@ -25615,14 +25609,14 @@ snapshots:
axe-core: 4.10.0
mustache: 4.2.0
[email protected]([email protected]1.1):
[email protected]([email protected]8.2):
dependencies:
'@types/junit-report-builder': 3.0.2
axe-core: 4.10.0
axe-html-reporter: 2.2.11([email protected])
junit-report-builder: 5.1.1
picocolors: 1.1.1
playwright: 1.51.1
playwright: 1.58.2
[email protected]:
dependencies:
@@ -29628,7 +29622,7 @@ snapshots:
[email protected]:
optional: true
[email protected](@types/[email protected])([email protected](@babel/[email protected])(@opentelemetry/[email protected])(@playwright/[email protected]1.1)([email protected])([email protected])([email protected]([email protected]))([email protected])([email protected]))([email protected]([email protected]))([email protected]):
[email protected](@types/[email protected])([email protected](@babel/[email protected])(@opentelemetry/[email protected])(@playwright/[email protected]8.2)([email protected])([email protected])([email protected]([email protected]))([email protected])([email protected]))([email protected]([email protected]))([email protected]):
dependencies:
'@formatjs/intl-localematcher': 0.6.1
'@orama/orama': 3.1.13
@@ -29649,20 +29643,20 @@ snapshots:
unist-util-visit: 5.0.0
optionalDependencies:
'@types/react': 19.2.10
next: 15.5.8(@babel/[email protected])(@opentelemetry/[email protected])(@playwright/[email protected]1.1)([email protected])([email protected])([email protected]([email protected]))([email protected])([email protected])
next: 15.5.8(@babel/[email protected])(@opentelemetry/[email protected])(@playwright/[email protected]8.2)([email protected])([email protected])([email protected]([email protected]))([email protected])([email protected])
react: 19.3.0-canary-5e9eedb5-20260312
react-dom: 19.3.0-canary-5e9eedb5-20260312([email protected])
transitivePeerDependencies:
- supports-color
[email protected]([email protected](@types/[email protected])([email protected](@babel/[email protected])(@opentelemetry/[email protected])(@playwright/[email protected]1.1)([email protected])([email protected])([email protected]([email protected]))([email protected])([email protected]))([email protected]([email protected]))([email protected]))([email protected](@babel/[email protected])(@opentelemetry/[email protected])(@playwright/[email protected]1.1)([email protected])([email protected])([email protected]([email protected]))([email protected])([email protected]))([email protected]):
[email protected]([email protected](@types/[email protected])([email protected](@babel/[email protected])(@opentelemetry/[email protected])(@playwright/[email protected]8.2)([email protected])([email protected])([email protected]([email protected]))([email protected])([email protected]))([email protected]([email protected]))([email protected]))([email protected](@babel/[email protected])(@opentelemetry/[email protected])(@playwright/[email protected]8.2)([email protected])([email protected])([email protected]([email protected]))([email protected])([email protected]))([email protected]):
dependencies:
'@mdx-js/mdx': 3.1.1
'@standard-schema/spec': 1.0.0
chokidar: 4.0.3
esbuild: 0.25.9
estree-util-value-to-estree: 3.5.0
fumadocs-core: 15.7.12(@types/[email protected])([email protected](@babel/[email protected])(@opentelemetry/[email protected])(@playwright/[email protected]1.1)([email protected])([email protected])([email protected]([email protected]))([email protected])([email protected]))([email protected]([email protected]))([email protected])
fumadocs-core: 15.7.12(@types/[email protected])([email protected](@babel/[email protected])(@opentelemetry/[email protected])(@playwright/[email protected]8.2)([email protected])([email protected])([email protected]([email protected]))([email protected])([email protected]))([email protected]([email protected]))([email protected])
js-yaml: 4.1.0
lru-cache: 11.2.1
picocolors: 1.1.1
@@ -29674,12 +29668,12 @@ snapshots:
unist-util-visit: 5.0.0
zod: 4.1.13
optionalDependencies:
next: 15.5.8(@babel/[email protected])(@opentelemetry/[email protected])(@playwright/[email protected]1.1)([email protected])([email protected])([email protected]([email protected]))([email protected])([email protected])
next: 15.5.8(@babel/[email protected])(@opentelemetry/[email protected])(@playwright/[email protected]8.2)([email protected])([email protected])([email protected]([email protected]))([email protected])([email protected])
react: 19.3.0-canary-5e9eedb5-20260312
transitivePeerDependencies:
- supports-color
[email protected](@types/[email protected](@types/[email protected]))(@types/[email protected])([email protected](@babel/[email protected])(@opentelemetry/[email protected])(@playwright/[email protected]1.1)([email protected])([email protected])([email protected]([email protected]))([email protected])([email protected]))([email protected]([email protected]))([email protected])([email protected]):
[email protected](@types/[email protected](@types/[email protected]))(@types/[email protected])([email protected](@babel/[email protected])(@opentelemetry/[email protected])(@playwright/[email protected]8.2)([email protected])([email protected])([email protected]([email protected]))([email protected])([email protected]))([email protected]([email protected]))([email protected])([email protected]):
dependencies:
'@radix-ui/react-accordion': 1.2.12(@types/[email protected](@types/[email protected]))(@types/[email protected])([email protected]([email protected]))([email protected])
'@radix-ui/react-collapsible': 1.1.12(@types/[email protected](@types/[email protected]))(@types/[email protected])([email protected]([email protected]))([email protected])
@@ -29692,7 +29686,7 @@ snapshots:
'@radix-ui/react-slot': 1.2.3(@types/[email protected])([email protected])
'@radix-ui/react-tabs': 1.1.13(@types/[email protected](@types/[email protected]))(@types/[email protected])([email protected]([email protected]))([email protected])
class-variance-authority: 0.7.1
fumadocs-core: 15.7.12(@types/[email protected])([email protected](@babel/[email protected])(@opentelemetry/[email protected])(@playwright/[email protected]1.1)([email protected])([email protected])([email protected]([email protected]))([email protected])([email protected]))([email protected]([email protected]))([email protected])
fumadocs-core: 15.7.12(@types/[email protected])([email protected](@babel/[email protected])(@opentelemetry/[email protected])(@playwright/[email protected]8.2)([email protected])([email protected])([email protected]([email protected]))([email protected])([email protected]))([email protected]([email protected]))([email protected])
lodash.merge: 4.6.2
next-themes: 0.4.6([email protected]([email protected]))([email protected])
postcss-selector-parser: 7.1.0
@@ -29703,7 +29697,7 @@ snapshots:
tailwind-merge: 3.3.1
optionalDependencies:
'@types/react': 19.2.10
next: 15.5.8(@babel/[email protected])(@opentelemetry/[email protected])(@playwright/[email protected]1.1)([email protected])([email protected])([email protected]([email protected]))([email protected])([email protected])
next: 15.5.8(@babel/[email protected])(@opentelemetry/[email protected])(@playwright/[email protected]8.2)([email protected])([email protected])([email protected]([email protected]))([email protected])([email protected])
tailwindcss: 4.1.13
transitivePeerDependencies:
- '@mixedbread/sdk'
@@ -31659,7 +31653,7 @@ snapshots:
jest-process-manager: 0.4.0([email protected])
jest-runner: 29.7.0
nyc: 15.1.0
playwright-core: 1.48.0
playwright-core: 1.51.1
rimraf: 3.0.2
uuid: 8.3.2
transitivePeerDependencies:
@@ -34031,7 +34025,7 @@ snapshots:
[email protected]: {}
[email protected](@babel/[email protected])(@opentelemetry/[email protected])(@playwright/[email protected]1.1)([email protected])([email protected])([email protected]([email protected]))([email protected])([email protected]):
[email protected](@babel/[email protected])(@opentelemetry/[email protected])(@playwright/[email protected]8.2)([email protected])([email protected])([email protected]([email protected]))([email protected])([email protected]):
dependencies:
'@next/env': 15.5.8
'@swc/helpers': 0.5.15
@@ -34050,7 +34044,7 @@ snapshots:
'@next/swc-win32-arm64-msvc': 15.5.7
'@next/swc-win32-x64-msvc': 15.5.7
'@opentelemetry/api': 1.9.0
'@playwright/test': 1.51.1
'@playwright/test': 1.58.2
babel-plugin-react-compiler: 0.0.0-experimental-1371fcb-20260227
sass: 1.77.8
sharp: 0.34.4
@@ -34058,7 +34052,7 @@ snapshots:
- '@babel/core'
- babel-plugin-macros
[email protected](@babel/[email protected])(@opentelemetry/[email protected])(@playwright/[email protected]1.1)([email protected])([email protected])([email protected]([email protected]))([email protected])([email protected]):
[email protected](@babel/[email protected])(@opentelemetry/[email protected])(@playwright/[email protected]8.2)([email protected])([email protected])([email protected]([email protected]))([email protected])([email protected]):
dependencies:
'@next/env': 16.0.8
'@swc/helpers': 0.5.15
@@ -34077,7 +34071,7 @@ snapshots:
'@next/swc-win32-arm64-msvc': 16.0.8
'@next/swc-win32-x64-msvc': 16.0.8
'@opentelemetry/api': 1.9.0
'@playwright/test': 1.51.1
'@playwright/test': 1.58.2
babel-plugin-react-compiler: 0.0.0-experimental-1371fcb-20260227
sass: 1.77.8
sharp: 0.34.4
@@ -35128,23 +35122,17 @@ snapshots:
dependencies:
find-up: 3.0.0
playwright-chromium@1.48.0:
playwright-chromium@1.58.2:
dependencies:
playwright-core: 1.48.0
[email protected]: {}
playwright-core: 1.58.2
[email protected]: {}
playwright@1.48.0:
dependencies:
playwright-core: 1.48.0
optionalDependencies:
fsevents: 2.3.2
playwright-core@1.58.2: {}
[email protected]1.1:
[email protected]8.2:
dependencies:
playwright-core: 1.51.1
playwright-core: 1.58.2
optionalDependencies:
fsevents: 2.3.2
@@ -116,7 +116,8 @@ describe.each([['', '/docs']])(
const script = document.createElement('script')
script.src = "${next.url}/_next/static/chunks/pages/_app.js"
script.onerror = (err) => {
script.onerror = (error) => {
console.error('script error', error)
statusEl.innerText = 'error'
}
script.onload = () => {
@@ -126,7 +127,13 @@ describe.each([['', '/docs']])(
})()`
// ensure direct port with mismatching port is blocked
const browser = await webdriver(`http://127.0.0.1:${port}`, '/about')
const browser = await webdriver(
`http://127.0.0.1:${port}`,
'/about',
{
permissions: ['local-network-access'],
}
)
await browser.eval(scriptSnippet)
await retry(async () => {
@@ -136,6 +143,7 @@ describe.each([['', '/docs']])(
})
// ensure different host is blocked
// Requires local-network-access permission to send a request to next.url
await browser.get(`https://example.vercel.sh/`)
await browser.eval(scriptSnippet)
@@ -145,7 +153,11 @@ describe.each([['', '/docs']])(
)
})
expect(next.cliOutput).toContain('Cross origin request detected from')
expect(next.cliOutput).toContain(
// We're not sending an Origin header
// TODO: redundant spacing
'Cross origin request detected to'
)
} finally {
server.close()
}
@@ -1,4 +1,5 @@
import { nextTestSetup } from 'e2e-utils'
import { retry } from 'next-test-utils'
describe('use-router-with-rewrites', () => {
const { next } = nextTestSetup({
@@ -68,30 +69,33 @@ describe('use-router-with-rewrites', () => {
const browser = await next.browser('/rewrite-to-same-segment/0')
await browser.elementById('router-push').click()
await retry(async () => {
expect(await browser.elementByCss('p').text()).toBe('1')
})
const url = new URL(await browser.url())
expect(url.pathname + url.search).toBe('/rewrite-to-same-segment/1')
expect(await browser.elementByCss('p').text()).toBe('1')
})
it('should preserve current pathname when using useRouter.replace with rewrites on dynamic route', async () => {
const browser = await next.browser('/rewrite-to-same-segment/0')
await browser.elementById('router-replace').click()
await retry(async () => {
expect(await browser.elementByCss('p').text()).toBe('2')
})
const url = new URL(await browser.url())
expect(url.pathname + url.search).toBe('/rewrite-to-same-segment/2')
expect(await browser.elementByCss('p').text()).toBe('2')
})
it('should preserve current pathname when using Link with rewrites on dynamic route', async () => {
const browser = await next.browser('/rewrite-to-same-segment/0')
await browser.elementByCss('a').click()
await retry(async () => {
expect(await browser.elementByCss('p').text()).toBe('3')
})
const url = new URL(await browser.url())
expect(url.pathname + url.search).toBe('/rewrite-to-same-segment/3')
expect(await browser.elementByCss('p').text()).toBe('3')
})
})
})
@@ -17,6 +17,7 @@ import {
check,
getRedboxHeader,
normalizeManifest,
retry,
} from 'next-test-utils'
import cheerio from 'cheerio'
@@ -245,11 +246,12 @@ function runTests({ dev }) {
await browser.eval('window.beforeNav = 1')
await browser.elementByCss(`#${id}`).click()
await check(() => browser.eval('window.location.pathname'), pathname)
expect(JSON.parse(await browser.elementByCss('#query').text())).toEqual(
navQuery
)
await retry(async () => {
expect(JSON.parse(await browser.elementByCss('#query').text())).toEqual(
navQuery
)
})
expect(await browser.eval('window.location.pathname')).toBe(pathname)
expect(await browser.eval('window.location.hash')).toBe(hash)
expect(
+25 -5
View File
@@ -12,6 +12,7 @@ import {
Locator,
Request as PlaywrightRequest,
Response as PlaywrightResponse,
BrowserContextOptions,
} from 'playwright'
import path from 'path'
@@ -19,10 +20,13 @@ type EventType = 'request' | 'response'
type PageLog = { source: string; message: string; args: unknown[] }
export type Permissions = BrowserContextOptions['permissions']
let page: Page
let browser: Browser | undefined
let context: BrowserContext | undefined
let contextHasJSEnabled: boolean = true
let contextPermissions: Permissions = undefined
let pageLogs: Array<Promise<PageLog> | PageLog> = []
let websocketFrames: Array<{ payload: string | Buffer }> = []
@@ -167,7 +171,8 @@ export class Playwright<TCurrent = undefined> {
javaScriptEnabled: boolean,
ignoreHTTPSErrors: boolean,
headless: boolean,
userAgent: string | undefined
userAgent: string | undefined,
permissions: Permissions
) {
let device
@@ -182,7 +187,13 @@ export class Playwright<TCurrent = undefined> {
}
if (browser) {
if (contextHasJSEnabled !== javaScriptEnabled) {
if (
contextHasJSEnabled !== javaScriptEnabled ||
// Even triggers on same set of permissions, but we don't want to deal
// with the complexity of diffing them, so we just always recreate the
// context when permissions are set.
contextPermissions !== permissions
) {
// If we have switched from having JS enable/disabled we need to recreate the context.
await teardown(this.teardownTracing.bind(this))
await context?.close()
@@ -192,8 +203,10 @@ export class Playwright<TCurrent = undefined> {
ignoreHTTPSErrors,
...(userAgent ? { userAgent } : {}),
...device,
permissions,
})
contextHasJSEnabled = javaScriptEnabled
contextPermissions = permissions
}
return
}
@@ -205,6 +218,7 @@ export class Playwright<TCurrent = undefined> {
ignoreHTTPSErrors,
...(userAgent ? { userAgent } : {}),
...device,
permissions,
})
contextHasJSEnabled = javaScriptEnabled
}
@@ -214,14 +228,16 @@ export class Playwright<TCurrent = undefined> {
await page?.close()
}
async launchBrowser(browserName: string, launchOptions: Record<string, any>) {
async launchBrowser(
browserName: string,
launchOptions: { headless: boolean }
) {
if (browserName === 'safari') {
return await webkit.launch(launchOptions)
} else if (browserName === 'firefox') {
return await firefox.launch({
...launchOptions,
firefoxUserPrefs: {
...launchOptions.firefoxUserPrefs,
// The "fission.webContentIsolationStrategy" pref must be
// set to 1 on Firefox due to the bug where a new history
// state is pushed on a page reload.
@@ -231,9 +247,13 @@ export class Playwright<TCurrent = undefined> {
},
})
} else {
let launchArgs: string[] = []
if (!launchOptions.headless) {
launchArgs.push('--auto-open-devtools-for-tabs')
}
return await chromium.launch({
devtools: !launchOptions.headless,
...launchOptions,
args: launchArgs,
ignoreDefaultArgs: ['--disable-back-forward-cache'],
})
}
+5 -1
View File
@@ -1,6 +1,7 @@
import { debugPrint, getFullUrl } from 'next-test-utils'
import os from 'os'
import {
Permissions,
Playwright,
PlaywrightNavigationWaitUntil,
} from './browsers/playwright'
@@ -48,6 +49,7 @@ if (typeof afterAll === 'function') {
}
export interface WebdriverOptions {
permissions?: Permissions
/**
* whether to wait for React hydration to finish
*/
@@ -121,6 +123,7 @@ export default async function webdriver(
extraHTTPHeaders,
locale,
disableJavaScript,
permissions,
ignoreHTTPSErrors,
headless,
cpuThrottleRate,
@@ -141,7 +144,8 @@ export default async function webdriver(
Boolean(ignoreHTTPSErrors),
// allow headless to be overwritten for a particular test
typeof headless !== 'undefined' ? headless : !!process.env.HEADLESS,
userAgent
userAgent,
permissions
)
;(global as any).browserName = browserName
+1 -1
View File
@@ -48,7 +48,7 @@
"minimist": "^1.2.8",
"picocolors": "1.0.1",
"pidusage-tree": "^2.0.5",
"playwright-chromium": "1.48.0",
"playwright-chromium": "1.58.2",
"split2": "^4.2.0",
"tree-kill": "^1.2.2"
}
@@ -348,7 +348,7 @@ export async function newBrowserSession(options: {
}): Promise<BrowserSession> {
const browser = await chromium.launch({
headless: options.headless ?? process.env.HEADLESS !== 'false',
devtools: true,
args: options.headless ? undefined : ['--auto-open-devtools-for-tabs'],
timeout: 60000,
})
const context = await browser.newContext({