From 54875cf3679dea2c1d9c591e2f694d217cc0ca32 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Sat, 26 Mar 2022 10:56:01 +0100 Subject: [PATCH 1/4] clean up react 18 tests --- packages/next/shared/lib/dynamic.tsx | 13 ++- .../react-18-invalid-config/index.test.js | 20 ++++- .../react-18-invalid-config/pages/dynamic.js | 0 .../react-18/app/components/bar.js | 16 ++-- .../app/pages/{_app.js => _app.js.txt} | 0 .../app/pages/suspense/backpressure.js | 28 ------- .../react-18/app/pages/suspense/no-thrown.js | 5 -- .../react-18/app/pages/suspense/thrown.js | 5 -- test/integration/react-18/test/basics.js | 8 -- test/integration/react-18/test/blocking.js | 26 ------ test/integration/react-18/test/concurrent.js | 9 --- test/integration/react-18/test/index.test.js | 79 ------------------- .../react-18/test/streaming-data.js | 16 ++++ .../app/pages/various-exports.server.js | 8 +- 14 files changed, 50 insertions(+), 183 deletions(-) create mode 100644 test/integration/react-18-invalid-config/pages/dynamic.js rename test/integration/react-18/app/pages/{_app.js => _app.js.txt} (100%) delete mode 100644 test/integration/react-18/app/pages/suspense/backpressure.js delete mode 100644 test/integration/react-18/app/pages/suspense/no-thrown.js delete mode 100644 test/integration/react-18/app/pages/suspense/thrown.js delete mode 100644 test/integration/react-18/test/blocking.js create mode 100644 test/integration/react-18/test/streaming-data.js diff --git a/packages/next/shared/lib/dynamic.tsx b/packages/next/shared/lib/dynamic.tsx index bf5bb6ee6245..36879c07d539 100644 --- a/packages/next/shared/lib/dynamic.tsx +++ b/packages/next/shared/lib/dynamic.tsx @@ -117,14 +117,11 @@ export default function dynamic

