Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/vitest-dev/vscode. VS Code extension for Vitest vitest.dev/vscode
testing vitest vscode
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140import type { ChildProcessWithoutNullStreams } from 'node:child_process'import type { Server } from 'node:http'import type WebSocket from 'ws'import type { ResolvedMeta } from '../apiProcess'import type { VitestPackage } from './pkg'import type { ExtensionWorkerProcess } from './types'import type { ProcessSpawnOptions } from './ws'import { spawn } from 'node:child_process'import { pathToFileURL } from 'node:url'import { WebSocketServer } from 'ws'import type { AddressInfo } from 'node:net'import { createBoundServer } from '../net'import { getConfig } from '../config'import { workerPath } from '../constants'import { createErrorLogger, log } from '../log'import { findRuntimeExecutable, formatPkg, showVitestError } from '../utils'import { waitForWsConnection } from './ws'
export async function createVitestProcess(pkg: VitestPackage, options?: ProcessSpawnOptions) { const pnpLoader = pkg.loader const pnp = pkg.pnp if (pnpLoader && !pnp) throw new Error('pnp file is required if loader option is used') const env = getConfig().env || {} const folderConfig = getConfig(pkg.folder) const runtimeArgs = folderConfig.nodeExecArgs || [] const execArgv = pnpLoader && pnp ? [ '--require', pnp, '--experimental-loader', pathToFileURL(pnpLoader).toString(), ...runtimeArgs, ] : runtimeArgs const executable = await findRuntimeExecutable(pkg.runtime, pkg.cwd) if (executable.endsWith('.CMD')) { log.error(`Executable resolved to CMD instead of EXE. The PATH: ${process.env.PATH}`) } let executablePath = workerPath if (folderConfig.runtime === 'deno') { execArgv.push('-A') executablePath = pathToFileURL(workerPath).toString() } const arvString = execArgv.join(' ') const script = `${executable} ${arvString ? `${arvString} ` : ''}${executablePath}`.trim() log.info('[API]', `Running ${formatPkg(pkg)} with "${script}"`) const logLevel = folderConfig.logLevel const server = await createBoundServer() const { port } = server.address() as AddressInfo const wss = new WebSocketServer({ server }) const wsAddress = `ws://localhost:${port}` const vitest = spawn(executable, [...execArgv, executablePath], { env: { ...process.env, ...env, VITEST_VSCODE_LOG: env.VITEST_VSCODE_LOG ?? process.env.VITEST_VSCODE_LOG ?? logLevel, VITEST_VSCODE: 'true', // same env var as `startVitest` // https://github.com/vitest-dev/vitest/blob/5c7e9ca05491aeda225ce4616f06eefcd068c0b4/packages/vitest/src/node/cli/cli-api.ts TEST: 'true', VITEST_WS_ADDRESS: wsAddress, VITEST: 'true', NODE_ENV: env.NODE_ENV ?? process.env.NODE_ENV ?? 'test', FORCE_COLOR: '1', }, cwd: pkg.cwd, })
vitest.stdout?.on('data', (d) => { const content = d.toString() log.worker('info', content) }) vitest.stderr?.on('data', (chunk) => { const string = chunk.toString() log.worker('error', string) if (string.startsWith(' MISSING DEPENDENCY')) { const error = string.split(/\r?\n/, 1)[0].slice(' MISSING DEPENDENCY'.length) showVitestError(error) } })
return new Promise<ResolvedMeta>((resolve, reject) => { function onExit(code: number | null) { reject(new Error(`Vitest process exited with code ${code}`)) }
function onError(error: Error) { reject(error) log.error('Current PATH:', process.env.PATH) }
vitest.on('exit', onExit) vitest.on('error', onError)
waitForWsConnection(wss, pkg, 'child_process', options) .then((meta) => { const process = new ExtensionChildProcess(vitest, server, meta.ws) resolve({ ...meta, process, }) }, reject) .finally(() => { vitest.off('exit', onExit) vitest.off('exit', onError) }) })}
class ExtensionChildProcess implements ExtensionWorkerProcess { constructor( private child: ChildProcessWithoutNullStreams, server: Server, ws: WebSocket, ) { child.on('exit', () => { server.close(createErrorLogger('Failed to close server')) }) // stop the process if websocket connection was somehow closed ws.on('close', () => { if (!child.killed) { child.kill() } }) }
get closed(): boolean { return this.child.exitCode != null }
onExit(listener: (code: number | null) => void, options?: { once?: boolean }) { const method = options?.once ? 'once' : 'on' this.child[method]('exit', listener) return () => { this.child.off('exit', listener) } }}