1
0
Fork 0
mirror of https://github.com/terribleplan/next.js.git synced 2024-01-19 02:48:18 +00:00
next.js/test/lib/next-test-utils.js

272 lines
6.9 KiB
JavaScript
Raw Normal View History

New test setup (#640) * Use jest-cli instead of gulp plugin. * Use jest-cli instead of gulp plugin. * Move fixtures into the examples dir. * Move test code of example app to the basic example. * Add isolated tests for server/resolve * Allow tests to use cheerio. * Use portfinder to get a unique port. * Move back integration tests into the example dir. * Introduce next-test-utils. * Remove gulp-jest * Add coveralls support. * Use transpiled version of code in dist. This is to make sure same file gets covered by both unit/isolated tests and integration tests. * Add support for source maps. * Use code from dist always. * Use nyc to stop instrument. * Add integration test suite for production usage. * Use jest-cli. * Add support for running e2e tests. * Check gzipPath with fs.stat before serving Otherwise, serve package might throw issues other than ENOENT * Install chromedriver with npm install. * Install chrome on travis-ci. * Add --forceExit to Jest. * Run tests only on Node v6. That's because selenium-webdriver only supports Node 6 LTS. * Use chromedriver NPM module to install chromedriver. * Use wd as the webdriver client. * Run chromedriver before tests. * Run travis for both node 4 and 6 * Remove unwanted npm install script. * Move some common text utilities to next-test-utils * Add lint checks and testing in npm prepublish hook. * Use npm on travis-ci. We are having some caching issues with yarn and chromedriver. * Make tests work on windows.\n But chromedriver doesn't work. * Clean up dependencies. * Run chromedriver in background without any tools. * Fix a typo in the code. * Use ES6 features used in node4 inside the gulpfile. * Add some comments. * Add support for running in windows. * Stop chromedriver properly on windows. * Fix typos.
2017-01-12 04:14:49 +00:00
import fetch from 'node-fetch'
import qs from 'querystring'
import http from 'http'
2017-05-09 23:24:34 +00:00
import express from 'express'
import path from 'path'
import getPort from 'get-port'
import spawn from 'cross-spawn'
import { readFileSync, writeFileSync, existsSync, unlinkSync } from 'fs'
import fkill from 'fkill'
New test setup (#640) * Use jest-cli instead of gulp plugin. * Use jest-cli instead of gulp plugin. * Move fixtures into the examples dir. * Move test code of example app to the basic example. * Add isolated tests for server/resolve * Allow tests to use cheerio. * Use portfinder to get a unique port. * Move back integration tests into the example dir. * Introduce next-test-utils. * Remove gulp-jest * Add coveralls support. * Use transpiled version of code in dist. This is to make sure same file gets covered by both unit/isolated tests and integration tests. * Add support for source maps. * Use code from dist always. * Use nyc to stop instrument. * Add integration test suite for production usage. * Use jest-cli. * Add support for running e2e tests. * Check gzipPath with fs.stat before serving Otherwise, serve package might throw issues other than ENOENT * Install chromedriver with npm install. * Install chrome on travis-ci. * Add --forceExit to Jest. * Run tests only on Node v6. That's because selenium-webdriver only supports Node 6 LTS. * Use chromedriver NPM module to install chromedriver. * Use wd as the webdriver client. * Run chromedriver before tests. * Run travis for both node 4 and 6 * Remove unwanted npm install script. * Move some common text utilities to next-test-utils * Add lint checks and testing in npm prepublish hook. * Use npm on travis-ci. We are having some caching issues with yarn and chromedriver. * Make tests work on windows.\n But chromedriver doesn't work. * Clean up dependencies. * Run chromedriver in background without any tools. * Fix a typo in the code. * Use ES6 features used in node4 inside the gulpfile. * Add some comments. * Add support for running in windows. * Stop chromedriver properly on windows. * Fix typos.
2017-01-12 04:14:49 +00:00
// `next` here is the symlink in `test/node_modules/next` which points to the root directory.
// This is done so that requiring from `next` works.
// The reason we don't import the relative path `../../dist/<etc>` is that it would lead to inconsistent module singletons
import server from 'next/dist/server/next'
import _pkg from 'next/package.json'
New test setup (#640) * Use jest-cli instead of gulp plugin. * Use jest-cli instead of gulp plugin. * Move fixtures into the examples dir. * Move test code of example app to the basic example. * Add isolated tests for server/resolve * Allow tests to use cheerio. * Use portfinder to get a unique port. * Move back integration tests into the example dir. * Introduce next-test-utils. * Remove gulp-jest * Add coveralls support. * Use transpiled version of code in dist. This is to make sure same file gets covered by both unit/isolated tests and integration tests. * Add support for source maps. * Use code from dist always. * Use nyc to stop instrument. * Add integration test suite for production usage. * Use jest-cli. * Add support for running e2e tests. * Check gzipPath with fs.stat before serving Otherwise, serve package might throw issues other than ENOENT * Install chromedriver with npm install. * Install chrome on travis-ci. * Add --forceExit to Jest. * Run tests only on Node v6. That's because selenium-webdriver only supports Node 6 LTS. * Use chromedriver NPM module to install chromedriver. * Use wd as the webdriver client. * Run chromedriver before tests. * Run travis for both node 4 and 6 * Remove unwanted npm install script. * Move some common text utilities to next-test-utils * Add lint checks and testing in npm prepublish hook. * Use npm on travis-ci. We are having some caching issues with yarn and chromedriver. * Make tests work on windows.\n But chromedriver doesn't work. * Clean up dependencies. * Run chromedriver in background without any tools. * Fix a typo in the code. * Use ES6 features used in node4 inside the gulpfile. * Add some comments. * Add support for running in windows. * Stop chromedriver properly on windows. * Fix typos.
2017-01-12 04:14:49 +00:00
export const nextServer = server
export const pkg = _pkg
export function initNextServerScript (scriptPath, successRegexp, env) {
return new Promise((resolve, reject) => {
const instance = spawn('node', [scriptPath], { env })
function handleStdout (data) {
const message = data.toString()
if (successRegexp.test(message)) {
resolve(instance)
}
process.stdout.write(message)
}
function handleStderr (data) {
process.stderr.write(data.toString())
}
instance.stdout.on('data', handleStdout)
instance.stderr.on('data', handleStderr)
instance.on('close', () => {
instance.stdout.removeListener('data', handleStdout)
instance.stderr.removeListener('data', handleStderr)
})
instance.on('error', (err) => {
reject(err)
})
})
}
export function renderViaAPI (app, pathname, query) {
const url = `${pathname}${query ? `?${qs.stringify(query)}` : ''}`
return app.renderToHTML({ url }, {}, pathname, query)
New test setup (#640) * Use jest-cli instead of gulp plugin. * Use jest-cli instead of gulp plugin. * Move fixtures into the examples dir. * Move test code of example app to the basic example. * Add isolated tests for server/resolve * Allow tests to use cheerio. * Use portfinder to get a unique port. * Move back integration tests into the example dir. * Introduce next-test-utils. * Remove gulp-jest * Add coveralls support. * Use transpiled version of code in dist. This is to make sure same file gets covered by both unit/isolated tests and integration tests. * Add support for source maps. * Use code from dist always. * Use nyc to stop instrument. * Add integration test suite for production usage. * Use jest-cli. * Add support for running e2e tests. * Check gzipPath with fs.stat before serving Otherwise, serve package might throw issues other than ENOENT * Install chromedriver with npm install. * Install chrome on travis-ci. * Add --forceExit to Jest. * Run tests only on Node v6. That's because selenium-webdriver only supports Node 6 LTS. * Use chromedriver NPM module to install chromedriver. * Use wd as the webdriver client. * Run chromedriver before tests. * Run travis for both node 4 and 6 * Remove unwanted npm install script. * Move some common text utilities to next-test-utils * Add lint checks and testing in npm prepublish hook. * Use npm on travis-ci. We are having some caching issues with yarn and chromedriver. * Make tests work on windows.\n But chromedriver doesn't work. * Clean up dependencies. * Run chromedriver in background without any tools. * Fix a typo in the code. * Use ES6 features used in node4 inside the gulpfile. * Add some comments. * Add support for running in windows. * Stop chromedriver properly on windows. * Fix typos.
2017-01-12 04:14:49 +00:00
}
export function renderViaHTTP (appPort, pathname, query) {
return fetchViaHTTP(appPort, pathname, query).then((res) => res.text())
}
export function fetchViaHTTP (appPort, pathname, query) {
const url = `http://localhost:${appPort}${pathname}${query ? `?${qs.stringify(query)}` : ''}`
return fetch(url)
New test setup (#640) * Use jest-cli instead of gulp plugin. * Use jest-cli instead of gulp plugin. * Move fixtures into the examples dir. * Move test code of example app to the basic example. * Add isolated tests for server/resolve * Allow tests to use cheerio. * Use portfinder to get a unique port. * Move back integration tests into the example dir. * Introduce next-test-utils. * Remove gulp-jest * Add coveralls support. * Use transpiled version of code in dist. This is to make sure same file gets covered by both unit/isolated tests and integration tests. * Add support for source maps. * Use code from dist always. * Use nyc to stop instrument. * Add integration test suite for production usage. * Use jest-cli. * Add support for running e2e tests. * Check gzipPath with fs.stat before serving Otherwise, serve package might throw issues other than ENOENT * Install chromedriver with npm install. * Install chrome on travis-ci. * Add --forceExit to Jest. * Run tests only on Node v6. That's because selenium-webdriver only supports Node 6 LTS. * Use chromedriver NPM module to install chromedriver. * Use wd as the webdriver client. * Run chromedriver before tests. * Run travis for both node 4 and 6 * Remove unwanted npm install script. * Move some common text utilities to next-test-utils * Add lint checks and testing in npm prepublish hook. * Use npm on travis-ci. We are having some caching issues with yarn and chromedriver. * Make tests work on windows.\n But chromedriver doesn't work. * Clean up dependencies. * Run chromedriver in background without any tools. * Fix a typo in the code. * Use ES6 features used in node4 inside the gulpfile. * Add some comments. * Add support for running in windows. * Stop chromedriver properly on windows. * Fix typos.
2017-01-12 04:14:49 +00:00
}
export function findPort () {
return getPort()
}
export function runNextCommand (argv, options = {}) {
const cwd = path.dirname(require.resolve('next/package'))
return new Promise((resolve, reject) => {
console.log(`Running command "next ${argv.join(' ')}"`)
const instance = spawn('node', ['dist/bin/next', ...argv], { cwd, stdio: options.stdout ? ['ignore', 'pipe', 'ignore'] : 'inherit' })
let stdoutOutput = ''
if (options.stdout) {
instance.stdout.on('data', function (chunk) {
stdoutOutput += chunk
})
}
instance.on('close', () => {
resolve({
stdout: stdoutOutput
})
})
instance.on('error', (err) => {
reject(err)
})
})
}
export function runNextCommandDev (argv, stdOut) {
const cwd = path.dirname(require.resolve('next/package'))
return new Promise((resolve, reject) => {
const instance = spawn('node', ['dist/bin/next', ...argv], { cwd })
function handleStdout (data) {
const message = data.toString()
if (/> Ready on/.test(message)) {
resolve(stdOut ? message : instance)
}
process.stdout.write(message)
}
function handleStderr (data) {
process.stderr.write(data.toString())
}
instance.stdout.on('data', handleStdout)
instance.stderr.on('data', handleStderr)
instance.on('close', () => {
instance.stdout.removeListener('data', handleStdout)
instance.stderr.removeListener('data', handleStderr)
})
instance.on('error', (err) => {
reject(err)
})
})
}
// Launch the app in dev mode.
export function launchApp (dir, port) {
return runNextCommandDev([dir, '-p', port])
}
export function nextBuild (dir) {
return runNextCommand(['build', dir])
}
export function nextExport (dir, {outdir}) {
return runNextCommand(['export', dir, '--outdir', outdir])
}
// Kill a launched app
export async function killApp (instance) {
await fkill(instance.pid)
}
export async function startApp (app) {
await app.prepare()
const handler = app.getRequestHandler()
const server = http.createServer(handler)
server.__app = app
await promiseCall(server, 'listen')
return server
}
export async function stopApp (server) {
2017-05-09 23:24:34 +00:00
if (server.__app) {
await server.__app.close()
}
await promiseCall(server, 'close')
}
function promiseCall (obj, method, ...args) {
return new Promise((resolve, reject) => {
const newArgs = [
...args,
function (err, res) {
if (err) return reject(err)
resolve(res)
}
]
obj[method](...newArgs)
})
}
export function waitFor (millis) {
return new Promise((resolve) => setTimeout(resolve, millis))
}
2017-05-09 23:24:34 +00:00
export async function startStaticServer (dir) {
const app = express()
const server = http.createServer(app)
app.use(express.static(dir))
await promiseCall(server, 'listen')
return server
}
export async function check (contentFn, regex) {
let found = false
const timeout = setTimeout(async () => {
if (found) {
return
}
let content
try {
content = await contentFn()
} catch (err) {
console.error('Error while getting content', {regex})
}
console.error('TIMED OUT CHECK: ', {regex, content})
throw new Error('TIMED OUT: ' + regex + '\n\n' + content)
}, 1000 * 30)
while (!found) {
try {
const newContent = await contentFn()
if (regex.test(newContent)) {
found = true
clearTimeout(timeout)
break
}
await waitFor(1000)
} catch (ex) {}
}
}
export class File {
constructor (path) {
this.path = path
this.originalContent = existsSync(this.path) ? readFileSync(this.path, 'utf8') : null
}
write (content) {
if (!this.originalContent) {
this.originalContent = content
}
writeFileSync(this.path, content, 'utf8')
}
replace (pattern, newValue) {
const newContent = this.originalContent.replace(pattern, newValue)
this.write(newContent)
}
delete () {
unlinkSync(this.path)
}
restore () {
this.write(this.originalContent)
}
}
// react-error-overlay uses an iframe so we have to read the contents from the frame
export async function getReactErrorOverlayContent (browser) {
let found = false
setTimeout(() => {
if (found) {
return
}
console.error('TIMED OUT CHECK FOR IFRAME')
throw new Error('TIMED OUT CHECK FOR IFRAME')
}, 1000 * 30)
while (!found) {
try {
await browser.waitForElementByCss('iframe', 10000)
const hasIframe = await browser.hasElementByCssSelector('iframe')
if (!hasIframe) {
throw new Error('Waiting for iframe')
}
found = true
return browser.eval(`document.querySelector('iframe').contentWindow.document.body.innerHTML`)
} catch (ex) {
await waitFor(1000)
}
}
return browser.eval(`document.querySelector('iframe').contentWindow.document.body.innerHTML`)
}
export function getBrowserBodyText (browser) {
return browser.eval('document.getElementsByTagName("body")[0].innerText')
}