Skip to content

Commit beac4cf

Browse files
committed
add e2e test
1 parent d04372f commit beac4cf

File tree

9 files changed

+137
-0
lines changed

9 files changed

+137
-0
lines changed

examples/experimental/next.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const nextConfig: NextConfig = {
1010
experimental: {
1111
ppr: "incremental",
1212
nodeMiddleware: true,
13+
dynamicIO: true,
1314
},
1415
};
1516

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { revalidateTag } from "next/cache";
2+
3+
export function GET() {
4+
revalidateTag("fullyTagged");
5+
return new Response("DONE");
6+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { FullyCachedComponent, ISRComponent } from "@/components/cached";
2+
import { Suspense } from "react";
3+
4+
export default async function Page() {
5+
// Not working for now, need a patch in next to disable full revalidation during ISR revalidation
6+
return (
7+
<div>
8+
<h1>Cache</h1>
9+
<Suspense fallback={<p>Loading...</p>}>
10+
<FullyCachedComponent />
11+
</Suspense>
12+
<Suspense fallback={<p>Loading...</p>}>
13+
<ISRComponent />
14+
</Suspense>
15+
</div>
16+
);
17+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { Suspense } from "react";
2+
3+
export default function Layout({
4+
children,
5+
}: {
6+
children: React.ReactNode;
7+
}) {
8+
return (
9+
<div>
10+
<Suspense fallback={<p>Loading...</p>}>{children}</Suspense>
11+
</div>
12+
);
13+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { FullyCachedComponent, ISRComponent } from "@/components/cached";
2+
import { headers } from "next/headers";
3+
import { Suspense } from "react";
4+
5+
export default async function Page() {
6+
// To opt into SSR
7+
const _headers = await headers();
8+
return (
9+
<div>
10+
<h1>Cache</h1>
11+
<p>{_headers.get("accept") ?? "No accept headers"}</p>
12+
<Suspense fallback={<p>Loading...</p>}>
13+
<FullyCachedComponent />
14+
</Suspense>
15+
<Suspense fallback={<p>Loading...</p>}>
16+
<ISRComponent />
17+
</Suspense>
18+
</div>
19+
);
20+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { unstable_cacheTag, unstable_cacheLife } from "next/cache";
2+
3+
export async function FullyCachedComponent() {
4+
"use cache";
5+
unstable_cacheTag("fullyTagged");
6+
return (
7+
<div>
8+
<p data-testid="fullyCached">{Date.now()}</p>
9+
</div>
10+
);
11+
}
12+
13+
export async function ISRComponent() {
14+
"use cache";
15+
unstable_cacheLife({
16+
stale: 1,
17+
revalidate: 5,
18+
});
19+
return (
20+
<div>
21+
<p data-testid="isr">{Date.now()}</p>
22+
</div>
23+
);
24+
}

packages/open-next/src/adapters/composable-cache.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,4 +106,10 @@ export default {
106106
}
107107
await globalThis.tagCache.writeTags(Array.from(setToWrite));
108108
},
109+
110+
// This one is necessary for older versions of next
111+
async receiveExpiredTags(...tags: string[]) {
112+
// This function does absolutely nothing
113+
return;
114+
},
109115
} satisfies ComposableCacheHandler;

packages/open-next/src/types/cache.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,4 +164,8 @@ export interface ComposableCacheHandler {
164164
refreshTags(): Promise<void>;
165165
getExpiration(...tags: string[]): Promise<number>;
166166
expireTags(...tags: string[]): Promise<void>;
167+
/**
168+
* This function is only there for older versions and do nothing
169+
*/
170+
receiveExpiredTags(...tags: string[]): Promise<void>;
167171
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { test, expect } from "@playwright/test";
2+
3+
test("cached component should work in ssr", async ({ page }) => {
4+
await page.goto("/use-cache/ssr");
5+
let fullyCachedElt = page.getByTestId("fullyCached");
6+
let isrElt = page.getByTestId("isr");
7+
await expect(fullyCachedElt).toBeVisible();
8+
await expect(isrElt).toBeVisible();
9+
10+
const initialFullyCachedText = await fullyCachedElt.textContent();
11+
const initialIsrText = await isrElt.textContent();
12+
13+
let isrText = initialIsrText;
14+
15+
do {
16+
await page.reload();
17+
fullyCachedElt = page.getByTestId("fullyCached");
18+
isrElt = page.getByTestId("isr");
19+
await expect(fullyCachedElt).toBeVisible();
20+
await expect(isrElt).toBeVisible();
21+
isrText = await isrElt.textContent();
22+
await page.waitForTimeout(1000);
23+
} while (isrText === initialIsrText);
24+
25+
expect(fullyCachedElt).toHaveText(initialFullyCachedText ?? "");
26+
expect(isrElt).not.toHaveText(initialIsrText ?? "");
27+
});
28+
29+
test("revalidateTag should work for fullyCached component", async ({
30+
page,
31+
request,
32+
}) => {
33+
await page.goto("/use-cache/ssr");
34+
const fullyCachedElt = page.getByTestId("fullyCached");
35+
await expect(fullyCachedElt).toBeVisible();
36+
37+
const initialFullyCachedText = await fullyCachedElt.textContent();
38+
39+
const resp = await request.get("/api/revalidate");
40+
expect(resp.status()).toEqual(200);
41+
expect(await resp.text()).toEqual("DONE");
42+
43+
await page.reload();
44+
await expect(fullyCachedElt).toBeVisible();
45+
expect(fullyCachedElt).not.toHaveText(initialFullyCachedText ?? "");
46+
});

0 commit comments

Comments
 (0)