diff --git a/src/extension.ts b/src/extension.ts index 88b392bc..8299dff2 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -4,13 +4,14 @@ import { effect } from '@vue/reactivity' import { extensionId, getConfig } from './config' import { TestFileDiscoverer } from './discover' import { isVitestEnv } from './pure/isVitestEnv' -import { getVitestCommand, getVitestVersion, stringToCmd } from './pure/utils' +import { getVitestCommand, getVitestVersion, isNodeAvailable, stringToCmd } from './pure/utils' import { debugHandler, runHandler, updateSnapshot } from './runHandler' import { TestFile, WEAKMAP_TEST_DATA } from './TestData' import { TestWatcher } from './watch' import { Command } from './command' import { StatusBarItem } from './StatusBarItem' +const log = vscode.window.createOutputChannel('Vitest') export async function activate(context: vscode.ExtensionContext) { if ( vscode.workspace.workspaceFolders == null @@ -53,11 +54,24 @@ export async function activate(context: vscode.ExtensionContext) { cmd: 'npx', args: ['vitest'], } - const vitestVersion = await getVitestVersion(vitestCmd) + + const vitestVersion = await getVitestVersion(vitestCmd, getConfig().env || undefined).catch(async (e) => { + log.appendLine(e.toString()) + log.appendLine(`process.env.PATH = ${process.env.PATH}`) + log.appendLine(`vitest.nodeEnv = ${JSON.stringify(getConfig().env)}`) + let errorMsg = e.toString() + if (!isNodeAvailable(getConfig().env || undefined)) { + log.appendLine('Cannot spawn node process') + errorMsg += 'Cannot spawn node process. Please try setting vitest.nodeEnv as {"PATH": "/path/to/node"} in your settings.' + } + + vscode.window.showErrorMessage(errorMsg) + }) + console.dir({ vitestVersion }) const customTestCmd = getConfig().commandLine - if (semver.gte(vitestVersion, '0.8.0') || customTestCmd) { + if ((vitestVersion && semver.gte(vitestVersion, '0.8.0')) || customTestCmd) { // enable run/debug/watch tests only if vitest version >= 0.8.0 const testWatcher: undefined | TestWatcher = registerWatchHandler( vitestCmd ?? stringToCmd(customTestCmd!), diff --git a/src/pure/utils.ts b/src/pure/utils.ts index 0c47d9c1..89ad0471 100644 --- a/src/pure/utils.ts +++ b/src/pure/utils.ts @@ -76,28 +76,49 @@ export interface Cmd { export async function getVitestVersion( vitestCommand?: Cmd, + env?: Record, ): Promise { - let process + let child if (vitestCommand == null) { - process = spawn('npx', ['vitest', '-v'], { + child = spawn('npx', ['vitest', '-v'], { stdio: ['ignore', 'pipe', 'pipe'], + env: { ...process.env, ...env }, }) } else { - process = spawn(vitestCommand.cmd, [...vitestCommand.args, '-v'], { + child = spawn(vitestCommand.cmd, [...vitestCommand.args, '-v'], { stdio: ['ignore', 'pipe', 'pipe'], + env: { ...process.env, ...env }, }) } // eslint-disable-next-line no-unreachable-loop - for await (const line of chunksToLinesAsync(process.stdout)) { - process.kill() + for await (const line of chunksToLinesAsync(child.stdout)) { + child.kill() return line.match(/vitest\/(\d+.\d+.\d+)/)![1] } throw new Error(`Cannot get vitest version from "${JSON.stringify(vitestCommand)}"`) } +export function isNodeAvailable( + + env?: Record, + +): Promise { + const child = spawn('node', { + env: { ...process.env, ...env }, + }) + + return new Promise((resolve) => { + child.on('error', () => resolve(false)) + setTimeout(() => { + resolve(true) + child.kill() + }, 1000) + }) +} + const capitalizeFirstLetter = (string: string) => string.charAt(0).toUpperCase() + string.slice(1)