Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow custom host for --inspect and --inspect-brk #5509

Merged
merged 9 commits into from
Apr 8, 2024
4 changes: 2 additions & 2 deletions docs/guide/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,8 @@ Run only [benchmark](https://vitest.dev/guide/features.html#benchmarking-experim
| `--shard <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 <number>` | Stop test execution when given number of tests have failed |
| `--retry <times>` | Retry the test specific number of times if it fails |
| `--exclude <glob>` | Additional file globs to be excluded from test |
Expand Down
1 change: 1 addition & 0 deletions packages/vitest/src/constants.ts
Original file line number Diff line number Diff line change
@@ -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

Expand Down
25 changes: 22 additions & 3 deletions packages/vitest/src/node/cli/cli-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 === 0 || 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 === 0 || 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: '<timeout>',
Expand Down
27 changes: 24 additions & 3 deletions packages/vitest/src/node/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -20,6 +20,21 @@ function resolvePath(path: string, root: string) {
)
}

function parseInspector(inspect: string | undefined | boolean | number) {
if (typeof inspect === 'boolean' || inspect === undefined)
return {}
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 }
return { host, port: Number(port) || defaultInspectPort }
}

export function resolveApiServerConfig<Options extends ApiConfig & UserConfig>(
options: Options,
): ApiConfig | undefined {
Expand Down Expand Up @@ -88,8 +103,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: options.inspector?.waitForDebugger ?? !!resolved.inspectBrk,
}

if (viteConfig.base !== '/')
resolved.base = viteConfig.base
Expand Down
1 change: 1 addition & 0 deletions packages/vitest/src/node/workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down
9 changes: 6 additions & 3 deletions packages/vitest/src/runtime/inspector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,21 @@ let session: InstanceType<typeof inspector.Session>
*/
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')
// Inspector may be open already if "isolate: false" is used
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
Expand Down
26 changes: 24 additions & 2 deletions packages/vitest/src/types/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -675,15 +675,37 @@ 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.
* Provides similar experience as `--inspect-brk` Node CLI argument.
*
* 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.
Expand Down
51 changes: 49 additions & 2 deletions test/config/test/resolution.test.ts
Original file line number Diff line number Diff line change
@@ -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 = {}) {
Expand Down Expand Up @@ -263,3 +263,50 @@ describe('correctly defines api flag', () => {
})
})
})

describe.only.each([
sheremet-va marked this conversation as resolved.
Show resolved Hide resolved
'--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 "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,
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,
url,
])
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}"`),
)
})
})