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" + ] }