rsnext/test/lib/e2e-utils.ts
JJ Kasper 613e4c91e3
Update yarn PnP tests and disable swc file reading for PnP (#33236)
* Update yarn PnP tests and disable swc file reading for PnP

* update job

* Update test

* add env variable

* update destory

* test one

* bump timeout

* update pnp install command

* only run pnp test

* add more logs

* handle exit signal

* dont inherit stdio for install

* update server start

* re-add test type

* add build log

* additional logging

* update build command

* remove separate timeout

* update install command

* install separate for better time info

* add cache pre-warming

* update yarn config

* enable other pnp tests

* Separate out tests

* fix-lint

* update path

* update test concurrency for isolated tests

* update retries

* Revert "update test concurrency for isolated tests"

This reverts commit 3a6e924df8ec61d55d3ee8a58d24cd50f0141195.

* re-enable production tests

* apply suggestions
2022-01-14 09:43:30 -06:00

151 lines
3.7 KiB
TypeScript

import path from 'path'
import assert from 'assert'
import { NextConfig } from 'next'
import { InstallCommand, NextInstance } from './next-modes/base'
import { NextDevInstance } from './next-modes/next-dev'
import { NextStartInstance } from './next-modes/next-start'
const testsFolder = path.join(__dirname, '..')
let testFile
const testFileRegex = /\.test\.(js|tsx?)/
const visitedModules = new Set()
const checkParent = (mod) => {
if (!mod?.parent || visitedModules.has(mod)) return
testFile = mod.parent.filename || ''
visitedModules.add(mod)
if (!testFileRegex.test(testFile)) {
checkParent(mod.parent)
}
}
checkParent(module)
process.env.TEST_FILE_PATH = testFile
let testMode = process.env.NEXT_TEST_MODE
if (!testFileRegex.test(testFile)) {
throw new Error(
`e2e-utils imported from non-test file ${testFile} (must end with .test.(js,ts,tsx)`
)
}
const testFolderModes = ['e2e', 'development', 'production']
const testModeFromFile = testFolderModes.find((mode) =>
testFile.startsWith(path.join(testsFolder, mode))
)
if (testModeFromFile === 'e2e') {
const validE2EModes = ['dev', 'start', 'deploy']
if (!process.env.NEXT_TEST_JOB && !testMode) {
console.warn('Warn: no NEXT_TEST_MODE set, using default of start')
testMode = 'start'
}
assert(
validE2EModes.includes(testMode),
`NEXT_TEST_MODE must be one of ${validE2EModes.join(
', '
)} for e2e tests but received ${testMode}`
)
} else if (testModeFromFile === 'development') {
testMode = 'dev'
} else if (testModeFromFile === 'production') {
testMode = 'start'
}
if (testMode === 'dev') {
;(global as any).isNextDev = true
} else if (testMode === 'deploy') {
;(global as any).isNextDeploy = true
} else {
;(global as any).isNextStart = true
}
if (!testMode) {
throw new Error(
`No 'NEXT_TEST_MODE' set in environment, this is required for e2e-utils`
)
}
console.log(`Using test mode: ${testMode} in test folder ${testModeFromFile}`)
/**
* FileRef is wrapper around a file path that is meant be copied
* to the location where the next instance is being created
*/
export class FileRef {
public fsPath: string
constructor(path: string) {
this.fsPath = path
}
}
let nextInstance: NextInstance | undefined = undefined
if (typeof afterAll === 'function') {
afterAll(async () => {
if (nextInstance) {
await nextInstance.destroy()
throw new Error(
`next instance not destroyed before exiting, make sure to call .destroy() after the tests after finished`
)
}
})
}
/**
* Sets up and manages a Next.js instance in the configured
* test mode. The next instance will be isolated from the monorepo
* to prevent relying on modules that shouldn't be
*/
export async function createNext(opts: {
files: {
[filename: string]: string | FileRef
}
dependencies?: {
[name: string]: string
}
nextConfig?: NextConfig
skipStart?: boolean
installCommand?: InstallCommand
buildCommand?: string
startCommand?: string
}): Promise<NextInstance> {
try {
if (nextInstance) {
throw new Error(`createNext called without destroying previous instance`)
}
if (testMode === 'dev') {
// next dev
nextInstance = new NextDevInstance(opts)
} else if (testMode === 'deploy') {
// Vercel
throw new Error('to-implement')
} else {
// next build + next start
nextInstance = new NextStartInstance(opts)
}
nextInstance.on('destroy', () => {
nextInstance = undefined
})
await nextInstance.setup()
if (!opts.skipStart) {
await nextInstance.start()
}
return nextInstance!
} catch (err) {
console.error('Failed to create next instance', err)
try {
await nextInstance.destroy()
} catch (_) {}
process.exit(1)
}
}