2022-08-25 00:56:59 +02:00
|
|
|
import { join } from 'path'
|
|
|
|
import { createNext, FileRef } from 'e2e-utils'
|
|
|
|
import { NextInstance } from 'test/lib/next-modes/base'
|
|
|
|
import {
|
2022-11-21 23:15:55 +01:00
|
|
|
check,
|
2022-08-25 00:56:59 +02:00
|
|
|
fetchViaHTTP,
|
|
|
|
findPort,
|
|
|
|
initNextServerScript,
|
|
|
|
killApp,
|
|
|
|
renderViaHTTP,
|
|
|
|
} from 'next-test-utils'
|
|
|
|
|
|
|
|
const isNextProd = !(global as any).isNextDev && !(global as any).isNextDeploy
|
|
|
|
|
2022-11-21 23:15:55 +01:00
|
|
|
describe('streaming SSR with custom next configs', () => {
|
2022-08-25 00:56:59 +02:00
|
|
|
let next: NextInstance
|
|
|
|
|
|
|
|
beforeAll(async () => {
|
|
|
|
next = await createNext({
|
|
|
|
files: {
|
2022-10-07 00:16:42 +02:00
|
|
|
'app/page.js': `
|
|
|
|
export default function Page() {
|
|
|
|
return 'fake-app' /* this should not enable appDir */
|
|
|
|
}
|
|
|
|
`,
|
2022-08-25 00:56:59 +02:00
|
|
|
pages: new FileRef(join(__dirname, 'streaming-ssr/pages')),
|
|
|
|
},
|
|
|
|
nextConfig: require(join(__dirname, 'streaming-ssr/next.config.js')),
|
|
|
|
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')
|
|
|
|
})
|
|
|
|
|
2022-11-10 04:20:32 +01:00
|
|
|
it('should render next/router correctly in edge runtime', async () => {
|
|
|
|
const html = await renderViaHTTP(next.url, '/router')
|
|
|
|
expect(html).toContain('link')
|
|
|
|
})
|
|
|
|
|
2022-08-25 00:56:59 +02:00
|
|
|
it('should render multi-byte characters correctly in streaming', async () => {
|
|
|
|
const html = await renderViaHTTP(next.url, '/multi-byte')
|
|
|
|
expect(html).toContain('マルチバイト'.repeat(28))
|
|
|
|
})
|
2022-11-21 23:15:55 +01:00
|
|
|
|
|
|
|
if ((global as any).isNextDev) {
|
|
|
|
it('should work with custom document', async () => {
|
|
|
|
await next.patchFile(
|
|
|
|
'pages/_document.js',
|
|
|
|
`
|
|
|
|
import { Html, Head, Main, NextScript } from 'next/document'
|
|
|
|
|
|
|
|
export default function Document() {
|
|
|
|
return (
|
|
|
|
<Html>
|
|
|
|
<Head />
|
|
|
|
<body>
|
|
|
|
<Main />
|
|
|
|
<NextScript />
|
|
|
|
</body>
|
|
|
|
</Html>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
`
|
|
|
|
)
|
|
|
|
await check(async () => {
|
|
|
|
return await renderViaHTTP(next.url, '/')
|
|
|
|
}, /index/)
|
|
|
|
await next.deleteFile('pages/_document.js')
|
|
|
|
})
|
|
|
|
}
|
2022-08-25 00:56:59 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
if (isNextProd) {
|
2022-11-21 23:15:55 +01:00
|
|
|
describe('streaming SSR with custom server', () => {
|
2022-08-25 00:56:59 +02:00
|
|
|
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')),
|
|
|
|
})
|
|
|
|
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
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
})
|
|
|
|
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')
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|