From d1b67623f67f1b6e215fd2f41bd3b6238c4ef686 Mon Sep 17 00:00:00 2001 From: HaNdTriX Date: Thu, 9 Aug 2018 19:13:44 +0200 Subject: [PATCH] Throw error if getInitialProps is defined as as instance method (#4922) * Throw error if getInitialProps is defined as as instance method Omitting the static keyword happens pretty often. Therefore we should trigger a warning in devmode. Closes: #4782 * Document getInitialProps error * Add unit tests for loadGetInitialProps --- .../get-inital-props-as-an-instance-method.md | 39 ++++++++++++++ lib/utils.js | 8 +++ test/unit/loadGetInitialProps.test.js | 52 +++++++++++++++++++ 3 files changed, 99 insertions(+) create mode 100644 errors/get-inital-props-as-an-instance-method.md create mode 100644 test/unit/loadGetInitialProps.test.js diff --git a/errors/get-inital-props-as-an-instance-method.md b/errors/get-inital-props-as-an-instance-method.md new file mode 100644 index 0000000000000..d9c58e617f182 --- /dev/null +++ b/errors/get-inital-props-as-an-instance-method.md @@ -0,0 +1,39 @@ +# getInitialProps was defined as an instance method + +#### Why This Error Occurred + +`getInitialProps` must be a static method in order to be called by next.js. + +#### Possible Ways to Fix It + +Use the static keyword. + +```js +export default class YourEntryComponent extends React.Component { + static getInitialProps () { + return {} + } + + render () { + return 'foo' + } +} +``` + +or + +```js +const YourEntryComponent = function () { + return 'foo' +} + +YourEntryComponent.getInitialProps = () => { + return {} +} + +export default YourEntryComponent +``` + +### Useful Links + +- [Fetching data and component lifecycle](https://github.com/zeit/next.js#fetching-data-and-component-lifecycle) diff --git a/lib/utils.js b/lib/utils.js index 22faec6a62f2a..c1daa56f14994 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -54,6 +54,14 @@ export function isResSent (res) { } export async function loadGetInitialProps (Component, ctx) { + if (process.env.NODE_ENV !== 'production') { + if (Component.prototype && Component.prototype.getInitialProps) { + const compName = getDisplayName(Component) + const message = `"${compName}.getInitialProps()" is defined as an instance method - visit https://err.sh/next.js/get-inital-props-as-an-instance-method for more information.` + throw new Error(message) + } + } + if (!Component.getInitialProps) return {} const props = await Component.getInitialProps(ctx) diff --git a/test/unit/loadGetInitialProps.test.js b/test/unit/loadGetInitialProps.test.js new file mode 100644 index 0000000000000..860e90406b64c --- /dev/null +++ b/test/unit/loadGetInitialProps.test.js @@ -0,0 +1,52 @@ +/* global describe, it, expect */ +import { loadGetInitialProps } from '../../dist/lib/utils' + +describe('loadGetInitialProps', () => { + it('should throw if getInitialProps is defined as an instance method', () => { + class TestComponent { + getInitialProps () {} + } + const rejectPromise = loadGetInitialProps(TestComponent, {}) + const error = new Error('"TestComponent.getInitialProps()" is defined as an instance method - visit https://err.sh/next.js/get-inital-props-as-an-instance-method for more information.') + return expect(rejectPromise).rejects.toEqual(error) + }) + + it('should resolve to an object if getInitialProps is missing', async () => { + const result = await loadGetInitialProps(() => {}, {}) + expect(result).toEqual({}) + }) + + it('should resolve getInitialProps', async () => { + class TestComponent { + static async getInitialProps () { + return { foo: 1 } + } + } + const result = await loadGetInitialProps(TestComponent, {}) + expect(result).toEqual({ foo: 1 }) + }) + + it('should be able to return an invalid value if the request was already sent', async () => { + class TestComponent { + static async getInitialProps () { + return 'invalidValue' + } + } + const ctx = { + res: { + finished: true + } + } + const result = await loadGetInitialProps(TestComponent, ctx) + expect(result).toBe('invalidValue') + }) + + it('should throw if getInitialProps won\'t return an object ', () => { + class TestComponent { + static async getInitialProps () {} + } + const rejectPromise = loadGetInitialProps(TestComponent, {}) + const error = new Error('"TestComponent.getInitialProps()" should resolve to an object. But found "undefined" instead.') + return expect(rejectPromise).rejects.toEqual(error) + }) +})