( const suspenseOptions = loadableOptions as LoadableSuspenseOptions & { loader: Loader

} - if (!process.env.__NEXT_CONCURRENT_FEATURES) { - // Error if react root is not enabled and `suspense` option is set to true - if (!process.env.__NEXT_REACT_ROOT && suspenseOptions.suspense) { - // TODO: add error doc when this feature is stable - throw new Error( - `Invalid suspense option usage in next/dynamic. Read more: https://nextjs.org/docs/messages/invalid-dynamic-suspense` - ) - } + // Error if Fizz rendering is not enabled and `suspense` option is set to true + if (!process.env.__NEXT_CONCURRENT_FEATURES && suspenseOptions.suspense) { + throw new Error( + `Invalid suspense option usage in next/dynamic. Read more: https://nextjs.org/docs/messages/invalid-dynamic-suspense` + ) } if (suspenseOptions.suspense) { return loadableFn(suspenseOptions) diff --git a/test/integration/react-18-invalid-config/index.test.js b/test/integration/react-18-invalid-config/index.test.js index 9372f0f199f4..1739b9341084 100644 --- a/test/integration/react-18-invalid-config/index.test.js +++ b/test/integration/react-18-invalid-config/index.test.js @@ -24,8 +24,10 @@ describe('Invalid react 18 webpack config', () => { '`experimental.runtime` requires `experimental.reactRoot` to be enabled along with React 18.' ) }) +}) - it('should warn user when not using react 18 and `experimental.reactRoot` is enabled', async () => { +describe('React 17 with React 18 config', () => { + beforeAll(() => { const reactDomPackagePah = join(appDir, 'node_modules/react-dom') await fs.mkdirp(reactDomPackagePah) await fs.writeFile( @@ -33,12 +35,26 @@ describe('Invalid react 18 webpack config', () => { JSON.stringify({ name: 'react-dom', version: '17.0.0' }) ) writeNextConfig({ reactRoot: true }) - const { stderr } = await nextBuild(appDir, [], { stderr: true }) + }) + afterAll(() => { await fs.remove(reactDomPackagePah) nextConfig.restore() + }) + it('should warn user when not using react 18 and `experimental.reactRoot` is enabled', async () => { + const { stderr } = await nextBuild(appDir, [], { stderr: true }) expect(stderr).toContain( 'You have to use React 18 to use `experimental.reactRoot`.' ) }) + + test('suspense is not allowed in blocking rendering mode', async () => { + const { stderr, code } = await nextBuild(appDir, [], { + stderr: true, + }) + expect(stderr).toContain( + 'Invalid suspense option usage in next/dynamic. Read more: https://nextjs.org/docs/messages/invalid-dynamic-suspense' + ) + expect(code).toBe(1) + }) }) diff --git a/test/integration/react-18-invalid-config/pages/dynamic.js b/test/integration/react-18-invalid-config/pages/dynamic.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/test/integration/react-18/app/components/bar.js b/test/integration/react-18/app/components/bar.js index 44a8eb0864dc..20b105c45c99 100644 --- a/test/integration/react-18/app/components/bar.js +++ b/test/integration/react-18/app/components/bar.js @@ -1,22 +1,20 @@ import { Suspense } from 'react' import dynamic from 'next/dynamic' -import { useCachedPromise } from './promise-cache' +import { createStreamingData } from '../../test/streaming-data' const Foo = dynamic(() => import('./foo'), { suspense: true, }) -export default function Bar() { - useCachedPromise( - 'bar', - () => new Promise((resolve) => setTimeout(resolve, 300)), - true - ) +const Data = createStreamingData('bar') +export default function Bar() { return (

- bar - + + + +
diff --git a/test/integration/react-18/app/pages/_app.js b/test/integration/react-18/app/pages/_app.js.txt similarity index 100% rename from test/integration/react-18/app/pages/_app.js rename to test/integration/react-18/app/pages/_app.js.txt diff --git a/test/integration/react-18/app/pages/suspense/backpressure.js b/test/integration/react-18/app/pages/suspense/backpressure.js deleted file mode 100644 index 3c7218950e58..000000000000 --- a/test/integration/react-18/app/pages/suspense/backpressure.js +++ /dev/null @@ -1,28 +0,0 @@ -import React from 'react' -import { useCachedPromise } from '../../components/promise-cache' - -export default function Backpressure() { - const elements = [] - for (let i = 0; i < 2000; i++) { - elements.push( - loading...}> - - - ) - } - return {elements} -} - -function Item({ idx }) { - const key = idx.toString() - if (typeof window === 'undefined') { - // eslint-disable-next-line react-hooks/rules-of-hooks - useCachedPromise(key, () => Promise.resolve(), true) - } - return {key} -} - -// Disable offline build -export function getServerSideProps() { - return { props: {} } -} diff --git a/test/integration/react-18/app/pages/suspense/no-thrown.js b/test/integration/react-18/app/pages/suspense/no-thrown.js deleted file mode 100644 index 123ab2d39b0f..000000000000 --- a/test/integration/react-18/app/pages/suspense/no-thrown.js +++ /dev/null @@ -1,5 +0,0 @@ -import DynamicHello from '../../components/dynamic-hello' - -export default function NoThrown() { - return -} diff --git a/test/integration/react-18/app/pages/suspense/thrown.js b/test/integration/react-18/app/pages/suspense/thrown.js deleted file mode 100644 index 3f8d40a49ac4..000000000000 --- a/test/integration/react-18/app/pages/suspense/thrown.js +++ /dev/null @@ -1,5 +0,0 @@ -import DynamicHello from '../../components/dynamic-hello' - -export default function Thrown() { - return -} diff --git a/test/integration/react-18/test/basics.js b/test/integration/react-18/test/basics.js index bc63d2ad4f0f..49caa0fffbb8 100644 --- a/test/integration/react-18/test/basics.js +++ b/test/integration/react-18/test/basics.js @@ -17,14 +17,6 @@ export default (context) => { expect(await browser.elementById('react-dom-version').text()).toMatch(/18/) }) - it('should works with suspense in ssg', async () => { - const res1 = await fetchViaHTTP(context.appPort, '/suspense/thrown') - const res2 = await fetchViaHTTP(context.appPort, '/suspense/no-thrown') - - expect(res1.status).toBe(200) - expect(res2.status).toBe(200) - }) - it('should render fallback without preloads on server side', async () => { const html = await renderViaHTTP(context.appPort, '/suspense/no-preload') const $ = cheerio.load(html) diff --git a/test/integration/react-18/test/blocking.js b/test/integration/react-18/test/blocking.js deleted file mode 100644 index 0db4aacd6cf9..000000000000 --- a/test/integration/react-18/test/blocking.js +++ /dev/null @@ -1,26 +0,0 @@ -/* eslint-env jest */ - -import cheerio from 'cheerio' - -export default (context, render) => { - async function get$(path, query) { - const html = await render(path, query) - return cheerio.load(html) - } - - it('should render fallback on server side if suspense without ssr', async () => { - const $ = await get$('/suspense/no-preload') - const nextData = JSON.parse($('#__NEXT_DATA__').text()) - const content = $('#__next').text() - expect(content).toBe('fallback') - expect(nextData.dynamicIds).toBeUndefined() - }) - - // Testing the same thing as above. - it.skip('should render import fallback on server side if suspended without ssr', async () => { - const $ = await get$('/suspense/thrown') - const html = $('body').html() - expect(html).toContain('loading') - expect(JSON.parse($('#__NEXT_DATA__').text()).dynamicIds).toBeUndefined() - }) -} diff --git a/test/integration/react-18/test/concurrent.js b/test/integration/react-18/test/concurrent.js index 15eb424b16be..a49bcd4d5e98 100644 --- a/test/integration/react-18/test/concurrent.js +++ b/test/integration/react-18/test/concurrent.js @@ -62,15 +62,6 @@ export default (context, _render) => { }) }) - it('should drain the entire response', async () => { - await withBrowser('/suspense/backpressure', async (browser) => { - await check( - () => browser.eval('document.querySelectorAll(".item").length'), - /2000/ - ) - }) - }) - it('throws if useFlushEffects is used more than once', async () => { await renderViaHTTP(context.appPort, '/use-flush-effect/multiple-calls') expect(context.stderr).toContain( diff --git a/test/integration/react-18/test/index.test.js b/test/integration/react-18/test/index.test.js index 37e0fbe5263a..a73fe010d53f 100644 --- a/test/integration/react-18/test/index.test.js +++ b/test/integration/react-18/test/index.test.js @@ -13,7 +13,6 @@ import { hasRedbox, getRedboxHeader, } from 'next-test-utils' -import blocking from './blocking' import concurrent from './concurrent' import basics from './basics' import strictMode from './strict-mode' @@ -26,71 +25,6 @@ const nextConfig = new File(join(appDir, 'next.config.js')) const dynamicHello = new File(join(appDir, 'components/dynamic-hello.js')) const invalidPage = new File(join(appDir, 'pages/invalid.js')) -const USING_CREATE_ROOT = 'Using the createRoot API for React' - -async function getBuildOutput(dir) { - const { stdout, stderr } = await nextBuild(dir, [], { - stdout: true, - stderr: true, - nodeArgs, - }) - return stdout + stderr -} - -async function getDevOutput(dir) { - const port = await findPort() - - let stdout = '' - let stderr = '' - let instance = await launchApp(dir, port, { - stdout: true, - stderr: true, - onStdout(msg) { - stdout += msg - }, - onStderr(msg) { - stderr += msg - }, - nodeArgs, - }) - await killApp(instance) - return stdout + stderr -} - -describe('React 18 Support', () => { - describe('Use legacy render', () => { - beforeAll(() => { - nextConfig.replace('reactRoot: true', 'reactRoot: false') - }) - afterAll(() => { - nextConfig.restore() - }) - - test('supported version of react in dev', async () => { - const output = await getDevOutput(appDir) - expect(output).not.toMatch(USING_CREATE_ROOT) - }) - - test('supported version of react in build', async () => { - const output = await getBuildOutput(appDir) - expect(output).not.toMatch(USING_CREATE_ROOT) - }) - - test('suspense is not allowed in blocking rendering mode', async () => { - nextConfig.replace('withReact18({', '/*withReact18*/({') - const { stderr, code } = await nextBuild(appDir, [], { - stderr: true, - }) - nextConfig.replace('/*withReact18*/({', 'withReact18({') - - expect(stderr).toContain( - 'Invalid suspense option usage in next/dynamic. Read more: https://nextjs.org/docs/messages/invalid-dynamic-suspense' - ) - expect(code).toBe(1) - }) - }) -}) - describe('Basics', () => { runTests('default setting with react 18', (context) => basics(context)) }) @@ -115,19 +49,6 @@ describe('Strict mode - dev', () => { strictMode(context) }) -describe('Blocking mode', () => { - beforeAll(() => { - dynamicHello.replace('suspense = false', `suspense = true`) - }) - afterAll(() => { - dynamicHello.restore() - }) - - runTests('`runtime` is disabled', (context) => { - blocking(context, (p, q) => renderViaHTTP(context.appPort, p, q)) - }) -}) - function runTestsAgainstRuntime(runtime) { runTests( `Concurrent mode in the ${runtime} runtime`, diff --git a/test/integration/react-18/test/streaming-data.js b/test/integration/react-18/test/streaming-data.js new file mode 100644 index 000000000000..476170e90cbe --- /dev/null +++ b/test/integration/react-18/test/streaming-data.js @@ -0,0 +1,16 @@ +export function createStreamingData(value) { + let result + let promise + function Data() { + if (result) return result + if (!promise) + promise = new Promise((res) => { + setTimeout(() => { + result = value + res() + }, 500) + }) + throw promise + } + return Data +} diff --git a/test/integration/react-streaming-and-server-components/app/pages/various-exports.server.js b/test/integration/react-streaming-and-server-components/app/pages/various-exports.server.js index 5a9b4ce9acb5..7d8a12fe2968 100644 --- a/test/integration/react-streaming-and-server-components/app/pages/various-exports.server.js +++ b/test/integration/react-streaming-and-server-components/app/pages/various-exports.server.js @@ -23,12 +23,12 @@ export default function Page() {
- +
- - +
+
- +
) } From f39dd8cd468cdb5d461fe9fcd373720dac44008f Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Sat, 26 Mar 2022 11:34:39 +0100 Subject: [PATCH 2/4] test: clean up legacy tests --- .../react-18/app/components/bar.js | 22 -------- .../react-18/app/components/dynamic-hello.js | 18 ------- .../react-18/app/components/foo.js | 3 -- .../react-18/app/components/hello.js | 37 -------------- .../react-18/app/components/promise-cache.js | 37 -------------- .../react-18/app/components/red.js | 21 -------- .../react-18/app/components/red.tsx | 21 ++++++++ .../react-18/app/components/ts-foo.tsx | 3 -- .../react-18/app/pages/_app.js.txt | 11 ---- test/integration/react-18/app/pages/ssr.js | 8 --- .../react-18/app/pages/suspense/no-preload.js | 22 -------- .../react-18/app/pages/suspense/typing.tsx | 14 ------ .../{styled-jsx.js => styled-jsx.tsx} | 2 + test/integration/react-18/test/basics.js | 12 +---- test/integration/react-18/test/concurrent.js | 50 +------------------ test/integration/react-18/test/index.test.js | 5 -- .../react-18/test/streaming-data.js | 8 +-- .../app/components/bar.client.js | 3 ++ .../app/pages/dynamic-imports.js | 7 ++- .../app/pages/index.server.js | 4 -- .../test/basic.js | 4 +- .../test/rsc.js | 1 - 22 files changed, 42 insertions(+), 271 deletions(-) delete mode 100644 test/integration/react-18/app/components/bar.js delete mode 100644 test/integration/react-18/app/components/dynamic-hello.js delete mode 100644 test/integration/react-18/app/components/foo.js delete mode 100644 test/integration/react-18/app/components/hello.js delete mode 100644 test/integration/react-18/app/components/promise-cache.js delete mode 100644 test/integration/react-18/app/components/red.js create mode 100644 test/integration/react-18/app/components/red.tsx delete mode 100644 test/integration/react-18/app/components/ts-foo.tsx delete mode 100644 test/integration/react-18/app/pages/_app.js.txt delete mode 100644 test/integration/react-18/app/pages/ssr.js delete mode 100644 test/integration/react-18/app/pages/suspense/no-preload.js delete mode 100644 test/integration/react-18/app/pages/suspense/typing.tsx rename test/integration/react-18/app/pages/use-flush-effect/{styled-jsx.js => styled-jsx.tsx} (87%) create mode 100644 test/integration/react-streaming-and-server-components/app/components/bar.client.js diff --git a/test/integration/react-18/app/components/bar.js b/test/integration/react-18/app/components/bar.js deleted file mode 100644 index 20b105c45c99..000000000000 --- a/test/integration/react-18/app/components/bar.js +++ /dev/null @@ -1,22 +0,0 @@ -import { Suspense } from 'react' -import dynamic from 'next/dynamic' -import { createStreamingData } from '../../test/streaming-data' - -const Foo = dynamic(() => import('./foo'), { - suspense: true, -}) - -const Data = createStreamingData('bar') - -export default function Bar() { - return ( -
- - - - - - -
- ) -} diff --git a/test/integration/react-18/app/components/dynamic-hello.js b/test/integration/react-18/app/components/dynamic-hello.js deleted file mode 100644 index 61d0ecaea9b8..000000000000 --- a/test/integration/react-18/app/components/dynamic-hello.js +++ /dev/null @@ -1,18 +0,0 @@ -import { Suspense } from 'react' -import dynamic from 'next/dynamic' - -let ssr -const suspense = false - -const Hello = dynamic(() => import('./hello'), { - ssr, - suspense, -}) - -export default function DynamicHello(props) { - return ( - - - - ) -} diff --git a/test/integration/react-18/app/components/foo.js b/test/integration/react-18/app/components/foo.js deleted file mode 100644 index 3689dc33e306..000000000000 --- a/test/integration/react-18/app/components/foo.js +++ /dev/null @@ -1,3 +0,0 @@ -export default function Foo() { - return 'foo' -} diff --git a/test/integration/react-18/app/components/hello.js b/test/integration/react-18/app/components/hello.js deleted file mode 100644 index 2812405370b7..000000000000 --- a/test/integration/react-18/app/components/hello.js +++ /dev/null @@ -1,37 +0,0 @@ -import React from 'react' -import ReactDOM from 'react-dom' -import { useCachedPromise } from './promise-cache' - -export default function Hello({ name, thrown = false }) { - useCachedPromise( - name, - () => new Promise((resolve) => setTimeout(resolve, 200)), - thrown - ) - - const [hydrated, setHydrated] = React.useState(() => false) - React.useEffect(() => { - if (!hydrated) { - setHydrated(true) - } - }, [hydrated]) - - const serverRendered = React.useMemo(() => { - if (typeof window === 'undefined') { - return true - } - const elem = document.getElementById('server-rendered') - if (elem) { - return elem.innerText === 'true' - } - return false - }, []) - - return ( -

- hello {ReactDOM.version} - {serverRendered.toString()} - {hydrated ? {hydrated.toString()} : null} -

- ) -} diff --git a/test/integration/react-18/app/components/promise-cache.js b/test/integration/react-18/app/components/promise-cache.js deleted file mode 100644 index eab490fb9ae9..000000000000 --- a/test/integration/react-18/app/components/promise-cache.js +++ /dev/null @@ -1,37 +0,0 @@ -import React from 'react' - -const PromiseCacheContext = React.createContext(null) - -export const cache = new Map() -export const PromiseCacheProvider = PromiseCacheContext.Provider - -export function useCachedPromise(key, fn, thrown = false) { - const cache = React.useContext(PromiseCacheContext) - - if (!thrown) return undefined - let entry = cache.get(key) - if (!entry) { - entry = { - status: 'PENDING', - value: fn().then( - (value) => { - cache.set(key, { - status: 'RESOLVED', - value, - }) - }, - (err) => { - cache.set(key, { - status: 'REJECTED', - value: err, - }) - } - ), - } - cache.set(key, entry) - } - if (['PENDING', 'REJECTED'].includes(entry.status)) { - throw entry.value - } - return entry.value -} diff --git a/test/integration/react-18/app/components/red.js b/test/integration/react-18/app/components/red.js deleted file mode 100644 index 8f92c5ccc52d..000000000000 --- a/test/integration/react-18/app/components/red.js +++ /dev/null @@ -1,21 +0,0 @@ -import React from 'react' -import { useCachedPromise } from './promise-cache' - -export default function Styled({ name }) { - useCachedPromise( - name, - () => new Promise((resolve) => setTimeout(resolve, 1000)), - true - ) - - return ( -
-

This is Red.

- -
- ) -} diff --git a/test/integration/react-18/app/components/red.tsx b/test/integration/react-18/app/components/red.tsx new file mode 100644 index 000000000000..3da9eaccfef4 --- /dev/null +++ b/test/integration/react-18/app/components/red.tsx @@ -0,0 +1,21 @@ +import React, { Suspense } from 'react' +import { createStreamingData } from '../../test/streaming-data' + +const Data = createStreamingData() + +export default function Styled() { + return ( + + +
+

This is Red.

+ +
+
+
+ ) +} diff --git a/test/integration/react-18/app/components/ts-foo.tsx b/test/integration/react-18/app/components/ts-foo.tsx deleted file mode 100644 index f29172cb4aa5..000000000000 --- a/test/integration/react-18/app/components/ts-foo.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export default function TsFoo() { - return
ts-foo
-} diff --git a/test/integration/react-18/app/pages/_app.js.txt b/test/integration/react-18/app/pages/_app.js.txt deleted file mode 100644 index 1f136e7e8a8d..000000000000 --- a/test/integration/react-18/app/pages/_app.js.txt +++ /dev/null @@ -1,11 +0,0 @@ -import { PromiseCacheProvider } from '../components/promise-cache' - -function MyApp({ Component, pageProps }) { - return ( - - - - ) -} - -export default MyApp diff --git a/test/integration/react-18/app/pages/ssr.js b/test/integration/react-18/app/pages/ssr.js deleted file mode 100644 index 456cff7cb48e..000000000000 --- a/test/integration/react-18/app/pages/ssr.js +++ /dev/null @@ -1,8 +0,0 @@ -export default function SSR() { - return 'hello' -} - -export function getServerSideProps() { - // Prevent static optimization - return { props: {} } -} diff --git a/test/integration/react-18/app/pages/suspense/no-preload.js b/test/integration/react-18/app/pages/suspense/no-preload.js deleted file mode 100644 index 8ae8c7c599f2..000000000000 --- a/test/integration/react-18/app/pages/suspense/no-preload.js +++ /dev/null @@ -1,22 +0,0 @@ -import { Suspense } from 'react' -import dynamic from 'next/dynamic' - -const Bar = dynamic(() => import('../../components/bar'), { - ssr: false, - suspense: true, - // Explicitly declare loaded modules. - // For suspense cases, they'll be ignored. - // For loadable component cases, they'll be handled - loadableGenerated: { - modules: ['../../components/bar'], - webpack: [require.resolveWeak('../../components/bar')], - }, -}) - -export default function NoPreload() { - return ( - - - - ) -} diff --git a/test/integration/react-18/app/pages/suspense/typing.tsx b/test/integration/react-18/app/pages/suspense/typing.tsx deleted file mode 100644 index 5b5df73d7366..000000000000 --- a/test/integration/react-18/app/pages/suspense/typing.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import React, { Suspense } from 'react' -import dynamic from 'next/dynamic' - -const DynamicFoo = dynamic(() => import('../../components/ts-foo'), { - suspense: true, -}) - -export default function Typing() { - return ( - - - - ) -} diff --git a/test/integration/react-18/app/pages/use-flush-effect/styled-jsx.js b/test/integration/react-18/app/pages/use-flush-effect/styled-jsx.tsx similarity index 87% rename from test/integration/react-18/app/pages/use-flush-effect/styled-jsx.js rename to test/integration/react-18/app/pages/use-flush-effect/styled-jsx.tsx index 27105d3f9c3a..039f554337c3 100644 --- a/test/integration/react-18/app/pages/use-flush-effect/styled-jsx.js +++ b/test/integration/react-18/app/pages/use-flush-effect/styled-jsx.tsx @@ -1,3 +1,5 @@ +// use tsx to cover typescript usage of next/dynamic + suspense: true + import React from 'react' import dynamic from 'next/dynamic' diff --git a/test/integration/react-18/test/basics.js b/test/integration/react-18/test/basics.js index 49caa0fffbb8..051b6d4d2d5d 100644 --- a/test/integration/react-18/test/basics.js +++ b/test/integration/react-18/test/basics.js @@ -2,7 +2,7 @@ import webdriver from 'next-webdriver' import cheerio from 'cheerio' -import { fetchViaHTTP, renderViaHTTP } from 'next-test-utils' +import { renderViaHTTP } from 'next-test-utils' export default (context) => { it('no warnings for image related link props', async () => { @@ -17,16 +17,6 @@ export default (context) => { expect(await browser.elementById('react-dom-version').text()).toMatch(/18/) }) - it('should render fallback without preloads on server side', async () => { - const html = await renderViaHTTP(context.appPort, '/suspense/no-preload') - const $ = cheerio.load(html) - const nextData = JSON.parse($('#__NEXT_DATA__').text()) - const content = $('#__next').text() - // is suspended - expect(content).toBe('fallback') - expect(nextData.dynamicIds).toBeUndefined() - }) - it('useId() values should match on hydration', async () => { const html = await renderViaHTTP(context.appPort, '/use-id') const $ = cheerio.load(html) diff --git a/test/integration/react-18/test/concurrent.js b/test/integration/react-18/test/concurrent.js index a49bcd4d5e98..92871dbab3b8 100644 --- a/test/integration/react-18/test/concurrent.js +++ b/test/integration/react-18/test/concurrent.js @@ -7,7 +7,7 @@ export default (context, _render) => { async function withBrowser(path, cb) { let browser try { - browser = await webdriver(context.appPort, path, false) + browser = await webdriver(context.appPort, path) await cb(browser) } finally { if (browser) { @@ -16,52 +16,6 @@ export default (context, _render) => { } } - it('should resolve suspense modules on server side if suspense', async () => { - await withBrowser('/suspense/no-preload', async (browser) => { - await check(() => browser.waitForElementByCss('#__next').text(), /barfoo/) - await check( - () => browser.eval('typeof __NEXT_DATA__.dynamicIds'), - /undefined/ - ) - }) - }) - - it('should resolve suspense on server side if not suspended on server', async () => { - await withBrowser('/suspense/no-thrown', async (browser) => { - await check( - () => browser.waitForElementByCss('#server-rendered').text(), - /true/ - ) - await check( - () => browser.eval('typeof __NEXT_DATA__.dynamicIds'), - /undefined/ - ) - }) - }) - - it('should resolve suspense on server side if suspended on server', async () => { - await withBrowser('/suspense/thrown', async (browser) => { - await check( - () => browser.waitForElementByCss('#server-rendered').text(), - /true/ - ) - await check( - () => browser.eval('typeof __NEXT_DATA__.dynamicIds'), - /undefined/ - ) - }) - }) - - it('should hydrate suspenses on client side if suspended on server', async () => { - await withBrowser('/suspense/thrown', async (browser) => { - await check(() => browser.waitForElementByCss('#hydrated').text(), /true/) - await check( - () => browser.eval('typeof __NEXT_DATA__.dynamicIds'), - /undefined/ - ) - }) - }) - it('throws if useFlushEffects is used more than once', async () => { await renderViaHTTP(context.appPort, '/use-flush-effect/multiple-calls') expect(context.stderr).toContain( @@ -85,7 +39,7 @@ export default (context, _render) => { /blue/ ) await check( - () => browser.waitForElementByCss('#__jsx-c74678abd3b78a').text(), + () => browser.waitForElementByCss('#__jsx-8b0811664c4e575e').text(), /red/ ) }) diff --git a/test/integration/react-18/test/index.test.js b/test/integration/react-18/test/index.test.js index a73fe010d53f..168c815bc5b4 100644 --- a/test/integration/react-18/test/index.test.js +++ b/test/integration/react-18/test/index.test.js @@ -22,7 +22,6 @@ import webdriver from 'next-webdriver' const nodeArgs = ['-r', join(__dirname, 'require-hook.js')] const appDir = join(__dirname, '../app') const nextConfig = new File(join(appDir, 'next.config.js')) -const dynamicHello = new File(join(appDir, 'components/dynamic-hello.js')) const invalidPage = new File(join(appDir, 'pages/invalid.js')) describe('Basics', () => { @@ -72,16 +71,12 @@ function runTestsAgainstRuntime(runtime) { invalidPage.write(`export const value = 1`) } nextConfig.replace("// runtime: 'edge'", `runtime: '${runtime}'`) - dynamicHello.replace('suspense = false', `suspense = true`) - // `noSSR` mode will be ignored by suspense - dynamicHello.replace('let ssr', `let ssr = false`) }, afterAll: (env) => { if (env === 'dev') { invalidPage.delete() } nextConfig.restore() - dynamicHello.restore() }, } ) diff --git a/test/integration/react-18/test/streaming-data.js b/test/integration/react-18/test/streaming-data.js index 476170e90cbe..7940347c3949 100644 --- a/test/integration/react-18/test/streaming-data.js +++ b/test/integration/react-18/test/streaming-data.js @@ -1,14 +1,14 @@ -export function createStreamingData(value) { +export function createStreamingData() { let result let promise - function Data() { + function Data({ children, duration = 500 }) { if (result) return result if (!promise) promise = new Promise((res) => { setTimeout(() => { - result = value + result = children res() - }, 500) + }, duration) }) throw promise } diff --git a/test/integration/react-streaming-and-server-components/app/components/bar.client.js b/test/integration/react-streaming-and-server-components/app/components/bar.client.js new file mode 100644 index 000000000000..b58488a9c3b5 --- /dev/null +++ b/test/integration/react-streaming-and-server-components/app/components/bar.client.js @@ -0,0 +1,3 @@ +export default function bar() { + return 'bar.client' +} diff --git a/test/integration/react-streaming-and-server-components/app/pages/dynamic-imports.js b/test/integration/react-streaming-and-server-components/app/pages/dynamic-imports.js index 60e8bf7fe0c1..2b3c34f65a80 100644 --- a/test/integration/react-streaming-and-server-components/app/pages/dynamic-imports.js +++ b/test/integration/react-streaming-and-server-components/app/pages/dynamic-imports.js @@ -1,12 +1,17 @@ import { lazy, Suspense } from 'react' +import dynamic from 'next/dynamic' const Foo = lazy(() => import('../components/foo.client')) +const Bar = dynamic(() => import('../components/bar.client'), { + suspense: true, +}) export default function Page() { return (
- + +
) diff --git a/test/integration/react-streaming-and-server-components/app/pages/index.server.js b/test/integration/react-streaming-and-server-components/app/pages/index.server.js index 4bbf05c55236..7ca7e5e30855 100644 --- a/test/integration/react-streaming-and-server-components/app/pages/index.server.js +++ b/test/integration/react-streaming-and-server-components/app/pages/index.server.js @@ -1,4 +1,3 @@ -import Foo from '../components/foo.client' import Nav from '../components/nav.server' const envVar = process.env.ENV_VAR_TEST @@ -11,9 +10,6 @@ export default function Index({ header, router }) {
{'path:' + router.pathname}
{'env:' + envVar}
{'header:' + header}
-
- -