Update a couple flakey tests (#37071)

This commit is contained in:
JJ Kasper 2022-05-20 12:44:11 -05:00 committed by GitHub
parent 036ffa7057
commit 5af2fbb3a7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 134 additions and 294 deletions

View file

@ -491,12 +491,8 @@ describe('CLI Usage', () => {
stdout: true,
stderr: true,
})
expect((info.stderr || '').toLowerCase()).not.toContain('error')
// when a stable release is done the non-latest canary
// warning will show so skip this check for the stable release
if (pkg.version.includes('-canary')) {
expect(info.stderr || '').toBe('')
}
expect(info.stdout).toMatch(
new RegExp(`
Operating System:

View file

@ -1,3 +0,0 @@
{
"presets": ["next/babel"]
}

View file

@ -1,14 +0,0 @@
{
"name": "pnpm-app-multi-page",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"react": "^17.0.2",
"react-dom": "^17.0.2"
}
}

View file

@ -1,3 +0,0 @@
{
"presets": ["next/babel"]
}

View file

@ -1,14 +0,0 @@
{
"name": "pnpm-app",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"react": "^17.0.2",
"react-dom": "^17.0.2"
}
}

View file

@ -1,255 +0,0 @@
/* eslint-env jest */
import execa from 'execa'
import fs from 'fs-extra'
import os from 'os'
import path from 'path'
import { findPort, killProcess, renderViaHTTP, waitFor } from 'next-test-utils'
import webdriver from 'next-webdriver'
const packagesDir = path.join(__dirname, '..', '..', '..', '..', 'packages')
const APP_DIRS = {
app: path.join(__dirname, '..', 'app'),
'app-multi-page': path.join(__dirname, '..', 'app-multi-page'),
}
// runs a command showing logs and returning the stdout
const runCommand = (cwd, cmd, args) => {
const proc = execa(cmd, [...args], {
cwd,
stdio: [process.stdin, 'pipe', process.stderr],
})
let stdout = ''
proc.stdout.on('data', (data) => {
const s = data.toString()
process.stdout.write(s)
stdout += s
})
return new Promise((resolve, reject) => {
proc.on('exit', (code) => {
if (code === 0) {
return resolve({ ...proc, stdout })
}
reject(
new Error(`Command ${cmd} ${args.join(' ')} failed with code ${code}`)
)
})
})
}
const runNpm = (cwd, ...args) => execa('npm', [...args], { cwd })
const runPnpm = (cwd, ...args) => runCommand(cwd, 'npx', ['pnpm', ...args])
async function usingTempDir(fn) {
const folder = path.join(os.tmpdir(), Math.random().toString(36).substring(2))
await fs.mkdirp(folder)
try {
return await fn(folder)
} finally {
await fs.remove(folder)
}
}
/**
* Using 'npm pack', create a tarball of the given package in
* directory `pkg` and write it to `cwd`.
*
* `pkg` is relative to the monorepo 'packages/' directory.
*
* Return the absolute path to the tarball.
*/
async function pack(cwd, pkg) {
const pkgDir = path.join(packagesDir, pkg)
const { stdout } = await runNpm(
cwd,
'pack',
'--ignore-scripts', // Skip the prepublish script
path.join(packagesDir, pkg)
)
const tarballFilename = stdout.match(/.*\.tgz/)[0]
if (!tarballFilename) {
throw new Error(
`npm failed to pack "next" package tarball in directory ${pkgDir}.`
)
}
return path.join(cwd, tarballFilename)
}
/**
* Create a Next.js app in a temporary directory, and install dependencies with pnpm.
*
* "next" and its monorepo dependencies are installed by `npm pack`-ing tarballs from
* 'next.js/packages/*', because installing "next" directly via
* `pnpm add path/to/next.js/packages/next` results in a symlink:
* 'app/node_modules/next' -> 'path/to/next.js/packages/next'.
* This is undesired since modules inside "next" would be resolved to the
* next.js monorepo 'node_modules' and lead to false test results;
* installing from a tarball avoids this issue.
*
* The "next" package's monorepo dependencies (e.g. "@next/env", "@next/polyfill-module")
* are not bundled with `npm pack next.js/packages/next`,
* so they need to be packed individually.
* To ensure that they are installed upon installing "next", a package.json "pnpm.overrides"
* field is used to override these dependency paths at install time.
*/
async function usingPnpmCreateNextApp(appDir, fn) {
await usingTempDir(async (tempDir) => {
const nextTarballPath = await pack(tempDir, 'next')
const dependencyTarballPaths = {
'@next/env': await pack(tempDir, 'next-env'),
'@next/polyfill-module': await pack(tempDir, 'next-polyfill-module'),
'@next/polyfill-nomodule': await pack(tempDir, 'next-polyfill-nomodule'),
'@next/react-dev-overlay': await pack(tempDir, 'react-dev-overlay'),
'@next/react-refresh-utils': await pack(tempDir, 'react-refresh-utils'),
}
const tempAppDir = path.join(tempDir, 'app')
await fs.copy(appDir, tempAppDir)
// Inject dependency tarball paths into a "pnpm.overrides" field in package.json,
// so that they are installed from packed tarballs rather than from the npm registry.
const packageJsonPath = path.join(tempAppDir, 'package.json')
const overrides = {}
for (const [dependency, tarballPath] of Object.entries(
dependencyTarballPaths
)) {
overrides[dependency] = `file:${tarballPath}`
}
const packageJsonWithOverrides = {
...(await fs.readJson(packageJsonPath)),
pnpm: { overrides },
}
await fs.writeFile(
packageJsonPath,
JSON.stringify(packageJsonWithOverrides, null, 2)
)
await runPnpm(tempAppDir, 'install')
await runPnpm(tempAppDir, 'add', `next@${nextTarballPath}`)
await fs.copy(
path.join(__dirname, '../../../../packages/next-swc/native'),
path.join(tempAppDir, 'node_modules/@next/swc/native')
)
await fn(tempAppDir)
})
}
describe('pnpm support', () => {
it('should build with dependencies installed via pnpm', async () => {
await usingPnpmCreateNextApp(APP_DIRS['app'], async (appDir) => {
expect(
await fs.pathExists(path.join(appDir, 'pnpm-lock.yaml'))
).toBeTruthy()
const packageJsonPath = path.join(appDir, 'package.json')
const packageJson = await fs.readJson(packageJsonPath)
expect(packageJson.dependencies['next']).toMatch(/^file:/)
for (const dependency of [
'@next/env',
'@next/polyfill-module',
'@next/polyfill-nomodule',
'@next/react-dev-overlay',
'@next/react-refresh-utils',
]) {
expect(packageJson.pnpm.overrides[dependency]).toMatch(/^file:/)
}
const { stdout } = await runPnpm(appDir, 'run', 'build')
expect(stdout).toMatch(/Compiled successfully/)
})
})
it('should execute client-side JS on each page in outputStandalone', async () => {
await usingPnpmCreateNextApp(APP_DIRS['app-multi-page'], async (appDir) => {
const { stdout } = await runPnpm(appDir, 'run', 'build')
expect(stdout).toMatch(/Compiled successfully/)
let appPort
let appProcess
let browser
try {
appPort = await findPort()
const standaloneDir = path.resolve(appDir, '.next/standalone/app')
// simulate what happens in a Dockerfile
await fs.remove(path.join(appDir, 'node_modules'))
await fs.copy(
path.resolve(appDir, './.next/static'),
path.resolve(standaloneDir, './.next/static'),
{ overwrite: true }
)
appProcess = execa('node', ['server.js'], {
cwd: standaloneDir,
env: {
PORT: appPort,
},
stdio: 'inherit',
})
await waitFor(1000)
await renderViaHTTP(appPort, '/')
browser = await webdriver(appPort, '/', {
waitHydration: false,
})
expect(await browser.waitForElementByCss('#world').text()).toBe('World')
await browser.close()
browser = await webdriver(appPort, '/about', {
waitHydration: false,
})
expect(await browser.waitForElementByCss('#world').text()).toBe('World')
await browser.close()
} finally {
await killProcess(appProcess.pid)
await waitFor(5000)
}
})
})
it('should execute client-side JS on each page', async () => {
await usingPnpmCreateNextApp(APP_DIRS['app-multi-page'], async (appDir) => {
const { stdout } = await runPnpm(appDir, 'run', 'build')
expect(stdout).toMatch(/Compiled successfully/)
let appPort
let appProcess
let browser
try {
appPort = await findPort()
appProcess = execa('pnpm', ['run', 'start', '--', '--port', appPort], {
cwd: appDir,
stdio: 'inherit',
})
await waitFor(5000)
await renderViaHTTP(appPort, '/')
browser = await webdriver(appPort, '/', {
waitHydration: false,
})
expect(await browser.waitForElementByCss('#world').text()).toBe('World')
await browser.close()
browser = await webdriver(appPort, '/about', {
waitHydration: false,
})
expect(await browser.waitForElementByCss('#world').text()).toBe('World')
await browser.close()
} finally {
await killProcess(appProcess.pid)
await waitFor(5000)
}
})
})
})

View file

@ -0,0 +1,133 @@
/* eslint-env jest */
import path from 'path'
import execa from 'execa'
import fs from 'fs-extra'
import webdriver from 'next-webdriver'
import { createNext, FileRef } from 'e2e-utils'
import { NextInstance } from 'test/lib/next-modes/base'
import {
findPort,
initNextServerScript,
killApp,
renderViaHTTP,
} from 'next-test-utils'
describe('pnpm support', () => {
let next: NextInstance | undefined
beforeAll(async () => {
try {
const version = await execa('pnpm', ['--version'])
console.warn(`using pnpm version`, version.stdout)
} catch (_) {
// install pnpm if not available
await execa('npm', ['i', '-g', 'pnpm@latest'])
}
})
afterEach(async () => {
try {
await next?.destroy()
} catch (_) {}
})
it('should build with dependencies installed via pnpm', async () => {
next = await createNext({
files: {
pages: new FileRef(path.join(__dirname, '..', 'app/pages')),
'next.config.js': new FileRef(
path.join(__dirname, '..', 'app/next.config.js')
),
},
packageJson: {
scripts: {
build: 'next build',
start: 'next start',
},
},
installCommand: 'pnpm install',
buildCommand: 'pnpm run build',
})
expect(await next.readFile('pnpm-lock.yaml')).toBeTruthy()
expect(next.cliOutput).toMatch(/Compiled successfully/)
const html = await renderViaHTTP(next.url, '/')
expect(html).toContain('Hello World')
})
it('should execute client-side JS on each page in outputStandalone', async () => {
next = await createNext({
files: {
pages: new FileRef(path.join(__dirname, '..', 'app-multi-page/pages')),
'.npmrc': new FileRef(
path.join(__dirname, '..', 'app-multi-page/.npmrc')
),
'next.config.js': new FileRef(
path.join(__dirname, '..', 'app-multi-page/next.config.js')
),
},
packageJson: {
scripts: {
dev: 'next dev',
build: 'next build',
start: 'next start',
},
},
buildCommand: 'pnpm run build',
installCommand: '',
})
await next.stop()
expect(next.cliOutput).toMatch(/Compiled successfully/)
let appPort
let server
let browser
try {
appPort = await findPort()
const standaloneDir = path.join(
next.testDir,
'.next/standalone/',
path.basename(next.testDir)
)
// simulate what happens in a Dockerfile
await fs.remove(path.join(next.testDir, 'node_modules'))
await fs.copy(
path.join(next.testDir, './.next/static'),
path.join(standaloneDir, './.next/static'),
{ overwrite: true }
)
server = await initNextServerScript(
path.join(standaloneDir, 'server.js'),
/Listening/,
{
...process.env,
PORT: appPort,
},
undefined,
{
cwd: standaloneDir,
}
)
await renderViaHTTP(appPort, '/')
browser = await webdriver(appPort, '/', {
waitHydration: false,
})
expect(await browser.waitForElementByCss('#world').text()).toBe('World')
await browser.close()
browser = await webdriver(appPort, '/about', {
waitHydration: false,
})
expect(await browser.waitForElementByCss('#world').text()).toBe('World')
await browser.close()
} finally {
if (server) {
await killApp(server)
}
}
})
})