[Breaking] disable client router cache for page segments (#66039)

This configures the default client router cache `staleTime.dynamic`
value to be `0`.

This means that:
- Navigating between pages will always fire off a network request to get
RSC data for the page segment, rather than restoring from router cache
- Loading states will remain cached for 5 minutes (or whatever
`config.experimental.staleTimes.static` is set to)
- Shared layout data will continue to remain cached due to [partial
rendering](https://nextjs.org/docs/app/building-your-application/routing/linking-and-navigating#4-partial-rendering)
- Back/forward behavior will still restore from cache to ensure the
browser can restore scroll position.

It's possible to opt-out of this, and into the previous behavior, by
setting the
[`staleTimes`](https://nextjs.org/docs/app/api-reference/next-config-js/staleTimes)
config in `next.config.js`:

```js
/** @type {import('next').NextConfig} */
const nextConfig = {
  experimental: {
    staleTimes: {
      dynamic: 30
    },
  },
}

module.exports = nextConfig
```

<!-- Thanks for opening a PR! Your contribution is much appreciated.
To make sure your PR is handled as smoothly as possible we request that
you follow the checklist sections below.
Choose the right checklist for the change(s) that you're making:

## For Contributors

### Improving Documentation

- Run `pnpm prettier-fix` to fix formatting issues before opening the
PR.
- Read the Docs Contribution Guide to ensure your contribution follows
the docs guidelines:
https://nextjs.org/docs/community/contribution-guide

### Adding or Updating Examples

- The "examples guidelines" are followed from our contributing doc
https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md
- Make sure the linting passes by running `pnpm build && pnpm lint`. See
https://github.com/vercel/next.js/blob/canary/contributing/repository/linting.md

### Fixing a bug

- Related issues linked using `fixes #number`
- Tests added. See:
https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs
- Errors have a helpful link attached, see
https://github.com/vercel/next.js/blob/canary/contributing.md

### Adding a feature

- Implements an existing feature request or RFC. Make sure the feature
request has been accepted for implementation before opening a PR. (A
discussion must be opened, see
https://github.com/vercel/next.js/discussions/new?category=ideas)
- Related issues/discussions are linked using `fixes #number`
- e2e tests added
(https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs)
- Documentation added
- Telemetry added. In case of a feature if it's used or not.
- Errors have a helpful link attached, see
https://github.com/vercel/next.js/blob/canary/contributing.md


## For Maintainers

- Minimal description (aim for explaining to someone not on the team to
understand the PR)
- When linking to a Slack thread, you might want to share details of the
conclusion
- Link both the Linear (Fixes NEXT-xxx) and the GitHub issues
- Add review comments if necessary to explain to the reviewer the logic
behind a change

### What?

### Why?

### How?

Closes NEXT-
Fixes #

-->
This commit is contained in:
Zack Tanner 2024-05-21 13:54:23 -07:00 committed by GitHub
parent 16c4e47c14
commit 1f545aff05
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 542 additions and 125 deletions

View file

@ -364,7 +364,7 @@ The cache is stored in the browser's temporary memory. Two factors determine how
- **Session**: The cache persists across navigation. However, it's cleared on page refresh.
- **Automatic Invalidation Period**: The cache of an individual segment is automatically invalidated after a specific time. The duration depends on how the resource was [prefetched](/docs/app/api-reference/components/link#prefetch):
- **Default Prefetching** (`prefetch={null}` or unspecified): 30 seconds
- **Default Prefetching** (`prefetch={null}` or unspecified): 0 seconds
- **Full Prefetching**: (`prefetch={true}` or `router.prefetch`): 5 minutes
While a page refresh will clear **all** cached segments, the automatic invalidation period only affects the individual segment from the time it was prefetched.

View file

@ -28,7 +28,7 @@ module.exports = nextConfig
The `static` and `dynamic` properties correspond with the time period (in seconds) based on different types of [link prefetching](/docs/app/api-reference/components/link#prefetch).
- The `dynamic` property is used when the `prefetch` prop on `Link` is left unspecified or is set to `false`.
- Default: 30 seconds
- Default: 0 seconds (not cached)
- The `static` property is used when the `prefetch` prop on `Link` is set to `true`, or when calling [`router.prefetch`](/docs/app/building-your-application/caching#routerprefetch).
- Default: 5 minutes

View file

@ -178,7 +178,7 @@ export function getDefineEnv({
config.experimental.manualClientBasePath ?? false,
'process.env.__NEXT_CLIENT_ROUTER_DYNAMIC_STALETIME': JSON.stringify(
isNaN(Number(config.experimental.staleTimes?.dynamic))
? 30 // 30 seconds
? 0
: config.experimental.staleTimes?.dynamic
),
'process.env.__NEXT_CLIENT_ROUTER_STATIC_STALETIME': JSON.stringify(

View file

@ -239,7 +239,7 @@ export function prunePrefetchCache(
}
// These values are set by `define-env-plugin` (based on `nextConfig.experimental.staleTimes`)
// and default to 5 minutes (static) / 30 seconds (dynamic)
// and default to 5 minutes (static) / 0 seconds (dynamic)
const DYNAMIC_STALETIME_MS =
Number(process.env.__NEXT_CLIENT_ROUTER_DYNAMIC_STALETIME) * 1000

View file

@ -964,7 +964,7 @@ export const defaultConfig: NextConfig = {
optimizeServerReact: true,
useEarlyImport: false,
staleTimes: {
dynamic: 30,
dynamic: 0,
static: 300,
},
allowDevelopmentBuild: undefined,

View file

@ -0,0 +1,352 @@
import { nextTestSetup } from 'e2e-utils'
import { check } from 'next-test-utils'
import { BrowserInterface } from 'next-webdriver'
import {
browserConfigWithFixedTime,
createRequestsListener,
fastForwardTo,
getPathname,
} from './test-utils'
describe('app dir client cache semantics (default semantics)', () => {
const { next, isNextDev } = nextTestSetup({
files: __dirname,
})
if (isNextDev) {
// dev doesn't support prefetch={true}, so this just performs a basic test to make sure data is reused for 30s
it('should return fresh data every navigation', async () => {
let browser = (await next.browser(
'/',
browserConfigWithFixedTime
)) as BrowserInterface
// navigate to prefetch-auto page
await browser.elementByCss('[href="/1"]').click()
let initialNumber = await browser.elementById('random-number').text()
// Navigate back to the index, and then back to the prefetch-auto page
await browser.elementByCss('[href="/"]').click()
await browser.eval(fastForwardTo, 5 * 1000)
await browser.elementByCss('[href="/1"]').click()
let newNumber = await browser.elementById('random-number').text()
expect(newNumber).not.toBe(initialNumber)
})
} else {
describe('prefetch={true}', () => {
let browser: BrowserInterface
beforeEach(async () => {
browser = (await next.browser(
'/',
browserConfigWithFixedTime
)) as BrowserInterface
})
it('should prefetch the full page', async () => {
const { getRequests, clearRequests } =
await createRequestsListener(browser)
await check(() => {
return getRequests().some(
([url, didPartialPrefetch]) =>
getPathname(url) === '/0' && !didPartialPrefetch
)
? 'success'
: 'fail'
}, 'success')
clearRequests()
await browser
.elementByCss('[href="/0?timeout=0"]')
.click()
.waitForElementByCss('#random-number')
expect(
getRequests().every(([url]) => getPathname(url) !== '/0')
).toEqual(true)
})
it('should re-use the cache for the full page, only for 5 mins', async () => {
const randomNumber = await browser
.elementByCss('[href="/0?timeout=0"]')
.click()
.waitForElementByCss('#random-number')
.text()
await browser.elementByCss('[href="/"]').click()
const number = await browser
.elementByCss('[href="/0?timeout=0"]')
.click()
.waitForElementByCss('#random-number')
.text()
expect(number).toBe(randomNumber)
await browser.eval(fastForwardTo, 5 * 60 * 1000)
await browser.elementByCss('[href="/"]').click()
const newNumber = await browser
.elementByCss('[href="/0?timeout=0"]')
.click()
.waitForElementByCss('#random-number')
.text()
expect(newNumber).not.toBe(randomNumber)
})
it('should prefetch again after 5 mins if the link is visible again', async () => {
const { getRequests, clearRequests } =
await createRequestsListener(browser)
await check(() => {
return getRequests().some(
([url, didPartialPrefetch]) =>
getPathname(url) === '/0' && !didPartialPrefetch
)
? 'success'
: 'fail'
}, 'success')
const randomNumber = await browser
.elementByCss('[href="/0?timeout=0"]')
.click()
.waitForElementByCss('#random-number')
.text()
await browser.eval(fastForwardTo, 5 * 60 * 1000)
clearRequests()
await browser.elementByCss('[href="/"]').click()
await check(() => {
return getRequests().some(
([url, didPartialPrefetch]) =>
getPathname(url) === '/0' && !didPartialPrefetch
)
? 'success'
: 'fail'
}, 'success')
const number = await browser
.elementByCss('[href="/0?timeout=0"]')
.click()
.waitForElementByCss('#random-number')
.text()
expect(number).not.toBe(randomNumber)
})
})
describe('prefetch={false}', () => {
let browser: BrowserInterface
beforeEach(async () => {
browser = (await next.browser(
'/',
browserConfigWithFixedTime
)) as BrowserInterface
})
it('should not prefetch the page at all', async () => {
const { getRequests } = await createRequestsListener(browser)
await browser
.elementByCss('[href="/2"]')
.click()
.waitForElementByCss('#random-number')
expect(
getRequests().filter(([url]) => getPathname(url) === '/2')
).toHaveLength(1)
expect(
getRequests().some(
([url, didPartialPrefetch]) =>
getPathname(url) === '/2' && didPartialPrefetch
)
).toBe(false)
})
it('should not re-use the page segment cache', async () => {
const randomNumber = await browser
.elementByCss('[href="/2"]')
.click()
.waitForElementByCss('#random-number')
.text()
await browser.elementByCss('[href="/"]').click()
const number = await browser
.elementByCss('[href="/2"]')
.click()
.waitForElementByCss('#random-number')
.text()
expect(number).not.toBe(randomNumber)
await browser.eval(fastForwardTo, 30 * 1000)
await browser.elementByCss('[href="/"]').click()
const newNumber = await browser
.elementByCss('[href="/2"]')
.click()
.waitForElementByCss('#random-number')
.text()
expect(newNumber).not.toBe(randomNumber)
})
})
describe('prefetch={undefined} - default', () => {
let browser: BrowserInterface
beforeEach(async () => {
browser = (await next.browser(
'/',
browserConfigWithFixedTime
)) as BrowserInterface
})
it('should prefetch partially a dynamic page', async () => {
const { getRequests, clearRequests } =
await createRequestsListener(browser)
await check(() => {
return getRequests().some(
([url, didPartialPrefetch]) =>
getPathname(url) === '/1' && didPartialPrefetch
)
? 'success'
: 'fail'
}, 'success')
clearRequests()
await browser
.elementByCss('[href="/1"]')
.click()
.waitForElementByCss('#random-number')
expect(
getRequests().some(
([url, didPartialPrefetch]) =>
getPathname(url) === '/1' && !didPartialPrefetch
)
).toBe(true)
})
it('should not re-use the page segment cache', async () => {
const randomNumber = await browser
.elementByCss('[href="/1"]')
.click()
.waitForElementByCss('#random-number')
.text()
await browser.elementByCss('[href="/"]').click()
const number = await browser
.elementByCss('[href="/1"]')
.click()
.waitForElementByCss('#random-number')
.text()
expect(number).not.toBe(randomNumber)
await browser.eval(fastForwardTo, 5 * 1000)
await browser.elementByCss('[href="/"]').click()
const newNumber = await browser
.elementByCss('[href="/1"]')
.click()
.waitForElementByCss('#random-number')
.text()
expect(newNumber).not.toBe(randomNumber)
await browser.eval(fastForwardTo, 30 * 1000)
await browser.elementByCss('[href="/"]').click()
const newNumber2 = await browser
.elementByCss('[href="/1"]')
.click()
.waitForElementByCss('#random-number')
.text()
expect(newNumber2).not.toBe(newNumber)
})
it('should refetch the full page after 5 mins', async () => {
const randomLoadingNumber = await browser
.elementByCss('[href="/1?timeout=1000"]')
.click()
.waitForElementByCss('#loading')
.text()
const randomNumber = await browser
.waitForElementByCss('#random-number')
.text()
await browser.eval(fastForwardTo, 5 * 60 * 1000)
await browser
.elementByCss('[href="/"]')
.click()
.waitForElementByCss('[href="/1?timeout=1000"]')
const newLoadingNumber = await browser
.elementByCss('[href="/1?timeout=1000"]')
.click()
.waitForElementByCss('#loading')
.text()
const newNumber = await browser
.waitForElementByCss('#random-number')
.text()
expect(newLoadingNumber).not.toBe(randomLoadingNumber)
expect(newNumber).not.toBe(randomNumber)
})
it('should respect a loading boundary that returns `null`', async () => {
await browser.elementByCss('[href="/null-loading"]').click()
// the page content should disappear immediately
expect(
await browser.hasElementByCssSelector('[href="/null-loading"]')
).toBeFalse()
// the root layout should still be visible
expect(await browser.hasElementByCssSelector('#root-layout')).toBeTrue()
// the dynamic content should eventually appear
await browser.waitForElementByCss('#random-number')
expect(
await browser.hasElementByCssSelector('#random-number')
).toBeTrue()
})
})
it('should renew the initial seeded data after expiration time', async () => {
const browser = (await next.browser(
'/without-loading/1',
browserConfigWithFixedTime
)) as BrowserInterface
const initialNumber = await browser.elementById('random-number').text()
// Expire the cache
await browser.eval(fastForwardTo, 30 * 1000)
await browser.elementByCss('[href="/without-loading"]').click()
await browser.elementByCss('[href="/without-loading/1"]').click()
const newNumber = await browser.elementById('random-number').text()
// The number should be different, as the seeded data has expired after 30s
expect(newNumber).not.toBe(initialNumber)
})
}
})

View file

@ -8,9 +8,13 @@ import {
getPathname,
} from './test-utils'
describe('app dir client cache semantics', () => {
// This preserves existing tests for the 30s/5min heuristic (previous router defaults)
describe('app dir client cache semantics (30s/5min)', () => {
const { next, isNextDev } = nextTestSetup({
files: __dirname,
nextConfig: {
experimental: { staleTimes: { dynamic: 30, static: 180 } },
},
})
if (isNextDev) {

View file

@ -1 +0,0 @@
module.exports = {}

View file

@ -0,0 +1,129 @@
import { nextTestSetup } from 'e2e-utils'
import { retry } from 'next-test-utils'
import { NEXT_RSC_UNION_QUERY } from 'next/dist/client/components/app-router-headers'
const browserConfigWithFixedTime = {
beforePageLoad: (page) => {
page.addInitScript(() => {
const startTime = new Date()
const fixedTime = new Date('2023-04-17T00:00:00Z')
// Override the Date constructor
// @ts-ignore
// eslint-disable-next-line no-native-reassign
Date = class extends Date {
constructor() {
super()
// @ts-ignore
return new startTime.constructor(fixedTime)
}
static now() {
return fixedTime.getTime()
}
}
})
},
}
describe('app dir - prefetching (custom staleTime)', () => {
const { next, isNextDev } = nextTestSetup({
files: __dirname,
skipDeployment: true,
nextConfig: {
experimental: {
staleTimes: {
static: 180,
dynamic: 30,
},
},
},
})
if (isNextDev) {
it('should skip next dev for now', () => {})
return
}
it('should not fetch again when a static page was prefetched when navigating to it twice', async () => {
const browser = await next.browser('/404', browserConfigWithFixedTime)
let requests: string[] = []
browser.on('request', (req) => {
requests.push(new URL(req.url()).pathname)
})
await browser.eval('location.href = "/"')
await browser.eval(
`window.nd.router.prefetch("/static-page", {kind: "auto"})`
)
await retry(async () => {
expect(
requests.filter(
(request) =>
request === '/static-page' || request.includes(NEXT_RSC_UNION_QUERY)
).length
).toBe(1)
})
await browser
.elementByCss('#to-static-page')
.click()
.waitForElementByCss('#static-page')
await browser
.elementByCss('#to-home')
// Go back to home page
.click()
// Wait for homepage to load
.waitForElementByCss('#to-static-page')
// Click on the link to the static page again
.click()
// Wait for the static page to load again
.waitForElementByCss('#static-page')
await retry(async () => {
expect(
requests.filter(
(request) =>
request === '/static-page' || request.includes(NEXT_RSC_UNION_QUERY)
).length
).toBe(1)
})
})
it('should not re-fetch cached data when navigating back to a route group', async () => {
const browser = await next.browser('/prefetch-auto-route-groups')
// once the page has loaded, we expect a data fetch
expect(await browser.elementById('count').text()).toBe('1')
// once navigating to a sub-page, we expect another data fetch
await browser
.elementByCss("[href='/prefetch-auto-route-groups/sub/foo']")
.click()
// navigating back to the route group page shouldn't trigger any data fetch
await browser.elementByCss("[href='/prefetch-auto-route-groups']").click()
// confirm that the dashboard page is still rendering the stale fetch count, as it should be cached
expect(await browser.elementById('count').text()).toBe('1')
// navigating to a new sub-page, we expect another data fetch
await browser
.elementByCss("[href='/prefetch-auto-route-groups/sub/bar']")
.click()
// finally, going back to the route group page shouldn't trigger any data fetch
await browser.elementByCss("[href='/prefetch-auto-route-groups']").click()
// confirm that the dashboard page is still rendering the stale fetch count, as it should be cached
expect(await browser.elementById('count').text()).toBe('1')
await browser.refresh()
// reloading the page, we should now get an accurate total number of fetches
// the initial fetch, 2 sub-page fetches, and a final fetch when reloading the page
expect(await browser.elementById('count').text()).toBe('4')
})
})

View file

@ -114,51 +114,6 @@ describe('app dir - prefetching', () => {
).toBe(1)
})
it('should not fetch again when a static page was prefetched when navigating to it twice', async () => {
const browser = await next.browser('/404', browserConfigWithFixedTime)
let requests: string[] = []
browser.on('request', (req) => {
requests.push(new URL(req.url()).pathname)
})
await browser.eval('location.href = "/"')
await browser.eval(
`window.nd.router.prefetch("/static-page", {kind: "auto"})`
)
await check(() => {
return requests.some(
(req) =>
req.includes('static-page') && !req.includes(NEXT_RSC_UNION_QUERY)
)
? 'success'
: JSON.stringify(requests)
}, 'success')
await browser
.elementByCss('#to-static-page')
.click()
.waitForElementByCss('#static-page')
await browser
.elementByCss('#to-home')
// Go back to home page
.click()
// Wait for homepage to load
.waitForElementByCss('#to-static-page')
// Click on the link to the static page again
.click()
// Wait for the static page to load again
.waitForElementByCss('#static-page')
expect(
requests.filter(
(request) =>
request === '/static-page' || request.includes(NEXT_RSC_UNION_QUERY)
).length
).toBe(1)
})
it('should calculate `_rsc` query based on `Next-Url`', async () => {
const browser = await next.browser('/404', browserConfigWithFixedTime)
let staticPageRequests: string[] = []
@ -373,38 +328,5 @@ describe('app dir - prefetching', () => {
)
})
})
it('should not re-fetch cached data when navigating back to a route group', async () => {
const browser = await next.browser('/prefetch-auto-route-groups')
// once the page has loaded, we expect a data fetch
expect(await browser.elementById('count').text()).toBe('1')
// once navigating to a sub-page, we expect another data fetch
await browser
.elementByCss("[href='/prefetch-auto-route-groups/sub/foo']")
.click()
// navigating back to the route group page shouldn't trigger any data fetch
await browser.elementByCss("[href='/prefetch-auto-route-groups']").click()
// confirm that the dashboard page is still rendering the stale fetch count, as it should be cached
expect(await browser.elementById('count').text()).toBe('1')
// navigating to a new sub-page, we expect another data fetch
await browser
.elementByCss("[href='/prefetch-auto-route-groups/sub/bar']")
.click()
// finally, going back to the route group page shouldn't trigger any data fetch
await browser.elementByCss("[href='/prefetch-auto-route-groups']").click()
// confirm that the dashboard page is still rendering the stale fetch count, as it should be cached
expect(await browser.elementById('count').text()).toBe('1')
await browser.refresh()
// reloading the page, we should now get an accurate total number of fetches
// the initial fetch, 2 sub-page fetches, and a final fetch when reloading the page
expect(await browser.elementById('count').text()).toBe('4')
})
})
})

View file

@ -666,10 +666,12 @@ describe('app dir - basic', () => {
}
})
// TODO-APP: Re-enable this test.
it('should soft push', async () => {
const browser = await next.browser('/link-soft-push')
// set a flag once the page loads so we can track if a hard nav occurred (which would reset the flag)
await browser.eval('window.__nextSoftPushTest = 1')
try {
// Click the link on the page, and verify that the history entry was
// added.
@ -685,26 +687,25 @@ describe('app dir - basic', () => {
await browser.back()
await browser.elementById('link').click()
// Get the date again, and compare, they should be the same.
// Get the ID again, and compare, they should be the same.
const secondID = await browser.elementById('render-id').text()
if (isPPREnabledByDefault) {
// TODO: Investigate why this fails when PPR is enabled. It doesn't
// always fail, though, so we should also fix the flakiness of
// the test.
} else {
// This is the correct behavior.
expect(firstID).toBe(secondID)
}
// router cache should have invalidated the page content, so the IDs should be different
expect(firstID).not.toBe(secondID)
// verify that the flag is still set
expect(await browser.eval('window.__nextSoftPushTest')).toBe(1)
} finally {
await browser.close()
}
})
// TODO-APP: investigate this test
it.skip('should soft replace', async () => {
it('should soft replace', async () => {
const browser = await next.browser('/link-soft-replace')
// set a flag once the page loads so we can track if a hard nav occurred (which would reset the flag)
await browser.eval('window.__nextSoftPushTest = 1')
try {
// Get the render ID so we can compare it.
const firstID = await browser.elementById('render-id').text()
@ -713,12 +714,14 @@ describe('app dir - basic', () => {
// added.
expect(await browser.eval('window.history.length')).toBe(2)
await browser.elementById('self-link').click()
await browser.waitForElementByCss('#render-id')
expect(await browser.eval('window.history.length')).toBe(2)
await retry(async () => {
// Get the id on the rendered page.
const secondID = await browser.elementById('render-id').text()
expect(secondID).toBe(firstID)
expect(secondID).not.toBe(firstID)
expect(await browser.eval('window.history.length')).toBe(2)
})
// Navigate to the subpage, verify that the history entry was NOT added.
await browser.elementById('subpage-link').click()
@ -730,9 +733,12 @@ describe('app dir - basic', () => {
await browser.waitForElementByCss('#render-id')
expect(await browser.eval('window.history.length')).toBe(2)
// Get the date again, and compare, they should be the same.
// Get the ID again, and compare, they should be the same.
const thirdID = await browser.elementById('render-id').text()
expect(thirdID).toBe(firstID)
expect(thirdID).not.toBe(firstID)
// verify that the flag is still set
expect(await browser.eval('window.__nextSoftPushTest')).toBe(1)
} finally {
await browser.close()
}

View file

@ -9,11 +9,16 @@
"app-dir static/dynamic handling should output debug info for static bailouts"
]
},
"test/e2e/app-dir/app-client-cache/client-cache.test.ts": {
"test/e2e/app-dir/app-client-cache/client-cache.original.test.ts": {
"failed": [
"app dir client cache semantics prefetch={undefined} - default should re-use the full cache for only 30 seconds",
"app dir client cache semantics prefetch={undefined} - default should renew the 30s cache once the data is revalidated",
"app dir client cache semantics prefetch={undefined} - default should refetch the full page after 5 mins"
"app dir client cache semantics (30s/5min) prefetch={undefined} - default should re-use the full cache for only 30 seconds",
"app dir client cache semantics (30s/5min) prefetch={undefined} - default should renew the 30s cache once the data is revalidated",
"app dir client cache semantics (30s/5min) prefetch={undefined} - default should refetch the full page after 5 mins"
]
},
"test/e2e/app-dir/app-client-cache/client-cache.defaults.test.ts": {
"failed": [
"app dir client cache semantics (default semantics) prefetch={undefined} - default should refetch the full page after 5 mins"
]
},
"test/e2e/app-dir/headers-static-bailout/headers-static-bailout.test.ts": {

View file

@ -274,21 +274,21 @@
"flakey": [],
"runtimeError": false
},
"test/e2e/app-dir/app-client-cache/client-cache.test.ts": {
"test/e2e/app-dir/app-client-cache/client-cache.original.test.ts": {
"passed": [
"app dir client cache semantics prefetch={false} should not prefetch the page at all",
"app dir client cache semantics prefetch={false} should re-use the cache only for 30 seconds",
"app dir client cache semantics prefetch={true} should prefetch again after 5 mins if the link is visible again",
"app dir client cache semantics prefetch={true} should prefetch the full page",
"app dir client cache semantics prefetch={true} should re-use the cache for the full page, only for 5 mins",
"app dir client cache semantics prefetch={undefined} - default should prefetch partially a dynamic page",
"app dir client cache semantics prefetch={undefined} - default should re-use the full cache for only 30 seconds",
"app dir client cache semantics prefetch={undefined} - default should refetch below the fold after 30 seconds",
"app dir client cache semantics prefetch={undefined} - default should refetch the full page after 5 mins",
"app dir client cache semantics prefetch={undefined} - default should renew the 30s cache once the data is revalidated",
"app dir client cache semantics prefetch={undefined} - default should respect a loading boundary that returns `null`",
"app dir client cache semantics should renew the initial seeded data after expiration time",
"app dir client cache semantics should seed the prefetch cache with the fetched page data"
"app dir client cache semantics (30s/5min) prefetch={false} should not prefetch the page at all",
"app dir client cache semantics (30s/5min) prefetch={false} should re-use the cache only for 30 seconds",
"app dir client cache semantics (30s/5min) prefetch={true} should prefetch again after 5 mins if the link is visible again",
"app dir client cache semantics (30s/5min) prefetch={true} should prefetch the full page",
"app dir client cache semantics (30s/5min) prefetch={true} should re-use the cache for the full page, only for 5 mins",
"app dir client cache semantics (30s/5min) prefetch={undefined} - default should prefetch partially a dynamic page",
"app dir client cache semantics (30s/5min) prefetch={undefined} - default should re-use the full cache for only 30 seconds",
"app dir client cache semantics (30s/5min) prefetch={undefined} - default should refetch below the fold after 30 seconds",
"app dir client cache semantics (30s/5min) prefetch={undefined} - default should refetch the full page after 5 mins",
"app dir client cache semantics (30s/5min) prefetch={undefined} - default should renew the 30s cache once the data is revalidated",
"app dir client cache semantics (30s/5min) prefetch={undefined} - default should respect a loading boundary that returns `null`",
"app dir client cache semantics (30s/5min) should renew the initial seeded data after expiration time",
"app dir client cache semantics (30s/5min) should seed the prefetch cache with the fetched page data"
],
"failed": [],
"pending": [],
@ -1076,6 +1076,7 @@
"app dir - basic <Link /> should push to external url",
"app dir - basic <Link /> should replace to external url",
"app dir - basic <Link /> should soft push",
"app dir - basic <Link /> should soft replace",
"app dir - basic bootstrap scripts should only bootstrap with one script, prinitializing the rest",
"app dir - basic bootstrap scripts should successfully bootstrap even when using CSP",
"app dir - basic data fetch with response over 16KB with chunked encoding should load page when fetching a large amount of data",
@ -1173,7 +1174,6 @@
"app dir - basic template component should render the template that is a server component and rerender on navigation"
],
"pending": [
"app dir - basic <Link /> should soft replace",
"app dir - basic known bugs should support React fetch instrumentation client component",
"app dir - basic known bugs should support React fetch instrumentation client component client-navigation",
"app dir - basic should handle css imports in next/dynamic correctly",

View file

@ -2674,9 +2674,9 @@
"flakey": [],
"runtimeError": false
},
"test/e2e/app-dir/app-client-cache/client-cache.test.ts": {
"test/e2e/app-dir/app-client-cache/client-cache.original.test.ts": {
"passed": [
"app dir client cache semantics should renew the 30s cache once the data is revalidated"
"app dir client cache semantics (30s/5min) should renew the 30s cache once the data is revalidated"
],
"failed": [],
"pending": [],