Skip to content

Commit 5940f91

Browse files
authored
test(nextjs): Add UI components for cached/dynamic content (#24874)
Adds UI components and an index page so it's easier to know what's happening on each page when manually using the E2E tests. Example: <img width="798" height="334" alt="image" src="https://github.com/user-attachments/assets/1f5027f8-8602-4b10-be75-441cb781f78c" />
1 parent 06c015a commit 5940f91

29 files changed

Lines changed: 548 additions & 92 deletions

File tree

‎dev-packages/e2e-tests/test-applications/nextjs-16-cacheComponents/app/(cached-nesting)/cached-mid-layout/[id]/layout.tsx‎

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { ReactNode } from 'react';
22
import { cacheLife } from 'next/cache';
3+
import { CachedBox } from '@/components/scenarioBox';
34

45
// The awaited param puts the request id into the cache key, so a fresh id is a guaranteed miss
56
// and the entry cannot come from a build-time fill. `children` passes through as an uncached hole.
@@ -15,11 +16,14 @@ export default async function CachedMidLayout({
1516
const { id } = await params;
1617
await new Promise(resolve => setTimeout(resolve, 100));
1718
return (
18-
<div data-testid="cached-mid-layout">
19-
<p id="cached-layout-stamp">
20-
{id}:{Date.now()}
21-
</p>
22-
{children}
23-
</div>
19+
<main>
20+
<h1>Cached layout, dynamic page</h1>
21+
<CachedBox label="CachedMidLayout · use cache · hours · keyed by [id]">
22+
<p id="cached-layout-stamp">
23+
{id}:{Date.now()}
24+
</p>
25+
{children}
26+
</CachedBox>
27+
</main>
2428
);
2529
}
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import { headers } from 'next/headers';
2+
import { DynamicBox } from '@/components/scenarioBox';
23

34
export default async function Page() {
45
await headers();
5-
return <p id="dynamic-leaf">Dynamic leaf: {Date.now()}</p>;
6+
return (
7+
<DynamicBox label="page · awaits headers">
8+
<p id="dynamic-leaf">Dynamic leaf: {Date.now()}</p>
9+
</DynamicBox>
10+
);
611
}

‎dev-packages/e2e-tests/test-applications/nextjs-16-cacheComponents/app/(cached-nesting)/dynamic-layouts/[id]/layout-cached-leaf/page.tsx‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
import { cacheLife } from 'next/cache';
2+
import { CachedBox } from '@/components/scenarioBox';
23

34
async function CachedLeaf({ id }: { id: string }) {
45
'use cache';
56
cacheLife('hours');
67
await new Promise(resolve => setTimeout(resolve, 100));
78
return (
8-
<p id="cached-leaf">
9-
{id}:{Date.now()}
10-
</p>
9+
<CachedBox label="CachedLeaf · use cache · hours">
10+
<p id="cached-leaf">
11+
{id}:{Date.now()}
12+
</p>
13+
</CachedBox>
1114
);
1215
}
1316

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
11
import type { ReactNode } from 'react';
22
import { headers } from 'next/headers';
3+
import { DynamicBox } from '@/components/scenarioBox';
34

45
export default async function DynamicLayout({ children }: { children: ReactNode }) {
56
await headers();
6-
return <div data-testid="dynamic-layout">{children}</div>;
7+
return (
8+
<main>
9+
<h1>Dynamic layout, cached leaf</h1>
10+
<DynamicBox label="DynamicLayout · awaits headers">
11+
<p>request-time: {Date.now()}</p>
12+
{children}
13+
</DynamicBox>
14+
</main>
15+
);
716
}

‎dev-packages/e2e-tests/test-applications/nextjs-16-cacheComponents/app/(cached-nesting)/mixed-lifetimes/[id]/layout.tsx‎

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { ReactNode } from 'react';
22
import { cacheLife } from 'next/cache';
3+
import { CachedBox } from '@/components/scenarioBox';
34

45
// Hard-expires after 2s while the page's cached component lives for hours, so one request can
56
// refill the layout while hitting the component: two cached levels with different origin traces.
@@ -14,11 +15,14 @@ export default async function ShortLivedLayout({
1415
cacheLife({ revalidate: 1, expire: 2 });
1516
const { id } = await params;
1617
return (
17-
<div data-testid="short-lived-layout">
18-
<p id="layout-stamp">
19-
{id}:{Date.now()}
20-
</p>
21-
{children}
22-
</div>
18+
<main>
19+
<h1>Mixed lifetimes</h1>
20+
<CachedBox label="ShortLivedLayout · use cache · expires after 2s · keyed by [id]">
21+
<p id="layout-stamp">
22+
{id}:{Date.now()}
23+
</p>
24+
{children}
25+
</CachedBox>
26+
</main>
2327
);
2428
}
Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,27 @@
11
import { headers } from 'next/headers';
22
import { cacheLife } from 'next/cache';
3+
import { CachedBox, DynamicBox } from '@/components/scenarioBox';
34

45
async function LongLivedComponent({ id }: { id: string }) {
56
'use cache';
67
cacheLife('hours');
78
await new Promise(resolve => setTimeout(resolve, 100));
89
return (
9-
<p id="component-stamp">
10-
{id}:{Date.now()}
11-
</p>
10+
<CachedBox label="LongLivedComponent · use cache · hours">
11+
<p id="component-stamp">
12+
{id}:{Date.now()}
13+
</p>
14+
</CachedBox>
1215
);
1316
}
1417

1518
export default async function Page({ params }: { params: Promise<{ id: string }> }) {
1619
const { id } = await params;
1720
await headers();
18-
return <LongLivedComponent id={id} />;
21+
return (
22+
<DynamicBox label="page · awaits headers">
23+
<p>request-time: {Date.now()}</p>
24+
<LongLivedComponent id={id} />
25+
</DynamicBox>
26+
);
1927
}
Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import { headers } from 'next/headers';
2+
import { DynamicBox } from '@/components/scenarioBox';
23

34
export default async function Page() {
45
await headers();
5-
return <p id="route-a">Route a: {Date.now()}</p>;
6+
return (
7+
<DynamicBox label="route a · awaits headers">
8+
<p id="route-a">Route a: {Date.now()}</p>
9+
</DynamicBox>
10+
);
611
}
Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import { headers } from 'next/headers';
2+
import { DynamicBox } from '@/components/scenarioBox';
23

34
export default async function Page() {
45
await headers();
5-
return <p id="route-b">Route b: {Date.now()}</p>;
6+
return (
7+
<DynamicBox label="route b · awaits headers">
8+
<p id="route-b">Route b: {Date.now()}</p>
9+
</DynamicBox>
10+
);
611
}

‎dev-packages/e2e-tests/test-applications/nextjs-16-cacheComponents/app/(cached-nesting)/shared-layout/[id]/layout.tsx‎

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { ReactNode } from 'react';
22
import { cacheLife } from 'next/cache';
3+
import { CachedBox } from '@/components/scenarioBox';
34

45
// One cache entry (keyed by id) shared by the sibling routes `a` and `b` below.
56
export default async function SharedLayout({
@@ -14,11 +15,14 @@ export default async function SharedLayout({
1415
const { id } = await params;
1516
await new Promise(resolve => setTimeout(resolve, 100));
1617
return (
17-
<div data-testid="shared-layout">
18-
<p id="shared-layout-stamp">
19-
{id}:{Date.now()}
20-
</p>
21-
{children}
22-
</div>
18+
<main>
19+
<h1>Shared layout across sibling routes</h1>
20+
<CachedBox label="SharedLayout · use cache · hours · shared by /a and /b">
21+
<p id="shared-layout-stamp">
22+
{id}:{Date.now()}
23+
</p>
24+
{children}
25+
</CachedBox>
26+
</main>
2327
);
2428
}
Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
import { Suspense } from 'react';
22
import { cacheLife } from 'next/cache';
3+
import { CachedBox, DynamicBox } from '@/components/scenarioBox';
34

45
async function CachedSection({ id, label }: { id: string; label: string }) {
56
'use cache';
67
cacheLife('hours');
78
await new Promise(resolve => setTimeout(resolve, 100));
89
return (
9-
<section id={`cached-${label}`}>
10-
{label}:{id}:{Date.now()}
11-
</section>
10+
<CachedBox label={`CachedSection "${label}" · use cache · hours`}>
11+
<section id={`cached-${label}`}>
12+
{label}:{id}:{Date.now()}
13+
</section>
14+
</CachedBox>
1215
);
1316
}
1417

@@ -18,17 +21,21 @@ async function DynamicContent({ searchParams }: { searchParams: Promise<{ id?: s
1821
// separate entries (the props are part of the cache key).
1922
const { id = 'default-id' } = await searchParams;
2023
return (
21-
<>
24+
<DynamicBox label="dynamic hole · awaits searchParams">
25+
<p>request-time: {Date.now()}</p>
2226
<CachedSection id={id} label="first" />
2327
<CachedSection id={id} label="second" />
24-
</>
28+
</DynamicBox>
2529
);
2630
}
2731

2832
export default function Page({ searchParams }: { searchParams: Promise<{ id?: string }> }) {
2933
return (
30-
<Suspense fallback={<div>Loading...</div>}>
31-
<DynamicContent searchParams={searchParams} />
32-
</Suspense>
34+
<main>
35+
<h1>Cached sibling components</h1>
36+
<Suspense fallback={<div>Loading...</div>}>
37+
<DynamicContent searchParams={searchParams} />
38+
</Suspense>
39+
</main>
3340
);
3441
}

0 commit comments

Comments
 (0)