diff --git a/packages/next/shared/lib/dynamic.tsx b/packages/next/shared/lib/dynamic.tsx index ba5871238998580..771e4b5aaa375a3 100644 --- a/packages/next/shared/lib/dynamic.tsx +++ b/packages/next/shared/lib/dynamic.tsx @@ -122,7 +122,6 @@ export default function dynamic

( `Disallowed suspense option usage with next/dynamic in blocking mode` ) } - suspenseOptions.suspense = false } if (suspenseOptions.suspense) { return loadableFn(suspenseOptions) diff --git a/test/integration/react-18/app/pages/suspense/unwrapped.js b/test/integration/react-18/app/pages/suspense/unwrapped.js index 3909e80679a6a9d..93c32bbbc50100b 100644 --- a/test/integration/react-18/app/pages/suspense/unwrapped.js +++ b/test/integration/react-18/app/pages/suspense/unwrapped.js @@ -1,10 +1,19 @@ -import React from 'react' +import React, { Suspense } from 'react' import dynamic from 'next/dynamic' +// flag for testing +const wrapped = true + const Hello = dynamic(() => import('../../components/hello'), { suspense: true, }) export default function Unwrapped() { - return + if (!wrapped) return + + return ( + + + + ) } diff --git a/test/integration/react-18/test/blocking.js b/test/integration/react-18/test/blocking.js index 3adb476c5a018b2..c4feeb2e8a301f6 100644 --- a/test/integration/react-18/test/blocking.js +++ b/test/integration/react-18/test/blocking.js @@ -20,8 +20,6 @@ export default (context, render) => { const $ = await get$('/suspense/thrown') const html = $('body').html() expect(html).toContain('loading') - expect( - JSON.parse($('#__NEXT_DATA__').text()).dynamicIds - ).not.toBeUndefined() + expect(JSON.parse($('#__NEXT_DATA__').text()).dynamicIds).toBeUndefined() }) } diff --git a/test/integration/react-18/test/index.test.js b/test/integration/react-18/test/index.test.js index d0f889adcccd1bc..a63d78b92372c84 100644 --- a/test/integration/react-18/test/index.test.js +++ b/test/integration/react-18/test/index.test.js @@ -23,9 +23,8 @@ 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 unwrappedPage = new File(join(appDir, 'pages/suspense/unwrapped.js')) -const SUSPENSE_ERROR_MESSAGE = - 'Disallowed suspense option usage with next/dynamic' const UNSUPPORTED_PRERELEASE = "You are using an unsupported prerelease of 'react-dom'" const USING_CREATE_ROOT = 'Using the createRoot API for React' @@ -81,12 +80,15 @@ describe('React 18 Support', () => { expect(output).not.toMatch(UNSUPPORTED_PRERELEASE) }) - it('suspense is not allowed in blocking rendering mode', async () => { - const appPort = await findPort() - const app = await launchApp(appDir, appPort) - const html = await renderViaHTTP(appPort, '/suspense/unwrapped') - await killApp(app) - expect(html).toContain(SUSPENSE_ERROR_MESSAGE) + test('suspense is not allowed in blocking rendering mode (prod)', async () => { + const { stderr, code } = await nextBuild(appDir, [], { + nodeArgs, + stderr: true, + }) + expect(code).toBe(1) + expect(stderr).toContain( + 'Disallowed suspense option usage with next/dynamic' + ) }) }) @@ -118,10 +120,21 @@ describe('React 18 Support', () => { }) describe('Basics', () => { - runTests('default setting with react 18', 'dev', (context) => basics(context)) - runTests('default setting with react 18', 'prod', (context) => - basics(context) - ) + runTests('default setting with react 18', (context) => basics(context)) + + it('suspense is not allowed in blocking rendering mode (dev)', async () => { + // set dynamic.suspense = true but not wrapping with + unwrappedPage.replace('wrapped = true', 'wrapped = false') + const appPort = await findPort() + const app = await launchApp(appDir, appPort, { nodeArgs }) + const html = await renderViaHTTP(appPort, '/suspense/unwrapped') + unwrappedPage.restore() + await killApp(app) + // expect(html).toContain('Disallowed suspense option usage with next/dynamic') + expect(html).toContain( + 'A React component suspended while rendering, but no fallback UI was specified' + ) + }) }) describe('Blocking mode', () => { @@ -132,11 +145,7 @@ describe('Blocking mode', () => { dynamicHello.restore() }) - runTests('concurrentFeatures is disabled', 'dev', (context) => - blocking(context, (p, q) => renderViaHTTP(context.appPort, p, q)) - ) - - runTests('concurrentFeatures is disabled', 'prod', (context) => + runTests('concurrentFeatures is disabled', (context) => blocking(context, (p, q) => renderViaHTTP(context.appPort, p, q)) ) }) @@ -156,15 +165,12 @@ describe('Concurrent mode', () => { dynamicHello.restore() }) - runTests('concurrentFeatures is enabled', 'dev', (context) => - concurrent(context, (p, q) => renderViaHTTP(context.appPort, p, q)) - ) - runTests('concurrentFeatures is enabled', 'prod', (context) => + runTests('concurrentFeatures is enabled', (context) => concurrent(context, (p, q) => renderViaHTTP(context.appPort, p, q)) ) }) -function runTests(name, mode, fn) { +function runTest(mode, name, fn) { const context = { appDir } describe(`${name} (${mode})`, () => { beforeAll(async () => { @@ -186,3 +192,8 @@ function runTests(name, mode, fn) { fn(context) }) } + +function runTests(name, fn) { + runTest('dev', name, fn) + runTest('prod', name, fn) +}