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(vitest): add new CLI options #5163

Merged
merged 3 commits into from
Feb 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 8 additions & 1 deletion docs/config/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -957,21 +957,23 @@ Minimum number of workers to run tests in. `poolOptions.{threads,vmThreads}.minT

- **Type:** `number`
- **Default:** `5000`
- **CLI:** `--test-timeout=5000`
- **CLI:** `--test-timeout=5000`, `--testTimeout=5000`

Default timeout of a test in milliseconds

### hookTimeout

- **Type:** `number`
- **Default:** `10000`
- **CLI:** `--hook-timeout=10000`, `--hookTimeout=10000`

Default timeout of a hook in milliseconds

### teardownTimeout<NonProjectOption />

- **Type:** `number`
- **Default:** `10000`
- **CLI:** `--teardown-timeout=5000`, `--teardownTimeout=5000`

Default timeout to wait for close when Vitest shuts down, in milliseconds

Expand Down Expand Up @@ -1411,6 +1413,7 @@ See [istanbul documentation](https://github.com/istanbuljs/nyc#ignoring-methods)
```

- **Available for providers:** `'v8' | 'istanbul'`
- **CLI:** `--coverage.watermarks.statements=50,80`, `--coverage.watermarks.branches=50,80`

Watermarks for statements, lines, branches and functions. See [istanbul documentation](https://github.com/istanbuljs/nyc#high-and-low-watermarks) for more information.

Expand Down Expand Up @@ -1783,6 +1786,7 @@ By default, Vitest exports a proxy, bypassing CSS Modules processing. If you rel

- **Type**: `number`
- **Default**: `5`
- **CLI**: `--max-concurrency=10`, `--maxConcurrency=10`

A number of tests that are allowed to run at the same time marked with `test.concurrent`.

Expand All @@ -1791,13 +1795,15 @@ Test above this limit will be queued to run when available slot appears.
### cache<NonProjectOption />

- **Type**: `false | { dir? }`
- **CLI**: `--no-cache`, `--cache=false`

Options to configure Vitest cache policy. At the moment Vitest stores cache for test results to run the longer and failed tests first.

#### cache.dir

- **Type**: `string`
- **Default**: `node_modules/.vitest`
- **CLI**: `--cache.dir=./cache`

Path to cache directory.

Expand Down Expand Up @@ -1946,6 +1952,7 @@ Path to custom tsconfig, relative to the project root.

- **Type**: `number`
- **Default**: `300`
- **CLI**: `--slow-test-threshold=<number>`, `--slowTestThreshold=<number>`

The number of milliseconds after which a test is considered slow and reported as such in the results.

Expand Down
8 changes: 6 additions & 2 deletions packages/vitest/src/node/cli/cac.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,12 @@ function addCommand(cli: CAC, name: string, option: CLIOption<any>) {
command += ` ${option.argument}`

function transform(value: unknown) {
if (!option.array && Array.isArray(value))
throw new Error(`Expected a single value for option "${command}"`)
if (!option.array && Array.isArray(value)) {
const received = value.map(s => typeof s === 'string' ? `"${s}"` : s).join(', ')
throw new Error(
`Expected a single value for option "${command}", received [${received}]`,
)
}
if (option.transform)
return option.transform(value)
if (option.array)
Expand Down
83 changes: 66 additions & 17 deletions packages/vitest/src/node/cli/cli-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@ const poolForksCommands: CLIOptions<ForksOptions & WorkerContextOptions> = {
execArgv: null,
}

function watermarkTransform(value: unknown) {
if (typeof value === 'string')
return value.split(',').map(Number)
return value
}

function transformNestedBoolean(value: unknown) {
if (typeof value === 'boolean')
return { enabled: value }
Expand Down Expand Up @@ -249,9 +255,32 @@ export const cliOptionsConfig: VitestCLIOptions = {
argument: '<path>',
normalize: true,
},
// TODO: suport watermarks via a special command?
// CAC requires --watermarks.statements=50 --watermarks.statements=80 for "statements:[50,80]" which looks rediculous
watermarks: null,
watermarks: {
description: null,
argument: '', // no displayed
subcommands: {
statements: {
description: 'High and low watermarks for statements in the format of <high>,<low>',
argument: '<watermarks>',
transform: watermarkTransform,
},
lines: {
description: 'High and low watermarks for lines in the format of <high>,<low>',
argument: '<watermarks>',
transform: watermarkTransform,
},
branches: {
description: 'High and low watermarks for branches in the format of <high>,<low>',
argument: '<watermarks>',
transform: watermarkTransform,
},
functions: {
description: 'High and low watermarks for functions in the format of <high>,<low>',
argument: '<watermarks>',
transform: watermarkTransform,
},
},
},
},
},
mode: {
Expand Down Expand Up @@ -434,6 +463,10 @@ export const cliOptionsConfig: VitestCLIOptions = {
description: 'Default timeout of a test in milliseconds (default: 5000)',
argument: '<timeout>',
},
hookTimeout: {
description: 'Default hook timeout in milliseconds (default: 10000)',
argument: '<timeout>',
},
bail: {
description: 'Stop test execution when given number of tests have failed (default: 0)',
argument: '<number>',
Expand Down Expand Up @@ -492,14 +525,35 @@ export const cliOptionsConfig: VitestCLIOptions = {
description: 'The name of the project to run if you are using Vitest workspace feature. This can be repeated for multiple projects: --project=1 --project=2',
argument: '<name>',
},
// slowTestThreshold: {
// description: 'Threshold in milliseconds for a test to be considered slow (default: 300)',
// argument: '<threshold>',
// },
// teardownTimeout: {
// description: 'Default timeout of a teardown function in milliseconds (default: 10000)',
// argument: '<timeout>',
// },
slowTestThreshold: {
description: 'Threshold in milliseconds for a test to be considered slow (default: 300)',
argument: '<threshold>',
},
teardownTimeout: {
description: 'Default timeout of a teardown function in milliseconds (default: 10000)',
argument: '<timeout>',
},
cache: {
description: 'Enable cache',
argument: '', // allow only boolean
subcommands: {
dir: {
description: 'Path to the cache directory',
argument: '<path>',
normalize: true,
},
},
// cache can only be "false" or an object
transform(cache) {
if (cache)
return {}
return cache
},
},
maxConcurrency: {
description: 'Maximum number of concurrent tests in a suite (default: 5)',
argument: '<number>',
},

// CLI only options
run: {
Expand Down Expand Up @@ -537,18 +591,13 @@ export const cliOptionsConfig: VitestCLIOptions = {
unstubGlobals: null,
uiBase: null,
benchmark: null,
name: null,
include: null,
testTransformMode: null,
hookTimeout: null,
fakeTimers: null,
cache: null,
chaiConfig: null,
clearMocks: null,
css: null,
maxConcurrency: null,
poolMatchGlobs: null,
deps: null,
slowTestThreshold: null,
teardownTimeout: null,
name: null,
}
65 changes: 63 additions & 2 deletions test/core/test/cli-test.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ test('nested coverage options have correct types', async () => {
--coverage.thresholds.lines 100
--coverage.thresholds.functions 30
--coverage.thresholds.branches 25

--coverage.watermarks.statements 50,80
--coverage.watermarks.lines=30,40
--coverage.watermarks.branches=70,80
--coverage.watermarks.functions 20,60
`).coverage).toEqual({
enabled: true,
reporter: ['text'],
Expand All @@ -85,6 +90,12 @@ test('nested coverage options have correct types', async () => {
autoUpdate: true,
100: true,
},
watermarks: {
statements: [50, 80],
lines: [30, 40],
branches: [70, 80],
functions: [20, 60],
},
})
})

Expand All @@ -110,7 +121,7 @@ test('all coverage enable options are working correctly', () => {

test('fails when an array is passed down for a single value', async () => {
expect(() => parseArguments('--coverage.provider v8 --coverage.provider istanbul'))
.toThrowErrorMatchingInlineSnapshot(`[Error: Expected a single value for option "--coverage.provider <name>"]`)
.toThrowErrorMatchingInlineSnapshot(`[Error: Expected a single value for option "--coverage.provider <name>", received ["v8", "istanbul"]]`)
})

test('even if coverage is boolean, don\'t fail', () => {
Expand All @@ -137,7 +148,14 @@ test('array options', () => {
}
`)

expect(parseArguments('--reporter json --reporter=default --coverage.reporter=json --coverage.reporter html --coverage.extension=ts --coverage.extension=tsx')).toMatchInlineSnapshot(`
expect(parseArguments(`
--reporter json
--reporter=default
--coverage.reporter=json
--coverage.reporter html
--coverage.extension=ts
--coverage.extension=tsx
`)).toMatchInlineSnapshot(`
{
"coverage": {
"extension": [
Expand All @@ -156,3 +174,46 @@ test('array options', () => {
}
`)
})

test('hookTimeout is parsed correctly', () => {
expect(parseArguments('--hookTimeout 1000')).toEqual({ hookTimeout: 1000 })
expect(parseArguments('--hook-timeout 1000')).toEqual({ hookTimeout: 1000 })
expect(parseArguments('--hook-timeout=1000')).toEqual({ hookTimeout: 1000 })
expect(parseArguments('--hookTimeout=1000')).toEqual({ hookTimeout: 1000 })
})

test('teardownTimeout is parsed correctly', () => {
expect(parseArguments('--teardownTimeout 1000')).toEqual({ teardownTimeout: 1000 })
expect(parseArguments('--teardown-timeout 1000')).toEqual({ teardownTimeout: 1000 })
expect(parseArguments('--teardownTimeout=1000')).toEqual({ teardownTimeout: 1000 })
expect(parseArguments('--teardown-timeout=1000')).toEqual({ teardownTimeout: 1000 })
})

test('slowTestThreshold is parsed correctly', () => {
expect(parseArguments('--slowTestThreshold 1000')).toEqual({ slowTestThreshold: 1000 })
expect(parseArguments('--slow-test-threshold 1000')).toEqual({ slowTestThreshold: 1000 })
expect(parseArguments('--slowTestThreshold=1000')).toEqual({ slowTestThreshold: 1000 })
expect(parseArguments('--slow-test-threshold=1000')).toEqual({ slowTestThreshold: 1000 })
})

test('maxConcurrency is parsed correctly', () => {
expect(parseArguments('--maxConcurrency 1000')).toEqual({ maxConcurrency: 1000 })
expect(parseArguments('--max-concurrency 1000')).toEqual({ maxConcurrency: 1000 })
expect(parseArguments('--maxConcurrency=1000')).toEqual({ maxConcurrency: 1000 })
expect(parseArguments('--max-concurrency=1000')).toEqual({ maxConcurrency: 1000 })
})

test('cache is parsed correctly', () => {
expect(parseArguments('--cache')).toEqual({ cache: {} })
expect(parseArguments('--no-cache')).toEqual({ cache: false })

expect(parseArguments('--cache.dir=./test/cache.json')).toEqual({
cache: { dir: 'test/cache.json' },
})
expect(parseArguments('--cache.dir ./test/cache.json')).toEqual({
cache: { dir: 'test/cache.json' },
})
expect(parseArguments('--cache.dir .\\test\\cache.json')).toEqual({
cache: { dir: 'test/cache.json' },
})
})