From 54274bd0ff9204bc51d3ed249b14906ff761249a Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Wed, 24 Aug 2022 22:39:15 +0200 Subject: [PATCH 1/4] test: merge edge ssr tests --- .../index.test.ts | 33 ----- .../custom-server/next.config.js | 0 .../custom-server/pages/index.js | 0 .../streaming-ssr}/custom-server/server.js | 0 .../streaming-ssr}/index.test.ts | 118 ++++++++++-------- .../streaming-ssr/next.config.js | 3 + .../streaming-ssr/pages/api/user/[id].js | 7 ++ .../streaming-ssr/pages/api/user/login.js | 3 + .../streaming-ssr/pages/hello.js | 0 .../streaming-ssr/pages/index.js | 0 .../streaming-ssr/pages/multi-byte.js | 0 test/e2e/switchable-runtime/index.test.ts | 9 ++ test/e2e/switchable-runtime/next.config.js | 15 +++ .../test/index.test.js | 2 +- .../prerender-preview/test/index.test.js | 2 +- .../streaming-ssr/next.config.js | 6 - 16 files changed, 103 insertions(+), 95 deletions(-) delete mode 100644 test/e2e/edge-vs.-non-edge-api-route-priority/index.test.ts rename test/{production/react-18-streaming-ssr => e2e/streaming-ssr}/custom-server/next.config.js (100%) rename test/{production/react-18-streaming-ssr => e2e/streaming-ssr}/custom-server/pages/index.js (100%) rename test/{production/react-18-streaming-ssr => e2e/streaming-ssr}/custom-server/server.js (100%) rename test/{production/react-18-streaming-ssr => e2e/streaming-ssr}/index.test.ts (57%) create mode 100644 test/e2e/streaming-ssr/streaming-ssr/next.config.js create mode 100644 test/e2e/streaming-ssr/streaming-ssr/pages/api/user/[id].js create mode 100644 test/e2e/streaming-ssr/streaming-ssr/pages/api/user/login.js rename test/{production/react-18-streaming-ssr => e2e/streaming-ssr}/streaming-ssr/pages/hello.js (100%) rename test/{production/react-18-streaming-ssr => e2e/streaming-ssr}/streaming-ssr/pages/index.js (100%) rename test/{production/react-18-streaming-ssr => e2e/streaming-ssr}/streaming-ssr/pages/multi-byte.js (100%) delete mode 100644 test/production/react-18-streaming-ssr/streaming-ssr/next.config.js diff --git a/test/e2e/edge-vs.-non-edge-api-route-priority/index.test.ts b/test/e2e/edge-vs.-non-edge-api-route-priority/index.test.ts deleted file mode 100644 index 48fe0a3e92ba..000000000000 --- a/test/e2e/edge-vs.-non-edge-api-route-priority/index.test.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { createNext } from 'e2e-utils' -import { NextInstance } from 'test/lib/next-modes/base' -import { fetchViaHTTP } from 'next-test-utils' - -describe('Edge vs. non-Edge API route priority', () => { - let next: NextInstance - - beforeAll(async () => { - next = await createNext({ - files: { - 'pages/api/user/login.js': ` - export default async function handler(_, res) { - res.send('from login.js') - } - `, - 'pages/api/user/[id].js': ` - export const config = { - runtime: 'experimental-edge', - } - export default async function handler() { - return new Response('from [id].js') - }`, - }, - dependencies: {}, - }) - }) - afterAll(() => next.destroy()) - - it('more specific route should match', async () => { - const res = await fetchViaHTTP(next.url, '/api/user/login') - expect(await res.text()).toBe('from login.js') - }) -}) diff --git a/test/production/react-18-streaming-ssr/custom-server/next.config.js b/test/e2e/streaming-ssr/custom-server/next.config.js similarity index 100% rename from test/production/react-18-streaming-ssr/custom-server/next.config.js rename to test/e2e/streaming-ssr/custom-server/next.config.js diff --git a/test/production/react-18-streaming-ssr/custom-server/pages/index.js b/test/e2e/streaming-ssr/custom-server/pages/index.js similarity index 100% rename from test/production/react-18-streaming-ssr/custom-server/pages/index.js rename to test/e2e/streaming-ssr/custom-server/pages/index.js diff --git a/test/production/react-18-streaming-ssr/custom-server/server.js b/test/e2e/streaming-ssr/custom-server/server.js similarity index 100% rename from test/production/react-18-streaming-ssr/custom-server/server.js rename to test/e2e/streaming-ssr/custom-server/server.js diff --git a/test/production/react-18-streaming-ssr/index.test.ts b/test/e2e/streaming-ssr/index.test.ts similarity index 57% rename from test/production/react-18-streaming-ssr/index.test.ts rename to test/e2e/streaming-ssr/index.test.ts index bc4fb8df0c54..1f646f6b5638 100644 --- a/test/production/react-18-streaming-ssr/index.test.ts +++ b/test/e2e/streaming-ssr/index.test.ts @@ -14,22 +14,19 @@ const react18Deps = { 'react-dom': '^18.0.0', } +const isNextProd = !(global as any).isNextDev && !(global as any).isNextDeploy + describe('react 18 streaming SSR in minimal mode', () => { let next: NextInstance beforeAll(async () => { - process.env.NEXT_PRIVATE_MINIMAL_MODE = '1' + if (isNextProd) { + process.env.NEXT_PRIVATE_MINIMAL_MODE = '1' + } next = await createNext({ files: { - 'pages/index.js': ` - export default function Page() { - return

streaming

- } - export async function getServerSideProps() { - return { props: {} } - } - `, + pages: new FileRef(join(__dirname, './streaming-ssr/pages')), }, nextConfig: { experimental: { @@ -57,10 +54,19 @@ describe('react 18 streaming SSR in minimal mode', () => { }) }) afterAll(() => { - delete process.env.NEXT_PRIVATE_MINIMAL_MODE + if (isNextProd) { + delete process.env.NEXT_PRIVATE_MINIMAL_MODE + } next.destroy() }) + it('should match more specific route along with dynamic routes', async () => { + const res1 = await fetchViaHTTP(next.url, '/api/user/login') + const res2 = await fetchViaHTTP(next.url, '/api/user/any') + expect(await res1.text()).toBe('login') + expect(await res2.text()).toBe('[id]') + }) + it('should pass correct nextRuntime values', async () => { const content = await next.readFile('runtimes.txt') expect(content.split('\n').sort()).toEqual(['client', 'edge', 'nodejs']) @@ -68,16 +74,18 @@ describe('react 18 streaming SSR in minimal mode', () => { it('should generate html response by streaming correctly', async () => { const html = await renderViaHTTP(next.url, '/') - expect(html).toContain('streaming') + expect(html).toContain('index') }) - it('should have generated a static 404 page', async () => { - expect(await next.readFile('.next/server/pages/404.html')).toBeTruthy() + if (isNextProd) { + it('should have generated a static 404 page', async () => { + expect(await next.readFile('.next/server/pages/404.html')).toBeTruthy() - const res = await fetchViaHTTP(next.url, '/non-existent') - expect(res.status).toBe(404) - expect(await res.text()).toContain('This page could not be found') - }) + const res = await fetchViaHTTP(next.url, '/non-existent') + expect(res.status).toBe(404) + expect(await res.text()).toContain('This page could not be found') + }) + } }) describe('react 18 streaming SSR with custom next configs', () => { @@ -123,42 +131,44 @@ describe('react 18 streaming SSR with custom next configs', () => { }) }) -describe('react 18 streaming SSR with custom server', () => { - let next - let server - let appPort - beforeAll(async () => { - next = await createNext({ - files: { - pages: new FileRef(join(__dirname, 'custom-server/pages')), - 'server.js': new FileRef(join(__dirname, 'custom-server/server.js')), - }, - nextConfig: require(join(__dirname, 'custom-server/next.config.js')), - dependencies: react18Deps, +if (isNextProd) { + describe('react 18 streaming SSR with custom server', () => { + let next + let server + let appPort + beforeAll(async () => { + next = await createNext({ + files: { + pages: new FileRef(join(__dirname, 'custom-server/pages')), + 'server.js': new FileRef(join(__dirname, 'custom-server/server.js')), + }, + nextConfig: require(join(__dirname, 'custom-server/next.config.js')), + dependencies: react18Deps, + }) + await next.stop() + + const testServer = join(next.testDir, 'server.js') + appPort = await findPort() + server = await initNextServerScript( + testServer, + /Listening/, + { + ...process.env, + PORT: appPort, + }, + undefined, + { + cwd: next.testDir, + } + ) + }) + afterAll(async () => { + await next.destroy() + if (server) await killApp(server) + }) + it('should render page correctly under custom server', async () => { + const html = await renderViaHTTP(appPort, '/') + expect(html).toContain('streaming') }) - await next.stop() - - const testServer = join(next.testDir, 'server.js') - appPort = await findPort() - server = await initNextServerScript( - testServer, - /Listening/, - { - ...process.env, - PORT: appPort, - }, - undefined, - { - cwd: next.testDir, - } - ) - }) - afterAll(async () => { - await next.destroy() - if (server) await killApp(server) - }) - it('should render page correctly under custom server', async () => { - const html = await renderViaHTTP(appPort, '/') - expect(html).toContain('streaming') }) -}) +} diff --git a/test/e2e/streaming-ssr/streaming-ssr/next.config.js b/test/e2e/streaming-ssr/streaming-ssr/next.config.js new file mode 100644 index 000000000000..ce3f975d0eac --- /dev/null +++ b/test/e2e/streaming-ssr/streaming-ssr/next.config.js @@ -0,0 +1,3 @@ +module.exports = { + trailingSlash: true, +} diff --git a/test/e2e/streaming-ssr/streaming-ssr/pages/api/user/[id].js b/test/e2e/streaming-ssr/streaming-ssr/pages/api/user/[id].js new file mode 100644 index 000000000000..c5649d2074e4 --- /dev/null +++ b/test/e2e/streaming-ssr/streaming-ssr/pages/api/user/[id].js @@ -0,0 +1,7 @@ +export default async function handler() { + return new Response('[id]') +} + +export const config = { + runtime: 'experimental-edge', +} diff --git a/test/e2e/streaming-ssr/streaming-ssr/pages/api/user/login.js b/test/e2e/streaming-ssr/streaming-ssr/pages/api/user/login.js new file mode 100644 index 000000000000..31493ce1ef6a --- /dev/null +++ b/test/e2e/streaming-ssr/streaming-ssr/pages/api/user/login.js @@ -0,0 +1,3 @@ +export default async function handler(_, res) { + res.send('login') +} diff --git a/test/production/react-18-streaming-ssr/streaming-ssr/pages/hello.js b/test/e2e/streaming-ssr/streaming-ssr/pages/hello.js similarity index 100% rename from test/production/react-18-streaming-ssr/streaming-ssr/pages/hello.js rename to test/e2e/streaming-ssr/streaming-ssr/pages/hello.js diff --git a/test/production/react-18-streaming-ssr/streaming-ssr/pages/index.js b/test/e2e/streaming-ssr/streaming-ssr/pages/index.js similarity index 100% rename from test/production/react-18-streaming-ssr/streaming-ssr/pages/index.js rename to test/e2e/streaming-ssr/streaming-ssr/pages/index.js diff --git a/test/production/react-18-streaming-ssr/streaming-ssr/pages/multi-byte.js b/test/e2e/streaming-ssr/streaming-ssr/pages/multi-byte.js similarity index 100% rename from test/production/react-18-streaming-ssr/streaming-ssr/pages/multi-byte.js rename to test/e2e/streaming-ssr/streaming-ssr/pages/multi-byte.js diff --git a/test/e2e/switchable-runtime/index.test.ts b/test/e2e/switchable-runtime/index.test.ts index 7ec464455d62..b7d1ab0efb96 100644 --- a/test/e2e/switchable-runtime/index.test.ts +++ b/test/e2e/switchable-runtime/index.test.ts @@ -286,6 +286,10 @@ describe('Switchable runtime', () => { isStatic: false, isEdge: true, }) + await testRoute(context.appPort, '/rewrite/edge', { + isStatic: false, + isEdge: true, + }) }) // TODO: edge rsc in app dir @@ -305,6 +309,11 @@ describe('Switchable runtime', () => { text = await response.text() expect(text).toMatch(/Returned by Edge API Route .+\/api\/edge/) + // Rewrite should also work + response = await fetchViaHTTP(context.appPort, 'rewrite/api/edge') + text = await response.text() + expect(text).toMatch(/Returned by Edge API Route .+\/api\/edge/) + if (!(global as any).isNextDeploy) { const manifest = await readJson( join(context.appDir, '.next/server/middleware-manifest.json') diff --git a/test/e2e/switchable-runtime/next.config.js b/test/e2e/switchable-runtime/next.config.js index 31dd1d92233e..a055cc5ad2bc 100644 --- a/test/e2e/switchable-runtime/next.config.js +++ b/test/e2e/switchable-runtime/next.config.js @@ -1,7 +1,22 @@ +/** @type {import('next').NextConfig} */ module.exports = { reactStrictMode: true, experimental: { appDir: true, serverComponents: true, }, + async rewrites() { + return { + afterFiles: [ + { + source: '/rewrite/edge', + destination: '/edge', + }, + { + source: '/rewrite/api/edge', + destination: '/api/edge', + }, + ], + } + }, } diff --git a/test/integration/getserversideprops-preview/test/index.test.js b/test/integration/getserversideprops-preview/test/index.test.js index 00a636a1881e..b3ec85122f95 100644 --- a/test/integration/getserversideprops-preview/test/index.test.js +++ b/test/integration/getserversideprops-preview/test/index.test.js @@ -239,7 +239,7 @@ describe('ServerSide Props Preview Mode', () => { expect(cookies.length).toBe(2) }) - /** @type import('next-webdriver').Chain */ + /** @type {import('next-webdriver').Chain} */ let browser it('should start the client-side browser', async () => { browser = await webdriver( diff --git a/test/integration/prerender-preview/test/index.test.js b/test/integration/prerender-preview/test/index.test.js index ce9d77087f93..885cdb19d149 100644 --- a/test/integration/prerender-preview/test/index.test.js +++ b/test/integration/prerender-preview/test/index.test.js @@ -300,7 +300,7 @@ describe('Prerender Preview Mode', () => { expect(cookies.length).toBe(2) }) - /** @type import('next-webdriver').Chain */ + /** @type {import('next-webdriver').Chain} */ let browser it('should start the client-side browser', async () => { browser = await webdriver( diff --git a/test/production/react-18-streaming-ssr/streaming-ssr/next.config.js b/test/production/react-18-streaming-ssr/streaming-ssr/next.config.js deleted file mode 100644 index 04abd7efb81a..000000000000 --- a/test/production/react-18-streaming-ssr/streaming-ssr/next.config.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - trailingSlash: true, - experimental: { - runtime: 'experimental-edge', - }, -} From f7a13f3c69cca43554bd38c4c72bde466f3cbbbf Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Wed, 24 Aug 2022 22:49:50 +0200 Subject: [PATCH 2/4] update build test deploy yml --- .github/workflows/build_test_deploy.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build_test_deploy.yml b/.github/workflows/build_test_deploy.yml index fd346920c8d6..6f308ce4fa89 100644 --- a/.github/workflows/build_test_deploy.yml +++ b/.github/workflows/build_test_deploy.yml @@ -1222,7 +1222,8 @@ jobs: - run: TEST_WASM=true xvfb-run node run-tests.js test/integration/production/test/index.test.js if: ${{needs.build.outputs.docsChange == 'nope'}} - - run: TEST_WASM=true xvfb-run node run-tests.js test/production/react-18-streaming-ssr/index.test.ts + # test wasm parsing for runtime in page config + - run: TEST_WASM=true xvfb-run node run-tests.js test/e2e/streaming-ssr/index.test.ts if: ${{needs.build.outputs.docsChange == 'nope'}} # Build binaries for publishing From 30ba579a8dcef29e8afea77976cfe99fbed19a73 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Wed, 24 Aug 2022 23:35:26 +0200 Subject: [PATCH 3/4] update test --- test/e2e/streaming-ssr/index.test.ts | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/test/e2e/streaming-ssr/index.test.ts b/test/e2e/streaming-ssr/index.test.ts index 1f646f6b5638..2ff86e826eb5 100644 --- a/test/e2e/streaming-ssr/index.test.ts +++ b/test/e2e/streaming-ssr/index.test.ts @@ -16,7 +16,7 @@ const react18Deps = { const isNextProd = !(global as any).isNextDev && !(global as any).isNextDeploy -describe('react 18 streaming SSR in minimal mode', () => { +describe('react 18 streaming SSR in minimal mode with node runtime', () => { let next: NextInstance beforeAll(async () => { @@ -26,7 +26,13 @@ describe('react 18 streaming SSR in minimal mode', () => { next = await createNext({ files: { - pages: new FileRef(join(__dirname, './streaming-ssr/pages')), + 'pages/index.js': ` + export default function Page() { + return

streaming

+ } + export async function getServerSideProps() { + return { props: {} } + }`, }, nextConfig: { experimental: { @@ -60,13 +66,6 @@ describe('react 18 streaming SSR in minimal mode', () => { next.destroy() }) - it('should match more specific route along with dynamic routes', async () => { - const res1 = await fetchViaHTTP(next.url, '/api/user/login') - const res2 = await fetchViaHTTP(next.url, '/api/user/any') - expect(await res1.text()).toBe('login') - expect(await res2.text()).toBe('[id]') - }) - it('should pass correct nextRuntime values', async () => { const content = await next.readFile('runtimes.txt') expect(content.split('\n').sort()).toEqual(['client', 'edge', 'nodejs']) @@ -74,7 +73,7 @@ describe('react 18 streaming SSR in minimal mode', () => { it('should generate html response by streaming correctly', async () => { const html = await renderViaHTTP(next.url, '/') - expect(html).toContain('index') + expect(html).toContain('streaming') }) if (isNextProd) { @@ -103,6 +102,13 @@ describe('react 18 streaming SSR with custom next configs', () => { }) afterAll(() => next.destroy()) + it('should match more specific route along with dynamic routes', async () => { + const res1 = await fetchViaHTTP(next.url, '/api/user/login') + const res2 = await fetchViaHTTP(next.url, '/api/user/any') + expect(await res1.text()).toBe('login') + expect(await res2.text()).toBe('[id]') + }) + it('should render styled-jsx styles in streaming', async () => { const html = await renderViaHTTP(next.url, '/') expect(html).toContain('color:blue') From 2416922f0cf3b4eb422a61bed388e95d5c7033fa Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Thu, 25 Aug 2022 00:06:30 +0200 Subject: [PATCH 4/4] move minimal mode test to prod --- test/e2e/streaming-ssr/index.test.ts | 142 +++++++++++++-------------- 1 file changed, 71 insertions(+), 71 deletions(-) diff --git a/test/e2e/streaming-ssr/index.test.ts b/test/e2e/streaming-ssr/index.test.ts index 2ff86e826eb5..482346e66ae3 100644 --- a/test/e2e/streaming-ssr/index.test.ts +++ b/test/e2e/streaming-ssr/index.test.ts @@ -16,77 +16,6 @@ const react18Deps = { const isNextProd = !(global as any).isNextDev && !(global as any).isNextDeploy -describe('react 18 streaming SSR in minimal mode with node runtime', () => { - let next: NextInstance - - beforeAll(async () => { - if (isNextProd) { - process.env.NEXT_PRIVATE_MINIMAL_MODE = '1' - } - - next = await createNext({ - files: { - 'pages/index.js': ` - export default function Page() { - return

streaming

- } - export async function getServerSideProps() { - return { props: {} } - }`, - }, - nextConfig: { - experimental: { - runtime: 'nodejs', - }, - webpack(config, { nextRuntime }) { - const path = require('path') - const fs = require('fs') - - const runtimeFilePath = path.join(__dirname, 'runtimes.txt') - let runtimeContent = '' - - try { - runtimeContent = fs.readFileSync(runtimeFilePath, 'utf8') - runtimeContent += '\n' - } catch (_) {} - - runtimeContent += nextRuntime || 'client' - - fs.writeFileSync(runtimeFilePath, runtimeContent) - return config - }, - }, - dependencies: react18Deps, - }) - }) - afterAll(() => { - if (isNextProd) { - delete process.env.NEXT_PRIVATE_MINIMAL_MODE - } - next.destroy() - }) - - it('should pass correct nextRuntime values', async () => { - const content = await next.readFile('runtimes.txt') - expect(content.split('\n').sort()).toEqual(['client', 'edge', 'nodejs']) - }) - - it('should generate html response by streaming correctly', async () => { - const html = await renderViaHTTP(next.url, '/') - expect(html).toContain('streaming') - }) - - if (isNextProd) { - it('should have generated a static 404 page', async () => { - expect(await next.readFile('.next/server/pages/404.html')).toBeTruthy() - - const res = await fetchViaHTTP(next.url, '/non-existent') - expect(res.status).toBe(404) - expect(await res.text()).toContain('This page could not be found') - }) - } -}) - describe('react 18 streaming SSR with custom next configs', () => { let next: NextInstance @@ -177,4 +106,75 @@ if (isNextProd) { expect(html).toContain('streaming') }) }) + + describe('react 18 streaming SSR in minimal mode with node runtime', () => { + let next: NextInstance + + beforeAll(async () => { + if (isNextProd) { + process.env.NEXT_PRIVATE_MINIMAL_MODE = '1' + } + + next = await createNext({ + files: { + 'pages/index.js': ` + export default function Page() { + return

streaming

+ } + export async function getServerSideProps() { + return { props: {} } + }`, + }, + nextConfig: { + experimental: { + runtime: 'nodejs', + }, + webpack(config, { nextRuntime }) { + const path = require('path') + const fs = require('fs') + + const runtimeFilePath = path.join(__dirname, 'runtimes.txt') + let runtimeContent = '' + + try { + runtimeContent = fs.readFileSync(runtimeFilePath, 'utf8') + runtimeContent += '\n' + } catch (_) {} + + runtimeContent += nextRuntime || 'client' + + fs.writeFileSync(runtimeFilePath, runtimeContent) + return config + }, + }, + dependencies: react18Deps, + }) + }) + afterAll(() => { + if (isNextProd) { + delete process.env.NEXT_PRIVATE_MINIMAL_MODE + } + next.destroy() + }) + + it('should pass correct nextRuntime values', async () => { + const content = await next.readFile('runtimes.txt') + expect(content.split('\n').sort()).toEqual(['client', 'edge', 'nodejs']) + }) + + it('should generate html response by streaming correctly', async () => { + const html = await renderViaHTTP(next.url, '/') + expect(html).toContain('streaming') + }) + + if (isNextProd) { + it('should have generated a static 404 page', async () => { + expect(await next.readFile('.next/server/pages/404.html')).toBeTruthy() + + const res = await fetchViaHTTP(next.url, '/non-existent') + expect(res.status).toBe(404) + expect(await res.text()).toContain('This page could not be found') + }) + } + }) }