From e00e47d560d0473397f42d937b1b4485cc5d71d9 Mon Sep 17 00:00:00 2001 From: Zack Tanner <1939140+ztanner@users.noreply.github.com> Date: Sun, 9 Jun 2024 09:34:14 -0700 Subject: [PATCH] ensure router cache updates reference the latest cache values --- .../reducers/navigate-reducer.ts | 5 +- .../client-cache.defaults.test.ts | 3 +- .../client-cache.experimental.test.ts | 3 +- .../client-cache.original.test.ts | 3 +- .../client-cache.parallel-routes.test.ts | 81 +++++++++++++++++++ .../app/@breadcrumbs/[id]/page.js | 7 ++ .../parallel-routes/app/@breadcrumbs/page.js | 3 + .../fixtures/parallel-routes/app/[id]/page.js | 18 +++++ .../fixtures/parallel-routes/app/layout.js | 12 +++ .../fixtures/parallel-routes/app/page.js | 11 +++ .../fixtures/regular/app/[id]/client.js | 5 ++ .../regular}/app/[id]/loading.js | 0 .../{ => fixtures/regular}/app/[id]/page.js | 2 + .../{ => fixtures/regular}/app/layout.js | 0 .../regular}/app/null-loading/loading.js | 0 .../regular}/app/null-loading/page.js | 0 .../{ => fixtures/regular}/app/page.js | 0 .../without-loading/@breadcrumbs/[id]/page.js | 7 ++ .../app/without-loading/@breadcrumbs/page.js | 3 + .../regular}/app/without-loading/[id]/page.js | 0 .../regular/app/without-loading/layout.js | 8 ++ .../regular}/app/without-loading/page.js | 0 .../app-dir/app-client-cache/next.config.js | 1 + 23 files changed, 168 insertions(+), 4 deletions(-) create mode 100644 test/e2e/app-dir/app-client-cache/client-cache.parallel-routes.test.ts create mode 100644 test/e2e/app-dir/app-client-cache/fixtures/parallel-routes/app/@breadcrumbs/[id]/page.js create mode 100644 test/e2e/app-dir/app-client-cache/fixtures/parallel-routes/app/@breadcrumbs/page.js create mode 100644 test/e2e/app-dir/app-client-cache/fixtures/parallel-routes/app/[id]/page.js create mode 100644 test/e2e/app-dir/app-client-cache/fixtures/parallel-routes/app/layout.js create mode 100644 test/e2e/app-dir/app-client-cache/fixtures/parallel-routes/app/page.js create mode 100644 test/e2e/app-dir/app-client-cache/fixtures/regular/app/[id]/client.js rename test/e2e/app-dir/app-client-cache/{ => fixtures/regular}/app/[id]/loading.js (100%) rename test/e2e/app-dir/app-client-cache/{ => fixtures/regular}/app/[id]/page.js (86%) rename test/e2e/app-dir/app-client-cache/{ => fixtures/regular}/app/layout.js (100%) rename test/e2e/app-dir/app-client-cache/{ => fixtures/regular}/app/null-loading/loading.js (100%) rename test/e2e/app-dir/app-client-cache/{ => fixtures/regular}/app/null-loading/page.js (100%) rename test/e2e/app-dir/app-client-cache/{ => fixtures/regular}/app/page.js (100%) create mode 100644 test/e2e/app-dir/app-client-cache/fixtures/regular/app/without-loading/@breadcrumbs/[id]/page.js create mode 100644 test/e2e/app-dir/app-client-cache/fixtures/regular/app/without-loading/@breadcrumbs/page.js rename test/e2e/app-dir/app-client-cache/{ => fixtures/regular}/app/without-loading/[id]/page.js (100%) create mode 100644 test/e2e/app-dir/app-client-cache/fixtures/regular/app/without-loading/layout.js rename test/e2e/app-dir/app-client-cache/{ => fixtures/regular}/app/without-loading/page.js (100%) create mode 100644 test/e2e/app-dir/app-client-cache/next.config.js diff --git a/packages/next/src/client/components/router-reducer/reducers/navigate-reducer.ts b/packages/next/src/client/components/router-reducer/reducers/navigate-reducer.ts index fe2853eade6430..7798c3ab7c57be 100644 --- a/packages/next/src/client/components/router-reducer/reducers/navigate-reducer.ts +++ b/packages/next/src/client/components/router-reducer/reducers/navigate-reducer.ts @@ -167,7 +167,7 @@ function navigateReducer_noPPR( updatedCanonicalUrl.split('#', 1)[0] let currentTree = state.tree - const currentCache = state.cache + let currentCache = state.cache let scrollableSegments: FlightSegmentPath[] = [] for (const flightDataPath of flightData) { const flightSegmentPath = flightDataPath.slice( @@ -258,6 +258,9 @@ function navigateReducer_noPPR( mutable.cache = cache } else if (applied) { mutable.cache = cache + // If we applied the cache, we update the "current cache" value so any other + // segments in the FlightDataPath will be able to reference the updated cache. + currentCache = cache } currentTree = newTree diff --git a/test/e2e/app-dir/app-client-cache/client-cache.defaults.test.ts b/test/e2e/app-dir/app-client-cache/client-cache.defaults.test.ts index f8a168aca14c74..dad47c457c4c05 100644 --- a/test/e2e/app-dir/app-client-cache/client-cache.defaults.test.ts +++ b/test/e2e/app-dir/app-client-cache/client-cache.defaults.test.ts @@ -7,10 +7,11 @@ import { fastForwardTo, getPathname, } from './test-utils' +import path from 'path' describe('app dir client cache semantics (default semantics)', () => { const { next, isNextDev } = nextTestSetup({ - files: __dirname, + files: path.join(__dirname, 'fixture', 'regular'), }) if (isNextDev) { diff --git a/test/e2e/app-dir/app-client-cache/client-cache.experimental.test.ts b/test/e2e/app-dir/app-client-cache/client-cache.experimental.test.ts index 604ead35788625..690b652789d955 100644 --- a/test/e2e/app-dir/app-client-cache/client-cache.experimental.test.ts +++ b/test/e2e/app-dir/app-client-cache/client-cache.experimental.test.ts @@ -1,11 +1,12 @@ import { nextTestSetup } from 'e2e-utils' import { browserConfigWithFixedTime, fastForwardTo } from './test-utils' import { findAllTelemetryEvents } from 'next-test-utils' +import path from 'path' describe('app dir client cache semantics (experimental staleTimes)', () => { describe('dynamic: 0', () => { const { next, isNextDev } = nextTestSetup({ - files: __dirname, + files: path.join(__dirname, 'fixture', 'regular'), nextConfig: { experimental: { staleTimes: { dynamic: 0 } }, }, diff --git a/test/e2e/app-dir/app-client-cache/client-cache.original.test.ts b/test/e2e/app-dir/app-client-cache/client-cache.original.test.ts index f5065702d6466f..1c3baa4341204d 100644 --- a/test/e2e/app-dir/app-client-cache/client-cache.original.test.ts +++ b/test/e2e/app-dir/app-client-cache/client-cache.original.test.ts @@ -7,11 +7,12 @@ import { fastForwardTo, getPathname, } from './test-utils' +import path from 'path' // 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, + files: path.join(__dirname, 'fixture', 'regular'), nextConfig: { experimental: { staleTimes: { dynamic: 30, static: 180 } }, }, diff --git a/test/e2e/app-dir/app-client-cache/client-cache.parallel-routes.test.ts b/test/e2e/app-dir/app-client-cache/client-cache.parallel-routes.test.ts new file mode 100644 index 00000000000000..7a418405623086 --- /dev/null +++ b/test/e2e/app-dir/app-client-cache/client-cache.parallel-routes.test.ts @@ -0,0 +1,81 @@ +import { nextTestSetup } from 'e2e-utils' +import { check } from 'next-test-utils' +import { BrowserInterface } from 'next-webdriver' +import { + browserConfigWithFixedTime, + createRequestsListener, + fastForwardTo, + getPathname, +} from './test-utils' +import path from 'path' + +describe('app dir client cache with parallel routes', () => { + const { next } = nextTestSetup({ + files: path.join(__dirname, 'fixtures', 'parallel-routes'), + }) + + 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"]') + .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"]') + .click() + .waitForElementByCss('#random-number') + .text() + + await browser.elementByCss('[href="/"]').click() + + const number = await browser + .elementByCss('[href="/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"]') + .click() + .waitForElementByCss('#random-number') + .text() + + expect(newNumber).not.toBe(randomNumber) + }) + }) +}) diff --git a/test/e2e/app-dir/app-client-cache/fixtures/parallel-routes/app/@breadcrumbs/[id]/page.js b/test/e2e/app-dir/app-client-cache/fixtures/parallel-routes/app/@breadcrumbs/[id]/page.js new file mode 100644 index 00000000000000..43ade54c21804c --- /dev/null +++ b/test/e2e/app-dir/app-client-cache/fixtures/parallel-routes/app/@breadcrumbs/[id]/page.js @@ -0,0 +1,7 @@ +export default function Page({ params }) { + return ( +
{JSON.stringify(params)}{' '} +
{JSON.stringify(params)}{' '} +