Skip to content

Commit 579ed15

Browse files
authored
add e2e for dynamicparams in app-router (#794)
* add e2e for dynamicparams in app-router * fix comment * review * review * comment * fix id
1 parent 404893a commit 579ed15

File tree

3 files changed

+148
-0
lines changed
  • examples/app-router/app/isr
  • packages/tests-e2e/tests/appRouter

3 files changed

+148
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#dynamicparams
2+
export const dynamicParams = false; // or true, to make it try SSR unknown paths
3+
4+
const POSTS = Array.from({ length: 20 }, (_, i) => ({
5+
id: String(i + 1),
6+
title: `Post ${i + 1}`,
7+
content: `This is post ${i + 1}`,
8+
}));
9+
10+
async function fakeGetPostsFetch() {
11+
return POSTS.slice(0, 10);
12+
}
13+
14+
async function fakeGetPostFetch(id: string) {
15+
return POSTS.find((post) => post.id === id);
16+
}
17+
18+
export async function generateStaticParams() {
19+
const fakePosts = await fakeGetPostsFetch();
20+
return fakePosts.map((post) => ({
21+
id: post.id,
22+
}));
23+
}
24+
25+
export default async function Page({
26+
params,
27+
}: {
28+
params: Promise<{ id: string }>;
29+
}) {
30+
const { id } = await params;
31+
const post = await fakeGetPostFetch(id);
32+
return (
33+
<main>
34+
<h1 data-testid="title">{post?.title}</h1>
35+
<p data-testid="content">{post?.content}</p>
36+
</main>
37+
);
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { notFound } from "next/navigation";
2+
3+
// We'll prerender only the params from `generateStaticParams` at build time.
4+
// If a request comes in for a path that hasn't been generated,
5+
// Next.js will server-render the page on-demand.
6+
// https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#dynamicparams
7+
export const dynamicParams = true; // or false, to 404 on unknown paths
8+
9+
const POSTS = Array.from({ length: 20 }, (_, i) => ({
10+
id: String(i + 1),
11+
title: `Post ${i + 1}`,
12+
content: `This is post ${i + 1}`,
13+
}));
14+
15+
async function fakeGetPostsFetch() {
16+
return POSTS.slice(0, 10);
17+
}
18+
19+
async function fakeGetPostFetch(id: string) {
20+
return POSTS.find((post) => post.id === id);
21+
}
22+
23+
export async function generateStaticParams() {
24+
const fakePosts = await fakeGetPostsFetch();
25+
return fakePosts.map((post) => ({
26+
id: post.id,
27+
}));
28+
}
29+
30+
export default async function Page({
31+
params,
32+
}: {
33+
params: Promise<{ id: string }>;
34+
}) {
35+
const { id } = await params;
36+
const post = await fakeGetPostFetch(id);
37+
if (Number(id) === 1337) {
38+
throw new Error("This is an error!");
39+
}
40+
if (!post) {
41+
notFound();
42+
}
43+
return (
44+
<main>
45+
<h1 data-testid="title">{post.title}</h1>
46+
<p data-testid="content">{post.content}</p>
47+
</main>
48+
);
49+
}

packages/tests-e2e/tests/appRouter/isr.test.ts

+61
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,64 @@ test("Incremental Static Regeneration with data cache", async ({ page }) => {
9393
expect(originalCachedDate).toEqual(finalCachedDate);
9494
expect(originalFetchedDate).toEqual(finalFetchedDate);
9595
});
96+
97+
test.describe("dynamicParams set to true", () => {
98+
test("should be HIT on a path that was prebuilt", async ({ page }) => {
99+
const res = await page.goto("/isr/dynamic-params-true/1");
100+
expect(res?.status()).toEqual(200);
101+
expect(res?.headers()["x-nextjs-cache"]).toEqual("HIT");
102+
const title = await page.getByTestId("title").textContent();
103+
const content = await page.getByTestId("content").textContent();
104+
expect(title).toEqual("Post 1");
105+
expect(content).toEqual("This is post 1");
106+
});
107+
108+
// In `next start` this test would fail on subsequent requests because `x-nextjs-cache` would be `HIT`
109+
// However, once deployed to AWS, Cloudfront will cache `MISS`
110+
test("should SSR on a path that was not prebuilt", async ({ page }) => {
111+
const res = await page.goto("/isr/dynamic-params-true/11");
112+
expect(res?.headers()["x-nextjs-cache"]).toEqual("MISS");
113+
const title = await page.getByTestId("title").textContent();
114+
const content = await page.getByTestId("content").textContent();
115+
expect(title).toEqual("Post 11");
116+
expect(content).toEqual("This is post 11");
117+
});
118+
119+
test("should 404 when you call notFound", async ({ page }) => {
120+
const res = await page.goto("/isr/dynamic-params-true/21");
121+
expect(res?.status()).toEqual(404);
122+
expect(res?.headers()["cache-control"]).toBe(
123+
"private, no-cache, no-store, max-age=0, must-revalidate",
124+
);
125+
await expect(page.getByText("404")).toBeAttached();
126+
});
127+
128+
test("should 500 for a path that throws an error", async ({ page }) => {
129+
const res = await page.goto("/isr/dynamic-params-true/1337");
130+
expect(res?.status()).toEqual(500);
131+
expect(res?.headers()["cache-control"]).toBe(
132+
"private, no-cache, no-store, max-age=0, must-revalidate",
133+
);
134+
});
135+
});
136+
137+
test.describe("dynamicParams set to false", () => {
138+
test("should be HIT on a path that was prebuilt", async ({ page }) => {
139+
const res = await page.goto("/isr/dynamic-params-false/1");
140+
expect(res?.status()).toEqual(200);
141+
expect(res?.headers()["x-nextjs-cache"]).toEqual("HIT");
142+
const title = await page.getByTestId("title").textContent();
143+
const content = await page.getByTestId("content").textContent();
144+
expect(title).toEqual("Post 1");
145+
expect(content).toEqual("This is post 1");
146+
});
147+
148+
test("should 404 for a path that is not found", async ({ page }) => {
149+
const res = await page.goto("/isr/dynamic-params-false/11");
150+
expect(res?.status()).toEqual(404);
151+
expect(res?.headers()["cache-control"]).toBe(
152+
"private, no-cache, no-store, max-age=0, must-revalidate",
153+
);
154+
await expect(page.getByText("404")).toBeAttached();
155+
});
156+
});

0 commit comments

Comments
 (0)