From 85038cf8fdc6982f174caf25dfa1ab3b2c109dc7 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Wed, 29 Jul 2020 23:47:20 -0500 Subject: [PATCH] Add additional pageProps check (#15667) `pageProps` should always be defined to ensure everything is working as expected although to prevent a breaking change this adds an additional check before attempting to access `pageProps` before hydration. It also adds tests to prevent regressing on this Closes: https://github.com/vercel/next.js/issues/15647 --- packages/next/client/index.js | 1 + test/integration/no-page-props/pages/_app.js | 24 ++++ test/integration/no-page-props/pages/gsp.js | 11 ++ test/integration/no-page-props/pages/gssp.js | 11 ++ test/integration/no-page-props/pages/index.js | 21 ++++ .../no-page-props/test/index.test.js | 104 ++++++++++++++++++ 6 files changed, 172 insertions(+) create mode 100644 test/integration/no-page-props/pages/_app.js create mode 100644 test/integration/no-page-props/pages/gsp.js create mode 100644 test/integration/no-page-props/pages/gssp.js create mode 100644 test/integration/no-page-props/pages/index.js create mode 100644 test/integration/no-page-props/test/index.test.js diff --git a/packages/next/client/index.js b/packages/next/client/index.js index 2b1ee736a78d0..91a723c06738e 100644 --- a/packages/next/client/index.js +++ b/packages/next/client/index.js @@ -57,6 +57,7 @@ if ( !( page === '/_error' && hydrateProps && + hydrateProps.pageProps && hydrateProps.pageProps.statusCode === '404' ) ) { diff --git a/test/integration/no-page-props/pages/_app.js b/test/integration/no-page-props/pages/_app.js new file mode 100644 index 0000000000000..613e7714d2a5d --- /dev/null +++ b/test/integration/no-page-props/pages/_app.js @@ -0,0 +1,24 @@ +function App({ Component, pageProps }) { + return +} + +if (typeof window !== 'undefined') { + window.uncaughtErrors = [] + window.addEventListener('error', (err) => { + window.uncaughtErrors.push(err) + }) + window.addEventListener('unhandledrejection', (err) => { + window.uncaughtErrors.push(err) + }) +} + +App.getInitialProps = async ({ Component, ctx }) => { + const props = {} + + if (Component.getInitialProps) { + props.initialProps = await Component.getInitialProps(ctx) + } + return props +} + +export default App diff --git a/test/integration/no-page-props/pages/gsp.js b/test/integration/no-page-props/pages/gsp.js new file mode 100644 index 0000000000000..82117da6a7dec --- /dev/null +++ b/test/integration/no-page-props/pages/gsp.js @@ -0,0 +1,11 @@ +export default function Gsp() { + return

getStaticProps

+} + +export const getStaticProps = () => { + return { + props: { + hello: 'world', + }, + } +} diff --git a/test/integration/no-page-props/pages/gssp.js b/test/integration/no-page-props/pages/gssp.js new file mode 100644 index 0000000000000..cc7bc7e1eb2b1 --- /dev/null +++ b/test/integration/no-page-props/pages/gssp.js @@ -0,0 +1,11 @@ +export default function Gssp() { + return

getServerSideProps

+} + +export const getServerSideProps = () => { + return { + props: { + hello: 'world', + }, + } +} diff --git a/test/integration/no-page-props/pages/index.js b/test/integration/no-page-props/pages/index.js new file mode 100644 index 0000000000000..eab144bd52f4b --- /dev/null +++ b/test/integration/no-page-props/pages/index.js @@ -0,0 +1,21 @@ +import Link from 'next/link' + +export default function Index() { + return ( + <> +

index

+ + to gsp + +
+ + to gssp + +
+ + to non-existent + +
+ + ) +} diff --git a/test/integration/no-page-props/test/index.test.js b/test/integration/no-page-props/test/index.test.js new file mode 100644 index 0000000000000..22d0af1070369 --- /dev/null +++ b/test/integration/no-page-props/test/index.test.js @@ -0,0 +1,104 @@ +/* eslint-env jest */ + +import { join } from 'path' +import webdriver from 'next-webdriver' +import { + nextBuild, + nextStart, + findPort, + killApp, + launchApp, +} from 'next-test-utils' + +jest.setTimeout(1000 * 60 * 1) +const appDir = join(__dirname, '..') +let app +let appPort + +const runTests = () => { + it('should load auto-export page correctly', async () => { + const browser = await webdriver(appPort, '/') + expect(await browser.elementByCss('#index').text()).toBe('index') + expect(await browser.eval('window.uncaughtErrors')).toEqual([]) + }) + + it('should load getStaticProps page correctly', async () => { + const browser = await webdriver(appPort, '/gsp') + expect(await browser.elementByCss('#gsp').text()).toBe('getStaticProps') + expect(await browser.eval('window.uncaughtErrors')).toEqual([]) + }) + + it('should load getServerSideProps page correctly', async () => { + const browser = await webdriver(appPort, '/gssp') + expect(await browser.elementByCss('#gssp').text()).toBe( + 'getServerSideProps' + ) + expect(await browser.eval('window.uncaughtErrors')).toEqual([]) + }) + + it('should load 404 page correctly', async () => { + const browser = await webdriver(appPort, '/non-existent') + expect(await browser.elementByCss('h2').text()).toBe( + 'An unexpected error has occurred.' + ) + expect(await browser.eval('window.uncaughtErrors')).toEqual([]) + }) + + it('should navigate between pages correctly', async () => { + const browser = await webdriver(appPort, '/') + + await browser.eval('window.beforeNav = "hi"') + await browser.elementByCss('#to-gsp').click() + await browser.waitForElementByCss('#gsp') + + expect(await browser.elementByCss('#gsp').text()).toBe('getStaticProps') + expect(await browser.eval('window.beforeNav')).toBe('hi') + + await browser.back() + await browser.waitForElementByCss('#index') + expect(await browser.eval('window.beforeNav')).toBe('hi') + + await browser.elementByCss('#to-gssp').click() + await browser.waitForElementByCss('#gssp') + + expect(await browser.elementByCss('#gssp').text()).toBe( + 'getServerSideProps' + ) + expect(await browser.eval('window.beforeNav')).toBe('hi') + + await browser.back() + await browser.waitForElementByCss('#index') + expect(await browser.eval('window.beforeNav')).toBe('hi') + + await browser.elementByCss('#to-404').click() + await browser.waitForElementByCss('h2') + expect(await browser.eval('window.beforeNav')).toBe(null) + expect(await browser.elementByCss('h2').text()).toBe( + 'An unexpected error has occurred.' + ) + expect(await browser.eval('window.uncaughtErrors')).toEqual([]) + }) +} + +describe('Error no pageProps', () => { + describe('dev mode', () => { + beforeAll(async () => { + appPort = await findPort() + app = await launchApp(appDir, appPort) + }) + afterAll(() => killApp(app)) + + runTests() + }) + + describe('production mode', () => { + beforeAll(async () => { + await nextBuild(appDir) + appPort = await findPort() + app = await nextStart(appDir, appPort) + }) + afterAll(() => killApp(app)) + + runTests() + }) +})