[READ-ONLY] Mirror of https://github.com/vitest-dev/vitest. Next generation testing framework powered by Vite. vitest.dev
test testing-tools vite
12

Configure Feed

Select the types of activity you want to include in your feed.

fix(vitest): remove excessive listeners when running without isolation, don't reset the state (#5132)

authored by

Vladimir and committed by
GitHub
(Feb 7, 2024, 12:17 PM +0100) b607f1ea 6f5b42b7

+31 -19
+26 -11
packages/vitest/src/runtime/execute.ts
··· 42 42 43 43 const bareVitestRegexp = /^@?vitest(\/|$)/ 44 44 45 - export async function startVitestExecutor(options: ContextExecutorOptions) { 46 - // @ts-expect-error injected untyped global 47 - const state = (): WorkerGlobalState => globalThis.__vitest_worker__ || options.state 48 - const rpc = () => state().rpc 45 + const dispose: (() => void)[] = [] 49 46 50 - process.exit = (code = process.exitCode || 0): never => { 51 - throw new Error(`process.exit unexpectedly called with "${code}"`) 52 - } 47 + function listenForErrors(state: () => WorkerGlobalState) { 48 + dispose.forEach(fn => fn()) 49 + dispose.length = 0 53 50 54 51 function catchError(err: unknown, type: string) { 55 52 const worker = state() ··· 60 57 error.VITEST_TEST_PATH = relative(state().config.root, worker.filepath) 61 58 error.VITEST_AFTER_ENV_TEARDOWN = worker.environmentTeardownRun 62 59 } 63 - rpc().onUnhandledError(error, type) 60 + state().rpc.onUnhandledError(error, type) 64 61 } 65 62 66 - process.setMaxListeners(25) 63 + const uncaughtException = (e: Error) => catchError(e, 'Uncaught Exception') 64 + const unhandledRejection = (e: Error) => catchError(e, 'Unhandled Rejection') 67 65 68 - process.on('uncaughtException', e => catchError(e, 'Uncaught Exception')) 69 - process.on('unhandledRejection', e => catchError(e, 'Unhandled Rejection')) 66 + process.on('uncaughtException', uncaughtException) 67 + process.on('unhandledRejection', unhandledRejection) 68 + 69 + dispose.push(() => { 70 + process.off('uncaughtException', uncaughtException) 71 + process.off('unhandledRejection', unhandledRejection) 72 + }) 73 + } 74 + 75 + export async function startVitestExecutor(options: ContextExecutorOptions) { 76 + // @ts-expect-error injected untyped global 77 + const state = (): WorkerGlobalState => globalThis.__vitest_worker__ || options.state 78 + const rpc = () => state().rpc 79 + 80 + process.exit = (code = process.exitCode || 0): never => { 81 + throw new Error(`process.exit unexpectedly called with "${code}"`) 82 + } 83 + 84 + listenForErrors(state) 70 85 71 86 const getTransformMode = () => { 72 87 return state().environment.transformMode ?? 'ssr'
+4
packages/vitest/src/runtime/rpc.ts
··· 73 73 if (functionName === 'fetch' || functionName === 'transform' || functionName === 'resolveId') 74 74 message += ` with "${JSON.stringify(args)}"` 75 75 76 + // JSON.stringify cannot serialize Error instances 77 + if (functionName === 'onUnhandledError') 78 + message += ` with "${args[0]?.message || args[0]}"` 79 + 76 80 throw new Error(message) 77 81 }, 78 82 ...options,
+1 -8
packages/vitest/src/runtime/worker.ts
··· 3 3 import { ModuleCacheMap } from 'vite-node/client' 4 4 import type { ContextRPC } from '../types/rpc' 5 5 import { loadEnvironment } from '../integrations/env/loader' 6 - import type { WorkerGlobalState } from '../types/worker' 7 6 import { isChildProcess, setProcessTitle } from '../utils/base' 8 7 import { setupInspect } from './inspector' 9 8 import { createRuntimeRpc, rpcDone } from './rpc' ··· 20 19 21 20 process.env.VITEST_WORKER_ID = String(ctx.workerId) 22 21 process.env.VITEST_POOL_ID = String(poolId) 23 - 24 - let state: WorkerGlobalState | null = null 25 22 26 23 try { 27 24 // worker is a filepath or URL to a file that exposes a default export with "getRpcOptions" and "runTests" methods ··· 46 43 if (ctx.environment.transformMode) 47 44 environment.transformMode = ctx.environment.transformMode 48 45 49 - state = { 46 + const state = { 50 47 ctx, 51 48 // here we create a new one, workers can reassign this if they need to keep it non-isolated 52 49 moduleCache: new ModuleCacheMap(), ··· 70 67 finally { 71 68 await rpcDone().catch(() => {}) 72 69 inspectorCleanup() 73 - if (state) { 74 - state.environment = null as any 75 - state = null 76 - } 77 70 } 78 71 }