diff --git a/tests/e2e/routing.test.ts b/tests/e2e/routing.test.ts
new file mode 100644
index 0000000000..ad51cf0536
--- /dev/null
+++ b/tests/e2e/routing.test.ts
@@ -0,0 +1,38 @@
+import { expect } from '@playwright/test'
+import { test } from '../utils/playwright-helpers.js'
+
+const ssrRoutes = [
+ ['/static', 'pages router, static rendering, static routing'],
+ ['/prerendered', 'pages router, prerendering, static routing'],
+ ['/posts/prerendered/1', 'pages router, prerendering, dynamic routing'],
+ ['/dynamic', 'pages router, dynamic rendering, static routing'],
+ ['/posts/dynamic/1', 'pages router, dynamic rendering, dynamic routing'],
+ ['/api/okay', 'pages router, api route, static routing'],
+ ['/api/posts/1', 'pages router, api route, dynamic routing'],
+ ['/static-fetch-1', 'app router, prerendering, static routing'],
+ ['/static-fetch/1', 'app router, prerendering, dynamic routing'],
+ ['/static-fetch-dynamic-1', 'app router, dynamic rendering, static routing'],
+ ['/static-fetch-dynamic/1', 'app router, dynamic rendering, dynamic routing'],
+ ['/api/revalidate-handler', 'app router, route handler, static routing'],
+ ['/api/static/1', 'app router, route handler, dynamic routing'],
+]
+
+const notFoundRoutes = [
+ ['/non-existing', 'default'],
+ ['/prerendered/3', 'prerendering, dynamic routing'],
+ ['/dynamic/3', 'dynamic rendering, dynamic routing'],
+ ['/api/non-existing', 'route handler, static routing'],
+]
+
+test(`routing works correctly`, async ({ page, serverComponents }) => {
+ for (const [path, description] of ssrRoutes) {
+ const url = new URL(path, serverComponents.url).href
+ const response = await page.goto(url)
+ expect(response?.status(), `expected 200 response for ${description}`).toBe(200)
+ }
+ for (const [path, description] of notFoundRoutes) {
+ const url = new URL(path, serverComponents.url).href
+ const response = await page.goto(url)
+ expect(response?.status(), `expected 404 response for ${description}`).toBe(404)
+ }
+})
diff --git a/tests/fixtures/server-components/app/static-fetch-dynamic/page.js b/tests/fixtures/server-components/app/static-fetch-dynamic-1/page.js
similarity index 100%
rename from tests/fixtures/server-components/app/static-fetch-dynamic/page.js
rename to tests/fixtures/server-components/app/static-fetch-dynamic-1/page.js
diff --git a/tests/fixtures/server-components/app/static-fetch-dynamic/[id]/page.js b/tests/fixtures/server-components/app/static-fetch-dynamic/[id]/page.js
new file mode 100644
index 0000000000..85c8019450
--- /dev/null
+++ b/tests/fixtures/server-components/app/static-fetch-dynamic/[id]/page.js
@@ -0,0 +1,33 @@
+export async function generateStaticParams() {
+ return [{ id: '1' }, { id: '2' }]
+}
+
+async function getData(params) {
+ const res = await fetch(`https://api.tvmaze.com/shows/${params.id}`, {
+ next: {
+ tags: [`show-${params.id}`],
+ },
+ })
+ return res.json()
+}
+
+export default async function Page({ params }) {
+ const data = await getData(params)
+
+ return (
+ <>
+
Hello, Force Dynamically Rendered Server Component
+ Paths /1 and /2 prerendered; other paths not found
+
+ - Show
+ - {data.name}
+ - Param
+ - {params.id}
+ - Time
+ - {new Date().toISOString()}
+
+ >
+ )
+}
+
+export const dynamic = 'force-dynamic'
diff --git a/tests/fixtures/server-components/next-env.d.ts b/tests/fixtures/server-components/next-env.d.ts
index 4f11a03dc6..725dd6f245 100644
--- a/tests/fixtures/server-components/next-env.d.ts
+++ b/tests/fixtures/server-components/next-env.d.ts
@@ -1,5 +1,6 @@
///
///
+///
// NOTE: This file should not be edited
-// see https://nextjs.org/docs/basic-features/typescript for more information.
+// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.
diff --git a/tests/fixtures/server-components/pages/api/okay.js b/tests/fixtures/server-components/pages/api/okay.js
new file mode 100644
index 0000000000..45a65589e6
--- /dev/null
+++ b/tests/fixtures/server-components/pages/api/okay.js
@@ -0,0 +1,3 @@
+export default async function handler(req, res) {
+ return res.send({ code: 200, message: 'okay' })
+}
diff --git a/tests/fixtures/server-components/pages/api/posts/[id].js b/tests/fixtures/server-components/pages/api/posts/[id].js
new file mode 100644
index 0000000000..3fd01f0efb
--- /dev/null
+++ b/tests/fixtures/server-components/pages/api/posts/[id].js
@@ -0,0 +1,4 @@
+export default function handler(req, res) {
+ const { id } = req.query
+ res.send({ code: 200, message: `okay ${id}` })
+}
diff --git a/tests/fixtures/server-components/pages/dynamic.js b/tests/fixtures/server-components/pages/dynamic.js
new file mode 100644
index 0000000000..c0b8aae2ba
--- /dev/null
+++ b/tests/fixtures/server-components/pages/dynamic.js
@@ -0,0 +1,11 @@
+export default function Yar({ title }) {
+ return {title}
+}
+
+export async function getServerSideProps() {
+ return {
+ props: {
+ title: 'My Page',
+ },
+ }
+}
diff --git a/tests/fixtures/server-components/pages/posts/dynamic/[id].js b/tests/fixtures/server-components/pages/posts/dynamic/[id].js
new file mode 100644
index 0000000000..3b4b8d565d
--- /dev/null
+++ b/tests/fixtures/server-components/pages/posts/dynamic/[id].js
@@ -0,0 +1,25 @@
+export default function Page({ params }) {
+ return (
+ <>
+ Hello, Dyanmically fetched show
+
+ - Param
+ - {params.id}
+ - Time
+ - {new Date().toISOString()}
+
+ >
+ )
+}
+
+export async function getServerSideProps({ params }) {
+ const res = await fetch(`https://api.tvmaze.com/shows/${params.id}`)
+ const data = await res.json()
+
+ return {
+ props: {
+ params,
+ data,
+ },
+ }
+}
diff --git a/tests/fixtures/server-components/pages/posts/prerendered/[id].js b/tests/fixtures/server-components/pages/posts/prerendered/[id].js
new file mode 100644
index 0000000000..d797fbf74b
--- /dev/null
+++ b/tests/fixtures/server-components/pages/posts/prerendered/[id].js
@@ -0,0 +1,33 @@
+export default function Page({ params }) {
+ return (
+ <>
+ Hello, Statically fetched show
+ Paths /1 and /2 prerendered; other paths not found
+
+ - Param
+ - {params.id}
+ - Time
+ - {new Date().toISOString()}
+
+ >
+ )
+}
+
+export async function getStaticPaths() {
+ return {
+ paths: [{ params: { id: '1' } }, { params: { id: '2' } }],
+ fallback: false,
+ }
+}
+
+export async function getStaticProps({ params }) {
+ const res = await fetch(`https://api.tvmaze.com/shows/${params.id}`)
+ const data = await res.json()
+
+ return {
+ props: {
+ params,
+ data,
+ },
+ }
+}
diff --git a/tests/fixtures/server-components/pages/prerendered.js b/tests/fixtures/server-components/pages/prerendered.js
new file mode 100644
index 0000000000..520a3d0b96
--- /dev/null
+++ b/tests/fixtures/server-components/pages/prerendered.js
@@ -0,0 +1,11 @@
+export default function Yar({ title }) {
+ return {title}
+}
+
+export async function getStaticProps() {
+ return {
+ props: {
+ title: 'My Page',
+ },
+ }
+}
diff --git a/tests/fixtures/server-components/pages/static.js b/tests/fixtures/server-components/pages/static.js
new file mode 100644
index 0000000000..b6992717b0
--- /dev/null
+++ b/tests/fixtures/server-components/pages/static.js
@@ -0,0 +1,3 @@
+export default function Yup() {
+ return Yup
+}
diff --git a/tests/fixtures/server-components/tsconfig.json b/tests/fixtures/server-components/tsconfig.json
index b3222239ed..fc46f3d6cf 100644
--- a/tests/fixtures/server-components/tsconfig.json
+++ b/tests/fixtures/server-components/tsconfig.json
@@ -1,6 +1,10 @@
{
"compilerOptions": {
- "lib": ["dom", "dom.iterable", "esnext"],
+ "lib": [
+ "dom",
+ "dom.iterable",
+ "esnext"
+ ],
"allowJs": true,
"skipLibCheck": true,
"strict": false,
@@ -16,8 +20,16 @@
{
"name": "next"
}
- ]
+ ],
+ "strictNullChecks": true
},
- "include": ["next-env.d.ts", ".next/types/**/*.ts", "**/*.ts", "**/*.tsx"],
- "exclude": ["node_modules"]
+ "include": [
+ "next-env.d.ts",
+ ".next/types/**/*.ts",
+ "**/*.ts",
+ "**/*.tsx"
+ ],
+ "exclude": [
+ "node_modules"
+ ]
}