未验证 提交 51b35f1f 编写于 作者: J Joe Haddad 提交者: GitHub

Test Prerender in Emulated Serverless Mode (#10660)

* Test Prerender in Emulated Serverless Mode

* Clean up between runs
上级 18ecaa9d
const http = require('http')
const url = require('url')
const fs = require('fs')
const path = require('path')
const server = http.createServer((req, res) => {
let { pathname } = url.parse(req.url)
pathname = pathname.replace(/\/$/, '')
let isDataReq = false
if (pathname.startsWith('/_next/data')) {
isDataReq = true
pathname = pathname
.replace(`/_next/data/${process.env.BUILD_ID}/`, '/')
.replace(/\.json$/, '')
}
console.log('serving', pathname)
require(`./.next/serverless/pages${pathname}`).render(req, res)
if (pathname === '/favicon.ico') {
res.statusCode = 404
return res.end()
}
if (pathname.startsWith('/_next/static/')) {
res.write(
fs.readFileSync(
path.join(
__dirname,
'./.next/static/',
decodeURI(pathname.slice('/_next/static/'.length))
),
'utf8'
)
)
return res.end()
} else {
const ext = isDataReq ? 'json' : 'html'
if (
fs.existsSync(
path.join(__dirname, `./.next/serverless/pages${pathname}.${ext}`)
)
) {
res.write(
fs.readFileSync(
path.join(__dirname, `./.next/serverless/pages${pathname}.${ext}`),
'utf8'
)
)
return res.end()
}
let re
try {
re = require(`./.next/serverless/pages${pathname}`)
} catch {
const d = decodeURI(pathname)
if (
fs.existsSync(
path.join(__dirname, `./.next/serverless/pages${d}.${ext}`)
)
) {
res.write(
fs.readFileSync(
path.join(__dirname, `./.next/serverless/pages${d}.${ext}`),
'utf8'
)
)
return res.end()
}
const routesManifest = require('./.next/routes-manifest.json')
const { dynamicRoutes } = routesManifest
dynamicRoutes.some(({ page, regex }) => {
if (new RegExp(regex).test(pathname)) {
if (
fs.existsSync(
path.join(__dirname, `./.next/serverless/pages${page}.${ext}`)
)
) {
res.write(
fs.readFileSync(
path.join(__dirname, `./.next/serverless/pages${page}.${ext}`),
'utf8'
)
)
res.end()
return true
}
re = require(`./.next/serverless/pages${page}`)
return true
}
return false
})
}
if (!res.finished) {
return typeof re.render === 'function'
? re.render(req, res)
: re.default(req, res)
}
}
})
server.listen(process.env.PORT, () => {
......
......@@ -245,7 +245,7 @@ const navigateTest = (dev = false) => {
})
}
const runTests = (dev = false) => {
const runTests = (dev = false, looseMode = false) => {
navigateTest(dev)
it('should SSR normal page correctly', async () => {
......@@ -518,14 +518,16 @@ const runTests = (dev = false) => {
expect(curRandom).toBe(initialRandom + '')
})
} else {
it('should should use correct caching headers for a no-revalidate page', async () => {
const initialRes = await fetchViaHTTP(appPort, '/something')
expect(initialRes.headers.get('cache-control')).toBe(
's-maxage=31536000, stale-while-revalidate'
)
const initialHtml = await initialRes.text()
expect(initialHtml).toMatch(/hello.*?world/)
})
if (!looseMode) {
it('should should use correct caching headers for a no-revalidate page', async () => {
const initialRes = await fetchViaHTTP(appPort, '/something')
expect(initialRes.headers.get('cache-control')).toBe(
's-maxage=31536000, stale-while-revalidate'
)
const initialHtml = await initialRes.text()
expect(initialHtml).toMatch(/hello.*?world/)
})
}
it('outputs a prerender-manifest correctly', async () => {
const manifest = JSON.parse(
......@@ -600,20 +602,22 @@ const runTests = (dev = false) => {
}
})
it('should handle de-duping correctly', async () => {
let vals = new Array(10).fill(null)
if (!looseMode) {
it('should handle de-duping correctly', async () => {
let vals = new Array(10).fill(null)
// use data route so we don't get the fallback
vals = await Promise.all(
vals.map(() =>
renderViaHTTP(appPort, `/_next/data/${buildId}/blog/post-10.json`)
// use data route so we don't get the fallback
vals = await Promise.all(
vals.map(() =>
renderViaHTTP(appPort, `/_next/data/${buildId}/blog/post-10.json`)
)
)
)
const val = vals[0]
const val = vals[0]
expect(JSON.parse(val).pageProps.post).toBe('post-10')
expect(new Set(vals).size).toBe(1)
})
expect(JSON.parse(val).pageProps.post).toBe('post-10')
expect(new Set(vals).size).toBe(1)
})
}
it('should not revalidate when set to false', async () => {
const route = '/something'
......@@ -628,43 +632,45 @@ const runTests = (dev = false) => {
expect(initialHtml).toBe(newHtml)
})
it('should handle revalidating HTML correctly', async () => {
const route = '/blog/post-2/comment-2'
const initialHtml = await renderViaHTTP(appPort, route)
expect(initialHtml).toMatch(/Post:.*?post-2/)
expect(initialHtml).toMatch(/Comment:.*?comment-2/)
if (!looseMode) {
it('should handle revalidating HTML correctly', async () => {
const route = '/blog/post-2/comment-2'
const initialHtml = await renderViaHTTP(appPort, route)
expect(initialHtml).toMatch(/Post:.*?post-2/)
expect(initialHtml).toMatch(/Comment:.*?comment-2/)
let newHtml = await renderViaHTTP(appPort, route)
expect(newHtml).toBe(initialHtml)
let newHtml = await renderViaHTTP(appPort, route)
expect(newHtml).toBe(initialHtml)
await waitFor(2 * 1000)
await renderViaHTTP(appPort, route)
await waitFor(2 * 1000)
await renderViaHTTP(appPort, route)
await waitFor(2 * 1000)
newHtml = await renderViaHTTP(appPort, route)
expect(newHtml === initialHtml).toBe(false)
expect(newHtml).toMatch(/Post:.*?post-2/)
expect(newHtml).toMatch(/Comment:.*?comment-2/)
})
await waitFor(2 * 1000)
newHtml = await renderViaHTTP(appPort, route)
expect(newHtml === initialHtml).toBe(false)
expect(newHtml).toMatch(/Post:.*?post-2/)
expect(newHtml).toMatch(/Comment:.*?comment-2/)
})
it('should handle revalidating JSON correctly', async () => {
const route = `/_next/data/${buildId}/blog/post-2/comment-3.json`
const initialJson = await renderViaHTTP(appPort, route)
expect(initialJson).toMatch(/post-2/)
expect(initialJson).toMatch(/comment-3/)
it('should handle revalidating JSON correctly', async () => {
const route = `/_next/data/${buildId}/blog/post-2/comment-3.json`
const initialJson = await renderViaHTTP(appPort, route)
expect(initialJson).toMatch(/post-2/)
expect(initialJson).toMatch(/comment-3/)
let newJson = await renderViaHTTP(appPort, route)
expect(newJson).toBe(initialJson)
let newJson = await renderViaHTTP(appPort, route)
expect(newJson).toBe(initialJson)
await waitFor(2 * 1000)
await renderViaHTTP(appPort, route)
await waitFor(2 * 1000)
await renderViaHTTP(appPort, route)
await waitFor(2 * 1000)
newJson = await renderViaHTTP(appPort, route)
expect(newJson === initialJson).toBe(false)
expect(newJson).toMatch(/post-2/)
expect(newJson).toMatch(/comment-3/)
})
await waitFor(2 * 1000)
newJson = await renderViaHTTP(appPort, route)
expect(newJson === initialJson).toBe(false)
expect(newJson).toMatch(/post-2/)
expect(newJson).toMatch(/comment-3/)
})
}
it('should not fetch prerender data on mount', async () => {
const browser = await webdriver(appPort, '/blog/post-100')
......@@ -682,7 +688,7 @@ const runTests = (dev = false) => {
}
}
describe('SPR Prerender', () => {
describe('SSG Prerender', () => {
afterAll(() => fs.remove(nextConfig))
describe('dev mode', () => {
......@@ -724,6 +730,7 @@ describe('SPR Prerender', () => {
`module.exports = { target: 'serverless' }`,
'utf8'
)
await fs.remove(join(appDir, '.next'))
await nextBuild(appDir)
stderr = ''
appPort = await findPort()
......@@ -766,6 +773,7 @@ describe('SPR Prerender', () => {
export default () => 'hello world'
`
)
await fs.remove(join(appDir, '.next'))
const { stderr } = await nextBuild(appDir, [], { stderr: true })
await fs.remove(brokenPage)
expect(stderr).toContain(
......@@ -777,10 +785,43 @@ describe('SPR Prerender', () => {
})
})
describe('enumlated serverless mode', () => {
beforeAll(async () => {
const startServerlessEmulator = async (dir, port, buildId) => {
const scriptPath = join(dir, 'server.js')
const env = Object.assign(
{},
{ ...process.env },
{ PORT: port, BUILD_ID: buildId }
)
return initNextServerScript(scriptPath, /ready on/i, env)
}
await fs.writeFile(
nextConfig,
`module.exports = { target: 'experimental-serverless-trace' }`,
'utf8'
)
await fs.remove(join(appDir, '.next'))
await nextBuild(appDir)
distPagesDir = join(appDir, '.next/serverless/pages')
buildId = await fs.readFile(join(appDir, '.next/BUILD_ID'), 'utf8')
stderr = ''
appPort = await findPort()
app = await startServerlessEmulator(appDir, appPort, buildId)
})
afterAll(() => killApp(app))
runTests(false, true)
})
describe('production mode', () => {
let buildOutput = ''
beforeAll(async () => {
await fs.remove(nextConfig)
await fs.remove(join(appDir, '.next'))
const { stdout } = await nextBuild(appDir, [], { stdout: true })
buildOutput = stdout
......@@ -820,6 +861,7 @@ describe('SPR Prerender', () => {
},
}`
)
await fs.remove(join(appDir, '.next'))
await nextBuild(appDir)
await nextExport(appDir, { outdir: exportDir })
app = await startStaticServer(exportDir)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册