Make sure to handle // during hydration (#11788)

* Make sure to handle // during hydration

* Add test for navigating from // URL
This commit is contained in:
JJ Kasper 2020-04-22 10:56:49 -05:00 committed by GitHub
parent ec26b1bba3
commit eb367db9d1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 68 additions and 18 deletions

View file

@ -226,13 +226,17 @@ export default class Router implements BaseRouter {
this.isFallback = isFallback
if (typeof window !== 'undefined') {
// in order for `e.state` to work on the `onpopstate` event
// we have to register the initial route upon initialization
this.changeState(
'replaceState',
formatWithValidation({ pathname, query }),
as
)
// make sure "as" doesn't start with double slashes or else it can
// throw an error as it's considered invalid
if (as.substr(0, 2) !== '//') {
// in order for `e.state` to work on the `onpopstate` event
// we have to register the initial route upon initialization
this.changeState(
'replaceState',
formatWithValidation({ pathname, query }),
as
)
}
window.addEventListener('popstate', this.onPopState)
}

View file

@ -0,0 +1,6 @@
export default () => {
if (typeof window !== 'undefined') {
window.didHydrate = true
}
return 'oops thats a 404'
}

View file

@ -3,24 +3,64 @@
import path from 'path'
import fs from 'fs-extra'
import webdriver from 'next-webdriver'
import { nextBuild, nextStart, findPort, killApp } from 'next-test-utils'
import {
nextBuild,
nextStart,
findPort,
killApp,
launchApp,
check,
} from 'next-test-utils'
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 60 * 1
const appDir = path.join(__dirname, '..')
let app
let appPort
describe('Hydration', () => {
beforeAll(async () => {
await fs.remove(path.join(appDir, '.next'))
await nextBuild(appDir)
appPort = await findPort()
app = await nextStart(appDir, appPort)
})
afterAll(() => killApp(app))
it('Hydrates correctly', async () => {
const runTests = () => {
it('hydrates correctly for normal page', async () => {
const browser = await webdriver(appPort, '/')
expect(await browser.eval('window.didHydrate')).toBe(true)
})
it('hydrates correctly for //', async () => {
const browser = await webdriver(appPort, '//')
expect(await browser.eval('window.didHydrate')).toBe(true)
})
it('should be able to navigate after loading //', async () => {
const browser = await webdriver(appPort, '//')
await browser.eval('window.beforeNav = true')
await browser.eval('window.next.router.push("/details")')
await check(
() => browser.eval('document.documentElement.innerHTML'),
/details/
)
expect(await browser.eval('window.beforeNav')).toBe(true)
})
}
describe('Hydration', () => {
describe('dev mode', () => {
beforeAll(async () => {
await fs.remove(path.join(appDir, '.next'))
appPort = await findPort()
app = await launchApp(appDir, appPort)
})
afterAll(() => killApp(app))
runTests()
})
describe('production mode', () => {
beforeAll(async () => {
await fs.remove(path.join(appDir, '.next'))
await nextBuild(appDir)
appPort = await findPort()
app = await nextStart(appDir, appPort)
})
afterAll(() => killApp(app))
runTests()
})
})