From da6dc9d4f77e2237c2f04d327f40d2098e364535 Mon Sep 17 00:00:00 2001
From: Anthony Fu
Date: Thu, 12 May 2022 13:12:43 +0800
Subject: [PATCH] test: refactor test utils and setup (#8135)
---
.eslintrc.cjs | 3 +-
playground/cli-module/__tests__/serve.ts | 34 ++-
playground/cli/__tests__/serve.ts | 34 ++-
playground/legacy/__tests__/ssr/serve.ts | 8 +-
playground/lib/__tests__/lib.spec.ts | 6 +-
playground/lib/__tests__/serve.ts | 24 +-
.../optimize-missing-deps/__test__/serve.ts | 8 +-
.../__tests__/resolve-config.spec.ts | 2 +-
playground/resolve-config/__tests__/serve.ts | 7 +-
playground/ssr-deps/__tests__/serve.ts | 8 +-
playground/ssr-html/__tests__/serve.ts | 8 +-
playground/ssr-pug/__tests__/serve.ts | 8 +-
playground/ssr-react/__tests__/serve.ts | 14 +-
playground/ssr-vue/__tests__/serve.ts | 14 +-
playground/ssr-webworker/__tests__/serve.ts | 10 +-
playground/test-utils.ts | 62 +++--
.../__tests__/serve.ts | 21 ++
.../tsconfig-json-load-error.spec.ts | 10 +-
playground/vitestSetup.ts | 212 ++++++++++--------
.../worker/__tests__/es/es-worker.spec.ts | 6 +-
.../worker/__tests__/iife/worker.spec.ts | 2 +-
.../sourcemap-hidden-worker.spec.ts | 5 +-
.../sourcemap-inline-worker.spec.ts | 5 +-
.../sourcemap/sourcemap-worker.spec.ts | 2 +-
playground/worker/index.html | 8 +-
playground/worker/worker/main-format-es.js | 4 +-
26 files changed, 274 insertions(+), 251 deletions(-)
create mode 100644 playground/tsconfig-json-load-error/__tests__/serve.ts
diff --git a/.eslintrc.cjs b/.eslintrc.cjs
index 9f6bf0deb86303..d5050bd4853167 100644
--- a/.eslintrc.cjs
+++ b/.eslintrc.cjs
@@ -120,7 +120,8 @@ module.exports = defineConfig({
'node/no-extraneous-import': 'off',
'node/no-extraneous-require': 'off',
'node/no-missing-import': 'off',
- 'node/no-missing-require': 'off'
+ 'node/no-missing-require': 'off',
+ 'no-undef': 'off'
}
},
{
diff --git a/playground/cli-module/__tests__/serve.ts b/playground/cli-module/__tests__/serve.ts
index 1085c5e924a1c3..87d036600f77e6 100644
--- a/playground/cli-module/__tests__/serve.ts
+++ b/playground/cli-module/__tests__/serve.ts
@@ -3,11 +3,18 @@
import execa from 'execa'
import kill from 'kill-port'
-import { isWindows, ports, viteBinPath } from '~utils'
+import {
+ isBuild,
+ isWindows,
+ killProcess,
+ ports,
+ rootDir,
+ viteBinPath
+} from '~utils'
export const port = ports['cli-module']
-export async function serve(root: string, isProd: boolean) {
+export async function serve() {
// collect stdout and stderr streams from child processes here to avoid interfering with regular vitest output
const streams = {
build: { out: [], err: [] },
@@ -35,11 +42,11 @@ export async function serve(root: string, isProd: boolean) {
}
// only run `vite build` when needed
- if (isProd) {
+ if (isBuild) {
const buildCommand = `${viteBinPath} build`
try {
const buildProcess = execa.command(buildCommand, {
- cwd: root,
+ cwd: rootDir,
stdio: 'pipe'
})
collectStreams('build', buildProcess)
@@ -56,12 +63,12 @@ export async function serve(root: string, isProd: boolean) {
// run `vite --port x` or `vite preview --port x` to start server
const viteServerArgs = ['--port', `${port}`, '--strict-port']
- if (isProd) {
+ if (isBuild) {
viteServerArgs.unshift('preview')
}
const serverCommand = `${viteBinPath} ${viteServerArgs.join(' ')}`
const serverProcess = execa.command(serverCommand, {
- cwd: root,
+ cwd: rootDir,
stdio: 'pipe'
})
collectStreams('server', serverProcess)
@@ -71,7 +78,7 @@ export async function serve(root: string, isProd: boolean) {
if (serverProcess) {
const timeoutError = `server process still alive after 3s`
try {
- killProcess(serverProcess)
+ await killProcess(serverProcess)
await resolvedOrTimeout(serverProcess, 10000, timeoutError)
} catch (e) {
if (e === timeoutError || (!serverProcess.killed && !isWindows)) {
@@ -132,19 +139,6 @@ async function startedOnPort(serverProcess, port, timeout) {
).finally(() => serverProcess.stdout.off('data', checkPort))
}
-// helper function to kill process, uses taskkill on windows to ensure child process is killed too
-function killProcess(serverProcess) {
- if (isWindows) {
- try {
- execa.commandSync(`taskkill /pid ${serverProcess.pid} /T /F`)
- } catch (e) {
- console.error('failed to taskkill:', e)
- }
- } else {
- serverProcess.kill('SIGTERM', { forceKillAfterTimeout: 2000 })
- }
-}
-
// helper function that rejects with errorMessage if promise isn't settled within ms
async function resolvedOrTimeout(promise, ms, errorMessage) {
let timer
diff --git a/playground/cli/__tests__/serve.ts b/playground/cli/__tests__/serve.ts
index 8e23db9d38686b..6f80726e309082 100644
--- a/playground/cli/__tests__/serve.ts
+++ b/playground/cli/__tests__/serve.ts
@@ -3,11 +3,18 @@
import execa from 'execa'
import kill from 'kill-port'
-import { isWindows, ports, viteBinPath } from '~utils'
+import {
+ isBuild,
+ isWindows,
+ killProcess,
+ ports,
+ rootDir,
+ viteBinPath
+} from '~utils'
export const port = ports.cli
-export async function serve(root: string, isProd: boolean) {
+export async function serve() {
// collect stdout and stderr streams from child processes here to avoid interfering with regular vitest output
const streams = {
build: { out: [], err: [] },
@@ -35,11 +42,11 @@ export async function serve(root: string, isProd: boolean) {
}
// only run `vite build` when needed
- if (isProd) {
+ if (isBuild) {
const buildCommand = `${viteBinPath} build`
try {
const buildProcess = execa.command(buildCommand, {
- cwd: root,
+ cwd: rootDir,
stdio: 'pipe'
})
collectStreams('build', buildProcess)
@@ -56,12 +63,12 @@ export async function serve(root: string, isProd: boolean) {
// run `vite --port x` or `vite preview --port x` to start server
const viteServerArgs = ['--port', `${port}`, '--strict-port']
- if (isProd) {
+ if (isBuild) {
viteServerArgs.unshift('preview')
}
const serverCommand = `${viteBinPath} ${viteServerArgs.join(' ')}`
const serverProcess = execa.command(serverCommand, {
- cwd: root,
+ cwd: rootDir,
stdio: 'pipe'
})
collectStreams('server', serverProcess)
@@ -71,7 +78,7 @@ export async function serve(root: string, isProd: boolean) {
if (serverProcess) {
const timeoutError = `server process still alive after 3s`
try {
- killProcess(serverProcess)
+ await killProcess(serverProcess)
await resolvedOrTimeout(serverProcess, 3000, timeoutError)
} catch (e) {
if (e === timeoutError || (!serverProcess.killed && !isWindows)) {
@@ -132,19 +139,6 @@ async function startedOnPort(serverProcess, port, timeout) {
).finally(() => serverProcess.stdout.off('data', checkPort))
}
-// helper function to kill process, uses taskkill on windows to ensure child process is killed too
-function killProcess(serverProcess) {
- if (isWindows) {
- try {
- execa.commandSync(`taskkill /pid ${serverProcess.pid} /T /F`)
- } catch (e) {
- console.error('failed to taskkill:', e)
- }
- } else {
- serverProcess.kill('SIGTERM', { forceKillAfterTimeout: 2000 })
- }
-}
-
// helper function that rejects with errorMessage if promise isn't settled within ms
async function resolvedOrTimeout(promise, ms, errorMessage) {
let timer
diff --git a/playground/legacy/__tests__/ssr/serve.ts b/playground/legacy/__tests__/ssr/serve.ts
index 314d0e729d9590..fc0fba377160ac 100644
--- a/playground/legacy/__tests__/ssr/serve.ts
+++ b/playground/legacy/__tests__/ssr/serve.ts
@@ -1,14 +1,14 @@
// this is automatically detected by playground/vitestSetup.ts and will replace
// the default e2e test serve behavior
import path from 'path'
-import { ports } from '~utils'
+import { ports, rootDir } from '~utils'
export const port = ports['legacy/ssr']
-export async function serve(root: string, _isProd: boolean) {
+export async function serve() {
const { build } = await import('vite')
await build({
- root,
+ root: rootDir,
logLevel: 'silent',
build: {
target: 'esnext',
@@ -22,7 +22,7 @@ export async function serve(root: string, _isProd: boolean) {
app.use('/', async (_req, res) => {
const { render } = await import(
- path.resolve(root, './dist/server/entry-server.js')
+ path.resolve(rootDir, './dist/server/entry-server.js')
)
const html = await render()
res.status(200).set({ 'Content-Type': 'text/html' }).end(html)
diff --git a/playground/lib/__tests__/lib.spec.ts b/playground/lib/__tests__/lib.spec.ts
index 470c124ed388dc..c64ccfa075d0e4 100644
--- a/playground/lib/__tests__/lib.spec.ts
+++ b/playground/lib/__tests__/lib.spec.ts
@@ -17,7 +17,7 @@ describe.runIf(isBuild)('build', () => {
test('umd', async () => {
expect(await page.textContent('.umd')).toBe('It works')
const code = fs.readFileSync(
- path.join(testDir(), 'dist/my-lib-custom-filename.umd.js'),
+ path.join(testDir, 'dist/my-lib-custom-filename.umd.js'),
'utf-8'
)
// esbuild helpers are injected inside of the UMD wrapper
@@ -27,7 +27,7 @@ describe.runIf(isBuild)('build', () => {
test('iife', async () => {
expect(await page.textContent('.iife')).toBe('It works')
const code = fs.readFileSync(
- path.join(testDir(), 'dist/my-lib-custom-filename.iife.js'),
+ path.join(testDir, 'dist/my-lib-custom-filename.iife.js'),
'utf-8'
)
// esbuild helpers are injected inside of the IIFE wrapper
@@ -40,7 +40,7 @@ describe.runIf(isBuild)('build', () => {
'hello vite'
)
const code = fs.readFileSync(
- path.join(testDir(), 'dist/lib/dynamic-import-message.es.js'),
+ path.join(testDir, 'dist/lib/dynamic-import-message.es.js'),
'utf-8'
)
expect(code).not.toMatch('__vitePreload')
diff --git a/playground/lib/__tests__/serve.ts b/playground/lib/__tests__/serve.ts
index 863df82ef570d7..070b1073837913 100644
--- a/playground/lib/__tests__/serve.ts
+++ b/playground/lib/__tests__/serve.ts
@@ -4,19 +4,27 @@
import path from 'path'
import http from 'http'
import sirv from 'sirv'
-import { page, ports, serverLogs, setViteUrl, viteTestUrl } from '~utils'
+import {
+ isBuild,
+ page,
+ ports,
+ rootDir,
+ serverLogs,
+ setViteUrl,
+ viteTestUrl
+} from '~utils'
export const port = ports.lib
-export async function serve(root, isBuildTest) {
+export async function serve() {
setupConsoleWarnCollector()
- if (!isBuildTest) {
+ if (!isBuild) {
const { createServer } = await import('vite')
process.env.VITE_INLINE = 'inline-serve'
const viteServer = await (
await createServer({
- root: root,
+ root: rootDir,
logLevel: 'silent',
server: {
watch: {
@@ -25,7 +33,7 @@ export async function serve(root, isBuildTest) {
},
host: true,
fs: {
- strict: !isBuildTest
+ strict: !isBuild
}
},
build: {
@@ -42,19 +50,19 @@ export async function serve(root, isBuildTest) {
} else {
const { build } = await import('vite')
await build({
- root,
+ root: rootDir,
logLevel: 'silent',
configFile: path.resolve(__dirname, '../vite.config.js')
})
await build({
- root,
+ root: rootDir,
logLevel: 'warn', // output esbuild warns
configFile: path.resolve(__dirname, '../vite.dyimport.config.js')
})
// start static file server
- const serve = sirv(path.resolve(root, 'dist'))
+ const serve = sirv(path.resolve(rootDir, 'dist'))
const httpServer = http.createServer((req, res) => {
if (req.url === '/ping') {
res.statusCode = 200
diff --git a/playground/optimize-missing-deps/__test__/serve.ts b/playground/optimize-missing-deps/__test__/serve.ts
index 7ceddad85dd19e..0548ea6fa0c427 100644
--- a/playground/optimize-missing-deps/__test__/serve.ts
+++ b/playground/optimize-missing-deps/__test__/serve.ts
@@ -2,13 +2,13 @@
// the default e2e test serve behavior
import path from 'path'
-import { ports } from '~utils'
+import { isBuild, ports, rootDir } from '~utils'
export const port = ports['optimize-missing-deps']
-export async function serve(root: string, isProd: boolean) {
- const { createServer } = require(path.resolve(root, 'server.js'))
- const { app, vite } = await createServer(root, isProd)
+export async function serve() {
+ const { createServer } = require(path.resolve(rootDir, 'server.js'))
+ const { app, vite } = await createServer(rootDir, isBuild)
return new Promise((resolve, reject) => {
try {
diff --git a/playground/resolve-config/__tests__/resolve-config.spec.ts b/playground/resolve-config/__tests__/resolve-config.spec.ts
index 9b3588cafcc47d..d6c637ca2d07a4 100644
--- a/playground/resolve-config/__tests__/resolve-config.spec.ts
+++ b/playground/resolve-config/__tests__/resolve-config.spec.ts
@@ -3,7 +3,7 @@ import path from 'path'
import { commandSync } from 'execa'
import { isBuild, testDir, viteBinPath } from '~utils'
-const fromTestDir = (...p: string[]) => path.resolve(testDir(), ...p)
+const fromTestDir = (...p: string[]) => path.resolve(testDir, ...p)
const build = (configName: string) => {
commandSync(`${viteBinPath} build`, { cwd: fromTestDir(configName) })
diff --git a/playground/resolve-config/__tests__/serve.ts b/playground/resolve-config/__tests__/serve.ts
index 97d68d8f7fb54f..e715deff5b1bfb 100644
--- a/playground/resolve-config/__tests__/serve.ts
+++ b/playground/resolve-config/__tests__/serve.ts
@@ -3,13 +3,14 @@
import path from 'path'
import fs from 'fs-extra'
+import { isBuild, rootDir } from '~utils'
const configNames = ['js', 'cjs', 'mjs', 'ts']
-export async function serve(root: string, isProd: boolean) {
- if (!isProd) return
+export async function serve() {
+ if (!isBuild) return
- const fromTestDir = (...p: string[]) => path.resolve(root, '..', ...p)
+ const fromTestDir = (...p: string[]) => path.resolve(rootDir, '..', ...p)
// create separate directories for all config types:
// ./{js,cjs,mjs,ts} and ./{js,cjs,mjs,ts}-module (with package#type)
diff --git a/playground/ssr-deps/__tests__/serve.ts b/playground/ssr-deps/__tests__/serve.ts
index 939d9bb297e4b2..979ed64782dd9b 100644
--- a/playground/ssr-deps/__tests__/serve.ts
+++ b/playground/ssr-deps/__tests__/serve.ts
@@ -3,15 +3,15 @@
import path from 'path'
import kill from 'kill-port'
-import { ports } from '~utils'
+import { isBuild, ports, rootDir } from '~utils'
export const port = ports['ssr-deps']
-export async function serve(root, isProd) {
+export async function serve() {
await kill(port)
- const { createServer } = require(path.resolve(root, 'server.js'))
- const { app, vite } = await createServer(root, isProd)
+ const { createServer } = require(path.resolve(rootDir, 'server.js'))
+ const { app, vite } = await createServer(rootDir, isBuild)
return new Promise((resolve, reject) => {
try {
diff --git a/playground/ssr-html/__tests__/serve.ts b/playground/ssr-html/__tests__/serve.ts
index 9cfebc53fcabb3..0740cce6cb456b 100644
--- a/playground/ssr-html/__tests__/serve.ts
+++ b/playground/ssr-html/__tests__/serve.ts
@@ -3,15 +3,15 @@
import path from 'path'
import kill from 'kill-port'
-import { ports } from '~utils'
+import { isBuild, ports, rootDir } from '~utils'
export const port = ports['ssr-html']
-export async function serve(root, isProd) {
+export async function serve() {
await kill(port)
- const { createServer } = require(path.resolve(root, 'server.js'))
- const { app, vite } = await createServer(root, isProd)
+ const { createServer } = require(path.resolve(rootDir, 'server.js'))
+ const { app, vite } = await createServer(rootDir, isBuild)
return new Promise((resolve, reject) => {
try {
diff --git a/playground/ssr-pug/__tests__/serve.ts b/playground/ssr-pug/__tests__/serve.ts
index b7b7ff0f8cd75f..bfaba4ce89d47c 100644
--- a/playground/ssr-pug/__tests__/serve.ts
+++ b/playground/ssr-pug/__tests__/serve.ts
@@ -3,15 +3,15 @@
import path from 'path'
import kill from 'kill-port'
-import { ports } from '~utils'
+import { isBuild, ports, rootDir } from '~utils'
export const port = ports['ssr-pug']
-export async function serve(root, isProd) {
+export async function serve() {
await kill(port)
- const { createServer } = require(path.resolve(root, 'server.js'))
- const { app, vite } = await createServer(root, isProd)
+ const { createServer } = require(path.resolve(rootDir, 'server.js'))
+ const { app, vite } = await createServer(rootDir, isBuild)
return new Promise((resolve, reject) => {
try {
diff --git a/playground/ssr-react/__tests__/serve.ts b/playground/ssr-react/__tests__/serve.ts
index 13a458db1d73c7..b022cb84755089 100644
--- a/playground/ssr-react/__tests__/serve.ts
+++ b/playground/ssr-react/__tests__/serve.ts
@@ -3,17 +3,17 @@
import path from 'path'
import kill from 'kill-port'
-import { ports } from '~utils'
+import { isBuild, ports, rootDir } from '~utils'
export const port = ports['ssr-react']
-export async function serve(root: string, isProd: boolean) {
- if (isProd) {
+export async function serve() {
+ if (isBuild) {
// build first
const { build } = await import('vite')
// client build
await build({
- root,
+ root: rootDir,
logLevel: 'silent', // exceptions are logged by Vitest
build: {
target: 'esnext',
@@ -24,7 +24,7 @@ export async function serve(root: string, isProd: boolean) {
})
// server build
await build({
- root,
+ root: rootDir,
logLevel: 'silent',
build: {
target: 'esnext',
@@ -36,8 +36,8 @@ export async function serve(root: string, isProd: boolean) {
await kill(port)
- const { createServer } = require(path.resolve(root, 'server.js'))
- const { app, vite } = await createServer(root, isProd)
+ const { createServer } = require(path.resolve(rootDir, 'server.js'))
+ const { app, vite } = await createServer(rootDir, isBuild)
return new Promise((resolve, reject) => {
try {
diff --git a/playground/ssr-vue/__tests__/serve.ts b/playground/ssr-vue/__tests__/serve.ts
index 5b678b85ab280c..301d62adda9a42 100644
--- a/playground/ssr-vue/__tests__/serve.ts
+++ b/playground/ssr-vue/__tests__/serve.ts
@@ -3,17 +3,17 @@
import path from 'path'
import kill from 'kill-port'
-import { ports } from '~utils'
+import { isBuild, ports, rootDir } from '~utils'
export const port = ports['ssr-vue']
-export async function serve(root, isProd) {
- if (isProd) {
+export async function serve() {
+ if (isBuild) {
// build first
const { build } = await import('vite')
// client build
await build({
- root,
+ root: rootDir,
logLevel: 'silent', // exceptions are logged by Vitest
build: {
target: 'esnext',
@@ -24,7 +24,7 @@ export async function serve(root, isProd) {
})
// server build
await build({
- root,
+ root: rootDir,
logLevel: 'silent',
build: {
target: 'esnext',
@@ -36,8 +36,8 @@ export async function serve(root, isProd) {
await kill(port)
- const { createServer } = require(path.resolve(root, 'server.js'))
- const { app, vite } = await createServer(root, isProd)
+ const { createServer } = require(path.resolve(rootDir, 'server.js'))
+ const { app, vite } = await createServer(rootDir, isBuild)
return new Promise((resolve, reject) => {
try {
diff --git a/playground/ssr-webworker/__tests__/serve.ts b/playground/ssr-webworker/__tests__/serve.ts
index c3b3306d55758d..09578b58499f6c 100644
--- a/playground/ssr-webworker/__tests__/serve.ts
+++ b/playground/ssr-webworker/__tests__/serve.ts
@@ -3,11 +3,11 @@
import path from 'path'
import kill from 'kill-port'
-import { ports } from '~utils'
+import { isBuild, ports, rootDir } from '~utils'
export const port = ports['ssr-webworker']
-export async function serve(root: string, isProd: boolean) {
+export async function serve() {
await kill(port)
// we build first, regardless of whether it's prod/build mode
@@ -16,7 +16,7 @@ export async function serve(root: string, isProd: boolean) {
// worker build
await build({
- root,
+ root: rootDir,
logLevel: 'silent',
build: {
target: 'esnext',
@@ -25,8 +25,8 @@ export async function serve(root: string, isProd: boolean) {
}
})
- const { createServer } = require(path.resolve(root, 'worker.js'))
- const { app } = await createServer(root, isProd)
+ const { createServer } = require(path.resolve(rootDir, 'worker.js'))
+ const { app } = await createServer(rootDir, isBuild)
return new Promise((resolve, reject) => {
try {
diff --git a/playground/test-utils.ts b/playground/test-utils.ts
index 47bab08b698336..987ecb5e950a23 100644
--- a/playground/test-utils.ts
+++ b/playground/test-utils.ts
@@ -13,24 +13,11 @@ import type { Manifest } from 'vite'
import { normalizePath } from 'vite'
import { fromComment } from 'convert-source-map'
import { expect } from 'vitest'
-import { page } from './vitestSetup'
+import type { ExecaChildProcess } from 'execa'
+import { isBuild, isWindows, page, testDir } from './vitestSetup'
export * from './vitestSetup'
-export const workspaceRoot = path.resolve(__dirname, '../')
-
-export const isBuild = !!process.env.VITE_TEST_BUILD
-export const isServe = !isBuild
-
-export const isWindows = process.platform === 'win32'
-export const viteBinPath = path.join(
- workspaceRoot,
- 'packages',
- 'vite',
- 'bin',
- 'vite.js'
-)
-
// make sure these ports are unique
export const ports = {
cli: 9510,
@@ -48,16 +35,6 @@ export const ports = {
'css/postcss-plugins-different-dir': 5006
}
-export function slash(p: string): string {
- return p.replace(/\\/g, '/')
-}
-
-export const testDir = () => {
- const testPath = expect.getState().testPath
- const testName = slash(testPath).match(/playground\/([\w-]+)\//)?.[1]
- return path.resolve(__dirname, '../playground-temp', testName)
-}
-
const hexToNameMap: Record = {}
Object.keys(colors).forEach((color) => {
hexToNameMap[colors[color]] = color
@@ -109,7 +86,7 @@ export async function getBgColor(el: string | ElementHandle): Promise {
}
export function readFile(filename: string): string {
- return fs.readFileSync(path.resolve(testDir(), filename), 'utf-8')
+ return fs.readFileSync(path.resolve(testDir, filename), 'utf-8')
}
export function editFile(
@@ -118,27 +95,27 @@ export function editFile(
runInBuild: boolean = false
): void {
if (isBuild && !runInBuild) return
- filename = path.resolve(testDir(), filename)
+ filename = path.resolve(testDir, filename)
const content = fs.readFileSync(filename, 'utf-8')
const modified = replacer(content)
fs.writeFileSync(filename, modified)
}
export function addFile(filename: string, content: string): void {
- fs.writeFileSync(path.resolve(testDir(), filename), content)
+ fs.writeFileSync(path.resolve(testDir, filename), content)
}
export function removeFile(filename: string): void {
- fs.unlinkSync(path.resolve(testDir(), filename))
+ fs.unlinkSync(path.resolve(testDir, filename))
}
export function listAssets(base = ''): string[] {
- const assetsDir = path.join(testDir(), 'dist', base, 'assets')
+ const assetsDir = path.join(testDir, 'dist', base, 'assets')
return fs.readdirSync(assetsDir)
}
export function findAssetFile(match: string | RegExp, base = ''): string {
- const assetsDir = path.join(testDir(), 'dist', base, 'assets')
+ const assetsDir = path.join(testDir, 'dist', base, 'assets')
const files = fs.readdirSync(assetsDir)
const file = files.find((file) => {
return file.match(match)
@@ -148,10 +125,7 @@ export function findAssetFile(match: string | RegExp, base = ''): string {
export function readManifest(base = ''): Manifest {
return JSON.parse(
- fs.readFileSync(
- path.join(testDir(), 'dist', base, 'manifest.json'),
- 'utf-8'
- )
+ fs.readFileSync(path.join(testDir, 'dist', base, 'manifest.json'), 'utf-8')
)
}
@@ -182,10 +156,26 @@ export const extractSourcemap = (content: string) => {
}
export const formatSourcemapForSnapshot = (map: any) => {
- const root = normalizePath(testDir())
+ const root = normalizePath(testDir)
const m = { ...map }
delete m.file
delete m.names
m.sources = m.sources.map((source) => source.replace(root, '/root'))
return m
}
+
+// helper function to kill process, uses taskkill on windows to ensure child process is killed too
+export async function killProcess(
+ serverProcess: ExecaChildProcess
+): Promise {
+ if (isWindows) {
+ try {
+ const { default: execa } = await import('execa')
+ execa.commandSync(`taskkill /pid ${serverProcess.pid} /T /F`)
+ } catch (e) {
+ console.error('failed to taskkill:', e)
+ }
+ } else {
+ serverProcess.kill('SIGTERM', { forceKillAfterTimeout: 2000 })
+ }
+}
diff --git a/playground/tsconfig-json-load-error/__tests__/serve.ts b/playground/tsconfig-json-load-error/__tests__/serve.ts
new file mode 100644
index 00000000000000..b2d63428db630b
--- /dev/null
+++ b/playground/tsconfig-json-load-error/__tests__/serve.ts
@@ -0,0 +1,21 @@
+import { startDefaultServe } from '~utils'
+
+export let serveError: Error | undefined
+
+export async function serve() {
+ try {
+ await startDefaultServe()
+ } catch (e) {
+ serveError = e
+ }
+}
+
+export function clearServeError() {
+ serveError = undefined
+}
+
+afterAll(() => {
+ if (serveError) {
+ throw serveError
+ }
+})
diff --git a/playground/tsconfig-json-load-error/__tests__/tsconfig-json-load-error.spec.ts b/playground/tsconfig-json-load-error/__tests__/tsconfig-json-load-error.spec.ts
index 52a02683b79c00..9235913e1ce496 100644
--- a/playground/tsconfig-json-load-error/__tests__/tsconfig-json-load-error.spec.ts
+++ b/playground/tsconfig-json-load-error/__tests__/tsconfig-json-load-error.spec.ts
@@ -1,7 +1,6 @@
+import { clearServeError, serveError } from './serve'
import {
- beforeAllError,
browserLogs,
- clearBeforeAllError,
editFile,
isBuild,
isServe,
@@ -12,12 +11,11 @@ import {
describe.runIf(isBuild)('build', () => {
test('should throw an error on build', () => {
- const buildError = beforeAllError
- expect(buildError).toBeTruthy()
- expect(buildError.message).toMatch(
+ expect(serveError).toBeTruthy()
+ expect(serveError.message).toMatch(
/^parsing .* failed: SyntaxError: Unexpected token } in JSON at position \d+$/
)
- clearBeforeAllError() // got expected error, null it here so testsuite does not fail from rethrow in afterAll
+ clearServeError() // got expected error, null it here so testsuite does not fail from rethrow in afterAll
})
test('should not output files to dist', () => {
diff --git a/playground/vitestSetup.ts b/playground/vitestSetup.ts
index 071d078a954455..9c1840b68ffd0a 100644
--- a/playground/vitestSetup.ts
+++ b/playground/vitestSetup.ts
@@ -18,52 +18,67 @@ import type { RollupError, RollupWatcher, RollupWatcherEvent } from 'rollup'
import type { File } from 'vitest'
import { beforeAll } from 'vitest'
-const isBuildTest = !!process.env.VITE_TEST_BUILD
+// #region env
+
+export const workspaceRoot = path.resolve(__dirname, '../')
+
+export const isBuild = !!process.env.VITE_TEST_BUILD
+export const isServe = !isBuild
+export const isWindows = process.platform === 'win32'
+export const viteBinPath = path.join(workspaceRoot, 'packages/vite/bin/vite.js')
+
+// #endregion
+
+// #region context
let server: ViteDevServer | http.Server
-let tempDir: string
-let rootDir: string
+
+/**
+ * Root of the Vite fixture
+ */
+export let rootDir: string
+/**
+ * Path to the current test file
+ */
+export let testPath: string
+/**
+ * Path to the test folder
+ */
+export let testDir: string
+/**
+ * Test folder name
+ */
+export let testName: string
export const serverLogs: string[] = []
export const browserLogs: string[] = []
export const browserErrors: Error[] = []
-/**
- * Error caught in beforeAll, useful if you want to test error scenarios on build
- */
-export let beforeAllError: Error | null = null
-
export let page: Page = undefined!
export let browser: Browser = undefined!
export let viteTestUrl: string = ''
export let watcher: RollupWatcher | undefined = undefined
-export function clearBeforeAllError() {
- beforeAllError = null
-}
-
export function setViteUrl(url: string) {
viteTestUrl = url
}
-export function slash(p: string): string {
- return p.replace(/\\/g, '/')
-}
+// #endregion
const DIR = path.join(os.tmpdir(), 'vitest_playwright_global_setup')
beforeAll(async (s) => {
const suite = s as File
- const wsEndpoint = fs.readFileSync(path.join(DIR, 'wsEndpoint'), 'utf-8')
- if (!wsEndpoint) {
- throw new Error('wsEndpoint not found')
- }
-
// skip browser setup for non-playground tests
if (!suite.filepath.includes('playground')) {
return
}
+ const wsEndpoint = fs.readFileSync(path.join(DIR, 'wsEndpoint'), 'utf-8')
+ if (!wsEndpoint) {
+ throw new Error('wsEndpoint not found')
+ }
+
browser = await chromium.connect(wsEndpoint)
page = await browser.newPage()
@@ -84,107 +99,48 @@ beforeAll(async (s) => {
browserErrors.push(error)
})
- const testPath = suite.filepath!
- const testName = slash(testPath).match(/playground\/([\w-]+)\//)?.[1]
+ testPath = suite.filepath!
+ testName = slash(testPath).match(/playground\/([\w-]+)\//)?.[1]
+ testDir = dirname(testPath)
// if this is a test placed under playground/xxx/__tests__
// start a vite server in that directory.
if (testName) {
- tempDir = resolve(__dirname, '../playground-temp/', testName)
+ testDir = resolve(workspaceRoot, 'playground-temp', testName)
// when `root` dir is present, use it as vite's root
- const testCustomRoot = resolve(tempDir, 'root')
- rootDir = fs.existsSync(testCustomRoot) ? testCustomRoot : tempDir
+ const testCustomRoot = resolve(testDir, 'root')
+ rootDir = fs.existsSync(testCustomRoot) ? testCustomRoot : testDir
const testCustomServe = [
resolve(dirname(testPath), 'serve.ts'),
- resolve(dirname(testPath), 'serve.cjs'),
resolve(dirname(testPath), 'serve.js')
].find((i) => fs.existsSync(i))
+
if (testCustomServe) {
// test has custom server configuration.
const mod = await import(testCustomServe)
const serve = mod.serve || mod.default?.serve
const preServe = mod.preServe || mod.default?.preServe
if (preServe) {
- await preServe(rootDir, isBuildTest)
+ await preServe()
}
if (serve) {
- server = await serve(rootDir, isBuildTest)
+ server = await serve()
return
}
- }
-
- const testCustomConfig = resolve(dirname(testPath), 'vite.config.js')
- let config: InlineConfig | undefined
- if (fs.existsSync(testCustomConfig)) {
- // test has custom server configuration.
- config = require(testCustomConfig)
- }
-
- const options: InlineConfig = {
- root: rootDir,
- logLevel: 'silent',
- server: {
- watch: {
- // During tests we edit the files too fast and sometimes chokidar
- // misses change events, so enforce polling for consistency
- usePolling: true,
- interval: 100
- },
- host: true,
- fs: {
- strict: !isBuildTest
- }
- },
- build: {
- // esbuild do not minify ES lib output since that would remove pure annotations and break tree-shaking
- // skip transpilation during tests to make it faster
- target: 'esnext'
- },
- customLogger: createInMemoryLogger(serverLogs)
- }
-
- setupConsoleWarnCollector(serverLogs)
-
- if (!isBuildTest) {
- process.env.VITE_INLINE = 'inline-serve'
- server = await (
- await createServer(mergeConfig(options, config || {}))
- ).listen()
- // use resolved port/base from server
- const base = server.config.base === '/' ? '' : server.config.base
- viteTestUrl = `http://localhost:${server.config.server.port}${base}`
- await page.goto(viteTestUrl)
} else {
- process.env.VITE_INLINE = 'inline-build'
- // determine build watch
- let resolvedConfig: ResolvedConfig
- const resolvedPlugin: () => PluginOption = () => ({
- name: 'vite-plugin-watcher',
- configResolved(config) {
- resolvedConfig = config
- }
- })
- options.plugins = [resolvedPlugin()]
- const rollupOutput = await build(mergeConfig(options, config || {}))
- const isWatch = !!resolvedConfig!.build.watch
- // in build watch,call startStaticServer after the build is complete
- if (isWatch) {
- watcher = rollupOutput as RollupWatcher
- await notifyRebuildComplete(watcher)
- }
- viteTestUrl = await startStaticServer(config)
- await page.goto(viteTestUrl)
+ await startDefaultServe()
}
}
- } catch (e: any) {
+ } catch (e) {
// Closing the page since an error in the setup, for example a runtime error
// when building the playground should skip further tests.
// If the page remains open, a command like `await page.click(...)` produces
// a timeout with an exception that hides the real error in the console.
await page.close()
- beforeAllError = e
+ await server?.close()
+ throw e
}
return async () => {
@@ -195,12 +151,74 @@ beforeAll(async (s) => {
if (browser) {
await browser.close()
}
- if (beforeAllError) {
- throw beforeAllError
- }
}
})
+export async function startDefaultServe() {
+ const testCustomConfig = resolve(dirname(testPath), 'vite.config.js')
+ let config: InlineConfig | undefined
+ if (fs.existsSync(testCustomConfig)) {
+ // test has custom server configuration.
+ config = require(testCustomConfig)
+ }
+
+ const options: InlineConfig = {
+ root: rootDir,
+ logLevel: 'silent',
+ server: {
+ watch: {
+ // During tests we edit the files too fast and sometimes chokidar
+ // misses change events, so enforce polling for consistency
+ usePolling: true,
+ interval: 100
+ },
+ host: true,
+ fs: {
+ strict: !isBuild
+ }
+ },
+ build: {
+ // esbuild do not minify ES lib output since that would remove pure annotations and break tree-shaking
+ // skip transpilation during tests to make it faster
+ target: 'esnext'
+ },
+ customLogger: createInMemoryLogger(serverLogs)
+ }
+
+ setupConsoleWarnCollector(serverLogs)
+
+ if (!isBuild) {
+ process.env.VITE_INLINE = 'inline-serve'
+ server = await (
+ await createServer(mergeConfig(options, config || {}))
+ ).listen()
+ // use resolved port/base from server
+ const base = server.config.base === '/' ? '' : server.config.base
+ viteTestUrl = `http://localhost:${server.config.server.port}${base}`
+ await page.goto(viteTestUrl)
+ } else {
+ process.env.VITE_INLINE = 'inline-build'
+ // determine build watch
+ let resolvedConfig: ResolvedConfig
+ const resolvedPlugin: () => PluginOption = () => ({
+ name: 'vite-plugin-watcher',
+ configResolved(config) {
+ resolvedConfig = config
+ }
+ })
+ options.plugins = [resolvedPlugin()]
+ const rollupOutput = await build(mergeConfig(options, config || {}))
+ const isWatch = !!resolvedConfig!.build.watch
+ // in build watch,call startStaticServer after the build is complete
+ if (isWatch) {
+ watcher = rollupOutput as RollupWatcher
+ await notifyRebuildComplete(watcher)
+ }
+ viteTestUrl = await startStaticServer(config)
+ await page.goto(viteTestUrl)
+ }
+}
+
function startStaticServer(config?: InlineConfig): Promise {
if (!config) {
// check if the test project has base config
@@ -305,3 +323,7 @@ function setupConsoleWarnCollector(logs: string[]) {
return warn.call(console, ...args)
}
}
+
+export function slash(p: string): string {
+ return p.replace(/\\/g, '/')
+}
diff --git a/playground/worker/__tests__/es/es-worker.spec.ts b/playground/worker/__tests__/es/es-worker.spec.ts
index 6d8cdaf9767d11..3ca94faac2e7d0 100644
--- a/playground/worker/__tests__/es/es-worker.spec.ts
+++ b/playground/worker/__tests__/es/es-worker.spec.ts
@@ -62,7 +62,7 @@ test('worker emitted and import.meta.url in nested worker (serve)', async () =>
describe.runIf(isBuild)('build', () => {
// assert correct files
test('inlined code generation', async () => {
- const assetsDir = path.resolve(testDir(), 'dist/es/assets')
+ const assetsDir = path.resolve(testDir, 'dist/es/assets')
const files = fs.readdirSync(assetsDir)
expect(files.length).toBe(26)
const index = files.find((f) => f.includes('main-module'))
@@ -106,10 +106,10 @@ test('classic worker', async () => {
})
test('emit chunk', async () => {
- expect(await page.textContent('.emti-chunk-worker')).toMatch(
+ expect(await page.textContent('.emit-chunk-worker')).toMatch(
'["A string",{"type":"emit-chunk-sub-worker","data":"A string"},{"type":"module-and-worker:worker","data":"A string"},{"type":"module-and-worker:module","data":"module and worker"},{"type":"emit-chunk-sub-worker","data":{"module":"module and worker","msg1":"module1","msg2":"module2","msg3":"module3"}}]'
)
- expect(await page.textContent('.emti-chunk-dynamic-import-worker')).toMatch(
+ expect(await page.textContent('.emit-chunk-dynamic-import-worker')).toMatch(
'"A string/es/"'
)
})
diff --git a/playground/worker/__tests__/iife/worker.spec.ts b/playground/worker/__tests__/iife/worker.spec.ts
index 0842d42e3562cc..3e5458bbe9a1a2 100644
--- a/playground/worker/__tests__/iife/worker.spec.ts
+++ b/playground/worker/__tests__/iife/worker.spec.ts
@@ -63,7 +63,7 @@ test('worker emitted and import.meta.url in nested worker (serve)', async () =>
describe.runIf(isBuild)('build', () => {
// assert correct files
test('inlined code generation', async () => {
- const assetsDir = path.resolve(testDir(), 'dist/iife/assets')
+ const assetsDir = path.resolve(testDir, 'dist/iife/assets')
const files = fs.readdirSync(assetsDir)
expect(files.length).toBe(13)
const index = files.find((f) => f.includes('main-module'))
diff --git a/playground/worker/__tests__/sourcemap-hidden/sourcemap-hidden-worker.spec.ts b/playground/worker/__tests__/sourcemap-hidden/sourcemap-hidden-worker.spec.ts
index 3b1f153ef1f19a..c60be7016d6477 100644
--- a/playground/worker/__tests__/sourcemap-hidden/sourcemap-hidden-worker.spec.ts
+++ b/playground/worker/__tests__/sourcemap-hidden/sourcemap-hidden-worker.spec.ts
@@ -5,10 +5,7 @@ import { isBuild, testDir } from '~utils'
describe.runIf(isBuild)('build', () => {
// assert correct files
test('sourcemap generation for web workers', async () => {
- const assetsDir = path.resolve(
- testDir(),
- 'dist/iife-sourcemap-hidden/assets'
- )
+ const assetsDir = path.resolve(testDir, 'dist/iife-sourcemap-hidden/assets')
const files = fs.readdirSync(assetsDir)
// should have 2 worker chunk
diff --git a/playground/worker/__tests__/sourcemap-inline/sourcemap-inline-worker.spec.ts b/playground/worker/__tests__/sourcemap-inline/sourcemap-inline-worker.spec.ts
index eaf62b25dde214..d82185a3f3f26b 100644
--- a/playground/worker/__tests__/sourcemap-inline/sourcemap-inline-worker.spec.ts
+++ b/playground/worker/__tests__/sourcemap-inline/sourcemap-inline-worker.spec.ts
@@ -5,10 +5,7 @@ import { isBuild, testDir } from '~utils'
describe.runIf(isBuild)('build', () => {
// assert correct files
test('sourcemap generation for web workers', async () => {
- const assetsDir = path.resolve(
- testDir(),
- 'dist/iife-sourcemap-inline/assets'
- )
+ const assetsDir = path.resolve(testDir, 'dist/iife-sourcemap-inline/assets')
const files = fs.readdirSync(assetsDir)
// should have 2 worker chunk
diff --git a/playground/worker/__tests__/sourcemap/sourcemap-worker.spec.ts b/playground/worker/__tests__/sourcemap/sourcemap-worker.spec.ts
index 10dcfcb5fba048..3b0a300c5e10f0 100644
--- a/playground/worker/__tests__/sourcemap/sourcemap-worker.spec.ts
+++ b/playground/worker/__tests__/sourcemap/sourcemap-worker.spec.ts
@@ -5,7 +5,7 @@ import { isBuild, testDir } from '~utils'
describe.runIf(isBuild)('build', () => {
// assert correct files
test('sourcemap generation for web workers', async () => {
- const assetsDir = path.resolve(testDir(), 'dist/iife-sourcemap/assets')
+ const assetsDir = path.resolve(testDir, 'dist/iife-sourcemap/assets')
const files = fs.readdirSync(assetsDir)
// should have 2 worker chunk
expect(files.length).toBe(26)
diff --git a/playground/worker/index.html b/playground/worker/index.html
index eae8c44119e3a6..243f3657ff0161 100644
--- a/playground/worker/index.html
+++ b/playground/worker/index.html
@@ -92,15 +92,15 @@
worker emit chunk
module and worker:worker in worker file
module and worker:module in worker file
- .emti-chunk-worker
+ .emit-chunk-worker
-
+
worker dynamic import to emit chunk
- .emti-chunk-dynamic-import-worker
+ .emit-chunk-dynamic-import-worker
-
+
module and worker:worker in simple file
diff --git a/playground/worker/worker/main-format-es.js b/playground/worker/worker/main-format-es.js
index e418c82a136927..2a385556c58684 100644
--- a/playground/worker/worker/main-format-es.js
+++ b/playground/worker/worker/main-format-es.js
@@ -13,7 +13,7 @@ const dataList = []
nestedWorker.addEventListener('message', (ev) => {
dataList.push(ev.data)
text(
- '.emti-chunk-worker',
+ '.emit-chunk-worker',
JSON.stringify(
dataList.sort(
(a, b) => JSON.stringify(a).length - JSON.stringify(b).length
@@ -29,7 +29,7 @@ const dynamicImportWorker = new Worker(
}
)
dynamicImportWorker.addEventListener('message', (ev) => {
- text('.emti-chunk-dynamic-import-worker', JSON.stringify(ev.data))
+ text('.emit-chunk-dynamic-import-worker', JSON.stringify(ev.data))
})
const moduleWorker = new Worker(