From eb367db9d14a875ff4da6c00ff9100f72103accd Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Wed, 22 Apr 2020 10:56:49 -0500 Subject: [PATCH] Make sure to handle // during hydration (#11788) * Make sure to handle // during hydration * Add test for navigating from // URL --- .../next/next-server/lib/router/router.ts | 18 +++--- test/integration/hydration/pages/404.js | 6 ++ test/integration/hydration/test/index.test.js | 62 +++++++++++++++---- 3 files changed, 68 insertions(+), 18 deletions(-) create mode 100644 test/integration/hydration/pages/404.js diff --git a/packages/next/next-server/lib/router/router.ts b/packages/next/next-server/lib/router/router.ts index 6fc5be2fb0..ef6abfee8b 100644 --- a/packages/next/next-server/lib/router/router.ts +++ b/packages/next/next-server/lib/router/router.ts @@ -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) } diff --git a/test/integration/hydration/pages/404.js b/test/integration/hydration/pages/404.js new file mode 100644 index 0000000000..c12a45d052 --- /dev/null +++ b/test/integration/hydration/pages/404.js @@ -0,0 +1,6 @@ +export default () => { + if (typeof window !== 'undefined') { + window.didHydrate = true + } + return 'oops thats a 404' +} diff --git a/test/integration/hydration/test/index.test.js b/test/integration/hydration/test/index.test.js index bca7263bf2..d800c2fd11 100644 --- a/test/integration/hydration/test/index.test.js +++ b/test/integration/hydration/test/index.test.js @@ -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() + }) })