From c2ef7b5b4af1d7a56f14be0f8b696f721da8776f Mon Sep 17 00:00:00 2001 From: Vladimir Date: Tue, 10 Mar 2026 14:08:47 +0100 Subject: [PATCH] feat: support deno runtime (#744) --- README.md | 7 +- package.json | 6 ++ packages/extension/src/config.ts | 2 + packages/extension/src/debug.ts | 68 +++++++++++-------- packages/extension/src/extension.ts | 11 +-- packages/extension/src/spawn/child_process.ts | 18 +++-- packages/extension/src/spawn/pkg.ts | 23 +++++++ packages/extension/src/spawn/terminal.ts | 5 +- packages/extension/src/utils.ts | 30 +++++--- packages/extension/src/watcher.ts | 3 +- packages/shared/src/index.ts | 4 +- packages/worker-legacy/src/index.ts | 20 +++--- packages/worker-legacy/src/reporter.ts | 4 +- packages/worker-legacy/src/worker.ts | 4 +- packages/worker/src/index.ts | 12 +++- packages/worker/src/reporter.ts | 54 ++++++++------- packages/worker/src/worker.ts | 4 +- 17 files changed, 174 insertions(+), 101 deletions(-) diff --git a/README.md b/README.md index 660f0c8..0a32ba2 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,9 @@ ## Features - **Run**, **debug**, and **watch** Vitest tests in Visual Studio Code. -- **Coverage** support (requires VS Code >= 1.88) -- An `@open` tag can be used when filtering tests, to only show the tests open in the editor. +- **Coverage** support - **Inline console.log display**: Console logs appear inline in the editor next to the code that produced them +- **Imports duration**: Displays the execution time for each import during continuous test runs. ## Requirements @@ -78,6 +78,7 @@ These options are resolved relative to the [workspace file](https://code.visuals - `vitest.ignoreWorkspace`: Ignores the workspace resolution step. The extension will only look for `vitest.config` files. - `vitest.configSearchPatternInclude`: [Glob pattern](https://code.visualstudio.com/docs/editor/glob-patterns) that should be used when this extension looks for config files. Note that this is applied to _config_ files, not test files inside configs. Default: `**/*{vite,vitest}*.config*.{ts,js,mjs,cjs,cts,mts}`. - `vitest.configSearchPatternExclude`: [Glob pattern](https://code.visualstudio.com/docs/editor/glob-patterns) that should be ignored when this extension looks for config files. Note that this is applied to _config_ files, not test files inside configs. Default: `{**/node_modules/**,**/vendor/**,**/.*/**,*.d.ts}`. If the extension cannot find Vitest, please open an issue. +- `vitest.runtime`: The default runtime to run tests in. Supported: `auto` (default) `node` and `deno`. If auto, the extension will looks for a `deno.enabled` config flag or a `deno.json` file in the root folder. - `vitest.shellType`: The method the extension uses to spawn a long-running Vitest process. This is particularly useful if you are using a custom shell script to set up the environment. When using the `terminal` shell type, the websocket connection will be established. Can either be `terminal` or `child_process`. Default: `child_process`. - `vitest.nodeExecutable`: The path to the Node.js executable. If not assigned, tries to find Node.js path via a PATH variable or a `which` command. This is applied only when `vitest.shellType` is `child_process` (the default). - `vitest.nodeExecArgs`: The arguments to pass to the Node.js executable. This is applied only when `vitest.shellType` is `child_process` (the default). @@ -119,7 +120,7 @@ You can also type the same command in the quick picker while the file is open. ### Import Breakdown -If you use Vitest 4.0.15 or higher, the extension will show how long it took to load the module on the same line where the import is defined. This number includes transform time and evaluation time, including static imports. +If you use Vitest 4.0.15 or higher, during continuous runs the extension will show how long it took to load the module on the same line where the import is defined. This number includes transform time and evaluation time, including static imports. If you hover over it, you can get a more detailed diagnostic. diff --git a/package.json b/package.json index f3e777f..0172812 100644 --- a/package.json +++ b/package.json @@ -329,6 +329,12 @@ "type": "number", "default": 1000, "scope": "resource" + }, + "vitest.runtime": { + "description": "Which runtime to use by default.", + "type": "string", + "default": "auto", + "enum": ["auto", "node", "deno"] } } } diff --git a/packages/extension/src/config.ts b/packages/extension/src/config.ts index 76fbde1..e302b4b 100644 --- a/packages/extension/src/config.ts +++ b/packages/extension/src/config.ts @@ -72,6 +72,7 @@ export function getConfig(workspaceFolder?: WorkspaceFolder) { const ignoreWorkspace = get('ignoreWorkspace', false) ?? false const showInlineConsoleLog = get('showInlineConsoleLog', true) ?? true const forceCancelTimeout = get('forceCancelTimeout', 1000) ?? 1000 + const runtime = get<'node' | 'deno' | 'auto'>('runtime', 'auto') ?? 'auto' return { env: get>('nodeEnv', null), @@ -79,6 +80,7 @@ export function getConfig(workspaceFolder?: WorkspaceFolder) { debugExclude: get('debugExclude'), debugOutFiles, filesWatcherInclude, + runtime, forceCancelTimeout, terminalShellArgs, terminalShellPath, diff --git a/packages/extension/src/debug.ts b/packages/extension/src/debug.ts index 3661677..a1f7a07 100644 --- a/packages/extension/src/debug.ts +++ b/packages/extension/src/debug.ts @@ -18,10 +18,11 @@ import { log } from './log' import { TestRunner } from './runner' import { onWsConnection } from './spawn/ws' import { getTestData, TestCase, TestFile, TestFolder, TestSuite } from './testTreeData' -import { findNode } from './utils' +import { findRuntimeExecutable } from './utils' const DebugSessionName = 'Vitest' const BrowserDebugSessionName = 'Vitest_Browser' +const AttachSessionName = 'Vitest (Test)' export async function debugTests( controller: vscode.TestController, @@ -48,6 +49,10 @@ export async function debugTests( const debugEnv = config.debugEnv || {} const logLevel = config.logLevel + if (pkg.runtime === 'deno') { + runtimeArgs.push('-A') + } + log.info('[DEBUG]', 'Starting debugging session', runtimeExecutable, ...(runtimeArgs || [])) const debugId = crypto.randomUUID() @@ -131,19 +136,21 @@ export async function debugTests( const disposables: vscode.Disposable[] = [] + const attachDebug = browserDebug || pkg.runtime === 'deno' + ? { + browser: browserDebug?.browser, + // wdio support this only since Vitest 4.beta-13 + port: config.debuggerPort ?? 9229, + host: browserDebug ? 'localhost' : '127.0.0.1', + } + : undefined + wss.on( 'connection', ws => onWsConnection( ws, pkg, - browserDebug - ? { - browser: browserDebug.browser, - // wdio support this only since Vitest 4.beta-13 - port: config.debuggerPort ?? 9229, - host: 'localhost', - } - : true, + attachDebug ?? true, config.shellType, async (metadata) => { metadata.handlers.onProcessLog((type, message) => { @@ -173,25 +180,30 @@ export async function debugTests( await metadata.dispose() }) - if (browserDebug) { - const browserAttachConfig: vscode.DebugConfiguration = { - __name: BrowserDebugSessionName, + if (attachDebug) { + const attachConfig: vscode.DebugConfiguration = { + __name: browserDebug + ? BrowserDebugSessionName + : AttachSessionName, __parentId: debugId, + type: browserDebug + ? (browserDebug.browser === 'edge' ? 'msedge' : 'chrome') + : 'node', request: 'attach', - name: `Debug Tests (${browserDebug.browser})`, - address: 'localhost', - port: config.debuggerPort ?? 9229, + name: `Debug Tests (${attachDebug.browser || 'test'})`, + address: attachDebug.host, + port: attachDebug.port, ...( config.debugOutFiles?.length ? { outFiles: config.debugOutFiles } : {} ), - webRoot: browserDebug.webRoot, + webRoot: browserDebug?.webRoot, smartStep: true, skipFiles, cwd: pkg.cwd, - type: browserDebug.browser === 'edge' ? 'msedge' : 'chrome', } + log.info('[DEBUG] Attaching to', attachConfig) let parentSession: vscode.DebugSession | undefined for (const session of debugManager.sessions.values()) { if (session.configuration.__vitestId === debugId) { @@ -200,7 +212,7 @@ export async function debugTests( } vscode.debug.startDebugging( pkg.folder, - browserAttachConfig, + attachConfig, { parentSession, // this is required for the "restart" button to work @@ -210,18 +222,18 @@ export async function debugTests( }, ).then( (fullfilled) => { - log.info('[DEBUG] Browser debugger started') - metadata.rpc.onBrowserDebug(fullfilled).catch(() => {}) + log.info('[DEBUG] Debug session started') + metadata.rpc.onDebugAttached(fullfilled).catch(() => {}) if (fullfilled) { - log.info('[DEBUG] Browser debugger attached') + log.info('[DEBUG] Debug session attached') } else { - log.error('[DEBUG] Browser debugger failed to attach') + log.error('[DEBUG] Debugger failed to attach') } }, (error) => { - metadata.rpc.onBrowserDebug(false).catch(() => {}) - log.error('[DEBUG] Browser debugger failed to launch', error.message) + metadata.rpc.onDebugAttached(false).catch(() => {}) + log.error('[DEBUG] Attach session failed to launch', error.message) }, ) } @@ -292,15 +304,15 @@ async function getRuntimeOptions(pkg: VitestPackage) { ] : runtimeArgs if (config.shellType === 'child_process') { - const executable = await findNode(pkg.cwd) + const executable = await findRuntimeExecutable(pkg.runtime, pkg.cwd) return { runtimeExecutable: executable, - runtimeArgs: execArgv, + runtimeArgs: [...execArgv], } } return { - runtimeExecutable: 'node', - runtimeArgs: execArgv, + runtimeExecutable: config.runtime, + runtimeArgs: [...execArgv], } } diff --git a/packages/extension/src/extension.ts b/packages/extension/src/extension.ts index a171491..3c90bde 100644 --- a/packages/extension/src/extension.ts +++ b/packages/extension/src/extension.ts @@ -21,7 +21,7 @@ import { ExtensionState } from './state' import { TagsManager } from './tagsManager' import { TestTree } from './testTree' import { getTestData, TestFile } from './testTreeData' -import { debounce, showVitestError } from './utils' +import { clearCachedRuntime, debounce, showVitestError } from './utils' import './polyfills' export async function activate(context: vscode.ExtensionContext) { @@ -312,11 +312,16 @@ class VitestExtension { 'vitest.terminalShellPath', 'vitest.filesWatcherInclude', 'vitest.cliArguments', + 'vitest.runtime', + 'deno.enabled', ] this.disposables = [ vscode.workspace.onDidChangeConfiguration((event) => { const configName = reloadConfigNames.find(x => event.affectsConfiguration(x)) + if (event.affectsConfiguration('vitest.runtime') || event.affectsConfiguration('deno.enabled')) { + clearCachedRuntime() + } if (configName) { this.defineTestProfiles(false).catch((error) => { log.error('[API]', `Failed to reload Vitest after "${configName}" has changed`, error) @@ -553,7 +558,3 @@ class VitestExtension { this.runQueues.clear() } } - -// TODO: add to readme recommended process: -// - press continuous run -// - start editing tests diff --git a/packages/extension/src/spawn/child_process.ts b/packages/extension/src/spawn/child_process.ts index 2f31910..1bc0d69 100644 --- a/packages/extension/src/spawn/child_process.ts +++ b/packages/extension/src/spawn/child_process.ts @@ -13,7 +13,7 @@ import { WebSocketServer } from 'ws' import { getConfig } from '../config' import { workerPath } from '../constants' import { createErrorLogger, log } from '../log' -import { findNode, formatPkg, showVitestError } from '../utils' +import { findRuntimeExecutable, formatPkg, showVitestError } from '../utils' import { waitForWsConnection } from './ws' export async function createVitestProcess(pkg: VitestPackage, options?: ProcessSpawnOptions) { @@ -22,7 +22,8 @@ export async function createVitestProcess(pkg: VitestPackage, options?: ProcessS if (pnpLoader && !pnp) throw new Error('pnp file is required if loader option is used') const env = getConfig().env || {} - const runtimeArgs = getConfig(pkg.folder).nodeExecArgs || [] + const folderConfig = getConfig(pkg.folder) + const runtimeArgs = folderConfig.nodeExecArgs || [] const execArgv = pnpLoader && pnp ? [ '--require', @@ -33,15 +34,20 @@ export async function createVitestProcess(pkg: VitestPackage, options?: ProcessS ] : runtimeArgs const arvString = execArgv.join(' ') - const executable = await findNode(pkg.cwd) - const script = `${executable} ${arvString ? `${arvString} ` : ''}${workerPath}`.trim() + const executable = await findRuntimeExecutable(pkg.runtime, pkg.cwd) + let executablePath = workerPath + if (folderConfig.runtime === 'deno') { + execArgv.push('-A') + executablePath = pathToFileURL(workerPath).toString() + } + const script = `${executable} ${arvString ? `${arvString} ` : ''}${executablePath}`.trim() log.info('[API]', `Running ${formatPkg(pkg)} with "${script}"`) - const logLevel = getConfig(pkg.folder).logLevel + const logLevel = folderConfig.logLevel const port = await getPort() const server = createServer().listen(port).unref() const wss = new WebSocketServer({ server }) const wsAddress = `ws://localhost:${port}` - const vitest = spawn(executable, [...execArgv, workerPath], { + const vitest = spawn(executable, [...execArgv, executablePath], { env: { ...process.env, ...env, diff --git a/packages/extension/src/spawn/pkg.ts b/packages/extension/src/spawn/pkg.ts index 4283c57..2de76c1 100644 --- a/packages/extension/src/spawn/pkg.ts +++ b/packages/extension/src/spawn/pkg.ts @@ -26,6 +26,7 @@ export interface VitestPackage { workspaceFile?: string loader?: string pnp?: string + runtime: 'deno' | 'node' } function isVitestInPackageJson(root: string) { @@ -69,6 +70,7 @@ function resolveVitestConfig(showWarning: boolean, configOrWorkspaceFile: vscode const id = normalize(configOrWorkspaceFile.fsPath) const prefix = `${basename(dirname(id))}:${basename(id)}` + const runtime = guessRuntime(cwd, folder) if (vitest.pnp) { return { @@ -81,6 +83,7 @@ function resolveVitestConfig(showWarning: boolean, configOrWorkspaceFile: vscode version: 'pnp', loader: vitest.pnp.loaderPath, pnp: vitest.pnp.pnpPath, + runtime, } } @@ -96,6 +99,7 @@ function resolveVitestConfig(showWarning: boolean, configOrWorkspaceFile: vscode vitestPackageJsonPath: vitest.vitestPackageJsonPath, vitestNodePath: vitest.vitestNodePath, version: pkg.version, + runtime, } } @@ -156,6 +160,7 @@ function resolveVitestWorkspacePackages(showWarning: boolean) { } const id = normalize(folder.uri.fsPath) const prefix = `${basename(cwd)}:${basename(id)}` + const runtime = guessRuntime(cwd, folder) meta.push({ folder, id, @@ -164,6 +169,7 @@ function resolveVitestWorkspacePackages(showWarning: boolean) { vitestPackageJsonPath: vitest.vitestPackageJsonPath, vitestNodePath: vitest.vitestNodePath, version: pkg.version, + runtime, }) }) return { @@ -214,6 +220,7 @@ export async function resolveVitestPackagesViaPackageJson(showWarning: boolean): const id = `${normalize(pkgPath.fsPath)}/${scriptName}` const prefix = `${basename(cwd)}/package.json:${scriptName}` + const runtime = guessRuntime(cwd, folder) meta.push({ folder, id, @@ -223,6 +230,7 @@ export async function resolveVitestPackagesViaPackageJson(showWarning: boolean): vitestPackageJsonPath: vitest.vitestPackageJsonPath, vitestNodePath: vitest.vitestNodePath, version: pkg.version, + runtime, }) }) @@ -332,6 +340,21 @@ async function resolveVitestConfigs(showWarning: boolean) { } } +function guessRuntime(cwd: string, folder: vscode.WorkspaceFolder): 'deno' | 'node' { + const vitestConfig = getConfig(folder) + if (vitestConfig.runtime !== 'auto') { + return vitestConfig.runtime + } + const denoConfig = vscode.workspace.getConfiguration('deno', folder) + if (denoConfig.get('enabled')) { + return 'deno' + } + if (existsSync(resolve(cwd, 'deno.json'))) { + return 'deno' + } + return 'node' +} + export function findFirstUniqueFolderNames(paths: string[]) { const folders: string[] = [] const mapCount: Record = {} diff --git a/packages/extension/src/spawn/terminal.ts b/packages/extension/src/spawn/terminal.ts index 54cad69..e571187 100644 --- a/packages/extension/src/spawn/terminal.ts +++ b/packages/extension/src/spawn/terminal.ts @@ -52,10 +52,13 @@ export async function createVitestTerminalProcess(pkg: VitestPackage, options?: throw new Error(`Terminal was ${getExitReason(terminal.exitStatus.reason)} with code ${terminal.exitStatus.code}`) } - let command = 'node' + let command = pkg.runtime if (pnpLoader && pnp) { command += ` --require ${pnp} --experimental-loader ${pathToFileURL(pnpLoader).toString()}` } + if (pkg.runtime === 'deno') { + command += ' -A' + } command += ` ${workerPath};` log.info('[TERMINAL]', `Initiated ws connection via ${wsAddress}`) diff --git a/packages/extension/src/utils.ts b/packages/extension/src/utils.ts index d96fc01..4a06f73 100644 --- a/packages/extension/src/utils.ts +++ b/packages/extension/src/utils.ts @@ -71,45 +71,53 @@ export function waitUntilExists(file: string, timeoutMs = 5000) { }) } -let pathToNodeJS: string | undefined +const pathToRuntime: { + deno?: string + node?: string +} = {} + +export function clearCachedRuntime() { + pathToRuntime.deno = undefined + pathToRuntime.node = undefined +} // based on https://github.com/microsoft/playwright-vscode/blob/main/src/utils.ts#L144 -export async function findNode(cwd: string): Promise { +export async function findRuntimeExecutable(runtime: 'node' | 'deno', cwd: string): Promise { if (getConfig().nodeExecutable) // if empty string, keep as undefined - pathToNodeJS = getConfig().nodeExecutable || undefined + pathToRuntime[runtime] = getConfig().nodeExecutable || undefined - if (pathToNodeJS) - return pathToNodeJS + if (pathToRuntime[runtime]) + return pathToRuntime[runtime] // Stage 1: Try to find Node.js via process.env.PATH - let node: string | null = await which('node', { nothrow: true }) + let node: string | null = await which(runtime, { nothrow: true }) // Stage 2: When extension host boots, it does not have the right env set, so we might need to wait. for (let i = 0; i < 5 && !node; ++i) { await new Promise(f => setTimeout(f, 200)) - node = await which('node', { nothrow: true }) + node = await which(runtime, { nothrow: true }) } // Stage 3: If we still haven't found Node.js, try to find it via a subprocess. // This evaluates shell rc/profile files and makes nvm work. - node ??= await findNodeViaShell(cwd) + node ??= await findRuntimeViaShell(runtime, cwd) if (!node) { const msg = `Unable to find 'node' executable.\nMake sure to have Node.js installed and available in your PATH.\nCurrent PATH: '${process.env.PATH}'.` log.error(msg) throw new Error(msg) } - pathToNodeJS = node + pathToRuntime[runtime] = node return node } -async function findNodeViaShell(cwd: string): Promise { +async function findRuntimeViaShell(runtime: 'node' | 'deno', cwd: string): Promise { if (process.platform === 'win32') return null return new Promise((resolve) => { const startToken = '___START_SHELL__' const endToken = '___END_SHELL__' try { - const childProcess = spawn(`${vscode.env.shell} -i -c 'if [[ $(type node 2>/dev/null) == *function* ]]; then node --version; fi; echo ${startToken} && which node && echo ${endToken}'`, { + const childProcess = spawn(`${vscode.env.shell} -i -c 'if [[ $(type ${runtime} 2>/dev/null) == *function* ]]; then ${runtime} --version; fi; echo ${startToken} && which ${runtime} && echo ${endToken}'`, { stdio: 'pipe', shell: true, cwd, diff --git a/packages/extension/src/watcher.ts b/packages/extension/src/watcher.ts index 779b9d9..713cb41 100644 --- a/packages/extension/src/watcher.ts +++ b/packages/extension/src/watcher.ts @@ -120,8 +120,7 @@ export class ExtensionWatcher extends vscode.Disposable { } return false } - catch (err: unknown) { - log.verbose?.('[VSCODE] Error checking file stats:', this.relative(api, uri), err as string) + catch { return true } } diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index dddaa87..2068781 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -72,7 +72,7 @@ export interface ExtensionWorkerTransport { getModuleEnvironments: (moduleId: string) => ExtensionEnvironment[] getTransformedModule: (project: string, environment: string, moduleId: string) => string | null - onBrowserDebug: (fulfilled: boolean) => void + onDebugAttached: (fulfilled: boolean) => void } export interface ExtensionWorkerEvents { @@ -146,7 +146,7 @@ export interface WorkerInitMetadata { } export interface WorkerRunnerDebugOptions { - browser: string + browser?: string port: number host: string } diff --git a/packages/worker-legacy/src/index.ts b/packages/worker-legacy/src/index.ts index a139b7f..2118508 100644 --- a/packages/worker-legacy/src/index.ts +++ b/packages/worker-legacy/src/index.ts @@ -95,6 +95,15 @@ export async function initVitest( } : {}, } + if (typeof data.debug === 'object') { + const inspect = `${data.debug.host}:${data.debug.port}` + if (data.debug.browser) { + cliOptions.inspect = inspect + } + else { + cliOptions.inspectBrk = inspect + } + } const vitest = await vitestModule.createVitest( 'test', cliOptions, @@ -150,16 +159,9 @@ export async function initVitest( // Enable printConsoleTrace for inline console log display context.project.config.printConsoleTrace = true - const options = context.project.config.browser - if (options?.enabled && typeof data.debug === 'object') { + const browser = context.project.config.browser + if (browser?.enabled && typeof data.debug === 'object') { context.project.config.setupFiles.push(meta.setupFilePaths.browserDebugLegacy) - context.vitest.config.inspector = { - enabled: true, - port: data.debug.port, - host: data.debug.host, - waitForDebugger: false, - } - context.project.config.inspector = context.vitest.config.inspector } }, }, diff --git a/packages/worker-legacy/src/reporter.ts b/packages/worker-legacy/src/reporter.ts index 2f6e659..2d2f6d6 100644 --- a/packages/worker-legacy/src/reporter.ts +++ b/packages/worker-legacy/src/reporter.ts @@ -77,7 +77,7 @@ export class VSCodeReporter implements Reporter { }) const __vscode_waitForDebugger: BrowserCommand<[]> = () => { return new Promise((resolve, reject) => { - ExtensionWorker.emitter.on('onBrowserDebug', (fullfilled) => { + ExtensionWorker.emitter.on('onDebugAttached', (fullfilled) => { if (fullfilled) { resolve() } @@ -120,7 +120,7 @@ export class VSCodeReporter implements Reporter { // If parsing fails, continue without parsed location } } - this.rpc.onConsoleLog(extendedLog) + return this.rpc.onConsoleLog(extendedLog) } private logPromises = new Set>() diff --git a/packages/worker-legacy/src/worker.ts b/packages/worker-legacy/src/worker.ts index 1e3650c..95185ce 100644 --- a/packages/worker-legacy/src/worker.ts +++ b/packages/worker-legacy/src/worker.ts @@ -352,8 +352,8 @@ export class ExtensionWorker implements ExtensionWorkerTransport { // ignore } - onBrowserDebug(fulfilled: boolean) { - ExtensionWorker.emitter.emit('onBrowserDebug', fulfilled) + onDebugAttached(fulfilled: boolean) { + ExtensionWorker.emitter.emit('onDebugAttached', fulfilled) } // TODO:(?) -- if environments are supported diff --git a/packages/worker/src/index.ts b/packages/worker/src/index.ts index 0579c9d..5e51992 100644 --- a/packages/worker/src/index.ts +++ b/packages/worker/src/index.ts @@ -60,9 +60,6 @@ export async function initVitest( reporter: undefined, ui: false, includeTaskLocation: true, - inspect: typeof data.debug === 'object' - ? `${data.debug.host}:${data.debug.port}` - : undefined, experimental: { importDurations: { limit: Infinity, @@ -71,6 +68,15 @@ export async function initVitest( }, }, } + if (typeof data.debug === 'object') { + const inspect = `${data.debug.host}:${data.debug.port}` + if (data.debug.browser) { + cliOptions.inspect = inspect + } + else { + cliOptions.inspectBrk = inspect + } + } const vitest = await vitestModule.createVitest( 'test', cliOptions, diff --git a/packages/worker/src/reporter.ts b/packages/worker/src/reporter.ts index 1373ca5..fe0ea7d 100644 --- a/packages/worker/src/reporter.ts +++ b/packages/worker/src/reporter.ts @@ -40,7 +40,7 @@ export class VSCodeReporter implements Reporter { onInit(vitest: VitestCore) { this.vitest = vitest - this.configureBrowserDebugging(vitest) + this.configureAttachDebugging(vitest) vitest.projects.forEach((project) => { this.ensureSetupFileIsAllowed(project.vite.config) @@ -57,27 +57,7 @@ export class VSCodeReporter implements Reporter { this.ensureSetupFileIsAllowed(config) const __vscode_waitForDebugger: BrowserCommand<[]> = () => { - return new Promise((resolve, reject) => { - if (this.debuggerAttached !== undefined) { - if (this.debuggerAttached) { - resolve() - return - } - else if (this.debuggerAttached === false) { - reject(new Error(`Browser Debugger failed to connect.`)) - return - } - } - - ExtensionWorker.emitter.on('onBrowserDebug', (fullfilled) => { - if (fullfilled) { - resolve() - } - else { - reject(new Error(`Browser Debugger failed to connect.`)) - } - }) - }) + return this.createAttachPromise() } // TODO: move this command init to configureVitest when Vitest 4 is out // @ts-expect-error private "parent" property @@ -112,7 +92,7 @@ export class VSCodeReporter implements Reporter { // If parsing fails, continue without parsed location } } - this.rpc.onConsoleLog(extendedLog) + return this.rpc.onConsoleLog(extendedLog) } onTaskUpdate(packs: RunnerTaskResultPack[]) { @@ -179,8 +159,32 @@ export class VSCodeReporter implements Reporter { config.execArgv.push(...this.execArgv) } - configureBrowserDebugging(vitest: VitestCore) { - ExtensionWorker.emitter.on('onBrowserDebug', (fullfilled) => { + private createAttachPromise() { + return new Promise((resolve, reject) => { + if (this.debuggerAttached !== undefined) { + if (this.debuggerAttached) { + resolve() + return + } + else if (this.debuggerAttached === false) { + reject(new Error(`Browser Debugger failed to connect.`)) + return + } + } + + ExtensionWorker.emitter.on('onDebugAttached', (fullfilled) => { + if (fullfilled) { + resolve() + } + else { + reject(new Error(`Browser Debugger failed to connect.`)) + } + }) + }) + } + + configureAttachDebugging(vitest: VitestCore) { + ExtensionWorker.emitter.on('onDebugAttached', (fullfilled) => { this.debuggerAttached = fullfilled }) diff --git a/packages/worker/src/worker.ts b/packages/worker/src/worker.ts index 6cd4822..61e5d62 100644 --- a/packages/worker/src/worker.ts +++ b/packages/worker/src/worker.ts @@ -133,7 +133,7 @@ export class ExtensionWorker implements ExtensionWorkerTransport { return await this.vitest.experimental_getSourceModuleDiagnostic(moduleId) } - onBrowserDebug(fulfilled: boolean) { - ExtensionWorker.emitter.emit('onBrowserDebug', fulfilled) + onDebugAttached(fulfilled: boolean) { + ExtensionWorker.emitter.emit('onDebugAttached', fulfilled) } } -- 2.51.2