From 4dfd98f29bd20073316ed569bc182497f0192216 Mon Sep 17 00:00:00 2001 From: eps1lon Date: Tue, 30 Apr 2024 12:59:20 +0200 Subject: [PATCH] Inline tests for integration/react-18 Adds indirection when trying to find a failing test or focusing on one. --- test/integration/react-18/test/basics.js | 55 ------- test/integration/react-18/test/concurrent.js | 38 ----- test/integration/react-18/test/index.test.js | 50 ------ test/integration/react-18/test/strict-mode.js | 16 -- .../app/components/foo.js | 0 .../app/components/red.tsx | 2 +- .../app/components}/streaming-data.js | 0 .../app/next.config.js | 0 .../app/package.json | 0 .../app/pages/dynamic-suspense.js | 0 .../app/pages/dynamic.js | 0 .../app/pages/index.js | 0 .../app/pages/use-flush-effect/styled-jsx.tsx | 0 .../app/pages/use-id.js | 0 .../app/tsconfig.json | 0 .../react-current-version/test/index.test.js | 147 ++++++++++++++++++ .../react-current-version/tsconfig.json | 24 +++ 17 files changed, 172 insertions(+), 160 deletions(-) delete mode 100644 test/integration/react-18/test/basics.js delete mode 100644 test/integration/react-18/test/concurrent.js delete mode 100644 test/integration/react-18/test/index.test.js delete mode 100644 test/integration/react-18/test/strict-mode.js rename test/integration/{react-18 => react-current-version}/app/components/foo.js (100%) rename test/integration/{react-18 => react-current-version}/app/components/red.tsx (85%) rename test/integration/{react-18/test => react-current-version/app/components}/streaming-data.js (100%) rename test/integration/{react-18 => react-current-version}/app/next.config.js (100%) rename test/integration/{react-18 => react-current-version}/app/package.json (100%) rename test/integration/{react-18 => react-current-version}/app/pages/dynamic-suspense.js (100%) rename test/integration/{react-18 => react-current-version}/app/pages/dynamic.js (100%) rename test/integration/{react-18 => react-current-version}/app/pages/index.js (100%) rename test/integration/{react-18 => react-current-version}/app/pages/use-flush-effect/styled-jsx.tsx (100%) rename test/integration/{react-18 => react-current-version}/app/pages/use-id.js (100%) rename test/integration/{react-18 => react-current-version}/app/tsconfig.json (100%) create mode 100644 test/integration/react-current-version/test/index.test.js create mode 100644 test/integration/react-current-version/tsconfig.json diff --git a/test/integration/react-18/test/basics.js b/test/integration/react-18/test/basics.js deleted file mode 100644 index 601ccef626349..0000000000000 --- a/test/integration/react-18/test/basics.js +++ /dev/null @@ -1,55 +0,0 @@ -/* eslint-env jest */ - -import webdriver from 'next-webdriver' -import cheerio from 'cheerio' -import { renderViaHTTP } from 'next-test-utils' - -export default (context, env) => { - it('should only render once in SSR', async () => { - await renderViaHTTP(context.appPort, '/') - expect([...context.stdout.matchAll(/__render__/g)].length).toBe(1) - }) - - it('no warnings for image related link props', async () => { - await renderViaHTTP(context.appPort, '/') - expect(context.stderr).not.toContain('Warning: Invalid DOM property') - expect(context.stderr).not.toContain('Warning: React does not recognize') - }) - - it('hydrates correctly for normal page', async () => { - const browser = await webdriver(context.appPort, '/') - expect(await browser.eval('window.didHydrate')).toBe(true) - expect(await browser.elementById('react-dom-version').text()).toMatch(/18/) - }) - - it('useId() values should match on hydration', async () => { - const html = await renderViaHTTP(context.appPort, '/use-id') - const $ = cheerio.load(html) - const ssrId = $('#id').text() - - const browser = await webdriver(context.appPort, '/use-id') - const csrId = await browser.eval('document.getElementById("id").innerText') - - expect(ssrId).toEqual(csrId) - }) - - it('should contain dynamicIds in next data for dynamic imports', async () => { - async function expectToContainPreload(page) { - const html = await renderViaHTTP(context.appPort, `/${page}`) - const $ = cheerio.load(html) - const { dynamicIds } = JSON.parse($('#__NEXT_DATA__').html()) - - if (env === 'dev') { - expect( - dynamicIds.find((id) => - id.includes(`pages/${page}.js -> ../components/foo`) - ) - ).toBeTruthy() - } else { - expect(dynamicIds.length).toBe(1) - } - } - await expectToContainPreload('dynamic') - await expectToContainPreload('dynamic-suspense') - }) -} diff --git a/test/integration/react-18/test/concurrent.js b/test/integration/react-18/test/concurrent.js deleted file mode 100644 index 04156020a4cdc..0000000000000 --- a/test/integration/react-18/test/concurrent.js +++ /dev/null @@ -1,38 +0,0 @@ -/* eslint-env jest */ - -import webdriver from 'next-webdriver' -import { check, renderViaHTTP } from 'next-test-utils' - -export default (context, _render) => { - async function withBrowser(path, cb) { - let browser - try { - browser = await webdriver(context.appPort, path) - await cb(browser) - } finally { - if (browser) { - await browser.close() - } - } - } - - it('flushes styled-jsx styles as the page renders', async () => { - const html = await renderViaHTTP( - context.appPort, - '/use-flush-effect/styled-jsx' - ) - const stylesOccurrence = html.match(/color:(\s)*(?:blue|#00f)/g) || [] - expect(stylesOccurrence.length).toBe(1) - - await withBrowser('/use-flush-effect/styled-jsx', async (browser) => { - await check( - () => browser.waitForElementByCss('#__jsx-900f996af369fc74').text(), - /(?:blue|#00f)/ - ) - await check( - () => 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 deleted file mode 100644 index da32192bc02c5..0000000000000 --- a/test/integration/react-18/test/index.test.js +++ /dev/null @@ -1,50 +0,0 @@ -/* eslint-env jest */ - -import { join } from 'path' - -import { File, renderViaHTTP, runDevSuite, runProdSuite } from 'next-test-utils' -import concurrent from './concurrent' -import basics from './basics' -import strictMode from './strict-mode' - -const appDir = join(__dirname, '../app') -const indexPage = new File(join(appDir, 'pages/index.js')) - -describe('Basics', () => { - runTests('default setting with react 18', basics) -}) - -function runTestsAgainstRuntime(runtime) { - runTests( - `Concurrent mode in the ${runtime} runtime`, - (context, env) => { - concurrent(context, (p, q) => renderViaHTTP(context.appPort, p, q)) - strictMode(context) - - it('should not have invalid config warning', async () => { - await renderViaHTTP(context.appPort, '/') - expect(context.stderr).not.toContain('not exist in this version') - }) - }, - { - beforeAll: (env) => { - indexPage.replace( - "// runtime: 'experimental-edge'", - `runtime: '${runtime}'` - ) - }, - afterAll: (env) => { - indexPage.restore() - }, - } - ) -} - -runTestsAgainstRuntime('experimental-edge') -runTestsAgainstRuntime('nodejs') - -function runTests(name, fn, opts) { - const suiteOptions = { ...opts, runTests: fn } - runDevSuite(name, appDir, suiteOptions) - runProdSuite(name, appDir, suiteOptions) -} diff --git a/test/integration/react-18/test/strict-mode.js b/test/integration/react-18/test/strict-mode.js deleted file mode 100644 index fc305ec469fdc..0000000000000 --- a/test/integration/react-18/test/strict-mode.js +++ /dev/null @@ -1,16 +0,0 @@ -/* eslint-env jest */ - -import webdriver from 'next-webdriver' - -export default (context) => { - describe('', () => { - it('should not have the initial route announced', async () => { - const browser = await webdriver(context.appPort, '/') - const title = await browser - .waitForElementByCss('#__next-route-announcer__') - .text() - - expect(title).toBe('') - }) - }) -} diff --git a/test/integration/react-18/app/components/foo.js b/test/integration/react-current-version/app/components/foo.js similarity index 100% rename from test/integration/react-18/app/components/foo.js rename to test/integration/react-current-version/app/components/foo.js diff --git a/test/integration/react-18/app/components/red.tsx b/test/integration/react-current-version/app/components/red.tsx similarity index 85% rename from test/integration/react-18/app/components/red.tsx rename to test/integration/react-current-version/app/components/red.tsx index 3da9eaccfef4b..1ea444aa515d2 100644 --- a/test/integration/react-18/app/components/red.tsx +++ b/test/integration/react-current-version/app/components/red.tsx @@ -1,5 +1,5 @@ import React, { Suspense } from 'react' -import { createStreamingData } from '../../test/streaming-data' +import { createStreamingData } from './streaming-data' const Data = createStreamingData() diff --git a/test/integration/react-18/test/streaming-data.js b/test/integration/react-current-version/app/components/streaming-data.js similarity index 100% rename from test/integration/react-18/test/streaming-data.js rename to test/integration/react-current-version/app/components/streaming-data.js diff --git a/test/integration/react-18/app/next.config.js b/test/integration/react-current-version/app/next.config.js similarity index 100% rename from test/integration/react-18/app/next.config.js rename to test/integration/react-current-version/app/next.config.js diff --git a/test/integration/react-18/app/package.json b/test/integration/react-current-version/app/package.json similarity index 100% rename from test/integration/react-18/app/package.json rename to test/integration/react-current-version/app/package.json diff --git a/test/integration/react-18/app/pages/dynamic-suspense.js b/test/integration/react-current-version/app/pages/dynamic-suspense.js similarity index 100% rename from test/integration/react-18/app/pages/dynamic-suspense.js rename to test/integration/react-current-version/app/pages/dynamic-suspense.js diff --git a/test/integration/react-18/app/pages/dynamic.js b/test/integration/react-current-version/app/pages/dynamic.js similarity index 100% rename from test/integration/react-18/app/pages/dynamic.js rename to test/integration/react-current-version/app/pages/dynamic.js diff --git a/test/integration/react-18/app/pages/index.js b/test/integration/react-current-version/app/pages/index.js similarity index 100% rename from test/integration/react-18/app/pages/index.js rename to test/integration/react-current-version/app/pages/index.js diff --git a/test/integration/react-18/app/pages/use-flush-effect/styled-jsx.tsx b/test/integration/react-current-version/app/pages/use-flush-effect/styled-jsx.tsx similarity index 100% rename from test/integration/react-18/app/pages/use-flush-effect/styled-jsx.tsx rename to test/integration/react-current-version/app/pages/use-flush-effect/styled-jsx.tsx diff --git a/test/integration/react-18/app/pages/use-id.js b/test/integration/react-current-version/app/pages/use-id.js similarity index 100% rename from test/integration/react-18/app/pages/use-id.js rename to test/integration/react-current-version/app/pages/use-id.js diff --git a/test/integration/react-18/app/tsconfig.json b/test/integration/react-current-version/app/tsconfig.json similarity index 100% rename from test/integration/react-18/app/tsconfig.json rename to test/integration/react-current-version/app/tsconfig.json diff --git a/test/integration/react-current-version/test/index.test.js b/test/integration/react-current-version/test/index.test.js new file mode 100644 index 0000000000000..77c59c103a3b3 --- /dev/null +++ b/test/integration/react-current-version/test/index.test.js @@ -0,0 +1,147 @@ +/* eslint-env jest */ + +import { join } from 'path' + +import cheerio from 'cheerio' +import { + check, + File, + renderViaHTTP, + runDevSuite, + runProdSuite, +} from 'next-test-utils' +import webdriver from 'next-webdriver' + +const appDir = join(__dirname, '../app') +const indexPage = new File(join(appDir, 'pages/index.js')) + +describe('Basics', () => { + runTests('default setting', (context, env) => { + it('should only render once in SSR', async () => { + await renderViaHTTP(context.appPort, '/') + expect([...context.stdout.matchAll(/__render__/g)].length).toBe(1) + }) + + it('no warnings for image related link props', async () => { + await renderViaHTTP(context.appPort, '/') + expect(context.stderr).not.toContain('Warning: Invalid DOM property') + expect(context.stderr).not.toContain('Warning: React does not recognize') + }) + + it('hydrates correctly for normal page', async () => { + const browser = await webdriver(context.appPort, '/') + expect(await browser.eval('window.didHydrate')).toBe(true) + expect(await browser.elementById('react-dom-version').text()).toMatch( + /18/ + ) + }) + + it('useId() values should match on hydration', async () => { + const html = await renderViaHTTP(context.appPort, '/use-id') + const $ = cheerio.load(html) + const ssrId = $('#id').text() + + const browser = await webdriver(context.appPort, '/use-id') + const csrId = await browser.eval( + 'document.getElementById("id").innerText' + ) + + expect(ssrId).toEqual(csrId) + }) + + it('should contain dynamicIds in next data for dynamic imports', async () => { + async function expectToContainPreload(page) { + const html = await renderViaHTTP(context.appPort, `/${page}`) + const $ = cheerio.load(html) + const { dynamicIds } = JSON.parse($('#__NEXT_DATA__').html()) + + if (env === 'dev') { + expect( + dynamicIds.find((id) => + id.includes(`pages/${page}.js -> ../components/foo`) + ) + ).toBeTruthy() + } else { + expect(dynamicIds.length).toBe(1) + } + } + await expectToContainPreload('dynamic') + await expectToContainPreload('dynamic-suspense') + }) + }) +}) + +function runTestsAgainstRuntime(runtime) { + runTests( + `Concurrent mode in the ${runtime} runtime`, + (context, env) => { + async function withBrowser(path, cb) { + let browser + try { + browser = await webdriver(context.appPort, path) + await cb(browser) + } finally { + if (browser) { + await browser.close() + } + } + } + + it('flushes styled-jsx styles as the page renders', async () => { + const html = await renderViaHTTP( + context.appPort, + '/use-flush-effect/styled-jsx' + ) + const stylesOccurrence = html.match(/color:(\s)*(?:blue|#00f)/g) || [] + expect(stylesOccurrence.length).toBe(1) + + await withBrowser('/use-flush-effect/styled-jsx', async (browser) => { + await check( + () => browser.waitForElementByCss('#__jsx-900f996af369fc74').text(), + /(?:blue|#00f)/ + ) + await check( + () => browser.waitForElementByCss('#__jsx-8b0811664c4e575e').text(), + /red/ + ) + }) + }) + + describe('', () => { + it('should not have the initial route announced', async () => { + const browser = await webdriver(context.appPort, '/') + const title = await browser + .waitForElementByCss('#__next-route-announcer__') + .text() + + expect(title).toBe('') + }) + }) + + it('should not have invalid config warning', async () => { + await renderViaHTTP(context.appPort, '/') + expect(context.stderr).not.toContain('not exist in this version') + }) + }, + { + beforeAll: (env) => { + indexPage.replace( + "// runtime: 'experimental-edge'", + `runtime: '${runtime}'` + ) + }, + afterAll: (env) => { + indexPage.restore() + }, + } + ) +} + +runTestsAgainstRuntime('experimental-edge') +runTestsAgainstRuntime('nodejs') + +function runTests(name, fn, opts) { + const suiteOptions = { ...opts, runTests: fn } + runDevSuite(name, appDir, suiteOptions) + runProdSuite(name, appDir, suiteOptions) +} diff --git a/test/integration/react-current-version/tsconfig.json b/test/integration/react-current-version/tsconfig.json new file mode 100644 index 0000000000000..1d4f624eff7d9 --- /dev/null +++ b/test/integration/react-current-version/tsconfig.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "target": "ES2017", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": false, + "noEmit": true, + "incremental": true, + "module": "esnext", + "esModuleInterop": true, + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "plugins": [ + { + "name": "next" + } + ] + }, + "include": ["next-env.d.ts", ".next/types/**/*.ts", "**/*.ts", "**/*.tsx"], + "exclude": ["node_modules"] +}