Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: merge edge ssr tests #39924

Merged
merged 4 commits into from Aug 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/build_test_deploy.yml
Expand Up @@ -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
Expand Down
33 changes: 0 additions & 33 deletions test/e2e/edge-vs.-non-edge-api-route-priority/index.test.ts

This file was deleted.

180 changes: 180 additions & 0 deletions test/e2e/streaming-ssr/index.test.ts
@@ -0,0 +1,180 @@
import { join } from 'path'
import { createNext, FileRef } from 'e2e-utils'
import { NextInstance } from 'test/lib/next-modes/base'
import {
fetchViaHTTP,
findPort,
initNextServerScript,
killApp,
renderViaHTTP,
} from 'next-test-utils'

const react18Deps = {
react: '^18.0.0',
'react-dom': '^18.0.0',
}

const isNextProd = !(global as any).isNextDev && !(global as any).isNextDeploy

describe('react 18 streaming SSR with custom next configs', () => {
let next: NextInstance

beforeAll(async () => {
next = await createNext({
files: {
pages: new FileRef(join(__dirname, 'streaming-ssr/pages')),
},
nextConfig: require(join(__dirname, 'streaming-ssr/next.config.js')),
dependencies: react18Deps,
installCommand: 'npm install',
})
})
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')
})

it('should redirect paths without trailing-slash and render when slash is appended', async () => {
const page = '/hello'
const redirectRes = await fetchViaHTTP(
next.url,
page,
{},
{ redirect: 'manual' }
)
const res = await fetchViaHTTP(next.url, page + '/')
const html = await res.text()

expect(redirectRes.status).toBe(308)
expect(res.status).toBe(200)
expect(html).toContain('hello nextjs')
expect(html).toContain('home')
})

it('should render multi-byte characters correctly in streaming', async () => {
const html = await renderViaHTTP(next.url, '/multi-byte')
expect(html).toContain('マルチバイト'.repeat(28))
})
})

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')
})
})

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 <p>streaming</p>
}
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')
})
}
})
}
3 changes: 3 additions & 0 deletions test/e2e/streaming-ssr/streaming-ssr/next.config.js
@@ -0,0 +1,3 @@
module.exports = {
trailingSlash: true,
}
7 changes: 7 additions & 0 deletions 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',
}
@@ -0,0 +1,3 @@
export default async function handler(_, res) {
res.send('login')
}
9 changes: 9 additions & 0 deletions test/e2e/switchable-runtime/index.test.ts
Expand Up @@ -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
Expand All @@ -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')
Expand Down
15 changes: 15 additions & 0 deletions 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',
},
],
}
},
}
Expand Up @@ -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(
Expand Down
2 changes: 1 addition & 1 deletion test/integration/prerender-preview/test/index.test.js
Expand Up @@ -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(
Expand Down