diff --git a/packages/next/src/client/components/app-router.tsx b/packages/next/src/client/components/app-router.tsx index a1706ceb8ed98..d15454d159913 100644 --- a/packages/next/src/client/components/app-router.tsx +++ b/packages/next/src/client/components/app-router.tsx @@ -373,12 +373,12 @@ function Router({ // would trigger the mpa navigation logic again from the lines below. // This will restore the router to the initial state in the event that the app is restored from bfcache. function handlePageShow(event: PageTransitionEvent) { - if (!event.persisted) return + if (!event.persisted || !window.history.state?.tree) return dispatch({ type: ACTION_RESTORE, url: new URL(window.location.href), - tree: window.history.state, + tree: window.history.state.tree, }) } diff --git a/test/lib/browsers/base.ts b/test/lib/browsers/base.ts index 3ac693da9e86a..e31985ed13fc5 100644 --- a/test/lib/browsers/base.ts +++ b/test/lib/browsers/base.ts @@ -99,13 +99,13 @@ export abstract class BrowserInterface implements PromiseLike { /** * Use browsers `go back` functionality. */ - back(): BrowserInterface { + back(options?: any): BrowserInterface { return this } /** * Use browsers `go forward` functionality. Inverse of back. */ - forward(): BrowserInterface { + forward(options?: any): BrowserInterface { return this } refresh(): BrowserInterface { diff --git a/test/lib/browsers/playwright.ts b/test/lib/browsers/playwright.ts index 024b54afa3b50..24a56fc27f2d0 100644 --- a/test/lib/browsers/playwright.ts +++ b/test/lib/browsers/playwright.ts @@ -212,14 +212,14 @@ export class Playwright extends BrowserInterface { await page.goto(url, { waitUntil: 'load' }) } - back(): BrowserInterface { + back(options): BrowserInterface { return this.chain(async () => { - await page.goBack() + await page.goBack(options) }) } - forward(): BrowserInterface { + forward(options): BrowserInterface { return this.chain(async () => { - await page.goForward() + await page.goForward(options) }) } refresh(): BrowserInterface { diff --git a/test/production/export-routing/app/layout.js b/test/production/bfcache-routing/app/layout.js similarity index 100% rename from test/production/export-routing/app/layout.js rename to test/production/bfcache-routing/app/layout.js diff --git a/test/production/export-routing/app/page.js b/test/production/bfcache-routing/app/page.js similarity index 93% rename from test/production/export-routing/app/page.js rename to test/production/bfcache-routing/app/page.js index 8998e00c040cd..54332c78468aa 100644 --- a/test/production/export-routing/app/page.js +++ b/test/production/bfcache-routing/app/page.js @@ -6,6 +6,7 @@ export default function Page() { const [counter, setCounter] = React.useState(0) return (
+

BFCache Test

diff --git a/test/production/export-routing/index.test.ts b/test/production/bfcache-routing/index.test.ts similarity index 54% rename from test/production/export-routing/index.test.ts rename to test/production/bfcache-routing/index.test.ts index 62ca0b49b8a8d..f813c720bd9ab 100644 --- a/test/production/export-routing/index.test.ts +++ b/test/production/bfcache-routing/index.test.ts @@ -8,7 +8,7 @@ import { import webdriver from 'next-webdriver' import { join } from 'path' -describe('export-routing', () => { +describe('bfcache-routing', () => { let port: number let app: Server @@ -35,20 +35,39 @@ describe('export-routing', () => { const browser = await webdriver(port, '/index.html', { headless: false }) + // we overwrite the typical waitUntil: 'load' option here as the event is never being triggered if we hit the bfcache + const bfOptions = { waitUntil: 'commit' } + await browser.elementByCss('a[href="https://example.vercel.sh"]').click() await browser.waitForCondition( 'window.location.origin === "https://example.vercel.sh"' ) - // this will never resolve in the failure case, as the page will be suspended indefinitely - await browser.back() + await browser.back(bfOptions) + + await browser.waitForCondition( + 'window.location.origin.includes("localhost")' + ) + + let html = await browser.evalAsync('document.documentElement.innerHTML') - expect(await browser.elementByCss('#counter').text()).toBe('0') + expect(html).toContain('BFCache Test') - // click the button - await browser.elementByCss('button').click() + await browser.evalAsync(`document.querySelector('button').click()`) + + // we should still be on the test page + html = await browser.evalAsync('document.documentElement.innerHTML') + expect(html).toContain('BFCache Test') + + await browser.forward(bfOptions) + await browser.back(bfOptions) + + await browser.waitForCondition( + 'window.location.origin.includes("localhost")' + ) - // counter should be 1 - expect(await browser.elementByCss('#counter').text()).toBe('1') + // we should be back on the test page with no errors + html = await browser.evalAsync('document.documentElement.innerHTML') + expect(html).toContain('BFCache Test') }) }) diff --git a/test/production/export-routing/next.config.js b/test/production/bfcache-routing/next.config.js similarity index 100% rename from test/production/export-routing/next.config.js rename to test/production/bfcache-routing/next.config.js