Migrate prerender tests to new set-up (#29245)

This commit is contained in:
JJ Kasper 2021-09-21 09:21:05 -05:00 committed by GitHub
parent 371ca582d1
commit 8e52126ea6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
44 changed files with 2724 additions and 2197 deletions

View file

@ -132,8 +132,6 @@
"seedrandom": "3.0.5",
"selenium-webdriver": "4.0.0-beta.4",
"shell-quote": "1.7.2",
"sqlite": "4.0.22",
"sqlite3": "5.0.2",
"styled-jsx-plugin-postcss": "3.0.2",
"tailwindcss": "1.1.3",
"taskr": "1.1.0",

File diff suppressed because one or more lines are too long

View file

@ -136,7 +136,7 @@ describe('basePath', () => {
})
if (!dev) {
if (!(global as any).isDeploy) {
if (!(global as any).isNextDeploy) {
it('should add basePath to routes-manifest', async () => {
const routesManifest = JSON.parse(
await next.readFile('.next/routes-manifest.json')
@ -487,7 +487,7 @@ describe('basePath', () => {
)
})
if (!(global as any).isDeploy) {
if (!(global as any).isNextDeploy) {
it('should navigate an absolute local url with basePath', async () => {
const browser = await webdriver(
next.url,
@ -843,5 +843,5 @@ describe('basePath', () => {
}
})
}
runTests((global as any).isDev)
runTests((global as any).isNextDev)
})

View file

@ -1,23 +1,36 @@
/* eslint-env jest */
import fs from 'fs-extra'
import { join, sep } from 'path'
import path from 'path'
import { createNext, FileRef } from 'e2e-utils'
import { NextInstance } from 'test/lib/next-modes/base'
import webdriver from 'next-webdriver'
import {
findPort,
killApp,
launchApp,
nextBuild,
nextStart,
} from 'next-test-utils'
let app
let appPort
const appDir = join(__dirname, '..')
describe('prerender native module', () => {
let next: NextInstance
beforeAll(async () => {
next = await createNext({
files: {
pages: new FileRef(
path.join(__dirname, 'prerender-native-module/pages')
),
'data.sqlite': new FileRef(
path.join(__dirname, 'prerender-native-module/data.sqlite')
),
},
dependencies: {
sqlite: '4.0.22',
sqlite3: '5.0.2',
},
nextConfig: {
experimental: {
nftTracing: true,
},
},
})
})
afterAll(() => next.destroy())
const runTests = () => {
it('should render index correctly', async () => {
const browser = await webdriver(appPort, '/')
const browser = await webdriver(next.url, '/')
expect(await browser.elementByCss('#index').text()).toBe('index page')
expect(JSON.parse(await browser.elementByCss('#props').text())).toEqual({
index: true,
@ -25,7 +38,7 @@ const runTests = () => {
})
it('should render /blog/first correctly', async () => {
const browser = await webdriver(appPort, '/blog/first')
const browser = await webdriver(next.url, '/blog/first')
expect(await browser.elementByCss('#blog').text()).toBe('blog page')
expect(JSON.parse(await browser.elementByCss('#props').text())).toEqual({
@ -39,7 +52,7 @@ const runTests = () => {
})
it('should render /blog/second correctly', async () => {
const browser = await webdriver(appPort, '/blog/second')
const browser = await webdriver(next.url, '/blog/second')
await browser.waitForElementByCss('#blog')
expect(await browser.elementByCss('#blog').text()).toBe('blog page')
@ -52,26 +65,8 @@ const runTests = () => {
],
})
})
}
describe('Prerender native module', () => {
describe('production', () => {
beforeAll(async () => {
const result = await nextBuild(appDir, undefined, {
cwd: appDir,
stderr: true,
stdout: true,
})
if (result.code !== 0) {
console.error(result)
throw new Error(`Failed to build, exited with code ${result.code}`)
}
appPort = await findPort()
app = await nextStart(appDir, appPort, { cwd: appDir })
})
afterAll(() => killApp(app))
if ((global as any).isNextStart) {
it('should output traces', async () => {
const checks = [
{
@ -101,9 +96,8 @@ describe('Prerender native module', () => {
]
for (const check of checks) {
const contents = await fs.readFile(
join(appDir, '.next/server/pages/', check.page + '.js.nft.json'),
'utf8'
const contents = await next.readFile(
path.join('.next/server/pages/', check.page + '.js.nft.json')
)
const { version, files } = JSON.parse(contents)
expect(version).toBe(1)
@ -112,24 +106,12 @@ describe('Prerender native module', () => {
check.tests.every((item) => files.some((file) => item.test(file)))
).toBe(true)
if (sep === '/') {
if (path.sep === '/') {
expect(
check.notTests.some((item) => files.some((file) => item.test(file)))
).toBe(false)
}
}
})
runTests()
})
describe('dev', () => {
beforeAll(async () => {
appPort = await findPort()
app = await launchApp(appDir, appPort, { cwd: appDir })
})
afterAll(() => killApp(app))
runTests()
})
}
})

1873
test/e2e/prerender.test.ts Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,30 @@
import Link from 'next/link'
import fs from 'fs'
import path from 'path'
export async function getStaticProps() {
const text = fs
.readFileSync(path.join(process.cwd(), 'world.txt'), 'utf8')
.trim()
return {
props: {
world: text,
time: new Date().getTime(),
},
revalidate: true,
}
}
export default ({ world, time }) => (
<>
<p>hello {world}</p>
<span id="anotherTime">time: {time}</span>
<Link href="/">
<a id="home">to home</a>
</Link>
<br />
<Link href="/something">
<a id="something">to something</a>
</Link>
</>
)

View file

@ -0,0 +1,27 @@
import { useRouter } from 'next/router'
export const getStaticProps = () => {
return {
props: {
hello: 'world',
},
}
}
export const getStaticPaths = () => {
return {
paths: ['/api-docs/first'],
fallback: true,
}
}
export default function Slug(props) {
if (useRouter().isFallback) return 'Loading...'
return (
<>
<p id="api-docs">API Docs</p>
<p id="props">{JSON.stringify(props)}</p>
</>
)
}

View file

@ -0,0 +1,3 @@
export default function handler(req, res) {
throw new Error('lol')
}

View file

@ -0,0 +1,7 @@
export function getServerSideProps() {
throw new Error('lol')
}
export default function BadGssp() {
return <div />
}

View file

@ -0,0 +1,7 @@
export function getServerSideProps() {
return { props: {} }
}
export default function BadSsr() {
throw new Error('oops')
}

View file

@ -0,0 +1,43 @@
import React from 'react'
import Link from 'next/link'
import { useRouter } from 'next/router'
export async function getStaticPaths() {
return {
paths: [],
fallback: 'blocking',
}
}
export async function getStaticProps({ params }) {
await new Promise((resolve) => setTimeout(resolve, 1000))
return {
props: {
params,
hello: 'world',
post: params.slug,
random: Math.random(),
time: (await import('perf_hooks')).performance.now(),
},
revalidate: false,
}
}
export default ({ post, time, params }) => {
if (useRouter().isFallback) {
return <p>hi fallback</p>
}
return (
<>
<p>Post: {post}</p>
<span>time: {time}</span>
<div id="params">{JSON.stringify(params)}</div>
<div id="query">{JSON.stringify(useRouter().query)}</div>
<Link href="/">
<a id="home">to home</a>
</Link>
</>
)
}

View file

@ -0,0 +1,43 @@
import React from 'react'
import Link from 'next/link'
import { useRouter } from 'next/router'
export async function getStaticPaths() {
return {
paths: [{ params: { slug: 'a' } }, { params: { slug: 'b' } }],
fallback: 'blocking',
}
}
export async function getStaticProps({ params }) {
await new Promise((resolve) => setTimeout(resolve, 1000))
return {
props: {
params,
hello: 'world',
post: params.slug,
random: Math.random(),
time: (await import('perf_hooks')).performance.now(),
},
revalidate: 1,
}
}
export default ({ post, time, params }) => {
if (useRouter().isFallback) {
return <p>hi fallback</p>
}
return (
<>
<p>Post: {post}</p>
<span>time: {time}</span>
<div id="params">{JSON.stringify(params)}</div>
<div id="query">{JSON.stringify(useRouter().query)}</div>
<Link href="/">
<a id="home">to home</a>
</Link>
</>
)
}

View file

@ -0,0 +1,43 @@
import React from 'react'
import Link from 'next/link'
import { useRouter } from 'next/router'
export async function getStaticPaths() {
return {
paths: [],
fallback: 'blocking',
}
}
export async function getStaticProps({ params }) {
await new Promise((resolve) => setTimeout(resolve, 1000))
return {
props: {
params,
hello: 'world',
post: params.slug,
random: Math.random(),
time: (await import('perf_hooks')).performance.now(),
},
revalidate: 1,
}
}
export default ({ post, time, params }) => {
if (useRouter().isFallback) {
return <p>hi fallback</p>
}
return (
<>
<p>Post: {post}</p>
<span>time: {time}</span>
<div id="params">{JSON.stringify(params)}</div>
<div id="query">{JSON.stringify(useRouter().query)}</div>
<Link href="/">
<a id="home">to home</a>
</Link>
</>
)
}

View file

@ -0,0 +1,41 @@
import React from 'react'
import Link from 'next/link'
export async function getStaticPaths() {
return {
paths: [
'/blog/post-1/comment-1',
{ params: { post: 'post-2', comment: 'comment-2' } },
],
fallback: true,
}
}
export async function getStaticProps({ params }) {
return {
props: {
post: params.post,
comment: params.comment,
time: new Date().getTime(),
},
revalidate: 2,
}
}
export default ({ post, comment, time }) => {
// we're in a loading state
if (!post) {
return <p>loading...</p>
}
return (
<>
<p>Post: {post}</p>
<p>Comment: {comment}</p>
<span>time: {time}</span>
<Link href="/">
<a id="home">to home</a>
</Link>
</>
)
}

View file

@ -0,0 +1,61 @@
import React from 'react'
import Link from 'next/link'
import { useRouter } from 'next/router'
import 'firebase/firestore'
export async function getStaticPaths() {
return {
paths: [
'/blog/post-1',
{ params: { post: 'post-2' } },
'/blog/[post3]',
'/blog/post-4',
'/blog/post.1',
'/blog/post.1', // handle duplicates
],
fallback: true,
}
}
let counter = 0
export async function getStaticProps({ params }) {
if (params.post === 'post-10') {
await new Promise((resolve) => {
setTimeout(() => resolve(), 1000)
})
}
if (params.post === 'post-100') {
throw new Error('such broken..')
}
if (params.post === 'post-999') {
if (++counter < 6) {
throw new Error('try again..')
}
}
return {
props: {
params,
post: params.post,
time: (await import('perf_hooks')).performance.now(),
},
revalidate: 10,
}
}
export default ({ post, time, params }) => {
return (
<>
<p>Post: {post}</p>
<span>time: {time}</span>
<div id="params">{JSON.stringify(params)}</div>
<div id="query">{JSON.stringify(useRouter().query)}</div>
<Link href="/">
<a id="home">to home</a>
</Link>
</>
)
}

View file

@ -0,0 +1,24 @@
import React from 'react'
import Link from 'next/link'
export async function getStaticProps() {
return {
props: {
slugs: ['post-1', 'post-2'],
time: (await import('perf_hooks')).performance.now(),
},
revalidate: 10,
}
}
export default ({ slugs, time }) => {
return (
<>
<p>Posts: {JSON.stringify(slugs)}</p>
<span>time: {time}</span>
<Link href="/">
<a id="home">to home</a>
</Link>
</>
)
}

View file

@ -0,0 +1,41 @@
import Link from 'next/link'
export async function getStaticProps({ params: { slug } }) {
if (slug[0] === 'delayby3s') {
await new Promise((resolve) => setTimeout(resolve, 3000))
}
return {
props: {
slug,
},
revalidate: 1,
}
}
export async function getStaticPaths() {
return {
paths: [
{ params: { slug: ['first'] } },
'/catchall-explicit/second',
{ params: { slug: ['another', 'value'] } },
'/catchall-explicit/hello/another',
'/catchall-explicit/[first]/[second]',
{ params: { slug: ['[third]', '[fourth]'] } },
],
fallback: false,
}
}
export default function Page({ slug }) {
// Important to not check for `slug` existence (testing that build does not
// render fallback version and error)
return (
<>
<p id="catchall">Hi {slug.join(' ')}</p>{' '}
<Link href="/">
<a id="home">to home</a>
</Link>
</>
)
}

View file

@ -0,0 +1,29 @@
import Link from 'next/link'
export async function getStaticProps({ params: { slug } }) {
return {
props: {
slug: slug || [],
},
}
}
export async function getStaticPaths() {
return {
paths: [{ params: { slug: [] } }, { params: { slug: ['value'] } }],
fallback: false,
}
}
export default ({ slug }) => {
// Important to not check for `slug` existence (testing that build does not
// render fallback version and error)
return (
<>
<p id="catchall">Catch all: [{slug.join(', ')}]</p>
<Link href="/">
<a id="home">to home</a>
</Link>
</>
)
}

View file

@ -0,0 +1,34 @@
import { useRouter } from 'next/router'
export async function getStaticProps({ params: { slug } }) {
if (slug[0] === 'delayby3s') {
await new Promise((resolve) => setTimeout(resolve, 3000))
}
return {
props: {
slug,
},
revalidate: 1,
}
}
export async function getStaticPaths() {
return {
paths: [
{ params: { slug: ['first'] } },
'/catchall/second',
{ params: { slug: ['another', 'value'] } },
'/catchall/hello/another',
],
fallback: true,
}
}
export default ({ slug }) => {
const { isFallback } = useRouter()
if (isFallback) {
return <p id="catchall">fallback</p>
}
return <p id="catchall">Hi {slug.join(' ')}</p>
}

View file

@ -0,0 +1,24 @@
import Link from 'next/link'
export async function getStaticProps() {
return {
props: {
world: 'world',
time: new Date().getTime(),
},
}
}
export default ({ world, time }) => (
<>
<p>hello {world}</p>
<span>time: {time}</span>
<Link href="/">
<a id="home">to home</a>
</Link>
<br />
<Link href="/something">
<a id="something">to something</a>
</Link>
</>
)

View file

@ -0,0 +1,27 @@
import Link from 'next/link'
export async function getStaticProps({ params: { slug } }) {
return {
props: { slug },
}
}
export async function getStaticPaths() {
return {
paths: [{ params: { slug: '[first]' } }, '/dynamic/[second]'],
fallback: false,
}
}
export default ({ slug }) => {
// Important to not check for `slug` existence (testing that build does not
// render fallback version and error)
return (
<>
<p id="param">Hi {slug}!</p>{' '}
<Link href="/">
<a id="home">to home</a>
</Link>
</>
)
}

View file

@ -0,0 +1,43 @@
import React from 'react'
import Link from 'next/link'
import { useRouter } from 'next/router'
export async function getStaticPaths() {
return {
paths: [],
fallback: true,
}
}
export async function getStaticProps({ params }) {
await new Promise((resolve) => setTimeout(resolve, 1000))
return {
props: {
params,
hello: 'world',
post: params.slug,
random: Math.random(),
time: (await import('perf_hooks')).performance.now(),
},
revalidate: 1,
}
}
export default ({ post, time, params }) => {
if (useRouter().isFallback) {
return <p>hi fallback</p>
}
return (
<>
<p>Post: {post}</p>
<span>time: {time}</span>
<div id="params">{JSON.stringify(params)}</div>
<div id="query">{JSON.stringify(useRouter().query)}</div>
<Link href="/">
<a id="home">to home</a>
</Link>
</>
)
}

View file

@ -0,0 +1,93 @@
import Link from 'next/link'
export async function getStaticProps() {
// throw new Error('oops from getStaticProps')
return {
props: { world: 'world', time: new Date().getTime() },
// bad-prop
revalidate: 2,
}
}
const Page = ({ world, time }) => {
return (
<>
{/* <div id='after-change'>idk</div> */}
<p>hello {world}</p>
<span>time: {time}</span>
<Link href="/non-json/[p]" as="/non-json/1">
<a id="non-json">to non-json</a>
</Link>
<br />
<Link href="/another?hello=world" as="/another/?hello=world">
<a id="another">to another</a>
</Link>
<br />
<Link href="/something">
<a id="something">to something</a>
</Link>
<br />
<Link href="/normal">
<a id="normal">to normal</a>
</Link>
<br />
<Link href="/blog/[post]" as="/blog/post-1">
<a id="post-1">to dynamic</a>
</Link>
<Link href="/blog/[post]" as="/blog/post-100">
<a id="broken-post">to broken</a>
</Link>
<Link href="/blog/[post]" as="/blog/post-999" prefetch={false}>
<a id="broken-at-first-post">to broken at first</a>
</Link>
<br />
<Link href="/blog/[post]/[comment]" as="/blog/post-1/comment-1">
<a id="comment-1">to another dynamic</a>
</Link>
<Link href="/catchall/[...slug]" as="/catchall/first">
<a id="to-catchall">to catchall</a>
</Link>
<br />
<Link href="/index">
<a id="to-nested-index">to nested index</a>
</Link>
<br />
<Link href="/lang/[lang]/about?lang=en" as="/about">
<a id="to-rewritten-ssg">to rewritten static path page</a>
</Link>
<br />
<Link href="/catchall-optional/[[...slug]]" as="/catchall-optional">
<a id="catchall-optional-root">to optional catchall root</a>
</Link>
<Link href="/catchall-optional/[[...slug]]" as="/catchall-optional/value">
<a id="catchall-optional-value">to optional catchall page /value</a>
</Link>
<br />
<Link href="/dynamic/[slug]" as="/dynamic/[first]">
<a id="dynamic-first">to dynamic [first] page</a>
</Link>
<Link href="/dynamic/[slug]" as="/dynamic/[second]">
<a id="dynamic-second">to dynamic [second] page</a>
</Link>
<br />
<Link
href="/catchall-explicit/[...slug]"
as="/catchall-explicit/[first]/[second]"
>
<a id="catchall-explicit-string">
to catchall-explicit [first]/[second] page
</a>
</Link>
<Link
href="/catchall-explicit/[...slug]"
as="/catchall-explicit/[third]/[fourth]"
>
<a id="catchall-explicit-object">
to catchall-explicit [third]/[fourth] page
</a>
</Link>
</>
)
}
export default Page

View file

@ -0,0 +1,18 @@
import Link from 'next/link'
export async function getStaticProps() {
return {
props: { world: 'nested index' },
}
}
export default ({ world }) => {
return (
<>
<p>hello {world}</p>
<Link href="/">
<a id="home">to home</a>
</Link>
</>
)
}

View file

@ -0,0 +1,12 @@
export default ({ lang }) => <p id="about">About: {lang}</p>
export const getStaticProps = ({ params: { lang } }) => ({
props: {
lang,
},
})
export const getStaticPaths = () => ({
paths: ['en', 'es', 'fr', 'de'].map((p) => `/lang/${p}/about`),
fallback: false,
})

View file

@ -0,0 +1,21 @@
import { useRouter } from 'next/router'
export async function getStaticProps() {
return {
props: { time: new Date() },
}
}
export async function getStaticPaths() {
return { paths: [], fallback: 'blocking' }
}
const Page = ({ time }) => {
const { isFallback } = useRouter()
if (isFallback) return null
return <p>hello blocking {time.toString()}</p>
}
export default Page

View file

@ -0,0 +1,21 @@
import { useRouter } from 'next/router'
export async function getStaticProps() {
return {
props: { time: new Date() },
}
}
export async function getStaticPaths() {
return { paths: [], fallback: true }
}
const Page = ({ time }) => {
const { isFallback } = useRouter()
if (isFallback) return null
return <p>hello {time.toString()}</p>
}
export default Page

View file

@ -0,0 +1 @@
export default () => <p id="normal-text">a normal page</p>

View file

@ -0,0 +1,34 @@
import React from 'react'
import Link from 'next/link'
import { useRouter } from 'next/router'
export async function getStaticProps({ params }) {
return {
props: {
world: 'world',
params: params || {},
time: new Date().getTime(),
random: Math.random(),
},
revalidate: false,
}
}
export default ({ world, time, params, random }) => {
return (
<>
<p>hello: {world}</p>
<span>time: {time}</span>
<div id="random">{random}</div>
<div id="params">{JSON.stringify(params)}</div>
<div id="query">{JSON.stringify(useRouter().query)}</div>
<Link href="/">
<a id="home">to home</a>
</Link>
<br />
<Link href="/another">
<a id="another">to another</a>
</Link>
</>
)
}

View file

@ -0,0 +1,28 @@
import React from 'react'
import Link from 'next/link'
export async function getStaticPaths() {
return { paths: [], fallback: true }
}
export async function getStaticProps({ params }) {
return {
props: {
user: params.user,
time: (await import('perf_hooks')).performance.now(),
},
revalidate: 10,
}
}
export default ({ user, time }) => {
return (
<>
<p>User: {user}</p>
<span>time: {time}</span>
<Link href="/">
<a id="home">to home</a>
</Link>
</>
)
}

View file

@ -0,0 +1 @@
world

View file

@ -1,5 +0,0 @@
module.exports = {
experimental: {
nftTracing: true,
},
}

View file

@ -1,22 +0,0 @@
module.exports = {
// target
rewrites() {
return [
{
source: '/some-rewrite/:item',
destination: '/blog/post-:item',
},
{
source: '/about',
destination: '/lang/en/about',
},
{
source: '/blocked-create',
destination: '/blocking-fallback/blocked-create',
},
]
},
experimental: {
nftTracing: true,
},
}

View file

@ -1,111 +0,0 @@
const http = require('http')
const url = require('url')
const fs = require('fs')
const path = require('path')
const server = http.createServer(async (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)
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) {
try {
return await (typeof re.render === 'function'
? re.render(req, res)
: re.default(req, res))
} catch (e) {
console.log('FAIL_FUNCTION', e)
res.statusCode = 500
res.write('FAIL_FUNCTION')
res.end()
}
}
}
})
server.listen(process.env.PORT, () => {
console.log('ready on', process.env.PORT)
})

File diff suppressed because it is too large Load diff

View file

@ -42,9 +42,11 @@ if (testModeFromFile === 'e2e') {
}
if (testMode === 'dev') {
;(global as any).isDev = true
;(global as any).isNextDev = true
} else if (testMode === 'deploy') {
;(global as any).isDeploy = true
;(global as any).isNextDeploy = true
} else {
;(global as any).isNextStart = true
}
if (!testMode) {

View file

@ -165,6 +165,10 @@ export class NextInstance {
return ''
}
public get cliOutput(): string {
return ''
}
// TODO: block these in deploy mode
public async readFile(filename: string) {
return fs.readFile(path.join(this.testDir, filename), 'utf8')

View file

@ -2,6 +2,8 @@ import { spawn } from 'child_process'
import { NextInstance } from './base'
export class NextDevInstance extends NextInstance {
private _cliOutput: string
public get buildId() {
return 'development'
}
@ -10,6 +12,10 @@ export class NextDevInstance extends NextInstance {
await super.createTestDir()
}
public get cliOutput() {
return this._cliOutput || ''
}
public async start() {
if (this.childProcess) {
throw new Error('next already started')
@ -32,11 +38,13 @@ export class NextDevInstance extends NextInstance {
this.childProcess.stdout.on('data', (chunk) => {
const msg = chunk.toString()
process.stdout.write(chunk)
this._cliOutput += msg
this.emit('stdout', [msg])
})
this.childProcess.stderr.on('data', (chunk) => {
const msg = chunk.toString()
process.stderr.write(chunk)
this._cliOutput += msg
this.emit('stderr', [msg])
})

View file

@ -5,11 +5,16 @@ import { NextInstance } from './base'
export class NextStartInstance extends NextInstance {
private _buildId: string
private _cliOutput: string
public get buildId() {
return this._buildId
}
public get cliOutput() {
return this._cliOutput
}
public async setup() {
await super.createTestDir()
}
@ -33,11 +38,13 @@ export class NextStartInstance extends NextInstance {
this.childProcess.stdout.on('data', (chunk) => {
const msg = chunk.toString()
process.stdout.write(chunk)
this._cliOutput += msg
this.emit('stdout', [msg])
})
this.childProcess.stderr.on('data', (chunk) => {
const msg = chunk.toString()
process.stderr.write(chunk)
this._cliOutput += msg
this.emit('stderr', [msg])
})
}

View file

@ -528,9 +528,8 @@ export async function retry(fn, duration = 3000, interval = 500, description) {
}
export async function hasRedbox(browser, expected = true) {
let attempts = 30
do {
const has = await evaluate(browser, () => {
for (let i = 0; i < 30; i++) {
const result = await evaluate(browser, () => {
return Boolean(
[].slice
.call(document.querySelectorAll('nextjs-portal'))
@ -541,15 +540,12 @@ export async function hasRedbox(browser, expected = true) {
)
)
})
if (has) {
return true
}
if (--attempts < 0) {
break
}
await new Promise((resolve) => setTimeout(resolve, 1000))
} while (expected)
if (result === expected) {
return result
}
await waitFor(1000)
}
return false
}

126
yarn.lock
View file

@ -6250,13 +6250,6 @@ bl@^4.1.0:
inherits "^2.0.4"
readable-stream "^3.4.0"
block-stream@*:
version "0.0.9"
resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a"
integrity sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=
dependencies:
inherits "~2.0.0"
bluebird@^3.5.0, bluebird@^3.5.5:
version "3.7.2"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
@ -9905,16 +9898,6 @@ fsevents@~2.3.1:
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.1.tgz#b209ab14c61012636c8863507edf7fb68cc54e9f"
integrity sha512-YR47Eg4hChJGAB1O3yEAOkGO+rlzutoICGqGo9EZ4lKWokzZRSyIW1QmTzqjtw8MJdj9srP869CuWw/hyzSiBw==
fstream@^1.0.0, fstream@^1.0.12:
version "1.0.12"
resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045"
integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==
dependencies:
graceful-fs "^4.1.2"
inherits "~2.0.0"
mkdirp ">=0.5 0"
rimraf "2"
function-bind@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
@ -11032,7 +11015,7 @@ inflight@^1.0.4:
once "^1.3.0"
wrappy "1"
inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3, inherits@~2.0.4:
inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3, inherits@~2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
@ -13832,7 +13815,7 @@ mkdirp-infer-owner@^2.0.0:
infer-owner "^1.0.4"
mkdirp "^1.0.3"
"mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@~0.5.1:
mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@~0.5.1:
version "0.5.5"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
dependencies:
@ -14025,11 +14008,6 @@ no-case@^2.2.0, no-case@^2.3.2:
dependencies:
lower-case "^1.1.1"
node-addon-api@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.1.0.tgz#98b21931557466c6729e51cb77cd39c965f42239"
integrity sha512-flmrDNB06LIl5lywUz7YlNGZH/5p0M7W28k8hzd9Lshtdh1wshD2Y+U4h9LD6KObOy1f+fEVdgprPrEymjM5uw==
node-dir@^0.1.17:
version "0.1.17"
resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.17.tgz#5f5665d93351335caabef8f1c554516cf5f1e4e5"
@ -14064,24 +14042,6 @@ node-gyp-build@^4.2.2:
resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.2.3.tgz#ce6277f853835f718829efb47db20f3e4d9c4739"
integrity sha512-MN6ZpzmfNCRM+3t57PTJHgHyw/h4OWnZ6mR8P5j/uZtqQr46RRuDE/P+g3n0YR/AiYXeWixZZzaip77gdICfRg==
node-gyp@3.x:
version "3.8.0"
resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.8.0.tgz#540304261c330e80d0d5edce253a68cb3964218c"
integrity sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==
dependencies:
fstream "^1.0.0"
glob "^7.0.3"
graceful-fs "^4.1.2"
mkdirp "^0.5.0"
nopt "2 || 3"
npmlog "0 || 1 || 2 || 3 || 4"
osenv "0"
request "^2.87.0"
rimraf "2"
semver "~5.3.0"
tar "^2.0.0"
which "1"
node-gyp@^5.0.2:
version "5.1.1"
resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-5.1.1.tgz#eb915f7b631c937d282e33aed44cb7a025f62a3e"
@ -14169,22 +14129,6 @@ node-notifier@5.4.0:
shellwords "^0.1.1"
which "^1.3.0"
node-pre-gyp@^0.11.0:
version "0.11.0"
resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz#db1f33215272f692cd38f03238e3e9b47c5dd054"
integrity sha512-TwWAOZb0j7e9eGaf9esRx3ZcLaE5tQ2lvYy1pb5IAaG1a2e2Kv5Lms1Y4hpj+ciXJRofIxxlt5haeQ/2ANeE0Q==
dependencies:
detect-libc "^1.0.2"
mkdirp "^0.5.1"
needle "^2.2.1"
nopt "^4.0.1"
npm-packlist "^1.1.6"
npmlog "^4.0.2"
rc "^1.2.7"
rimraf "^2.6.1"
semver "^5.3.0"
tar "^4"
node-pre-gyp@^0.13.0:
version "0.13.0"
resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.13.0.tgz#df9ab7b68dd6498137717838e4f92a33fc9daa42"
@ -14235,13 +14179,6 @@ node-version@^1.0.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/node-version/-/node-version-1.2.0.tgz#34fde3ffa8e1149bd323983479dda620e1b5060d"
"nopt@2 || 3":
version "3.0.6"
resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9"
integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k=
dependencies:
abbrev "1"
nopt@^4.0.1:
version "4.0.3"
resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48"
@ -14437,7 +14374,7 @@ npm-run-path@^4.0.0, npm-run-path@^4.0.1:
dependencies:
path-key "^3.0.0"
"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0, npmlog@^4.0.2, npmlog@^4.1.2:
npmlog@^4.0.0, npmlog@^4.0.2, npmlog@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
dependencies:
@ -14737,7 +14674,7 @@ os-tmpdir@^1.0.0, os-tmpdir@~1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
osenv@0, osenv@^0.1.4:
osenv@^0.1.4:
version "0.1.5"
resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410"
integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==
@ -17126,7 +17063,7 @@ request-promise-core@1.1.2:
dependencies:
lodash "^4.17.11"
request@^2.86.0, request@^2.87.0, request@^2.88.0, request@^2.88.2:
request@^2.86.0, request@^2.88.0, request@^2.88.2:
version "2.88.2"
resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3"
integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==
@ -17356,12 +17293,6 @@ rgba-regex@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3"
rimraf@2, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.3:
version "2.7.1"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
dependencies:
glob "^7.1.3"
rimraf@2.6.3, rimraf@~2.6.2:
version "2.6.3"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
@ -17374,6 +17305,12 @@ rimraf@3.0.0:
dependencies:
glob "^7.1.3"
rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.3:
version "2.7.1"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
dependencies:
glob "^7.1.3"
rimraf@^3.0.0, rimraf@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
@ -17668,11 +17605,6 @@ semver@^7.2.1, semver@^7.3.5:
dependencies:
lru-cache "^6.0.0"
semver@~5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8=
send@0.17.1:
version "0.17.1"
resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8"
@ -18100,21 +18032,6 @@ sprintf-js@~1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
sqlite3@5.0.2:
version "5.0.2"
resolved "https://registry.yarnpkg.com/sqlite3/-/sqlite3-5.0.2.tgz#00924adcc001c17686e0a6643b6cbbc2d3965083"
integrity sha512-1SdTNo+BVU211Xj1csWa8lV6KM0CtucDwRyA0VHl91wEH1Mgh7RxUpI4rVvG7OhHrzCSGaVyW5g8vKvlrk9DJA==
dependencies:
node-addon-api "^3.0.0"
node-pre-gyp "^0.11.0"
optionalDependencies:
node-gyp "3.x"
sqlite@4.0.22:
version "4.0.22"
resolved "https://registry.yarnpkg.com/sqlite/-/sqlite-4.0.22.tgz#4a987dbcf8ccffa9a2ccc80d8a8491c62f5d19e0"
integrity sha512-i2qvk6PyZJ35cpdocdO1DF+wMU5a6eRkcn+Dmt+HpGvYJ+pKodK6tZM0DnouCf4tXt1Whs2T2smtrEyFWAauWg==
sshpk@^1.7.0:
version "1.16.1"
resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877"
@ -18685,15 +18602,6 @@ tar@4.4.10:
safe-buffer "^5.1.2"
yallist "^3.0.3"
tar@^2.0.0:
version "2.2.2"
resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.2.tgz#0ca8848562c7299b8b446ff6a4d60cdbb23edc40"
integrity sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==
dependencies:
block-stream "*"
fstream "^1.0.12"
inherits "2"
tar@^4, tar@^4.4.12:
version "4.4.13"
resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525"
@ -20154,18 +20062,18 @@ which-typed-array@^1.1.2:
has-symbols "^1.0.1"
is-typed-array "^1.1.3"
which@1, which@^1.2.12, which@^1.2.8, which@^1.2.9, which@^1.3.0, which@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
dependencies:
isexe "^2.0.0"
which@1.2.x:
version "1.2.14"
resolved "https://registry.yarnpkg.com/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5"
dependencies:
isexe "^2.0.0"
which@^1.2.12, which@^1.2.8, which@^1.2.9, which@^1.3.0, which@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
dependencies:
isexe "^2.0.0"
which@^2.0.1, which@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"