diff --git a/packages/e2e/next/cypress.config.ts b/packages/e2e/next/cypress.config.ts
index aa3d5724..1ebb2275 100644
--- a/packages/e2e/next/cypress.config.ts
+++ b/packages/e2e/next/cypress.config.ts
@@ -1,5 +1,4 @@
-import { defineConfig } from 'cypress'
-import cypressTerminalReport from 'cypress-terminal-report/src/installLogsPrinter'
+import { defineConfig } from 'e2e-shared/cypress.config'
import fs from 'node:fs'
import semver from 'semver'
@@ -9,20 +8,11 @@ const basePath =
const nextJsVersion = readNextJsVersion()
export default defineConfig({
- e2e: {
- baseUrl: `http://localhost:3001${basePath}`,
- video: false,
- fixturesFolder: false,
- testIsolation: true,
- setupNodeEvents(on) {
- cypressTerminalReport(on)
- },
- retries: 2,
- env: {
- basePath,
- supportsShallowRouting: supportsShallowRouting(nextJsVersion),
- nextJsVersion
- }
+ baseUrl: `http://localhost:3001${basePath}`,
+ env: {
+ basePath,
+ supportsShallowRouting: supportsShallowRouting(nextJsVersion),
+ nextJsVersion
}
})
diff --git a/packages/e2e/next/cypress/e2e/hash-preservation.cy.js b/packages/e2e/next/cypress/e2e/hash-preservation.cy.js
deleted file mode 100644
index 83ad4e0b..00000000
--- a/packages/e2e/next/cypress/e2e/hash-preservation.cy.js
+++ /dev/null
@@ -1,35 +0,0 @@
-///
-
-function runTest() {
- cy.contains('#hydration-marker', 'hydrated').should('be.hidden')
- cy.get('#string_set_a').click()
- cy.location('hash').should('eq', '#hash')
- cy.get('#string_set_b').click()
- cy.location('hash').should('eq', '#hash')
- cy.get('#string_clear').click()
- cy.location('hash').should('eq', '#hash')
-}
-
-describe('hash preservation (app router)', () => {
- it('works in standard routes', () => {
- cy.visit('/app/useQueryState#hash')
- runTest()
- })
-
- it('works in dynamic routes', () => {
- cy.visit('/app/useQueryState/dynamic/route#hash')
- runTest()
- })
-})
-
-describe('hash preservation (pages router)', () => {
- it('works in standard routes', () => {
- cy.visit('/pages/useQueryState#hash')
- runTest()
- })
-
- it('works in dynamic routes', () => {
- cy.visit('/pages/useQueryState/dynamic/route#hash')
- runTest()
- })
-})
diff --git a/packages/e2e/next/cypress/e2e/persist-across-navigation.cy.js b/packages/e2e/next/cypress/e2e/persist-across-navigation.cy.js
index 57358ff7..978a8584 100644
--- a/packages/e2e/next/cypress/e2e/persist-across-navigation.cy.js
+++ b/packages/e2e/next/cypress/e2e/persist-across-navigation.cy.js
@@ -3,7 +3,7 @@
it('Persists search params across navigation using a generated Link href', () => {
cy.visit('/app/persist-across-navigation/a')
cy.contains('#hydration-marker', 'hydrated').should('be.hidden')
- cy.get('input[type=text]').type('foo')
+ cy.get('input[type=text]').type('foo', { delay: 0 })
cy.get('input[type=checkbox]').check()
cy.get('a').click()
cy.location('pathname').should(
diff --git a/packages/e2e/next/cypress/e2e/shared/basic-io.cy.ts b/packages/e2e/next/cypress/e2e/shared/basic-io.cy.ts
new file mode 100644
index 00000000..b5d6de66
--- /dev/null
+++ b/packages/e2e/next/cypress/e2e/shared/basic-io.cy.ts
@@ -0,0 +1,25 @@
+import { testBasicIO } from 'e2e-shared/specs/basic-io.cy'
+
+testBasicIO({
+ hook: 'useQueryState',
+ path: '/app/basic-io/useQueryState',
+ nextJsRouter: 'app'
+})
+
+testBasicIO({
+ hook: 'useQueryStates',
+ path: '/app/basic-io/useQueryStates',
+ nextJsRouter: 'app'
+})
+
+testBasicIO({
+ hook: 'useQueryState',
+ path: '/pages/basic-io/useQueryState',
+ nextJsRouter: 'pages'
+})
+
+testBasicIO({
+ hook: 'useQueryStates',
+ path: '/pages/basic-io/useQueryStates',
+ nextJsRouter: 'pages'
+})
diff --git a/packages/e2e/next/cypress/e2e/shared/hash-preservation.cy.ts b/packages/e2e/next/cypress/e2e/shared/hash-preservation.cy.ts
new file mode 100644
index 00000000..e41a150d
--- /dev/null
+++ b/packages/e2e/next/cypress/e2e/shared/hash-preservation.cy.ts
@@ -0,0 +1,25 @@
+import { testHashPreservation } from 'e2e-shared/specs/hash-preservation.cy'
+
+testHashPreservation({
+ path: '/app/hash-preservation',
+ nextJsRouter: 'app',
+ description: 'standard route'
+})
+
+testHashPreservation({
+ path: '/app/hash-preservation/dynamic/route',
+ nextJsRouter: 'app',
+ description: 'dynamic route'
+})
+
+testHashPreservation({
+ path: '/pages/hash-preservation',
+ nextJsRouter: 'pages',
+ description: 'standard route'
+})
+
+testHashPreservation({
+ path: '/pages/hash-preservation/dynamic/route',
+ nextJsRouter: 'pages',
+ description: 'dynamic route'
+})
diff --git a/packages/e2e/next/cypress/e2e/shared/linking.cy.ts b/packages/e2e/next/cypress/e2e/shared/linking.cy.ts
new file mode 100644
index 00000000..371769df
--- /dev/null
+++ b/packages/e2e/next/cypress/e2e/shared/linking.cy.ts
@@ -0,0 +1,25 @@
+import { testLinking } from 'e2e-shared/specs/linking.cy'
+
+testLinking({
+ hook: 'useQueryState',
+ path: '/app/linking/useQueryState',
+ nextJsRouter: 'app'
+})
+
+testLinking({
+ hook: 'useQueryStates',
+ path: '/app/linking/useQueryStates',
+ nextJsRouter: 'app'
+})
+
+testLinking({
+ hook: 'useQueryState',
+ path: '/pages/linking/useQueryState',
+ nextJsRouter: 'pages'
+})
+
+testLinking({
+ hook: 'useQueryStates',
+ path: '/pages/linking/useQueryStates',
+ nextJsRouter: 'pages'
+})
diff --git a/packages/e2e/next/cypress/e2e/shared/push.cy.ts b/packages/e2e/next/cypress/e2e/shared/push.cy.ts
new file mode 100644
index 00000000..24d64ff3
--- /dev/null
+++ b/packages/e2e/next/cypress/e2e/shared/push.cy.ts
@@ -0,0 +1,59 @@
+import { testPush } from 'e2e-shared/specs/push.cy'
+
+testPush({
+ path: '/app/push/useQueryState',
+ hook: 'useQueryState',
+ nextJsRouter: 'app',
+ description: 'standard route'
+})
+
+testPush({
+ path: '/app/push/useQueryStates',
+ hook: 'useQueryStates',
+ nextJsRouter: 'app',
+ description: 'standard route'
+})
+
+testPush({
+ path: '/pages/push/useQueryState',
+ hook: 'useQueryState',
+ nextJsRouter: 'pages',
+ description: 'standard route'
+})
+
+testPush({
+ path: '/pages/push/useQueryStates',
+ hook: 'useQueryStates',
+ nextJsRouter: 'pages',
+ description: 'standard route'
+})
+
+// --
+
+testPush({
+ path: '/app/push/useQueryState/dynamic/route',
+ hook: 'useQueryState',
+ nextJsRouter: 'app',
+ description: 'dynamic route'
+})
+
+testPush({
+ path: '/app/push/useQueryStates/dynamic/route',
+ hook: 'useQueryStates',
+ nextJsRouter: 'app',
+ description: 'dynamic route'
+})
+
+testPush({
+ path: '/pages/push/useQueryState/dynamic/route',
+ hook: 'useQueryState',
+ nextJsRouter: 'pages',
+ description: 'dynamic route'
+})
+
+testPush({
+ path: '/pages/push/useQueryStates/dynamic/route',
+ hook: 'useQueryStates',
+ nextJsRouter: 'pages',
+ description: 'dynamic route'
+})
diff --git a/packages/e2e/next/cypress/e2e/shared/routing.cy.ts b/packages/e2e/next/cypress/e2e/shared/routing.cy.ts
new file mode 100644
index 00000000..56f172ee
--- /dev/null
+++ b/packages/e2e/next/cypress/e2e/shared/routing.cy.ts
@@ -0,0 +1,25 @@
+import { testRouting } from 'e2e-shared/specs/routing.cy'
+
+testRouting({
+ path: '/app/routing/useQueryState',
+ hook: 'useQueryState',
+ nextJsRouter: 'app'
+})
+
+testRouting({
+ path: '/app/routing/useQueryStates',
+ hook: 'useQueryStates',
+ nextJsRouter: 'app'
+})
+
+testRouting({
+ path: '/pages/routing/useQueryState',
+ hook: 'useQueryState',
+ nextJsRouter: 'pages'
+})
+
+testRouting({
+ path: '/pages/routing/useQueryStates',
+ hook: 'useQueryStates',
+ nextJsRouter: 'pages'
+})
diff --git a/packages/e2e/next/cypress/support/e2e.ts b/packages/e2e/next/cypress/support/e2e.ts
index aacfac29..d2091875 100644
--- a/packages/e2e/next/cypress/support/e2e.ts
+++ b/packages/e2e/next/cypress/support/e2e.ts
@@ -1,3 +1 @@
-import setup from 'cypress-terminal-report/src/installLogsCollector'
-
-setup()
+import 'e2e-shared/cypress/support/e2e'
diff --git a/packages/e2e/next/next.config.mjs b/packages/e2e/next/next.config.mjs
index fb55ff9b..12c1674c 100644
--- a/packages/e2e/next/next.config.mjs
+++ b/packages/e2e/next/next.config.mjs
@@ -10,6 +10,7 @@ const config = {
...(process.env.REACT_COMPILER === 'true' ? { reactCompiler: true } : {}),
serverSourceMaps: true
},
+ transpilePackages: ['e2e-shared'],
rewrites: async () => [
{
source: '/app/rewrites/source',
diff --git a/packages/e2e/next/package.json b/packages/e2e/next/package.json
index 7eec20f5..95d77a63 100644
--- a/packages/e2e/next/package.json
+++ b/packages/e2e/next/package.json
@@ -34,8 +34,9 @@
"babel-plugin-react-compiler": "19.0.0-beta-a7bf2bd-20241110",
"cypress": "^13.15.2",
"cypress-terminal-report": "^7.0.4",
- "semver": "^7.6.3",
+ "e2e-shared": "workspace:*",
"start-server-and-test": "^2.0.8",
+ "semver": "^7.6.3",
"typescript": "^5.6.3"
}
}
diff --git a/packages/e2e/next/src/app/app/(shared)/basic-io/useQueryState/page.tsx b/packages/e2e/next/src/app/app/(shared)/basic-io/useQueryState/page.tsx
new file mode 100644
index 00000000..b0e7003c
--- /dev/null
+++ b/packages/e2e/next/src/app/app/(shared)/basic-io/useQueryState/page.tsx
@@ -0,0 +1,10 @@
+import { UseQueryStateBasicIO } from 'e2e-shared/specs/basic-io'
+import { Suspense } from 'react'
+
+export default function Page() {
+ return (
+
+
+
+ )
+}
diff --git a/packages/e2e/next/src/app/app/(shared)/basic-io/useQueryStates/page.tsx b/packages/e2e/next/src/app/app/(shared)/basic-io/useQueryStates/page.tsx
new file mode 100644
index 00000000..f82eedfd
--- /dev/null
+++ b/packages/e2e/next/src/app/app/(shared)/basic-io/useQueryStates/page.tsx
@@ -0,0 +1,10 @@
+import { UseQueryStatesBasicIO } from 'e2e-shared/specs/basic-io'
+import { Suspense } from 'react'
+
+export default function Page() {
+ return (
+
+
+
+ )
+}
diff --git a/packages/e2e/next/src/app/app/(shared)/hash-preservation/dynamic/[route]/page.tsx b/packages/e2e/next/src/app/app/(shared)/hash-preservation/dynamic/[route]/page.tsx
new file mode 100644
index 00000000..c8c93fa3
--- /dev/null
+++ b/packages/e2e/next/src/app/app/(shared)/hash-preservation/dynamic/[route]/page.tsx
@@ -0,0 +1,10 @@
+import { HashPreservation } from 'e2e-shared/specs/hash-preservation'
+import { Suspense } from 'react'
+
+export default function Page() {
+ return (
+
+
+
+ )
+}
diff --git a/packages/e2e/next/src/app/app/(shared)/hash-preservation/page.tsx b/packages/e2e/next/src/app/app/(shared)/hash-preservation/page.tsx
new file mode 100644
index 00000000..c8c93fa3
--- /dev/null
+++ b/packages/e2e/next/src/app/app/(shared)/hash-preservation/page.tsx
@@ -0,0 +1,10 @@
+import { HashPreservation } from 'e2e-shared/specs/hash-preservation'
+import { Suspense } from 'react'
+
+export default function Page() {
+ return (
+
+
+
+ )
+}
diff --git a/packages/e2e/next/src/app/app/(shared)/linking/useQueryState/other/page.tsx b/packages/e2e/next/src/app/app/(shared)/linking/useQueryState/other/page.tsx
new file mode 100644
index 00000000..c8651b15
--- /dev/null
+++ b/packages/e2e/next/src/app/app/(shared)/linking/useQueryState/other/page.tsx
@@ -0,0 +1,10 @@
+import { LinkingUseQueryState } from 'e2e-shared/specs/linking'
+import { Suspense } from 'react'
+
+export default function Page() {
+ return (
+
+
+
+ )
+}
diff --git a/packages/e2e/next/src/app/app/(shared)/linking/useQueryState/page.tsx b/packages/e2e/next/src/app/app/(shared)/linking/useQueryState/page.tsx
new file mode 100644
index 00000000..c8651b15
--- /dev/null
+++ b/packages/e2e/next/src/app/app/(shared)/linking/useQueryState/page.tsx
@@ -0,0 +1,10 @@
+import { LinkingUseQueryState } from 'e2e-shared/specs/linking'
+import { Suspense } from 'react'
+
+export default function Page() {
+ return (
+
+
+
+ )
+}
diff --git a/packages/e2e/next/src/app/app/(shared)/linking/useQueryStates/other/page.tsx b/packages/e2e/next/src/app/app/(shared)/linking/useQueryStates/other/page.tsx
new file mode 100644
index 00000000..1fbae359
--- /dev/null
+++ b/packages/e2e/next/src/app/app/(shared)/linking/useQueryStates/other/page.tsx
@@ -0,0 +1,10 @@
+import { LinkingUseQueryStates } from 'e2e-shared/specs/linking'
+import { Suspense } from 'react'
+
+export default function Page() {
+ return (
+
+
+
+ )
+}
diff --git a/packages/e2e/next/src/app/app/(shared)/linking/useQueryStates/page.tsx b/packages/e2e/next/src/app/app/(shared)/linking/useQueryStates/page.tsx
new file mode 100644
index 00000000..1fbae359
--- /dev/null
+++ b/packages/e2e/next/src/app/app/(shared)/linking/useQueryStates/page.tsx
@@ -0,0 +1,10 @@
+import { LinkingUseQueryStates } from 'e2e-shared/specs/linking'
+import { Suspense } from 'react'
+
+export default function Page() {
+ return (
+
+
+
+ )
+}
diff --git a/packages/e2e/next/src/app/app/(shared)/push/useQueryState/dynamic/[route]/page.tsx b/packages/e2e/next/src/app/app/(shared)/push/useQueryState/dynamic/[route]/page.tsx
new file mode 100644
index 00000000..2cc0db3f
--- /dev/null
+++ b/packages/e2e/next/src/app/app/(shared)/push/useQueryState/dynamic/[route]/page.tsx
@@ -0,0 +1,10 @@
+import { PushUseQueryState } from 'e2e-shared/specs/push'
+import { Suspense } from 'react'
+
+export default function Page() {
+ return (
+
+
+
+ )
+}
diff --git a/packages/e2e/next/src/app/app/(shared)/push/useQueryState/page.tsx b/packages/e2e/next/src/app/app/(shared)/push/useQueryState/page.tsx
new file mode 100644
index 00000000..2cc0db3f
--- /dev/null
+++ b/packages/e2e/next/src/app/app/(shared)/push/useQueryState/page.tsx
@@ -0,0 +1,10 @@
+import { PushUseQueryState } from 'e2e-shared/specs/push'
+import { Suspense } from 'react'
+
+export default function Page() {
+ return (
+
+
+
+ )
+}
diff --git a/packages/e2e/next/src/app/app/(shared)/push/useQueryStates/dynamic/[route]/page.tsx b/packages/e2e/next/src/app/app/(shared)/push/useQueryStates/dynamic/[route]/page.tsx
new file mode 100644
index 00000000..52fcf3e0
--- /dev/null
+++ b/packages/e2e/next/src/app/app/(shared)/push/useQueryStates/dynamic/[route]/page.tsx
@@ -0,0 +1,10 @@
+import { PushUseQueryStates } from 'e2e-shared/specs/push'
+import { Suspense } from 'react'
+
+export default function Page() {
+ return (
+
+
+
+ )
+}
diff --git a/packages/e2e/next/src/app/app/(shared)/push/useQueryStates/page.tsx b/packages/e2e/next/src/app/app/(shared)/push/useQueryStates/page.tsx
new file mode 100644
index 00000000..52fcf3e0
--- /dev/null
+++ b/packages/e2e/next/src/app/app/(shared)/push/useQueryStates/page.tsx
@@ -0,0 +1,10 @@
+import { PushUseQueryStates } from 'e2e-shared/specs/push'
+import { Suspense } from 'react'
+
+export default function Page() {
+ return (
+
+
+
+ )
+}
diff --git a/packages/e2e/next/src/app/app/(shared)/routing/useQueryState/other/page.tsx b/packages/e2e/next/src/app/app/(shared)/routing/useQueryState/other/page.tsx
new file mode 100644
index 00000000..ad227737
--- /dev/null
+++ b/packages/e2e/next/src/app/app/(shared)/routing/useQueryState/other/page.tsx
@@ -0,0 +1,10 @@
+import { RoutingUseQueryState } from 'e2e-shared/specs/routing'
+import { Suspense } from 'react'
+
+export default function Page() {
+ return (
+
+
+
+ )
+}
diff --git a/packages/e2e/next/src/app/app/(shared)/routing/useQueryState/page.tsx b/packages/e2e/next/src/app/app/(shared)/routing/useQueryState/page.tsx
new file mode 100644
index 00000000..ad227737
--- /dev/null
+++ b/packages/e2e/next/src/app/app/(shared)/routing/useQueryState/page.tsx
@@ -0,0 +1,10 @@
+import { RoutingUseQueryState } from 'e2e-shared/specs/routing'
+import { Suspense } from 'react'
+
+export default function Page() {
+ return (
+
+
+
+ )
+}
diff --git a/packages/e2e/next/src/app/app/(shared)/routing/useQueryStates/other/page.tsx b/packages/e2e/next/src/app/app/(shared)/routing/useQueryStates/other/page.tsx
new file mode 100644
index 00000000..37366c60
--- /dev/null
+++ b/packages/e2e/next/src/app/app/(shared)/routing/useQueryStates/other/page.tsx
@@ -0,0 +1,10 @@
+import { RoutingUseQueryStates } from 'e2e-shared/specs/routing'
+import { Suspense } from 'react'
+
+export default function Page() {
+ return (
+
+
+
+ )
+}
diff --git a/packages/e2e/next/src/app/app/(shared)/routing/useQueryStates/page.tsx b/packages/e2e/next/src/app/app/(shared)/routing/useQueryStates/page.tsx
new file mode 100644
index 00000000..37366c60
--- /dev/null
+++ b/packages/e2e/next/src/app/app/(shared)/routing/useQueryStates/page.tsx
@@ -0,0 +1,10 @@
+import { RoutingUseQueryStates } from 'e2e-shared/specs/routing'
+import { Suspense } from 'react'
+
+export default function Page() {
+ return (
+
+
+
+ )
+}
diff --git a/packages/e2e/next/src/app/app/transitions/client.tsx b/packages/e2e/next/src/app/app/transitions/client.tsx
index 817bc136..e1523bf4 100644
--- a/packages/e2e/next/src/app/app/transitions/client.tsx
+++ b/packages/e2e/next/src/app/app/transitions/client.tsx
@@ -2,7 +2,6 @@
import { parseAsInteger, useQueryState } from 'nuqs'
import { useTransition } from 'react'
-import { HydrationMarker } from '../../../components/hydration-marker'
export function Client() {
const [isLoading, startTransition] = useTransition()
@@ -15,7 +14,6 @@ export function Client() {
)
return (
<>
-
{isLoading ? 'loading' : 'idle'}
>
diff --git a/packages/e2e/next/src/app/layout.tsx b/packages/e2e/next/src/app/layout.tsx
index 28b8c9ce..07def6bb 100644
--- a/packages/e2e/next/src/app/layout.tsx
+++ b/packages/e2e/next/src/app/layout.tsx
@@ -1,6 +1,7 @@
+import { HydrationMarker } from 'e2e-shared/components/hydration-marker'
import { NuqsAdapter } from 'nuqs/adapters/next/app'
import React, { Suspense } from 'react'
-import { HydrationMarker } from '../components/hydration-marker'
+import { Providers } from './providers'
export const metadata = {
title: 'nuqs e2e test bench'
@@ -17,7 +18,9 @@ export default function RootLayout({
- {children}
+
+ {children}
+