Skip to content

Commit 04ee28f

Browse files
authored
Add a test to show that 'use cache' works in generateMetadata (#80172)
When calling a function with a `'use cache'` directive from `generateMetadata`, and from the page/layout, the invocations are deduped and the result is shared. When `generateMetadata` itself also has a `'use cache'` directive, and it calls a nested function with a `'use cache'` directive, we do need to land #78703 for proper deduplication of the nested cache.
1 parent 9305b89 commit 04ee28f

File tree

4 files changed

+74
-0
lines changed

4 files changed

+74
-0
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { setTimeout } from 'timers/promises'
2+
3+
export async function getCachedData() {
4+
'use cache'
5+
await setTimeout(1000)
6+
return new Date().toISOString()
7+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { getCachedData } from './cached-data'
2+
3+
export default async function Layout({
4+
children,
5+
}: {
6+
children: React.ReactNode
7+
}) {
8+
return (
9+
<>
10+
<h1>Layout</h1>
11+
<p id="layout-data">{await getCachedData()}</p>
12+
<div>{children}</div>
13+
</>
14+
)
15+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { Metadata } from 'next'
2+
import { connection } from 'next/server'
3+
import { getCachedData } from './cached-data'
4+
5+
export async function generateMetadata(): Promise<Metadata> {
6+
// TODO: Deduping with nested caches requires #78703.
7+
// 'use cache'
8+
9+
return {
10+
description: new Date().toISOString(),
11+
title: await getCachedData(),
12+
}
13+
}
14+
15+
export default async function Page() {
16+
await connection()
17+
18+
return (
19+
<>
20+
<h2>Page</h2>
21+
<p id="page-data">{await getCachedData()}</p>
22+
</>
23+
)
24+
}

test/e2e/app-dir/use-cache/use-cache.test.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -980,6 +980,34 @@ describe('use-cache', () => {
980980
expect(randomOne).toBe(randomTwo)
981981
})
982982
})
983+
984+
it('shares caches between the page/layout and generateMetadata', async () => {
985+
const browser = await next.browser('/generate-metadata')
986+
const layoutData = await browser.elementByCss('#layout-data').text()
987+
const pageData = await browser.elementByCss('#page-data').text()
988+
const title = await browser.eval('document.title')
989+
990+
expect(layoutData).toBe(pageData)
991+
expect(pageData).toBe(title)
992+
993+
const initialDescription = await browser
994+
.elementByCss('meta[name="description"]')
995+
.getAttribute('content')
996+
997+
expect(initialDescription).not.toBe(title)
998+
999+
await browser.refresh()
1000+
1001+
const description = await browser
1002+
.elementByCss('meta[name="description"]')
1003+
.getAttribute('content')
1004+
1005+
// TODO: After #78703 has landed, we can enable the outer 'use cache' in
1006+
// generateMetadata, and still have the cached title (a nested cache) be
1007+
// shared with the page/layout. Then the description will also be cached (by
1008+
// the outer 'use cache'), and this expectation needs to be flipped.
1009+
expect(description).not.toBe(initialDescription)
1010+
})
9831011
})
9841012

9851013
async function getSanitizedLogs(browser: Playwright): Promise<string[]> {

0 commit comments

Comments
 (0)