From ed3e8f71252b581db84651877aabfbd5d2c34d8c Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Wed, 2 Jun 2021 17:11:03 +0200 Subject: [PATCH] Remove deprecated features (#25446) * Remove deprecated features In the next major version we'll want to merge this PR that removes some of the long-time deprecated features, it'll have a positive effect on bundle size. * Update tests * Update tests * Change unsized to layout=fill in test * Update sizes * Update rotation test * Update size limit test * Update test * Update test * Update test --- docs/upgrading.md | 32 ++++++ packages/next/client/image.tsx | 23 +--- packages/next/next-server/lib/dynamic.tsx | 45 +------- packages/next/next-server/lib/loadable.js | 64 +---------- packages/next/pages/_app.tsx | 92 +--------------- .../integration/basic/pages/dynamic/bundle.js | 62 ----------- test/integration/basic/test/dynamic.js | 73 +------------ .../build-output/test/index.test.js | 8 +- .../pages/nav/shallow-routing.js | 102 +++++++++--------- .../pages/nav/url-prop-change.js | 40 ------- .../pages/url-prop-override.js | 18 ---- .../client-navigation/pages/url-prop.js | 13 --- .../client-navigation/test/index.test.js | 26 ----- .../client-navigation/test/rendering.js | 18 +--- .../base-path/pages/invalid-unsized.js | 13 --- .../base-path/pages/rotated.js | 6 +- .../base-path/test/index.test.js | 11 +- .../default/test/index.test.js | 11 +- .../production/pages/dynamic/bundle.js | 61 ----------- test/integration/production/test/dynamic.js | 73 +------------ .../integration/production/test/index.test.js | 6 +- yarn.lock | 63 ++++++++++- 22 files changed, 171 insertions(+), 689 deletions(-) delete mode 100644 test/integration/basic/pages/dynamic/bundle.js delete mode 100644 test/integration/client-navigation/pages/nav/url-prop-change.js delete mode 100644 test/integration/client-navigation/pages/url-prop-override.js delete mode 100644 test/integration/client-navigation/pages/url-prop.js delete mode 100644 test/integration/image-component/base-path/pages/invalid-unsized.js delete mode 100644 test/integration/production/pages/dynamic/bundle.js diff --git a/docs/upgrading.md b/docs/upgrading.md index cc13023fc81c2..47757325c1564 100644 --- a/docs/upgrading.md +++ b/docs/upgrading.md @@ -4,6 +4,38 @@ description: Learn how to upgrade Next.js. # Upgrade Guide +## Upgrading from version 10 to 11 + +### Remove `super.componentDidCatch()` from `pages/_app.js` + +The `next/app` component's `componentDidCatch` has been deprecated since Next.js 9 as it's no longer needed and has since been a no-op, in Next.js 11 it has been removed. + +If your `pages/_app.js` has a custom `componentDidCatch` method you can remove `super.componentDidCatch` as it is no longer needed. + +### Remove `Container` from `pages/_app.js` + +This export has been deprecated since Next.js 9 as it's no longer needed and has since been a no-op with a warning during development. In Next.js 11 it has been removed. + +If your `pages/_app.js` imports `Container` from `next/app` you can remove `Container` as it has been removed. Learn more in [the documentation](https://nextjs.org/docs/messages/app-container-deprecated). + +### Remove `props.url` usage from page components + +This property has been deprecated since Next.js 4 and has since shown a warning during development. With the introduction of `getStaticProps` / `getServerSideProps` these methods already disallowed usage of `props.url`. In Next.js 11 it has been removed completely. + +You can learn more in [the documentation](https://nextjs.org/docs/messages/url-deprecated). + +### Remove `unsized` property on `next/image` + +The `unsized` property on `next/image` was deprecated in Next.js 10.0.1. You can use `layout="fill"` instead. In Next.js 11 `unsized` was removed. + +### Remove `modules` property on `next/dynamic` + +The `modules` and `render` option for `next/dynamic` have been deprecated since Next.js 9.5 showing a warning that it has been deprecated. This was done in order to make `next/dynamic` close to `React.lazy` in API surface. In Next.js 11 the `modules` and `render` options have been removed. + +This option hasn't been mentioned in the documentation since Next.js 8 so it's less likely that your application is using it. + +If you application does use `modules` and `render` you can refer to [the documentation](https://nextjs.org/docs/messages/next-dynamic-modules). + ## React 16 to 17 React 17 introduced a new [JSX Transform](https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html) that brings a long-time Next.js feature to the wider React ecosystem: Not having to `import React from 'react'` when using JSX. When using React 17 Next.js will automatically use the new transform. This transform does not make the `React` variable global, which was an unintended side-effect of the previous Next.js implementation. A [codemod is available](/docs/advanced-features/codemods.md#add-missing-react-import) to automatically fix cases where you accidentally used `React` without importing it. diff --git a/packages/next/client/image.tsx b/packages/next/client/image.tsx index eea353be48980..e41f5c4b94475 100644 --- a/packages/next/client/image.tsx +++ b/packages/next/client/image.tsx @@ -62,12 +62,6 @@ export type ImageProps = Omit< objectFit?: ImgElementStyle['objectFit'] objectPosition?: ImgElementStyle['objectPosition'] } & ( - | { - width?: never - height?: never - /** @deprecated Use `layout="fill"` instead */ - unsized: true - } | { width?: never; height?: never; layout: 'fill' } | { width: number | string @@ -260,12 +254,7 @@ export default function Image({ }: ImageProps) { let rest: Partial = all let layout: NonNullable = sizes ? 'responsive' : 'intrinsic' - let unsized = false - if ('unsized' in rest) { - unsized = Boolean(rest.unsized) - // Remove property so it's not spread into image: - delete rest['unsized'] - } else if ('layout' in rest) { + if ('layout' in rest) { // Override default layout if the user specified one: if (rest.layout) layout = rest.layout @@ -304,11 +293,6 @@ export default function Image({ `Image with src "${src}" has both "priority" and "loading='lazy'" properties. Only one should be used.` ) } - if (unsized) { - throw new Error( - `Image with src "${src}" has deprecated "unsized" property, which was removed in favor of the "layout='fill'" property` - ) - } } let isLazy = @@ -461,11 +445,6 @@ export default function Image({ }) } - if (unsized) { - wrapperStyle = undefined - sizerStyle = undefined - imgStyle = undefined - } return (
{sizerStyle ? ( diff --git a/packages/next/next-server/lib/dynamic.tsx b/packages/next/next-server/lib/dynamic.tsx index 53931abde0782..0b260d19e9641 100644 --- a/packages/next/next-server/lib/dynamic.tsx +++ b/packages/next/next-server/lib/dynamic.tsx @@ -33,16 +33,9 @@ export type LoadableBaseOptions

= LoadableGeneratedOptions & { ssr?: boolean } -export type LoadableOptions

= LoadableBaseOptions

& { - render?(loader: any, props: any): JSX.Element -} +export type LoadableOptions

= LoadableBaseOptions

-export type DynamicOptions

= LoadableBaseOptions

& { - /** - * @deprecated the modules option has been planned for removal - */ - render?(props: P, loaded: any): JSX.Element -} +export type DynamicOptions

= LoadableBaseOptions

export type LoadableFn

= ( opts: LoadableOptions

@@ -117,40 +110,6 @@ export default function dynamic

( // Support for passing options, eg: dynamic(import('../hello-world'), {loading: () =>

Loading something

}) loadableOptions = { ...loadableOptions, ...options } - if ( - typeof dynamicOptions === 'object' && - !(dynamicOptions instanceof Promise) - ) { - // show deprecation warning for `modules` key in development - if (process.env.NODE_ENV !== 'production') { - if (dynamicOptions.modules) { - console.warn( - 'The modules option for next/dynamic has been deprecated. See here for more info https://nextjs.org/docs/messages/next-dynamic-modules' - ) - } - } - // Support for `render` when using a mapping, eg: `dynamic({ modules: () => {return {HelloWorld: import('../hello-world')}, render(props, loaded) {} } }) - if (dynamicOptions.render) { - loadableOptions.render = (loaded, props) => - dynamicOptions.render!(props, loaded) - } - // Support for `modules` when using a mapping, eg: `dynamic({ modules: () => {return {HelloWorld: import('../hello-world')}, render(props, loaded) {} } }) - if (dynamicOptions.modules) { - loadableFn = Loadable.Map - const loadModules: LoaderMap = {} - const modules = dynamicOptions.modules() - Object.keys(modules).forEach((key) => { - const value: any = modules[key] - if (typeof value.then === 'function') { - loadModules[key] = () => value.then((mod: any) => mod.default || mod) - return - } - loadModules[key] = value - }) - loadableOptions.loader = loadModules - } - } - // coming from build/babel/plugins/react-loadable-plugin.js if (loadableOptions.loadableGenerated) { loadableOptions = { diff --git a/packages/next/next-server/lib/loadable.js b/packages/next/next-server/lib/loadable.js index a81d792610ed3..3b2381b319dfb 100644 --- a/packages/next/next-server/lib/loadable.js +++ b/packages/next/next-server/lib/loadable.js @@ -53,61 +53,10 @@ function load(loader) { return state } -function loadMap(obj) { - let state = { - loading: false, - loaded: {}, - error: null, - } - - let promises = [] - - try { - Object.keys(obj).forEach((key) => { - let result = load(obj[key]) - - if (!result.loading) { - state.loaded[key] = result.loaded - state.error = result.error - } else { - state.loading = true - } - - promises.push(result.promise) - - result.promise - .then((res) => { - state.loaded[key] = res - }) - .catch((err) => { - state.error = err - }) - }) - } catch (err) { - state.error = err - } - - state.promise = Promise.all(promises) - .then((res) => { - state.loading = false - return res - }) - .catch((err) => { - state.loading = false - throw err - }) - - return state -} - function resolve(obj) { return obj && obj.__esModule ? obj.default : obj } -function render(loaded, props) { - return React.createElement(resolve(loaded), props) -} - function createLoadableComponent(loadFn, options) { let opts = Object.assign( { @@ -115,7 +64,6 @@ function createLoadableComponent(loadFn, options) { loading: null, delay: 200, timeout: null, - render: render, webpack: null, modules: null, }, @@ -188,7 +136,7 @@ function createLoadableComponent(loadFn, options) { retry: subscription.retry, }) } else if (state.loaded) { - return opts.render(state.loaded, props) + return React.createElement(resolve(state.loaded), props) } else { return null } @@ -291,16 +239,6 @@ function Loadable(opts) { return createLoadableComponent(load, opts) } -function LoadableMap(opts) { - if (typeof opts.render !== 'function') { - throw new Error('LoadableMap requires a `render(loaded, props)` function') - } - - return createLoadableComponent(loadMap, opts) -} - -Loadable.Map = LoadableMap - function flushInitializers(initializers, ids) { let promises = [] diff --git a/packages/next/pages/_app.tsx b/packages/next/pages/_app.tsx index 0a2e8e80d8ab4..4036cfd89674e 100644 --- a/packages/next/pages/_app.tsx +++ b/packages/next/pages/_app.tsx @@ -1,6 +1,5 @@ -import React, { ErrorInfo } from 'react' +import React from 'react' import { - execOnce, loadGetInitialProps, AppContextType, AppInitialProps, @@ -36,94 +35,9 @@ export default class App

extends React.Component< static origGetInitialProps = appGetInitialProps static getInitialProps = appGetInitialProps - // Kept here for backwards compatibility. - // When someone ended App they could call `super.componentDidCatch`. - // @deprecated This method is no longer needed. Errors are caught at the top level - componentDidCatch(error: Error, _errorInfo: ErrorInfo): void { - throw error - } - render() { - const { router, Component, pageProps, __N_SSG, __N_SSP } = this - .props as AppProps - - return ( - - ) - } -} - -let warnContainer: () => void -let warnUrl: () => void - -if (process.env.NODE_ENV !== 'production') { - warnContainer = execOnce(() => { - console.warn( - `Warning: the \`Container\` in \`_app\` has been deprecated and should be removed. https://nextjs.org/docs/messages/app-container-deprecated` - ) - }) - - warnUrl = execOnce(() => { - console.error( - `Warning: the 'url' property is deprecated. https://nextjs.org/docs/messages/url-deprecated` - ) - }) -} - -// @deprecated noop for now until removal -export function Container(p: any) { - if (process.env.NODE_ENV !== 'production') warnContainer() - return p.children -} - -export function createUrl(router: Router) { - // This is to make sure we don't references the router object at call time - const { pathname, asPath, query } = router - return { - get query() { - if (process.env.NODE_ENV !== 'production') warnUrl() - return query - }, - get pathname() { - if (process.env.NODE_ENV !== 'production') warnUrl() - return pathname - }, - get asPath() { - if (process.env.NODE_ENV !== 'production') warnUrl() - return asPath - }, - back: () => { - if (process.env.NODE_ENV !== 'production') warnUrl() - router.back() - }, - push: (url: string, as?: string) => { - if (process.env.NODE_ENV !== 'production') warnUrl() - return router.push(url, as) - }, - pushTo: (href: string, as?: string) => { - if (process.env.NODE_ENV !== 'production') warnUrl() - const pushRoute = as ? href : '' - const pushUrl = as || href - - return router.push(pushRoute, pushUrl) - }, - replace: (url: string, as?: string) => { - if (process.env.NODE_ENV !== 'production') warnUrl() - return router.replace(url, as) - }, - replaceTo: (href: string, as?: string) => { - if (process.env.NODE_ENV !== 'production') warnUrl() - const replaceRoute = as ? href : '' - const replaceUrl = as || href + const { Component, pageProps } = this.props as AppProps - return router.replace(replaceRoute, replaceUrl) - }, + return } } diff --git a/test/integration/basic/pages/dynamic/bundle.js b/test/integration/basic/pages/dynamic/bundle.js deleted file mode 100644 index 81750ce977e9f..0000000000000 --- a/test/integration/basic/pages/dynamic/bundle.js +++ /dev/null @@ -1,62 +0,0 @@ -import React from 'react' -import dynamic from 'next/dynamic' -import Router from 'next/router' -import PropTypes from 'prop-types' - -const HelloBundle = dynamic({ - modules: (props) => { - const components = { - HelloContext: import('../../components/hello-context'), - Hello1: import('../../components/hello1'), - Hello2: import('../../components/hello2'), - } - - return components - }, - render: (props, { HelloContext, Hello1, Hello2 }) => ( -

-

{props.title}

- - - {props.showMore ? : null} -
- ), -}) - -export default class Bundle extends React.Component { - static childContextTypes = { - data: PropTypes.object, - } - - static getInitialProps({ query }) { - return { showMore: Boolean(query.showMore) } - } - - getChildContext() { - return { - data: { title: 'Vercel Rocks' }, - } - } - - toggleShowMore() { - if (this.props.showMore) { - Router.push('/dynamic/bundle') - return - } - - Router.push('/dynamic/bundle?showMore=1') - } - - render() { - const { showMore } = this.props - - return ( -
- - -
- ) - } -} diff --git a/test/integration/basic/test/dynamic.js b/test/integration/basic/test/dynamic.js index fcce8c706dfcc..c7600d7ea1505 100644 --- a/test/integration/basic/test/dynamic.js +++ b/test/integration/basic/test/dynamic.js @@ -1,7 +1,7 @@ /* eslint-env jest */ import webdriver from 'next-webdriver' import cheerio from 'cheerio' -import { waitFor, check } from 'next-test-utils' +import { check } from 'next-test-utils' export default (context, render) => { async function get$(path, query) { @@ -227,76 +227,5 @@ export default (context, render) => { } }) }) - - describe('Import mapping', () => { - it('should render dynamic imports bundle', async () => { - const $ = await get$('/dynamic/bundle') - const bodyText = $('body').text() - expect(/Dynamic Bundle/.test(bodyText)).toBe(true) - expect(/Hello World 1/.test(bodyText)).toBe(true) - expect(/Hello World 2/.test(bodyText)).toBe(false) - }) - - it('should render dynamic imports bundle with additional components', async () => { - const $ = await get$('/dynamic/bundle?showMore=1') - const bodyText = $('body').text() - expect(/Dynamic Bundle/.test(bodyText)).toBe(true) - expect(/Hello World 1/.test(bodyText)).toBe(true) - expect(/Hello World 2/.test(bodyText)).toBe(true) - }) - - it('should render components', async () => { - const browser = await webdriver(context.appPort, '/dynamic/bundle') - - while (true) { - const bodyText = await browser.elementByCss('body').text() - if ( - /Dynamic Bundle/.test(bodyText) && - /Hello World 1/.test(bodyText) && - !/Hello World 2/.test(bodyText) - ) { - break - } - await waitFor(1000) - } - - await browser.close() - }) - - it('should render support React context', async () => { - const browser = await webdriver(context.appPort, '/dynamic/bundle') - - while (true) { - const bodyText = await browser.elementByCss('body').text() - if (/Vercel Rocks/.test(bodyText)) break - await waitFor(1000) - } - - await browser.close() - }) - - it('should load new components and render for prop changes', async () => { - const browser = await webdriver(context.appPort, '/dynamic/bundle') - - await browser - .waitForElementByCss('#toggle-show-more') - .elementByCss('#toggle-show-more') - .click() - - while (true) { - const bodyText = await browser.elementByCss('body').text() - if ( - /Dynamic Bundle/.test(bodyText) && - /Hello World 1/.test(bodyText) && - /Hello World 2/.test(bodyText) - ) { - break - } - await waitFor(1000) - } - - await browser.close() - }) - }) }) } diff --git a/test/integration/build-output/test/index.test.js b/test/integration/build-output/test/index.test.js index ad72cba91446b..8a2571989cb64 100644 --- a/test/integration/build-output/test/index.test.js +++ b/test/integration/build-output/test/index.test.js @@ -123,22 +123,22 @@ describe('Build Output', () => { ) expect(indexSize.endsWith('B')).toBe(true) - expect(parseFloat(indexFirstLoad)).toBeCloseTo(gz ? 63.5 : 195, 1) + expect(parseFloat(indexFirstLoad)).toBeCloseTo(gz ? 63.3 : 194, 1) expect(indexFirstLoad.endsWith('kB')).toBe(true) expect(parseFloat(err404Size)).toBeCloseTo(gz ? 3.06 : 8.15, 1) expect(err404Size.endsWith('kB')).toBe(true) - expect(parseFloat(err404FirstLoad)).toBeCloseTo(gz ? 66.3 : 203, 1) + expect(parseFloat(err404FirstLoad)).toBeCloseTo(gz ? 66.1 : 202, 1) expect(err404FirstLoad.endsWith('kB')).toBe(true) - expect(parseFloat(sharedByAll)).toBeCloseTo(gz ? 63.2 : 194, 1) + expect(parseFloat(sharedByAll)).toBeCloseTo(gz ? 63 : 194, 1) expect(sharedByAll.endsWith('kB')).toBe(true) const appSizeValue = _appSize.endsWith('kB') ? parseFloat(_appSize) : parseFloat(_appSize) / 1000 - expect(appSizeValue).toBeCloseTo(gz ? 1.0 : 2.18, 1) + expect(appSizeValue).toBeCloseTo(gz ? 0.799 : 1.63, 1) expect(_appSize.endsWith('kB') || _appSize.endsWith(' B')).toBe(true) const webpackSizeValue = webpackSize.endsWith('kB') diff --git a/test/integration/client-navigation/pages/nav/shallow-routing.js b/test/integration/client-navigation/pages/nav/shallow-routing.js index 728467f9afde4..5703ae7f0c76a 100644 --- a/test/integration/client-navigation/pages/nav/shallow-routing.js +++ b/test/integration/client-navigation/pages/nav/shallow-routing.js @@ -1,6 +1,6 @@ import { Component } from 'react' import Link from 'next/link' -import Router from 'next/router' +import Router, { withRouter } from 'next/router' let getInitialPropsRunCount = 1 @@ -8,60 +8,62 @@ const linkStyle = { marginRight: 10, } -export default class extends Component { - static getInitialProps({ res }) { - if (res) return { getInitialPropsRunCount: 1 } - getInitialPropsRunCount++ +export default withRouter( + class extends Component { + static getInitialProps({ res }) { + if (res) return { getInitialPropsRunCount: 1 } + getInitialPropsRunCount++ - return { getInitialPropsRunCount } - } + return { getInitialPropsRunCount } + } - getCurrentCounter() { - const { url } = this.props - return url.query.counter ? parseInt(url.query.counter) : 0 - } + getCurrentCounter() { + const { router } = this.props + return router.query.counter ? parseInt(router.query.counter) : 0 + } - increase() { - const counter = this.getCurrentCounter() - const href = `/nav/shallow-routing?counter=${counter + 1}` - Router.push(href, href, { shallow: true }) - } + increase() { + const counter = this.getCurrentCounter() + const href = `/nav/shallow-routing?counter=${counter + 1}` + Router.push(href, href, { shallow: true }) + } - increaseNonShallow() { - const counter = this.getCurrentCounter() - const href = `/nav/shallow-routing?counter=${counter + 1}` - Router.push(href, href, {}) - } + increaseNonShallow() { + const counter = this.getCurrentCounter() + const href = `/nav/shallow-routing?counter=${counter + 1}` + Router.push(href, href, {}) + } - gotoNavShallow() { - const href = `/nav` - Router.push(href, href, { shallow: true }) - } + gotoNavShallow() { + const href = `/nav` + Router.push(href, href, { shallow: true }) + } - render() { - return ( -
- - - Home - - -
- Counter: {this.getCurrentCounter()} -
-
- getInitialProps run count: {this.props.getInitialPropsRunCount} + render() { + return ( +
+ + + Home + + +
+ Counter: {this.getCurrentCounter()} +
+
+ getInitialProps run count: {this.props.getInitialPropsRunCount} +
+ + +
- - - -
- ) + ) + } } -} +) diff --git a/test/integration/client-navigation/pages/nav/url-prop-change.js b/test/integration/client-navigation/pages/nav/url-prop-change.js deleted file mode 100644 index 0b2a1095f70cc..0000000000000 --- a/test/integration/client-navigation/pages/nav/url-prop-change.js +++ /dev/null @@ -1,40 +0,0 @@ -import React from 'react' -import Link from 'next/link' - -export default class UrlPropChange extends React.Component { - constructor(props) { - super(props) - this.state = { - previousUrl: {}, - url: props.url, - } - } - - componentDidUpdate(prevProps) { - if (prevProps.url !== this.props.url) { - this.setState(() => { - return { - previousUrl: prevProps.url, - url: this.props.url, - } - }) - } - } - - render() { - const { previousUrl, url } = this.state - return ( -
- Current: -
{JSON.stringify(url)}
-
-
- Previous: -
{JSON.stringify(previousUrl)}
- - Add querystring - -
- ) - } -} diff --git a/test/integration/client-navigation/pages/url-prop-override.js b/test/integration/client-navigation/pages/url-prop-override.js deleted file mode 100644 index 68d5067c8943c..0000000000000 --- a/test/integration/client-navigation/pages/url-prop-override.js +++ /dev/null @@ -1,18 +0,0 @@ -import React from 'react' -export default class extends React.Component { - static getInitialProps() { - return { - url: 'test', // This gets overridden by Next in lib/_app.js - } - } - render() { - const { url } = this.props - return ( -
-

{url.pathname}

-

{Object.keys(url.query).length}

-

{url.asPath}

-
- ) - } -} diff --git a/test/integration/client-navigation/pages/url-prop.js b/test/integration/client-navigation/pages/url-prop.js deleted file mode 100644 index 465d963d26722..0000000000000 --- a/test/integration/client-navigation/pages/url-prop.js +++ /dev/null @@ -1,13 +0,0 @@ -const Page = ({ url }) => { - return ( -
-

{url.pathname}

-

{Object.keys(url.query).length}

-

{url.asPath}

-
- ) -} - -Page.getInitialProps = () => ({}) - -export default Page diff --git a/test/integration/client-navigation/test/index.test.js b/test/integration/client-navigation/test/index.test.js index 3e73719dd690d..5f666b5a00648 100644 --- a/test/integration/client-navigation/test/index.test.js +++ b/test/integration/client-navigation/test/index.test.js @@ -42,7 +42,6 @@ describe('Client Navigation', () => { '/styled-jsx-external', '/with-cdm', '/url-prop', - '/url-prop-override', '/dynamic/ssr', '/dynamic/[slug]/route', @@ -57,7 +56,6 @@ describe('Client Navigation', () => { '/nav/redirect', '/nav/as-path', '/nav/as-path-using-router', - '/nav/url-prop-change', '/nested-cdm', ] @@ -169,30 +167,6 @@ describe('Client Navigation', () => { }) }) - describe('With url property', () => { - it('Should keep immutable pathname, asPath and query', async () => { - const browser = await webdriver(context.appPort, '/nav/url-prop-change') - await browser.elementByCss('#add-query').click() - const urlResult = await browser.elementByCss('#url-result').text() - const previousUrlResult = await browser - .elementByCss('#previous-url-result') - .text() - - expect(JSON.parse(urlResult)).toMatchObject({ - query: { added: 'yes' }, - pathname: '/nav/url-prop-change', - asPath: '/nav/url-prop-change?added=yes', - }) - expect(JSON.parse(previousUrlResult)).toMatchObject({ - query: {}, - pathname: '/nav/url-prop-change', - asPath: '/nav/url-prop-change', - }) - - await browser.close() - }) - }) - describe('with tag inside the ', () => { it('should navigate the page', async () => { const browser = await webdriver(context.appPort, '/nav/about') diff --git a/test/integration/client-navigation/test/rendering.js b/test/integration/client-navigation/test/rendering.js index a8eb14a3893e9..b991454c2fa09 100644 --- a/test/integration/client-navigation/test/rendering.js +++ b/test/integration/client-navigation/test/rendering.js @@ -209,7 +209,7 @@ export default function (render, fetch, ctx) { }) it('should render the page without `nextExport` property', async () => { - const html = await render('/url-prop') + const html = await render('/async-props') expect(html).not.toContain('"nextExport"') }) @@ -376,22 +376,6 @@ export default function (render, fetch, ctx) { expect($('.as-path-content').text()).toBe('/nav/as-path?aa=10') }) - describe('Url prop', () => { - it('should provide pathname, query and asPath', async () => { - const $ = await get$('/url-prop') - expect($('#pathname').text()).toBe('/url-prop') - expect($('#query').text()).toBe('0') - expect($('#aspath').text()).toBe('/url-prop') - }) - - it('should override props.url, even when getInitialProps returns url as property', async () => { - const $ = await get$('/url-prop-override') - expect($('#pathname').text()).toBe('/url-prop-override') - expect($('#query').text()).toBe('0') - expect($('#aspath').text()).toBe('/url-prop-override') - }) - }) - describe('404', () => { it('should 404 on not existent page', async () => { const $ = await get$('/non-existent') diff --git a/test/integration/image-component/base-path/pages/invalid-unsized.js b/test/integration/image-component/base-path/pages/invalid-unsized.js deleted file mode 100644 index 14d11eb704593..0000000000000 --- a/test/integration/image-component/base-path/pages/invalid-unsized.js +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react' -import Image from 'next/image' - -const Page = () => { - return ( -
-

Invalid Unsized

- -
- ) -} - -export default Page diff --git a/test/integration/image-component/base-path/pages/rotated.js b/test/integration/image-component/base-path/pages/rotated.js index 4aef229df511a..6dbe8f8267836 100644 --- a/test/integration/image-component/base-path/pages/rotated.js +++ b/test/integration/image-component/base-path/pages/rotated.js @@ -5,7 +5,11 @@ const Page = () => { return (

Hello World

- +

This is the rotated page

) diff --git a/test/integration/image-component/base-path/test/index.test.js b/test/integration/image-component/base-path/test/index.test.js index ae956271d969a..0b7142b7a2c3a 100644 --- a/test/integration/image-component/base-path/test/index.test.js +++ b/test/integration/image-component/base-path/test/index.test.js @@ -414,15 +414,6 @@ function runTests(mode) { 'Failed to parse src "//assets.example.com/img.jpg" on `next/image`, protocol-relative URL (//) must be changed to an absolute URL (http:// or https://)' ) }) - - it('should show invalid unsized error', async () => { - const browser = await webdriver(appPort, '/docs/invalid-unsized') - - expect(await hasRedbox(browser)).toBe(true) - expect(await getRedboxHeader(browser)).toContain( - 'Image with src "/docs/test.png" has deprecated "unsized" property, which was removed in favor of the "layout=\'fill\'" property' - ) - }) } it('should correctly ignore prose styles', async () => { @@ -483,7 +474,7 @@ function runTests(mode) { const computedWidth = await getComputed(browser, id, 'width') const computedHeight = await getComputed(browser, id, 'height') - expect(getRatio(computedWidth, computedHeight)).toBeCloseTo(1.333, 1) + expect(getRatio(computedWidth, computedHeight)).toBeCloseTo(0.5625, 1) } finally { if (browser) { await browser.close() diff --git a/test/integration/image-component/default/test/index.test.js b/test/integration/image-component/default/test/index.test.js index 6460efa45ac25..a1b034b36fb7b 100644 --- a/test/integration/image-component/default/test/index.test.js +++ b/test/integration/image-component/default/test/index.test.js @@ -480,15 +480,6 @@ function runTests(mode) { 'Failed to parse src "//assets.example.com/img.jpg" on `next/image`, protocol-relative URL (//) must be changed to an absolute URL (http:// or https://)' ) }) - - it('should show invalid unsized error', async () => { - const browser = await webdriver(appPort, '/invalid-unsized') - - expect(await hasRedbox(browser)).toBe(true) - expect(await getRedboxHeader(browser)).toContain( - 'Image with src "/test.png" has deprecated "unsized" property, which was removed in favor of the "layout=\'fill\'" property' - ) - }) } it('should correctly ignore prose styles', async () => { @@ -549,7 +540,7 @@ function runTests(mode) { const computedWidth = await getComputed(browser, id, 'width') const computedHeight = await getComputed(browser, id, 'height') - expect(getRatio(computedWidth, computedHeight)).toBeCloseTo(1.333, 1) + expect(getRatio(computedWidth, computedHeight)).toBeCloseTo(0.5625, 1) } finally { if (browser) { await browser.close() diff --git a/test/integration/production/pages/dynamic/bundle.js b/test/integration/production/pages/dynamic/bundle.js deleted file mode 100644 index 9a23bd8898cee..0000000000000 --- a/test/integration/production/pages/dynamic/bundle.js +++ /dev/null @@ -1,61 +0,0 @@ -import React from 'react' -import dynamic from 'next/dynamic' -import Router from 'next/router' -import PropTypes from 'prop-types' - -const HelloBundle = dynamic({ - modules: () => { - const components = { - HelloContext: import('../../components/hello-context'), - Hello1: import('../../components/hello1'), - Hello2: import('../../components/hello2'), - } - return components - }, - render: (props, { HelloContext, Hello1, Hello2 }) => ( -
-

{props.title}

- - - {props.showMore ? : null} -
- ), -}) - -export default class Bundle extends React.Component { - static childContextTypes = { - data: PropTypes.object, - } - - static getInitialProps({ query }) { - return { showMore: Boolean(query.showMore) } - } - - getChildContext() { - return { - data: { title: 'Vercel Rocks' }, - } - } - - toggleShowMore() { - if (this.props.showMore) { - Router.push('/dynamic/bundle') - return - } - - Router.push('/dynamic/bundle?showMore=1') - } - - render() { - const { showMore } = this.props - - return ( -
- - -
- ) - } -} diff --git a/test/integration/production/test/dynamic.js b/test/integration/production/test/dynamic.js index db9cb59df5250..d22f147e51e04 100644 --- a/test/integration/production/test/dynamic.js +++ b/test/integration/production/test/dynamic.js @@ -1,7 +1,7 @@ /* eslint-env jest */ import webdriver from 'next-webdriver' import cheerio from 'cheerio' -import { waitFor, check } from 'next-test-utils' +import { check } from 'next-test-utils' // These tests are similar to ../../basic/test/dynamic.js export default (context, render) => { @@ -162,76 +162,5 @@ export default (context, render) => { } }) }) - - describe('Import mapping', () => { - it('should render dynamic imports bundle', async () => { - const $ = await get$('/dynamic/bundle') - const bodyText = $('body').text() - expect(/Dynamic Bundle/.test(bodyText)).toBe(true) - expect(/Hello World 1/.test(bodyText)).toBe(true) - expect(/Hello World 2/.test(bodyText)).toBe(false) - }) - - it('should render dynamic imports bundle with additional components', async () => { - const $ = await get$('/dynamic/bundle?showMore=1') - const bodyText = $('body').text() - expect(/Dynamic Bundle/.test(bodyText)).toBe(true) - expect(/Hello World 1/.test(bodyText)).toBe(true) - expect(/Hello World 2/.test(bodyText)).toBe(true) - }) - - it('should render components', async () => { - const browser = await webdriver(context.appPort, '/dynamic/bundle') - - while (true) { - const bodyText = await browser.elementByCss('body').text() - if ( - /Dynamic Bundle/.test(bodyText) && - /Hello World 1/.test(bodyText) && - !/Hello World 2/.test(bodyText) - ) { - break - } - await waitFor(1000) - } - - await browser.close() - }) - - it('should render support React context', async () => { - const browser = await webdriver(context.appPort, '/dynamic/bundle') - - while (true) { - const bodyText = await browser.elementByCss('body').text() - if (/Vercel Rocks/.test(bodyText)) break - await waitFor(1000) - } - - await browser.close() - }) - - it('should load new components and render for prop changes', async () => { - const browser = await webdriver(context.appPort, '/dynamic/bundle') - - await browser - .waitForElementByCss('#toggle-show-more') - .elementByCss('#toggle-show-more') - .click() - - while (true) { - const bodyText = await browser.elementByCss('body').text() - if ( - /Dynamic Bundle/.test(bodyText) && - /Hello World 1/.test(bodyText) && - /Hello World 2/.test(bodyText) - ) { - break - } - await waitFor(1000) - } - - await browser.close() - }) - }) }) } diff --git a/test/integration/production/test/index.test.js b/test/integration/production/test/index.test.js index 499f27ab80f8e..50a3d892474a1 100644 --- a/test/integration/production/test/index.test.js +++ b/test/integration/production/test/index.test.js @@ -276,11 +276,13 @@ describe('Production Usage', () => { const manifestKey = Object.keys(reactLoadableManifest).find((item) => { return item .replace(/\\/g, '/') - .endsWith('bundle.js -> ../../components/hello1') + .endsWith('dynamic/css.js -> ../../components/dynamic-css/with-css') }) // test dynamic chunk - resources.add(url + reactLoadableManifest[manifestKey].files[0]) + reactLoadableManifest[manifestKey].files.forEach((f) => { + resources.add(url + f) + }) // test main.js runtime etc for (const item of buildManifest.pages['/']) { diff --git a/yarn.lock b/yarn.lock index d295cb4b50068..2657e2392c3a1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1061,6 +1061,13 @@ dependencies: regenerator-runtime "^0.13.4" +"@babel/runtime@^7.11.2": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.0.tgz#46794bc20b612c5f75e62dd071e24dfd95f1cbe6" + integrity sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/template@^7.10.4", "@babel/template@^7.12.7", "@babel/template@^7.3.3": version "7.12.7" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.12.7.tgz#c817233696018e39fbb6c491d2fb684e05ed43bc" @@ -4152,6 +4159,11 @@ assign-symbols@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" +ast-types-flow@^0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" + integrity sha1-9wtzXGvKGlycItmCw+Oef+ujva0= + ast-types@0.11.7: version "0.11.7" resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.11.7.tgz#f318bf44e339db6a320be0009ded64ec1471f46c" @@ -4262,6 +4274,16 @@ aws4@^1.8.0: version "1.9.0" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.0.tgz#24390e6ad61386b0a747265754d2a17219de862c" +axe-core@^4.0.2: + version "4.2.1" + resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.2.1.tgz#2e50bcf10ee5b819014f6e342e41e45096239e34" + integrity sha512-evY7DN8qSIbsW2H/TWQ1bX3sXN1d4MNb5Vb4n7BzPuCwRHdkZ1H2eNLuSh73EoQqkGKUtju2G2HCcjCfhvZIAA== + +axobject-query@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be" + integrity sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA== + babel-code-frame@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" @@ -6182,6 +6204,11 @@ d@1, d@^1.0.1: es5-ext "^0.10.50" type "^1.0.1" +damerau-levenshtein@^1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.7.tgz#64368003512a1a6992593741a09a9d31a836f55d" + integrity sha512-VvdQIPGdWP0SqFXghj79Wf/5LArmreyMsGLa6FG6iC4t3j7j5s71TrwWmT/4akbDQIqjfACkLZmjXhA7g2oUZw== + dargs@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/dargs/-/dargs-7.0.0.tgz#04015c41de0bcb69ec84050f3d9be0caf8d6d5cc" @@ -6663,6 +6690,11 @@ emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" +emoji-regex@^9.0.0: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + emojis-list@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" @@ -6944,6 +6976,23 @@ eslint-plugin-jest@24.3.5: dependencies: "@typescript-eslint/experimental-utils" "^4.0.1" +eslint-plugin-jsx-a11y@^6.4.1: + version "6.4.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.4.1.tgz#a2d84caa49756942f42f1ffab9002436391718fd" + integrity sha512-0rGPJBbwHoGNPU73/QCLP/vveMlM1b1Z9PponxO87jfr6tuH5ligXbDT6nHSSzBC8ovX2Z+BQu7Bk5D/Xgq9zg== + dependencies: + "@babel/runtime" "^7.11.2" + aria-query "^4.2.2" + array-includes "^3.1.1" + ast-types-flow "^0.0.7" + axe-core "^4.0.2" + axobject-query "^2.2.0" + damerau-levenshtein "^1.0.6" + emoji-regex "^9.0.0" + has "^1.0.3" + jsx-ast-utils "^3.1.0" + language-tags "^1.0.5" + eslint-plugin-react-hooks@4.2.0, eslint-plugin-react-hooks@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz#8c229c268d468956334c943bb45fc860280f5556" @@ -10091,7 +10140,7 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" -"jsx-ast-utils@^2.4.1 || ^3.0.0": +"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.1.0: version "3.2.0" resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz#41108d2cec408c3453c1bbe8a4aae9e1e2bd8f82" integrity sha512-EIsmt3O3ljsU6sot/J4E1zDRxfBNrhjyf/OKjlydwgEimQuznlM4Wv7U+ueONJMyEn1WRE0K8dhi3dVAXYT24Q== @@ -10182,6 +10231,18 @@ ky@0.19.1: version "0.19.1" resolved "https://registry.yarnpkg.com/ky/-/ky-0.19.1.tgz#c533884028c83f78167d12905dfecaf6dd760bec" +language-subtag-registry@~0.3.2: + version "0.3.21" + resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz#04ac218bea46f04cb039084602c6da9e788dd45a" + integrity sha512-L0IqwlIXjilBVVYKFT37X9Ih11Um5NEl9cbJIuU/SwP/zEEAbBPOnEeeuxVMf45ydWQRDQN3Nqc96OgbH1K+Pg== + +language-tags@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/language-tags/-/language-tags-1.0.5.tgz#d321dbc4da30ba8bf3024e040fa5c14661f9193a" + integrity sha1-0yHbxNowuovzAk4ED6XBRmH5GTo= + dependencies: + language-subtag-registry "~0.3.2" + last-call-webpack-plugin@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz#9742df0e10e3cf46e5c0381c2de90d3a7a2d7555"