未验证 提交 510815a7 编写于 作者: J Joe Haddad 提交者: GitHub

Add Flying Shuttle tests (#7000)

* Add Flying Shuttle tests

* Test second version of server

* Finish first version of tests

* Apply suggestions from code review
Co-Authored-By: NTimer <timer150@gmail.com>

* Apply suggestions from code review
Co-Authored-By: NTimer <timer150@gmail.com>
上级 711d45b6
import React from 'react'
import NextHead from 'next/head'
import { string } from 'prop-types'
const defaultDescription = ''
const defaultOGURL = ''
const defaultOGImage = ''
const Head = props => (
<NextHead>
<meta charSet='UTF-8' />
<title>{props.title || ''}</title>
<meta
name='description'
content={props.description || defaultDescription}
/>
<meta name='viewport' content='width=device-width, initial-scale=1' />
<link rel='icon' sizes='192x192' href='/static/touch-icon.png' />
<link rel='apple-touch-icon' href='/static/touch-icon.png' />
<link rel='mask-icon' href='/static/favicon-mask.svg' color='#49B882' />
<link rel='icon' href='/static/favicon.ico' />
<meta property='og:url' content={props.url || defaultOGURL} />
<meta property='og:title' content={props.title || ''} />
<meta
property='og:description'
content={props.description || defaultDescription}
/>
<meta name='twitter:site' content={props.url || defaultOGURL} />
<meta name='twitter:card' content='summary_large_image' />
<meta name='twitter:image' content={props.ogImage || defaultOGImage} />
<meta property='og:image' content={props.ogImage || defaultOGImage} />
<meta property='og:image:width' content='1200' />
<meta property='og:image:height' content='630' />
</NextHead>
)
Head.propTypes = {
title: string,
description: string,
url: string,
ogImage: string
}
export default Head
import React from 'react'
import Link from 'next/link'
const Nav = () => (
<nav>
<ul>
<li>
<Link prefetch href='/'>
<a>Home</a>
</Link>
</li>
<li>
<Link prefetch href='/other'>
<a>Other</a>
</Link>
</li>
<li>
<Link prefetch href='/about'>
<a>About</a>
</Link>
</li>
</ul>
<style jsx>{`
:global(body) {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, Avenir Next, Avenir,
Helvetica, sans-serif;
}
nav {
text-align: center;
}
ul {
display: flex;
justify-content: space-between;
}
nav > ul {
padding: 4px 16px;
}
li {
display: flex;
padding: 6px 8px;
}
a {
color: #067df7;
text-decoration: none;
font-size: 13px;
}
`}</style>
</nav>
)
export default Nav
import dynamic from 'next/dynamic'
const DynamicComponent = dynamic(() => import('./something2'))
export default () => (
<>
<div>lol</div>
<DynamicComponent />
</>
)
export default () => <div>omega lol</div>
module.exports = {
target: 'serverless',
experimental: {
flyingShuttle: true
}
}
import React from 'react'
import Head from '../../components/head'
import Nav from '../../components/nav'
import dynamic from 'next/dynamic'
const DynamicComponent = dynamic(() => import('../../components/something'))
const About = () => (
<div>
<Head title='About' />
<Nav />
<div className='hero'>
<h1 className='title'>All About Next.js!</h1>
<p className='description'>
To get started, edit <code>pages/about/index.js</code> and save to
reload.
</p>
</div>
<DynamicComponent />
<style jsx>{`
.hero {
width: 100%;
color: #333;
}
.title {
margin: 0;
width: 100%;
padding-top: 80px;
line-height: 1.15;
font-size: 48px;
}
.title,
.description {
text-align: center;
}
`}</style>
</div>
)
export default About
import React from 'react'
import Head from '../../components/head'
import Nav from '../../components/nav'
import dynamic from 'next/dynamic'
const DynamicComponent = dynamic(() => import('../../components/something'))
const About = () => (
<div>
<Head title='About' />
<Nav />
<div className='hero'>
<h1 className='title'>Everything About Next.js!</h1>
<p className='description'>
To get started, edit <code>pages/about/index.js</code> and save to
reload.
</p>
</div>
<DynamicComponent />
<style jsx>{`
.hero {
width: 100%;
color: #333;
}
.title {
margin: 0;
width: 100%;
padding-top: 80px;
line-height: 1.15;
font-size: 48px;
}
.title,
.description {
text-align: center;
}
`}</style>
</div>
)
export default About
import React from 'react'
import Head from '../components/head'
import Nav from '../components/nav'
import dynamic from 'next/dynamic'
const DynamicComponent = dynamic(() => import('../components/something'))
const Home = () => (
<div>
<Head title='Home' />
<Nav />
<div className='hero'>
<h1 className='title'>Welcome to Next.js!</h1>
<p className='description'>
To get started, edit <code>pages/index.js</code> and save to reload.
</p>
</div>
<DynamicComponent />
<style jsx>{`
.hero {
width: 100%;
color: #333;
}
.title {
margin: 0;
width: 100%;
padding-top: 80px;
line-height: 1.15;
font-size: 48px;
}
.title,
.description {
text-align: center;
}
`}</style>
</div>
)
export default Home
import React from 'react'
import Head from '../components/head'
import Nav from '../components/nav'
import dynamic from 'next/dynamic'
const DynamicComponent = dynamic(() => import('../components/something'))
const Home = () => (
<div>
<Head title='Other' />
<Nav />
<div className='hero'>
<h1 className='title'>Welcome to Other Next.js!</h1>
<p className='description'>
To get started, edit <code>pages/other.js</code> and save to reload.
</p>
</div>
<DynamicComponent />
<style jsx>{`
.hero {
width: 100%;
color: #333;
}
.title {
margin: 0;
width: 100%;
padding-top: 80px;
line-height: 1.15;
font-size: 48px;
}
.title,
.description {
text-align: center;
}
`}</style>
</div>
)
export default Home
const start = require('./server')
start(3000).then(() => console.log('http://localhost:3000'))
const express = require('express')
const http = require('http')
const path = require('path')
module.exports = function start (
port = 0,
directory = path.join(__dirname, '.next')
) {
return new Promise((resolve, reject) => {
const app = express()
const nextStaticDir = path.join(directory, 'static')
app.use('/_next/static', express.static(nextStaticDir))
app.get('/', (req, res) => {
require(path.join(directory, 'serverless/pages/index.js')).render(
req,
res
)
})
try {
const o = require(path.join(directory, 'serverless/pages/other.js'))
app.get('/other', (req, res) => {
o.render(req, res)
})
} catch (_) {
// ignored
}
app.get('/about', (req, res) => {
require(path.join(directory, 'serverless/pages/about.js')).render(
req,
res
)
})
const server = new http.Server(app)
server.listen(port, err => {
if (err) {
return reject(err)
}
resolve(server)
})
})
}
/* eslint-env jest */
/* global jasmine, test */
import webdriver from 'next-webdriver'
import path from 'path'
import {
runNextCommand,
stopApp,
renderViaHTTP,
waitFor
} from 'next-test-utils'
import stripAnsi from 'strip-ansi'
import startServer from '../server'
import fs from 'fs-extra'
const appDir = path.join(__dirname, '../')
let appPort
let secondAppPort
let server
let secondServer
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 60 * 5
describe('Flying Shuttle', () => {
beforeAll(async () => {
{
await fs.remove(path.join(appDir, '.next-first'))
await fs.mkdirp(path.join(appDir, '.next-first'))
const { stdout } = await runNextCommand(['build', appDir], {
stdout: true
})
const buildText = stripAnsi(stdout)
expect(buildText).toMatch(/could not locate flying shuttle/)
await fs.copy(
path.join(appDir, '.next'),
path.join(appDir, '.next-first')
)
server = await startServer(0, path.join(appDir, '.next-first'))
appPort = server.address().port
}
{
await fs.remove(path.join(appDir, '.next-second'))
await fs.mkdirp(path.join(appDir, '.next-second'))
await fs.rename(
path.join(appDir, 'pages', 'other.js'),
path.join(appDir, 'pages', 'other.js.hide')
)
await fs.rename(
path.join(appDir, 'pages', 'about', 'index.js'),
path.join(appDir, 'pages', 'about', 'index.js.hide')
)
await fs.rename(
path.join(appDir, 'pages', 'about', 'index.js2'),
path.join(appDir, 'pages', 'about', 'index.js')
)
const { stdout } = await runNextCommand(['build', appDir], {
stdout: true
})
const buildText = stripAnsi(stdout)
expect(buildText).toMatch(/found 2 changed and 1 unchanged page/)
await fs.copy(
path.join(appDir, '.next'),
path.join(appDir, '.next-second')
)
secondServer = await startServer(0, path.join(appDir, '.next-second'))
secondAppPort = secondServer.address().port
}
})
afterAll(async () => {
if (server) await stopApp(server)
if (secondServer) await stopApp(secondServer)
await fs.remove(path.join(appDir, '.next-first'))
await fs.remove(path.join(appDir, '.next-second'))
await fs.rename(
path.join(appDir, 'pages', 'other.js.hide'),
path.join(appDir, 'pages', 'other.js')
)
await fs.rename(
path.join(appDir, 'pages', 'about', 'index.js'),
path.join(appDir, 'pages', 'about', 'index.js2')
)
await fs.rename(
path.join(appDir, 'pages', 'about', 'index.js.hide'),
path.join(appDir, 'pages', 'about', 'index.js')
)
})
it('should render /index', async () => {
const html = await renderViaHTTP(appPort, '/')
expect(html).toMatch(/omega lol/)
expect(html).toMatch(/Welcome to Next/)
})
it('should render /other', async () => {
const html = await renderViaHTTP(appPort, '/other')
expect(html).toMatch(/omega lol/)
expect(html).toMatch(/Welcome to Other Next/)
})
it('should render /about', async () => {
const html = await renderViaHTTP(appPort, '/about')
expect(html).toMatch(/omega lol/)
expect(html).toMatch(/All About/)
})
it('should hydrate correctly /index', async () => {
const browser = await webdriver(appPort, '/')
try {
let text = await browser.text()
await waitFor(3000)
text = await browser.text()
expect(text).toMatch(/omega lol/)
expect(text).toMatch(/Welcome to Next/)
} finally {
await browser.close()
}
})
it('should hydrate correctly /other', async () => {
const browser = await webdriver(appPort, '/other')
try {
let text = await browser.text()
await waitFor(3000)
text = await browser.text()
expect(text).toMatch(/omega lol/)
expect(text).toMatch(/Welcome to Other Next/)
} finally {
await browser.close()
}
})
it('should hydrate correctly /about', async () => {
const browser = await webdriver(appPort, '/about')
try {
let text = await browser.text()
await waitFor(3000)
text = await browser.text()
expect(text).toMatch(/omega lol/)
expect(text).toMatch(/All About/)
} finally {
await browser.close()
}
})
it('should render /index', async () => {
const html = await renderViaHTTP(secondAppPort, '/')
expect(html).toMatch(/omega lol/)
expect(html).toMatch(/Welcome to Next/)
})
it('should 404 /other', async () => {
const html = await renderViaHTTP(secondAppPort, '/other')
expect(html).toMatch(/Cannot GET \/other/)
})
it('should render /about', async () => {
const html = await renderViaHTTP(secondAppPort, '/about')
expect(html).toMatch(/omega lol/)
expect(html).toMatch(/Everything About/)
})
it('should hydrate correctly /index', async () => {
const browser = await webdriver(secondAppPort, '/')
try {
let text = await browser.text()
await waitFor(3000)
text = await browser.text()
expect(text).toMatch(/omega lol/)
expect(text).toMatch(/Welcome to Next/)
} finally {
await browser.close()
}
})
it('should 404 on /other', async () => {
const browser = await webdriver(secondAppPort, '/other')
try {
const text = await browser.text()
expect(text).toMatch(/Cannot GET \/other/)
} finally {
await browser.close()
}
})
it('should hydrate correctly /about', async () => {
const browser = await webdriver(secondAppPort, '/about')
try {
let text = await browser.text()
await waitFor(3000)
text = await browser.text()
expect(text).toMatch(/omega lol/)
expect(text).toMatch(/Everything About/)
} finally {
await browser.close()
}
})
})
......@@ -5662,7 +5662,7 @@ fs-extra@5.0.0:
jsonfile "^4.0.0"
universalify "^0.1.0"
fs-extra@^7.0.0:
fs-extra@7.0.1, fs-extra@^7.0.0:
version "7.0.1"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9"
integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册