Skip to content

Commit

Permalink
feat(vitest): add new CLI options (#5163)
Browse files Browse the repository at this point in the history
  • Loading branch information
sheremet-va committed Feb 10, 2024
1 parent e4e93df commit 4e17942
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 22 deletions.
9 changes: 8 additions & 1 deletion docs/config/index.md
Expand Up @@ -965,21 +965,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 @@ -1419,6 +1421,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 @@ -1791,6 +1794,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 @@ -1799,13 +1803,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 @@ -1954,6 +1960,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
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
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
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' },
})
})

0 comments on commit 4e17942

Please sign in to comment.