2021-08-18 17:41:40 +02:00
|
|
|
import glob from 'glob'
|
2021-10-05 20:52:19 +02:00
|
|
|
import _fs from 'fs-extra'
|
2020-12-16 21:46:55 +01:00
|
|
|
import cheerio from 'cheerio'
|
2021-10-05 20:52:19 +02:00
|
|
|
import { join, dirname } from 'path'
|
|
|
|
import { createNext, FileRef } from 'e2e-utils'
|
|
|
|
import { NextInstance } from 'test/lib/next-modes/base'
|
2020-12-16 21:46:55 +01:00
|
|
|
import {
|
|
|
|
fetchViaHTTP,
|
|
|
|
findPort,
|
2021-08-18 17:41:40 +02:00
|
|
|
initNextServerScript,
|
|
|
|
killApp,
|
2020-12-16 21:46:55 +01:00
|
|
|
renderViaHTTP,
|
|
|
|
} from 'next-test-utils'
|
|
|
|
|
2021-10-05 20:52:19 +02:00
|
|
|
describe('should set-up next', () => {
|
|
|
|
let next: NextInstance
|
|
|
|
let server
|
|
|
|
let appPort
|
|
|
|
let errors = []
|
|
|
|
let requiredFilesManifest
|
2020-12-16 21:46:55 +01:00
|
|
|
|
|
|
|
beforeAll(async () => {
|
2021-10-05 20:52:19 +02:00
|
|
|
next = await createNext({
|
|
|
|
files: {
|
|
|
|
pages: new FileRef(join(__dirname, 'required-server-files/pages')),
|
|
|
|
lib: new FileRef(join(__dirname, 'required-server-files/lib')),
|
|
|
|
'data.txt': new FileRef(
|
|
|
|
join(__dirname, 'required-server-files/data.txt')
|
|
|
|
),
|
2021-08-18 17:41:40 +02:00
|
|
|
},
|
2021-10-05 20:52:19 +02:00
|
|
|
nextConfig: {
|
|
|
|
experimental: {
|
|
|
|
outputFileTracing: true,
|
|
|
|
},
|
|
|
|
eslint: {
|
|
|
|
ignoreDuringBuilds: true,
|
|
|
|
},
|
|
|
|
async rewrites() {
|
|
|
|
return [
|
|
|
|
{
|
|
|
|
source: '/some-catch-all/:path*',
|
|
|
|
destination: '/',
|
|
|
|
},
|
|
|
|
]
|
|
|
|
},
|
2021-03-03 20:20:48 +01:00
|
|
|
},
|
|
|
|
})
|
2021-10-05 20:52:19 +02:00
|
|
|
await next.stop()
|
|
|
|
const keptFiles = new Set<string>()
|
|
|
|
const nextServerTrace = require('next/dist/server/next-server.js.nft.json')
|
2020-12-16 21:46:55 +01:00
|
|
|
|
2021-10-05 20:52:19 +02:00
|
|
|
requiredFilesManifest = JSON.parse(
|
|
|
|
await next.readFile('.next/required-server-files.json')
|
2021-08-18 17:41:40 +02:00
|
|
|
)
|
2021-10-05 20:52:19 +02:00
|
|
|
requiredFilesManifest.files.forEach((file) => keptFiles.add(file))
|
2021-08-18 17:41:40 +02:00
|
|
|
|
2021-10-05 20:52:19 +02:00
|
|
|
const pageTraceFiles = glob.sync('**/*.nft.json', {
|
|
|
|
cwd: join(next.testDir, '.next/server/pages'),
|
2021-08-18 17:41:40 +02:00
|
|
|
})
|
2021-10-05 20:52:19 +02:00
|
|
|
for (const traceFile of pageTraceFiles) {
|
|
|
|
const pageDir = dirname(join('.next/server/pages', traceFile))
|
|
|
|
const trace = await _fs.readJSON(
|
|
|
|
join(next.testDir, '.next/server/pages', traceFile)
|
|
|
|
)
|
|
|
|
keptFiles.add(
|
|
|
|
join('.next/server/pages', traceFile.replace('.nft.json', ''))
|
|
|
|
)
|
2020-12-16 21:46:55 +01:00
|
|
|
|
2021-10-05 20:52:19 +02:00
|
|
|
for (const file of trace.files) {
|
|
|
|
keptFiles.add(join(pageDir, file))
|
|
|
|
}
|
|
|
|
}
|
2021-08-18 17:41:40 +02:00
|
|
|
|
2021-10-05 20:52:19 +02:00
|
|
|
const allFiles = glob.sync('**/*', {
|
|
|
|
cwd: next.testDir,
|
|
|
|
dot: true,
|
2021-08-18 17:41:40 +02:00
|
|
|
})
|
|
|
|
|
2021-10-05 20:52:19 +02:00
|
|
|
for (const file of allFiles) {
|
|
|
|
const filePath = join(next.testDir, file)
|
2020-12-16 21:46:55 +01:00
|
|
|
if (
|
2021-10-05 20:52:19 +02:00
|
|
|
!keptFiles.has(file) &&
|
|
|
|
!(await _fs.stat(filePath).catch(() => null))?.isDirectory() &&
|
|
|
|
!nextServerTrace.files.includes(file) &&
|
|
|
|
!file.match(/node_modules\/(react|react-dom)\//) &&
|
|
|
|
file !== 'node_modules/next/dist/server/next-server.js'
|
2020-12-16 21:46:55 +01:00
|
|
|
) {
|
2021-10-05 20:52:19 +02:00
|
|
|
await _fs.remove(filePath)
|
2020-12-16 21:46:55 +01:00
|
|
|
}
|
|
|
|
}
|
2021-10-05 20:52:19 +02:00
|
|
|
appPort = await findPort()
|
2020-12-16 21:46:55 +01:00
|
|
|
|
2021-10-05 20:52:19 +02:00
|
|
|
const testServer = join(next.testDir, 'server.js')
|
|
|
|
await _fs.writeFile(
|
|
|
|
testServer,
|
|
|
|
`
|
2021-08-18 17:41:40 +02:00
|
|
|
const http = require('http')
|
|
|
|
const NextServer = require('next/dist/server/next-server').default
|
2021-10-05 20:52:19 +02:00
|
|
|
const appPort = ${appPort}
|
2021-08-18 17:41:40 +02:00
|
|
|
|
2021-10-05 20:52:19 +02:00
|
|
|
const nextApp = new NextServer({
|
|
|
|
conf: ${JSON.stringify(requiredFilesManifest.config)},
|
|
|
|
dir: "${next.testDir}",
|
2021-08-18 17:41:40 +02:00
|
|
|
quiet: false,
|
|
|
|
minimalMode: true,
|
|
|
|
})
|
|
|
|
|
|
|
|
server = http.createServer(async (req, res) => {
|
|
|
|
try {
|
|
|
|
await nextApp.getRequestHandler()(req, res)
|
|
|
|
} catch (err) {
|
|
|
|
console.error('top-level', err)
|
|
|
|
res.statusCode = 500
|
|
|
|
res.end('error')
|
|
|
|
}
|
|
|
|
})
|
2021-10-05 20:52:19 +02:00
|
|
|
server.listen(appPort, (err) => {
|
|
|
|
if (err) throw err
|
|
|
|
console.log(\`Listening at ::${appPort}\`)
|
2021-08-18 17:41:40 +02:00
|
|
|
})
|
2021-10-05 20:52:19 +02:00
|
|
|
`
|
2021-08-18 17:41:40 +02:00
|
|
|
)
|
2020-12-16 21:46:55 +01:00
|
|
|
|
2021-08-18 17:41:40 +02:00
|
|
|
server = await initNextServerScript(
|
2021-10-05 20:52:19 +02:00
|
|
|
testServer,
|
2021-08-18 17:41:40 +02:00
|
|
|
/Listening at/,
|
|
|
|
{
|
|
|
|
...process.env,
|
|
|
|
NODE_ENV: 'production',
|
|
|
|
},
|
|
|
|
undefined,
|
|
|
|
{
|
2021-10-05 20:52:19 +02:00
|
|
|
cwd: next.testDir,
|
2021-08-18 17:41:40 +02:00
|
|
|
onStderr(msg) {
|
|
|
|
if (msg.includes('top-level')) {
|
|
|
|
errors.push(msg)
|
|
|
|
}
|
|
|
|
},
|
2020-12-16 21:46:55 +01:00
|
|
|
}
|
2021-08-18 17:41:40 +02:00
|
|
|
)
|
2020-12-16 21:46:55 +01:00
|
|
|
})
|
|
|
|
afterAll(async () => {
|
2021-10-05 20:52:19 +02:00
|
|
|
await next.destroy()
|
|
|
|
if (server) await killApp(server)
|
2020-12-16 21:46:55 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
it('should output required-server-files manifest correctly', async () => {
|
|
|
|
expect(requiredFilesManifest.version).toBe(1)
|
|
|
|
expect(Array.isArray(requiredFilesManifest.files)).toBe(true)
|
|
|
|
expect(Array.isArray(requiredFilesManifest.ignore)).toBe(true)
|
|
|
|
expect(requiredFilesManifest.files.length).toBeGreaterThan(0)
|
|
|
|
expect(requiredFilesManifest.ignore.length).toBeGreaterThan(0)
|
|
|
|
expect(typeof requiredFilesManifest.config.configFile).toBe('undefined')
|
|
|
|
expect(typeof requiredFilesManifest.config.trailingSlash).toBe('boolean')
|
2021-03-09 19:41:57 +01:00
|
|
|
expect(typeof requiredFilesManifest.appDir).toBe('string')
|
2020-12-16 21:46:55 +01:00
|
|
|
})
|
|
|
|
|
2021-09-10 10:15:13 +02:00
|
|
|
it('should set correct SWR headers with notFound gsp', async () => {
|
2021-10-05 20:52:19 +02:00
|
|
|
await next.patchFile('data.txt', 'show')
|
2021-09-10 10:15:13 +02:00
|
|
|
|
|
|
|
const res = await fetchViaHTTP(appPort, '/gsp', undefined, {
|
|
|
|
redirect: 'manual ',
|
|
|
|
})
|
|
|
|
expect(res.status).toBe(200)
|
|
|
|
expect(res.headers.get('cache-control')).toBe(
|
|
|
|
's-maxage=1, stale-while-revalidate'
|
|
|
|
)
|
|
|
|
|
2021-10-05 20:52:19 +02:00
|
|
|
await next.patchFile('data.txt', 'hide')
|
2021-09-10 10:15:13 +02:00
|
|
|
|
|
|
|
const res2 = await fetchViaHTTP(appPort, '/gsp', undefined, {
|
|
|
|
redirect: 'manual ',
|
|
|
|
})
|
|
|
|
expect(res2.status).toBe(404)
|
|
|
|
expect(res2.headers.get('cache-control')).toBe(
|
|
|
|
's-maxage=1, stale-while-revalidate'
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should set correct SWR headers with notFound gssp', async () => {
|
2021-10-05 20:52:19 +02:00
|
|
|
await next.patchFile('data.txt', 'show')
|
2021-09-10 10:15:13 +02:00
|
|
|
|
|
|
|
const res = await fetchViaHTTP(appPort, '/gssp', undefined, {
|
|
|
|
redirect: 'manual ',
|
|
|
|
})
|
|
|
|
expect(res.status).toBe(200)
|
|
|
|
expect(res.headers.get('cache-control')).toBe(
|
|
|
|
's-maxage=1, stale-while-revalidate'
|
|
|
|
)
|
|
|
|
|
2021-10-05 20:52:19 +02:00
|
|
|
await next.patchFile('data.txt', 'hide')
|
2021-09-10 10:15:13 +02:00
|
|
|
|
|
|
|
const res2 = await fetchViaHTTP(appPort, '/gssp', undefined, {
|
|
|
|
redirect: 'manual ',
|
|
|
|
})
|
|
|
|
expect(res2.status).toBe(404)
|
|
|
|
expect(res2.headers.get('cache-control')).toBe(
|
|
|
|
's-maxage=1, stale-while-revalidate'
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
2020-12-16 21:46:55 +01:00
|
|
|
it('should render SSR page correctly', async () => {
|
|
|
|
const html = await renderViaHTTP(appPort, '/')
|
|
|
|
const $ = cheerio.load(html)
|
|
|
|
const data = JSON.parse($('#props').text())
|
|
|
|
|
|
|
|
expect($('#index').text()).toBe('index page')
|
|
|
|
expect(data.hello).toBe('world')
|
|
|
|
|
|
|
|
const html2 = await renderViaHTTP(appPort, '/')
|
|
|
|
const $2 = cheerio.load(html2)
|
|
|
|
const data2 = JSON.parse($2('#props').text())
|
|
|
|
|
|
|
|
expect($2('#index').text()).toBe('index page')
|
|
|
|
expect(isNaN(data2.random)).toBe(false)
|
|
|
|
expect(data2.random).not.toBe(data.random)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should render dynamic SSR page correctly', async () => {
|
|
|
|
const html = await renderViaHTTP(appPort, '/dynamic/first')
|
|
|
|
const $ = cheerio.load(html)
|
|
|
|
const data = JSON.parse($('#props').text())
|
|
|
|
|
|
|
|
expect($('#dynamic').text()).toBe('dynamic page')
|
|
|
|
expect($('#slug').text()).toBe('first')
|
|
|
|
expect(data.hello).toBe('world')
|
|
|
|
|
|
|
|
const html2 = await renderViaHTTP(appPort, '/dynamic/second')
|
|
|
|
const $2 = cheerio.load(html2)
|
|
|
|
const data2 = JSON.parse($2('#props').text())
|
|
|
|
|
|
|
|
expect($2('#dynamic').text()).toBe('dynamic page')
|
|
|
|
expect($2('#slug').text()).toBe('second')
|
|
|
|
expect(isNaN(data2.random)).toBe(false)
|
|
|
|
expect(data2.random).not.toBe(data.random)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should render fallback page correctly', async () => {
|
|
|
|
const html = await renderViaHTTP(appPort, '/fallback/first')
|
|
|
|
const $ = cheerio.load(html)
|
|
|
|
const data = JSON.parse($('#props').text())
|
|
|
|
|
|
|
|
expect($('#fallback').text()).toBe('fallback page')
|
|
|
|
expect($('#slug').text()).toBe('first')
|
|
|
|
expect(data.hello).toBe('world')
|
|
|
|
|
|
|
|
const html2 = await renderViaHTTP(appPort, '/fallback/first')
|
|
|
|
const $2 = cheerio.load(html2)
|
|
|
|
const data2 = JSON.parse($2('#props').text())
|
|
|
|
|
|
|
|
expect($2('#fallback').text()).toBe('fallback page')
|
|
|
|
expect($2('#slug').text()).toBe('first')
|
|
|
|
expect(isNaN(data2.random)).toBe(false)
|
|
|
|
expect(data2.random).not.toBe(data.random)
|
|
|
|
|
|
|
|
const html3 = await renderViaHTTP(appPort, '/fallback/second')
|
|
|
|
const $3 = cheerio.load(html3)
|
|
|
|
const data3 = JSON.parse($3('#props').text())
|
|
|
|
|
|
|
|
expect($3('#fallback').text()).toBe('fallback page')
|
|
|
|
expect($3('#slug').text()).toBe('second')
|
|
|
|
expect(isNaN(data3.random)).toBe(false)
|
|
|
|
|
|
|
|
const { pageProps: data4 } = JSON.parse(
|
2021-10-05 20:52:19 +02:00
|
|
|
await renderViaHTTP(
|
|
|
|
appPort,
|
|
|
|
`/_next/data/${next.buildId}/fallback/third.json`
|
|
|
|
)
|
2020-12-16 21:46:55 +01:00
|
|
|
)
|
|
|
|
expect(data4.hello).toBe('world')
|
|
|
|
expect(data4.slug).toBe('third')
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should render SSR page correctly with x-matched-path', async () => {
|
|
|
|
const html = await renderViaHTTP(appPort, '/some-other-path', undefined, {
|
|
|
|
headers: {
|
|
|
|
'x-matched-path': '/',
|
|
|
|
},
|
|
|
|
})
|
|
|
|
const $ = cheerio.load(html)
|
|
|
|
const data = JSON.parse($('#props').text())
|
|
|
|
|
|
|
|
expect($('#index').text()).toBe('index page')
|
|
|
|
expect(data.hello).toBe('world')
|
|
|
|
|
|
|
|
const html2 = await renderViaHTTP(appPort, '/some-other-path', undefined, {
|
|
|
|
headers: {
|
|
|
|
'x-matched-path': '/',
|
|
|
|
},
|
|
|
|
})
|
|
|
|
const $2 = cheerio.load(html2)
|
|
|
|
const data2 = JSON.parse($2('#props').text())
|
|
|
|
|
|
|
|
expect($2('#index').text()).toBe('index page')
|
|
|
|
expect(isNaN(data2.random)).toBe(false)
|
|
|
|
expect(data2.random).not.toBe(data.random)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should render dynamic SSR page correctly with x-matched-path', async () => {
|
|
|
|
const html = await renderViaHTTP(appPort, '/some-other-path', undefined, {
|
|
|
|
headers: {
|
|
|
|
'x-matched-path': '/dynamic/[slug]?slug=first',
|
|
|
|
},
|
|
|
|
})
|
|
|
|
const $ = cheerio.load(html)
|
|
|
|
const data = JSON.parse($('#props').text())
|
|
|
|
|
|
|
|
expect($('#dynamic').text()).toBe('dynamic page')
|
|
|
|
expect($('#slug').text()).toBe('first')
|
|
|
|
expect(data.hello).toBe('world')
|
|
|
|
|
|
|
|
const html2 = await renderViaHTTP(appPort, '/some-other-path', undefined, {
|
|
|
|
headers: {
|
|
|
|
'x-matched-path': '/dynamic/[slug]?slug=second',
|
|
|
|
},
|
|
|
|
})
|
|
|
|
const $2 = cheerio.load(html2)
|
|
|
|
const data2 = JSON.parse($2('#props').text())
|
|
|
|
|
|
|
|
expect($2('#dynamic').text()).toBe('dynamic page')
|
|
|
|
expect($2('#slug').text()).toBe('second')
|
|
|
|
expect(isNaN(data2.random)).toBe(false)
|
|
|
|
expect(data2.random).not.toBe(data.random)
|
2021-05-18 21:24:22 +02:00
|
|
|
|
|
|
|
const html3 = await renderViaHTTP(appPort, '/some-other-path', undefined, {
|
|
|
|
headers: {
|
|
|
|
'x-matched-path': '/dynamic/[slug]?slug=%5Bslug%5D.json',
|
|
|
|
'x-now-route-matches': '1=second&slug=second',
|
|
|
|
},
|
|
|
|
})
|
|
|
|
const $3 = cheerio.load(html3)
|
|
|
|
const data3 = JSON.parse($3('#props').text())
|
|
|
|
|
|
|
|
expect($3('#dynamic').text()).toBe('dynamic page')
|
|
|
|
expect($3('#slug').text()).toBe('second')
|
|
|
|
expect(isNaN(data3.random)).toBe(false)
|
|
|
|
expect(data3.random).not.toBe(data.random)
|
2020-12-16 21:46:55 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
it('should render fallback page correctly with x-matched-path and routes-matches', async () => {
|
|
|
|
const html = await renderViaHTTP(appPort, '/fallback/first', undefined, {
|
|
|
|
headers: {
|
|
|
|
'x-matched-path': '/fallback/first',
|
|
|
|
'x-now-route-matches': '1=first',
|
|
|
|
},
|
|
|
|
})
|
|
|
|
const $ = cheerio.load(html)
|
|
|
|
const data = JSON.parse($('#props').text())
|
|
|
|
|
|
|
|
expect($('#fallback').text()).toBe('fallback page')
|
|
|
|
expect($('#slug').text()).toBe('first')
|
|
|
|
expect(data.hello).toBe('world')
|
|
|
|
|
|
|
|
const html2 = await renderViaHTTP(appPort, `/fallback/[slug]`, undefined, {
|
|
|
|
headers: {
|
|
|
|
'x-matched-path': '/fallback/[slug]',
|
|
|
|
'x-now-route-matches': '1=second',
|
|
|
|
},
|
|
|
|
})
|
|
|
|
const $2 = cheerio.load(html2)
|
|
|
|
const data2 = JSON.parse($2('#props').text())
|
|
|
|
|
|
|
|
expect($2('#fallback').text()).toBe('fallback page')
|
|
|
|
expect($2('#slug').text()).toBe('second')
|
|
|
|
expect(isNaN(data2.random)).toBe(false)
|
|
|
|
expect(data2.random).not.toBe(data.random)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should return data correctly with x-matched-path', async () => {
|
|
|
|
const res = await fetchViaHTTP(
|
|
|
|
appPort,
|
2021-10-05 20:52:19 +02:00
|
|
|
`/_next/data/${next.buildId}/dynamic/first.json`,
|
2020-12-16 21:46:55 +01:00
|
|
|
undefined,
|
|
|
|
{
|
|
|
|
headers: {
|
|
|
|
'x-matched-path': '/dynamic/[slug]?slug=first',
|
|
|
|
},
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
const { pageProps: data } = await res.json()
|
|
|
|
|
|
|
|
expect(data.slug).toBe('first')
|
|
|
|
expect(data.hello).toBe('world')
|
|
|
|
|
|
|
|
const res2 = await fetchViaHTTP(
|
|
|
|
appPort,
|
2021-10-05 20:52:19 +02:00
|
|
|
`/_next/data/${next.buildId}/fallback/[slug].json`,
|
2020-12-16 21:46:55 +01:00
|
|
|
undefined,
|
|
|
|
{
|
|
|
|
headers: {
|
2021-10-05 20:52:19 +02:00
|
|
|
'x-matched-path': `/_next/data/${next.buildId}/fallback/[slug].json`,
|
2020-12-16 21:46:55 +01:00
|
|
|
'x-now-route-matches': '1=second',
|
|
|
|
},
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
const { pageProps: data2 } = await res2.json()
|
|
|
|
|
|
|
|
expect(data2.slug).toBe('second')
|
|
|
|
expect(data2.hello).toBe('world')
|
|
|
|
})
|
|
|
|
|
2021-01-16 16:46:21 +01:00
|
|
|
it('should render fallback optional catch-all route correctly with x-matched-path and routes-matches', async () => {
|
|
|
|
const html = await renderViaHTTP(
|
|
|
|
appPort,
|
|
|
|
'/catch-all/[[...rest]]',
|
|
|
|
undefined,
|
|
|
|
{
|
|
|
|
headers: {
|
|
|
|
'x-matched-path': '/catch-all/[[...rest]]',
|
|
|
|
'x-now-route-matches': '',
|
|
|
|
},
|
|
|
|
}
|
|
|
|
)
|
|
|
|
const $ = cheerio.load(html)
|
|
|
|
const data = JSON.parse($('#props').text())
|
|
|
|
|
|
|
|
expect($('#catch-all').text()).toBe('optional catch-all page')
|
|
|
|
expect(data.params).toEqual({})
|
|
|
|
expect(data.hello).toBe('world')
|
|
|
|
|
|
|
|
const html2 = await renderViaHTTP(
|
|
|
|
appPort,
|
|
|
|
'/catch-all/[[...rest]]',
|
|
|
|
undefined,
|
|
|
|
{
|
|
|
|
headers: {
|
|
|
|
'x-matched-path': '/catch-all/[[...rest]]',
|
|
|
|
'x-now-route-matches': '1=hello&catchAll=hello',
|
|
|
|
},
|
|
|
|
}
|
|
|
|
)
|
|
|
|
const $2 = cheerio.load(html2)
|
|
|
|
const data2 = JSON.parse($2('#props').text())
|
|
|
|
|
|
|
|
expect($2('#catch-all').text()).toBe('optional catch-all page')
|
|
|
|
expect(data2.params).toEqual({ rest: ['hello'] })
|
|
|
|
expect(isNaN(data2.random)).toBe(false)
|
|
|
|
expect(data2.random).not.toBe(data.random)
|
|
|
|
|
|
|
|
const html3 = await renderViaHTTP(
|
|
|
|
appPort,
|
|
|
|
'/catch-all/[[..rest]]',
|
|
|
|
undefined,
|
|
|
|
{
|
|
|
|
headers: {
|
|
|
|
'x-matched-path': '/catch-all/[[...rest]]',
|
|
|
|
'x-now-route-matches': '1=hello/world&catchAll=hello/world',
|
|
|
|
},
|
|
|
|
}
|
|
|
|
)
|
|
|
|
const $3 = cheerio.load(html3)
|
|
|
|
const data3 = JSON.parse($3('#props').text())
|
|
|
|
|
|
|
|
expect($3('#catch-all').text()).toBe('optional catch-all page')
|
|
|
|
expect(data3.params).toEqual({ rest: ['hello', 'world'] })
|
|
|
|
expect(isNaN(data3.random)).toBe(false)
|
|
|
|
expect(data3.random).not.toBe(data.random)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should return data correctly with x-matched-path for optional catch-all route', async () => {
|
|
|
|
const res = await fetchViaHTTP(
|
|
|
|
appPort,
|
2021-10-05 20:52:19 +02:00
|
|
|
`/_next/data/${next.buildId}/catch-all.json`,
|
2021-01-16 16:46:21 +01:00
|
|
|
undefined,
|
|
|
|
{
|
|
|
|
headers: {
|
|
|
|
'x-matched-path': '/catch-all/[[...rest]]',
|
|
|
|
},
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
const { pageProps: data } = await res.json()
|
|
|
|
|
|
|
|
expect(data.params).toEqual({})
|
|
|
|
expect(data.hello).toBe('world')
|
|
|
|
|
|
|
|
const res2 = await fetchViaHTTP(
|
|
|
|
appPort,
|
2021-10-05 20:52:19 +02:00
|
|
|
`/_next/data/${next.buildId}/catch-all/[[...rest]].json`,
|
2021-01-16 16:46:21 +01:00
|
|
|
undefined,
|
|
|
|
{
|
|
|
|
headers: {
|
2021-10-05 20:52:19 +02:00
|
|
|
'x-matched-path': `/_next/data/${next.buildId}/catch-all/[[...rest]].json`,
|
2021-01-16 16:46:21 +01:00
|
|
|
'x-now-route-matches': '1=hello&rest=hello',
|
|
|
|
},
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
const { pageProps: data2 } = await res2.json()
|
|
|
|
|
|
|
|
expect(data2.params).toEqual({ rest: ['hello'] })
|
|
|
|
expect(data2.hello).toBe('world')
|
|
|
|
|
|
|
|
const res3 = await fetchViaHTTP(
|
|
|
|
appPort,
|
2021-10-05 20:52:19 +02:00
|
|
|
`/_next/data/${next.buildId}/catch-all/[[...rest]].json`,
|
2021-01-16 16:46:21 +01:00
|
|
|
undefined,
|
|
|
|
{
|
|
|
|
headers: {
|
2021-10-05 20:52:19 +02:00
|
|
|
'x-matched-path': `/_next/data/${next.buildId}/catch-all/[[...rest]].json`,
|
2021-01-16 16:46:21 +01:00
|
|
|
'x-now-route-matches': '1=hello/world&rest=hello/world',
|
|
|
|
},
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
const { pageProps: data3 } = await res3.json()
|
|
|
|
|
|
|
|
expect(data3.params).toEqual({ rest: ['hello', 'world'] })
|
|
|
|
expect(data3.hello).toBe('world')
|
|
|
|
})
|
|
|
|
|
2020-12-16 21:46:55 +01:00
|
|
|
it('should not apply trailingSlash redirect', async () => {
|
|
|
|
for (const path of [
|
|
|
|
'/',
|
|
|
|
'/dynamic/another/',
|
|
|
|
'/dynamic/another',
|
|
|
|
'/fallback/first/',
|
|
|
|
'/fallback/first',
|
|
|
|
'/fallback/another/',
|
|
|
|
'/fallback/another',
|
|
|
|
]) {
|
|
|
|
const res = await fetchViaHTTP(appPort, path, undefined, {
|
|
|
|
redirect: 'manual',
|
|
|
|
})
|
|
|
|
|
|
|
|
expect(res.status).toBe(200)
|
|
|
|
}
|
|
|
|
})
|
2021-01-16 16:46:21 +01:00
|
|
|
|
|
|
|
it('should normalize catch-all rewrite query values correctly', async () => {
|
|
|
|
const html = await renderViaHTTP(
|
|
|
|
appPort,
|
|
|
|
'/some-catch-all/hello/world',
|
|
|
|
{
|
|
|
|
path: 'hello/world',
|
|
|
|
},
|
|
|
|
{
|
|
|
|
headers: {
|
|
|
|
'x-matched-path': '/',
|
|
|
|
},
|
|
|
|
}
|
|
|
|
)
|
|
|
|
const $ = cheerio.load(html)
|
|
|
|
expect(JSON.parse($('#router').text()).query).toEqual({
|
|
|
|
path: ['hello', 'world'],
|
|
|
|
})
|
|
|
|
})
|
2021-02-11 10:31:49 +01:00
|
|
|
|
|
|
|
it('should bubble error correctly for gip page', async () => {
|
|
|
|
errors = []
|
|
|
|
const res = await fetchViaHTTP(appPort, '/errors/gip', { crash: '1' })
|
|
|
|
expect(res.status).toBe(500)
|
|
|
|
expect(await res.text()).toBe('error')
|
|
|
|
expect(errors.length).toBe(1)
|
2021-08-18 17:41:40 +02:00
|
|
|
expect(errors[0]).toContain('gip hit an oops')
|
2021-02-11 10:31:49 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
it('should bubble error correctly for gssp page', async () => {
|
|
|
|
errors = []
|
|
|
|
const res = await fetchViaHTTP(appPort, '/errors/gssp', { crash: '1' })
|
|
|
|
expect(res.status).toBe(500)
|
|
|
|
expect(await res.text()).toBe('error')
|
|
|
|
expect(errors.length).toBe(1)
|
2021-08-18 17:41:40 +02:00
|
|
|
expect(errors[0]).toContain('gssp hit an oops')
|
2021-02-11 10:31:49 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
it('should bubble error correctly for gsp page', async () => {
|
|
|
|
errors = []
|
|
|
|
const res = await fetchViaHTTP(appPort, '/errors/gsp/crash')
|
|
|
|
expect(res.status).toBe(500)
|
|
|
|
expect(await res.text()).toBe('error')
|
|
|
|
expect(errors.length).toBe(1)
|
2021-08-18 17:41:40 +02:00
|
|
|
expect(errors[0]).toContain('gsp hit an oops')
|
2021-02-11 10:31:49 +01:00
|
|
|
})
|
2021-03-02 20:51:53 +01:00
|
|
|
|
2021-07-02 22:54:53 +02:00
|
|
|
it('should bubble error correctly for API page', async () => {
|
|
|
|
errors = []
|
|
|
|
const res = await fetchViaHTTP(appPort, '/api/error')
|
|
|
|
expect(res.status).toBe(500)
|
|
|
|
expect(await res.text()).toBe('error')
|
|
|
|
expect(errors.length).toBe(1)
|
2021-08-18 17:41:40 +02:00
|
|
|
expect(errors[0]).toContain('some error from /api/error')
|
2021-07-02 22:54:53 +02:00
|
|
|
})
|
|
|
|
|
2021-03-02 20:51:53 +01:00
|
|
|
it('should normalize optional values correctly for SSP page', async () => {
|
|
|
|
const res = await fetchViaHTTP(
|
|
|
|
appPort,
|
|
|
|
'/optional-ssp',
|
|
|
|
{ rest: '', another: 'value' },
|
|
|
|
{
|
|
|
|
headers: {
|
|
|
|
'x-matched-path': '/optional-ssp/[[...rest]]',
|
|
|
|
},
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
const html = await res.text()
|
|
|
|
const $ = cheerio.load(html)
|
|
|
|
const props = JSON.parse($('#props').text())
|
|
|
|
expect(props.params).toEqual({})
|
|
|
|
expect(props.query).toEqual({ another: 'value' })
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should normalize optional values correctly for SSG page', async () => {
|
|
|
|
const res = await fetchViaHTTP(
|
|
|
|
appPort,
|
|
|
|
'/optional-ssg',
|
|
|
|
{ rest: '', another: 'value' },
|
|
|
|
{
|
|
|
|
headers: {
|
|
|
|
'x-matched-path': '/optional-ssg/[[...rest]]',
|
|
|
|
},
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
const html = await res.text()
|
|
|
|
const $ = cheerio.load(html)
|
|
|
|
const props = JSON.parse($('#props').text())
|
|
|
|
expect(props.params).toEqual({})
|
|
|
|
})
|
|
|
|
|
2021-07-06 23:28:43 +02:00
|
|
|
it('should normalize optional values correctly for SSG page with encoded slash', async () => {
|
|
|
|
const res = await fetchViaHTTP(
|
|
|
|
appPort,
|
|
|
|
'/optional-ssg/[[...rest]]',
|
|
|
|
undefined,
|
|
|
|
{
|
|
|
|
headers: {
|
|
|
|
'x-matched-path': '/optional-ssg/[[...rest]]',
|
|
|
|
'x-now-route-matches':
|
|
|
|
'1=en%2Fes%2Fhello%252Fworld&rest=en%2Fes%2Fhello%252Fworld',
|
|
|
|
},
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
const html = await res.text()
|
|
|
|
const $ = cheerio.load(html)
|
|
|
|
const props = JSON.parse($('#props').text())
|
|
|
|
expect(props.params).toEqual({
|
|
|
|
rest: ['en', 'es', 'hello/world'],
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2021-03-02 20:51:53 +01:00
|
|
|
it('should normalize optional values correctly for API page', async () => {
|
|
|
|
const res = await fetchViaHTTP(
|
|
|
|
appPort,
|
|
|
|
'/api/optional',
|
|
|
|
{ rest: '', another: 'value' },
|
|
|
|
{
|
|
|
|
headers: {
|
|
|
|
'x-matched-path': '/api/optional/[[...rest]]',
|
|
|
|
},
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
const json = await res.json()
|
|
|
|
expect(json.query).toEqual({ another: 'value' })
|
|
|
|
expect(json.url).toBe('/api/optional?another=value')
|
|
|
|
})
|
2021-03-04 23:09:45 +01:00
|
|
|
|
|
|
|
it('should match the index page correctly', async () => {
|
|
|
|
const res = await fetchViaHTTP(appPort, '/', undefined, {
|
|
|
|
headers: {
|
|
|
|
'x-matched-path': '/index',
|
|
|
|
},
|
|
|
|
redirect: 'manual',
|
|
|
|
})
|
|
|
|
|
|
|
|
const html = await res.text()
|
|
|
|
const $ = cheerio.load(html)
|
|
|
|
expect($('#index').text()).toBe('index page')
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should match the root dyanmic page correctly', async () => {
|
|
|
|
const res = await fetchViaHTTP(appPort, '/index', undefined, {
|
|
|
|
headers: {
|
|
|
|
'x-matched-path': '/[slug]',
|
|
|
|
},
|
|
|
|
redirect: 'manual',
|
|
|
|
})
|
|
|
|
|
|
|
|
const html = await res.text()
|
|
|
|
const $ = cheerio.load(html)
|
|
|
|
expect($('#slug-page').text()).toBe('[slug] page')
|
|
|
|
})
|
2020-12-16 21:46:55 +01:00
|
|
|
})
|