From 956dbbdad2861a7c8dcf120fd9b312e393f83d30 Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Mon, 8 Apr 2024 09:39:01 +0200 Subject: [PATCH 1/9] feat: allow custom host for --inspect and --inspect-brk --- packages/vitest/src/node/cli/cli-config.ts | 25 ++++++++++++++++++--- packages/vitest/src/node/config.ts | 18 +++++++++++++-- packages/vitest/src/runtime/inspector.ts | 9 +++++--- packages/vitest/src/types/config.ts | 26 ++++++++++++++++++++-- 4 files changed, 68 insertions(+), 10 deletions(-) diff --git a/packages/vitest/src/node/cli/cli-config.ts b/packages/vitest/src/node/cli/cli-config.ts index b5e16b9f526c..881becfec470 100644 --- a/packages/vitest/src/node/cli/cli-config.ts +++ b/packages/vitest/src/node/cli/cli-config.ts @@ -308,7 +308,9 @@ export const cliOptionsConfig: VitestCLIOptions = { if (typeof browser === 'boolean') return { enabled: browser } if (browser === 'true' || browser === 'false') - return { enabled: browser !== 'false' } + return { enabled: browser === 'true' } + if (browser === 'yes' || browser === 'no') + return { enabled: browser === 'yes' } if (typeof browser === 'string') return { enabled: true, name: browser } return browser @@ -465,11 +467,28 @@ export const cliOptionsConfig: VitestCLIOptions = { }, }, inspect: { - description: 'Enable Node.js inspector', + description: 'Enable Node.js inspector (default: 127.0.0.1:9229)', + argument: '[[host:]port]', + transform(portOrEnabled) { + if (portOrEnabled === 'true' || portOrEnabled === 'yes') + return true + if (portOrEnabled === 'false' || portOrEnabled === 'no') + return false + return portOrEnabled + }, }, inspectBrk: { - description: 'Enable Node.js inspector with break', + description: 'Enable Node.js inspector and break before the test starts', + argument: '[[host:]port]', + transform(portOrEnabled) { + if (portOrEnabled === 'true' || portOrEnabled === 'yes') + return true + if (portOrEnabled === 'false' || portOrEnabled === 'no') + return false + return portOrEnabled + }, }, + inspector: null, testTimeout: { description: 'Default timeout of a test in milliseconds (default: 5000)', argument: '', diff --git a/packages/vitest/src/node/config.ts b/packages/vitest/src/node/config.ts index 26d82b7fa1c1..5794bdf59f4c 100644 --- a/packages/vitest/src/node/config.ts +++ b/packages/vitest/src/node/config.ts @@ -20,6 +20,14 @@ function resolvePath(path: string, root: string) { ) } +function parseInspector(inspect: string | undefined | boolean) { + if (typeof inspect === 'boolean' || inspect === undefined) + return {} + + const [host, port] = inspect.split(':') + return { host, port: port ? Number(port) : undefined } +} + export function resolveApiServerConfig( options: Options, ): ApiConfig | undefined { @@ -88,8 +96,14 @@ export function resolveConfig( mode, } as any as ResolvedConfig - resolved.inspect = Boolean(resolved.inspect) - resolved.inspectBrk = Boolean(resolved.inspectBrk) + const inspector = resolved.inspect || resolved.inspectBrk + + resolved.inspector = { + ...resolved.inspector, + ...parseInspector(inspector), + enabled: !!inspector, + waitForDebugger: resolved.inspector.waitForDebugger ?? !!resolved.inspectBrk, + } if (viteConfig.base !== '/') resolved.base = viteConfig.base diff --git a/packages/vitest/src/runtime/inspector.ts b/packages/vitest/src/runtime/inspector.ts index fdc8f31ab25d..0631a7990bc5 100644 --- a/packages/vitest/src/runtime/inspector.ts +++ b/packages/vitest/src/runtime/inspector.ts @@ -12,7 +12,7 @@ let session: InstanceType */ export function setupInspect(ctx: ContextRPC) { const config = ctx.config - const isEnabled = config.inspect || config.inspectBrk + const isEnabled = config.inspector.enabled if (isEnabled) { inspector = __require('node:inspector') @@ -20,10 +20,13 @@ export function setupInspect(ctx: ContextRPC) { const isOpen = inspector.url() !== undefined if (!isOpen) { - inspector.open() + inspector.open( + config.inspector.port, + config.inspector.host, + config.inspector.waitForDebugger, + ) if (config.inspectBrk) { - inspector.waitForDebugger() const firstTestFile = ctx.files[0] // Stop at first test file diff --git a/packages/vitest/src/types/config.ts b/packages/vitest/src/types/config.ts index f75c660558c1..269936195a59 100644 --- a/packages/vitest/src/types/config.ts +++ b/packages/vitest/src/types/config.ts @@ -675,7 +675,7 @@ export interface InlineConfig { * * Requires `poolOptions.threads.singleThread: true` OR `poolOptions.forks.singleFork: true`. */ - inspect?: boolean + inspect?: boolean | string /** * Debug tests by opening `node:inspector` in worker / child process and wait for debugger to connect. @@ -683,7 +683,29 @@ export interface InlineConfig { * * Requires `poolOptions.threads.singleThread: true` OR `poolOptions.forks.singleFork: true`. */ - inspectBrk?: boolean + inspectBrk?: boolean | string + + /** + * Inspector options. If `--inspect` or `--inspect-brk` is enabled, these options will be passed to the inspector. + */ + inspector?: { + /** + * Enable inspector + */ + enabled?: boolean + /** + * Port to run inspector on + */ + port?: number + /** + * Host to run inspector on + */ + host?: string + /** + * Wait for debugger to connect before running tests + */ + waitForDebugger?: boolean + } /** * Modify default Chai config. Vitest uses Chai for `expect` and `assert` matches. From 00cbbeb60821da0bea5dd2f7837e20fb4902a0f9 Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Mon, 8 Apr 2024 09:47:03 +0200 Subject: [PATCH 2/9] chore: pass down inspector option --- packages/vitest/src/node/workspace.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/vitest/src/node/workspace.ts b/packages/vitest/src/node/workspace.ts index c9df549c8324..456a3b4e2744 100644 --- a/packages/vitest/src/node/workspace.ts +++ b/packages/vitest/src/node/workspace.ts @@ -410,6 +410,7 @@ export class WorkspaceProject { }, inspect: this.ctx.config.inspect, inspectBrk: this.ctx.config.inspectBrk, + inspector: this.ctx.config.inspector, alias: [], includeTaskLocation: this.config.includeTaskLocation ?? this.ctx.config.includeTaskLocation, env: { From 9a7f3719ef40218ad6c369f8655f5b567c132017 Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Mon, 8 Apr 2024 09:56:21 +0200 Subject: [PATCH 3/9] fix: guard check --- packages/vitest/src/node/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vitest/src/node/config.ts b/packages/vitest/src/node/config.ts index 5794bdf59f4c..3b3ebd22d21c 100644 --- a/packages/vitest/src/node/config.ts +++ b/packages/vitest/src/node/config.ts @@ -102,7 +102,7 @@ export function resolveConfig( ...resolved.inspector, ...parseInspector(inspector), enabled: !!inspector, - waitForDebugger: resolved.inspector.waitForDebugger ?? !!resolved.inspectBrk, + waitForDebugger: options.inspector?.waitForDebugger ?? !!resolved.inspectBrk, } if (viteConfig.base !== '/') From 81f07ce218d3dd2f379b5ee84d9b0519ef85bb65 Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Mon, 8 Apr 2024 10:48:35 +0200 Subject: [PATCH 4/9] fix: if no port, then host is a port --- docs/guide/cli.md | 4 ++-- packages/vitest/src/node/config.ts | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/guide/cli.md b/docs/guide/cli.md index 424775c82dfc..ef2bf603403e 100644 --- a/docs/guide/cli.md +++ b/docs/guide/cli.md @@ -96,8 +96,8 @@ Run only [benchmark](https://vitest.dev/guide/features.html#benchmarking-experim | `--shard ` | Execute tests in a specified shard | | `--sequence` | Define in what order to run tests. Use [cac's dot notation] to specify options (for example, use `--sequence.shuffle` to run tests in random order or `--sequence.shuffle --sequence.seed SEED_ID` to run a specific order) | | `--no-color` | Removes colors from the console output | -| `--inspect` | Enables Node.js inspector | -| `--inspect-brk` | Enables Node.js inspector with break | +| `--inspect [[host:]port]` | Enable Node.js inspector (default: 127.0.0.1:9229) | +| `--inspect-brk [[host:]port]` | Enables Node.js inspector and break before the test starts | | `--bail ` | Stop test execution when given number of tests have failed | | `--retry ` | Retry the test specific number of times if it fails | | `--exclude ` | Additional file globs to be excluded from test | diff --git a/packages/vitest/src/node/config.ts b/packages/vitest/src/node/config.ts index 3b3ebd22d21c..59d5e417c796 100644 --- a/packages/vitest/src/node/config.ts +++ b/packages/vitest/src/node/config.ts @@ -25,7 +25,9 @@ function parseInspector(inspect: string | undefined | boolean) { return {} const [host, port] = inspect.split(':') - return { host, port: port ? Number(port) : undefined } + if (!port) + return { port: Number(host) } + return { host, port: Number(port) } } export function resolveApiServerConfig( From 99beecc004e50a21b66c96048c556e99acacc615 Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Mon, 8 Apr 2024 11:26:58 +0200 Subject: [PATCH 5/9] fix: config receives a number --- packages/vitest/src/constants.ts | 1 + packages/vitest/src/node/config.ts | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/vitest/src/constants.ts b/packages/vitest/src/constants.ts index b82a3ec7034d..6098c05428a0 100644 --- a/packages/vitest/src/constants.ts +++ b/packages/vitest/src/constants.ts @@ -1,6 +1,7 @@ // if changed, update also jsdocs and docs export const defaultPort = 51204 export const defaultBrowserPort = 63315 +export const defaultInspectPort = 9229 export const EXIT_CODE_RESTART = 43 diff --git a/packages/vitest/src/node/config.ts b/packages/vitest/src/node/config.ts index 59d5e417c796..ceb291bf54b9 100644 --- a/packages/vitest/src/node/config.ts +++ b/packages/vitest/src/node/config.ts @@ -3,7 +3,7 @@ import { normalize, relative, resolve } from 'pathe' import c from 'picocolors' import type { ResolvedConfig as ResolvedViteConfig } from 'vite' import type { ApiConfig, ResolvedConfig, UserConfig, VitestRunMode } from '../types' -import { defaultBrowserPort, defaultPort, extraInlineDeps } from '../constants' +import { defaultBrowserPort, defaultInspectPort, defaultPort, extraInlineDeps } from '../constants' import { benchmarkConfigDefaults, configDefaults } from '../defaults' import { isCI, stdProvider, toArray } from '../utils' import type { BuiltinPool } from '../types/pool-options' @@ -20,13 +20,15 @@ function resolvePath(path: string, root: string) { ) } -function parseInspector(inspect: string | undefined | boolean) { +function parseInspector(inspect: string | undefined | boolean | number) { if (typeof inspect === 'boolean' || inspect === undefined) return {} + if (typeof inspect === 'number') + return { port: inspect } const [host, port] = inspect.split(':') if (!port) - return { port: Number(host) } + return { host, port: defaultInspectPort } return { host, port: Number(port) } } From 05d65f6d5f364a04fc2ac5dae5faabafeb00af1d Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Mon, 8 Apr 2024 15:45:27 +0200 Subject: [PATCH 6/9] test: add tests for inspector resolution --- packages/vitest/src/node/config.ts | 7 ++-- test/config/test/resolution.test.ts | 53 +++++++++++++++++++++++++++-- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/packages/vitest/src/node/config.ts b/packages/vitest/src/node/config.ts index ceb291bf54b9..3d03d9824818 100644 --- a/packages/vitest/src/node/config.ts +++ b/packages/vitest/src/node/config.ts @@ -26,10 +26,13 @@ function parseInspector(inspect: string | undefined | boolean | number) { if (typeof inspect === 'number') return { port: inspect } + if (inspect.match(/https?:\//)) + throw new Error(`Inspector host cannot be a URL. Use "host:port" instead of "${inspect}"`) + const [host, port] = inspect.split(':') if (!port) - return { host, port: defaultInspectPort } - return { host, port: Number(port) } + return { host } + return { host, port: Number(port) || defaultInspectPort } } export function resolveApiServerConfig( diff --git a/test/config/test/resolution.test.ts b/test/config/test/resolution.test.ts index f36b522e5831..15dcd3c1b883 100644 --- a/test/config/test/resolution.test.ts +++ b/test/config/test/resolution.test.ts @@ -1,7 +1,7 @@ import type { UserConfig } from 'vitest' import type { UserConfig as ViteUserConfig } from 'vite' -import { describe, expect, it } from 'vitest' -import { createVitest } from 'vitest/node' +import { describe, expect, it, onTestFinished, vi } from 'vitest' +import { createVitest, parseCLI } from 'vitest/node' import { extraInlineDeps } from 'vitest/config' async function vitest(cliOptions: UserConfig, configValue: UserConfig = {}, viteConfig: ViteUserConfig = {}) { @@ -263,3 +263,52 @@ describe('correctly defines api flag', () => { }) }) }) + +describe.only.each([ + '--inspect', + '--inspect-brk', +])('correctly parses %s flags', (inspectFlagName) => { + it.each([ + ['', { enabled: true }], + ['true', { enabled: true }], + ['yes', { enabled: true }], + ['false', { enabled: false }], + ['no', { enabled: false }], + + ['1002', { enabled: true, port: 1002 }], + ['www.remote.com:1002', { enabled: true, port: 1002, host: 'www.remote.com' }], + ['www.remote.com', { enabled: true, host: 'www.remote.com' }], + ])('parses "%s" value', async (cliValue, inspect) => { + const rawConfig = parseCLI([ + 'vitest', + '--no-file-parallelism', + `${inspectFlagName}=${cliValue}`, + ]) + const c = await config(rawConfig.options) + expect(c.inspector).toEqual({ + ...inspect, + waitForDebugger: inspectFlagName === '--inspect-brk' && inspect.enabled, + }) + }) + it('cannot use a URL', async () => { + const url = 'https://www.remote.com:1002' + const rawConfig = parseCLI([ + 'vitest', + '--no-file-parallelism', + inspectFlagName, + 'https://www.remote.com:1002', + ]) + const error = vi.fn() + const originalError = console.error + console.error = error + onTestFinished(() => { + console.error = originalError + }) + await expect(async () => { + await config(rawConfig.options) + }).rejects.toThrowError() + expect(error.mock.lastCall[0]).toEqual( + expect.stringContaining(`Inspector host cannot be a URL. Use "host:port" instead of "${url}"`), + ) + }) +}) From 02aad5521c8d9a1551399fd0150fafa5a3941901 Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Mon, 8 Apr 2024 15:49:28 +0200 Subject: [PATCH 7/9] chore: update test cli flag --- packages/vitest/src/node/cli/cli-config.ts | 4 ++-- test/config/test/resolution.test.ts | 10 ++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/packages/vitest/src/node/cli/cli-config.ts b/packages/vitest/src/node/cli/cli-config.ts index 881becfec470..13e2c6aa8db9 100644 --- a/packages/vitest/src/node/cli/cli-config.ts +++ b/packages/vitest/src/node/cli/cli-config.ts @@ -470,7 +470,7 @@ export const cliOptionsConfig: VitestCLIOptions = { description: 'Enable Node.js inspector (default: 127.0.0.1:9229)', argument: '[[host:]port]', transform(portOrEnabled) { - if (portOrEnabled === 'true' || portOrEnabled === 'yes') + if (portOrEnabled === 0 || portOrEnabled === 'true' || portOrEnabled === 'yes') return true if (portOrEnabled === 'false' || portOrEnabled === 'no') return false @@ -481,7 +481,7 @@ export const cliOptionsConfig: VitestCLIOptions = { description: 'Enable Node.js inspector and break before the test starts', argument: '[[host:]port]', transform(portOrEnabled) { - if (portOrEnabled === 'true' || portOrEnabled === 'yes') + if (portOrEnabled === 0 || portOrEnabled === 'true' || portOrEnabled === 'yes') return true if (portOrEnabled === 'false' || portOrEnabled === 'no') return false diff --git a/test/config/test/resolution.test.ts b/test/config/test/resolution.test.ts index 15dcd3c1b883..f7bf9f139c38 100644 --- a/test/config/test/resolution.test.ts +++ b/test/config/test/resolution.test.ts @@ -278,12 +278,10 @@ describe.only.each([ ['1002', { enabled: true, port: 1002 }], ['www.remote.com:1002', { enabled: true, port: 1002, host: 'www.remote.com' }], ['www.remote.com', { enabled: true, host: 'www.remote.com' }], - ])('parses "%s" value', async (cliValue, inspect) => { - const rawConfig = parseCLI([ - 'vitest', - '--no-file-parallelism', - `${inspectFlagName}=${cliValue}`, - ]) + ])(`parses "vitest ${inspectFlagName} %s" value`, async (cliValue, inspect) => { + const rawConfig = parseCLI( + `vitest --no-file-parallelism ${inspectFlagName} ${cliValue}`, + ) const c = await config(rawConfig.options) expect(c.inspector).toEqual({ ...inspect, From 80d00e033e989a61118e1e9f764285dfcd4a3f06 Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Mon, 8 Apr 2024 15:50:15 +0200 Subject: [PATCH 8/9] chore: cleanup --- test/config/test/resolution.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/config/test/resolution.test.ts b/test/config/test/resolution.test.ts index f7bf9f139c38..b1a8d6c40cf6 100644 --- a/test/config/test/resolution.test.ts +++ b/test/config/test/resolution.test.ts @@ -294,7 +294,7 @@ describe.only.each([ 'vitest', '--no-file-parallelism', inspectFlagName, - 'https://www.remote.com:1002', + url, ]) const error = vi.fn() const originalError = console.error From 5a5ca1c716a01f1ba935499f2fa616004280b05a Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Mon, 8 Apr 2024 16:33:15 +0200 Subject: [PATCH 9/9] chore: remove .only --- test/config/test/resolution.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/config/test/resolution.test.ts b/test/config/test/resolution.test.ts index b1a8d6c40cf6..f047d7d44760 100644 --- a/test/config/test/resolution.test.ts +++ b/test/config/test/resolution.test.ts @@ -264,7 +264,7 @@ describe('correctly defines api flag', () => { }) }) -describe.only.each([ +describe.each([ '--inspect', '--inspect-brk', ])('correctly parses %s flags', (inspectFlagName) => {