Skip to content

Commit

Permalink
fix bfcache restoration behavior (#54198)
Browse files Browse the repository at this point in the history
Follow up to #54081 -- this was
restoring the router tree improperly causing an error on bfcache hits

Had to override some default behaviors to prevent `forward` / `back` in
playwright from hanging indefinitely since no load event is firing in
these cases

Fixes #54184
Closes NEXT-1528
  • Loading branch information
ztanner committed Aug 17, 2023
1 parent 631018a commit c676f93
Show file tree
Hide file tree
Showing 7 changed files with 36 additions and 16 deletions.
4 changes: 2 additions & 2 deletions packages/next/src/client/components/app-router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
})
}

Expand Down
4 changes: 2 additions & 2 deletions test/lib/browsers/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,13 @@ export abstract class BrowserInterface implements PromiseLike<any> {
/**
* 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 {
Expand Down
8 changes: 4 additions & 4 deletions test/lib/browsers/playwright.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export default function Page() {
const [counter, setCounter] = React.useState(0)
return (
<div>
<h1>BFCache Test</h1>
<button onClick={() => setCounter((c) => c + 1)}>
Trigger Re-Render
</button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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')
})
})

0 comments on commit c676f93

Please sign in to comment.