diff --git a/docs/config/index.md b/docs/config/index.md
index 598e6b0ae218..47910be20820 100644
--- a/docs/config/index.md
+++ b/docs/config/index.md
@@ -965,7 +965,7 @@ 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
@@ -973,6 +973,7 @@ Default timeout of a test in milliseconds
- **Type:** `number`
- **Default:** `10000`
+- **CLI:** `--hook-timeout=10000`, `--hookTimeout=10000`
Default timeout of a hook in milliseconds
@@ -980,6 +981,7 @@ Default timeout of a hook in milliseconds
- **Type:** `number`
- **Default:** `10000`
+- **CLI:** `--teardown-timeout=5000`, `--teardownTimeout=5000`
Default timeout to wait for close when Vitest shuts down, in milliseconds
@@ -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.
@@ -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`.
@@ -1799,6 +1803,7 @@ Test above this limit will be queued to run when available slot appears.
### cache
- **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.
@@ -1806,6 +1811,7 @@ Options to configure Vitest cache policy. At the moment Vitest stores cache for
- **Type**: `string`
- **Default**: `node_modules/.vitest`
+- **CLI**: `--cache.dir=./cache`
Path to cache directory.
@@ -1954,6 +1960,7 @@ Path to custom tsconfig, relative to the project root.
- **Type**: `number`
- **Default**: `300`
+- **CLI**: `--slow-test-threshold=`, `--slowTestThreshold=`
The number of milliseconds after which a test is considered slow and reported as such in the results.
diff --git a/packages/vitest/src/node/cli/cac.ts b/packages/vitest/src/node/cli/cac.ts
index ff83e5a754c9..903b748445ad 100644
--- a/packages/vitest/src/node/cli/cac.ts
+++ b/packages/vitest/src/node/cli/cac.ts
@@ -17,8 +17,12 @@ function addCommand(cli: CAC, name: string, option: CLIOption) {
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)
diff --git a/packages/vitest/src/node/cli/cli-config.ts b/packages/vitest/src/node/cli/cli-config.ts
index b30fabd2f7d7..855af3e5bb3d 100644
--- a/packages/vitest/src/node/cli/cli-config.ts
+++ b/packages/vitest/src/node/cli/cli-config.ts
@@ -81,6 +81,12 @@ const poolForksCommands: CLIOptions = {
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 }
@@ -249,9 +255,32 @@ export const cliOptionsConfig: VitestCLIOptions = {
argument: '',
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 ,',
+ argument: '',
+ transform: watermarkTransform,
+ },
+ lines: {
+ description: 'High and low watermarks for lines in the format of ,',
+ argument: '',
+ transform: watermarkTransform,
+ },
+ branches: {
+ description: 'High and low watermarks for branches in the format of ,',
+ argument: '',
+ transform: watermarkTransform,
+ },
+ functions: {
+ description: 'High and low watermarks for functions in the format of ,',
+ argument: '',
+ transform: watermarkTransform,
+ },
+ },
+ },
},
},
mode: {
@@ -434,6 +463,10 @@ export const cliOptionsConfig: VitestCLIOptions = {
description: 'Default timeout of a test in milliseconds (default: 5000)',
argument: '',
},
+ hookTimeout: {
+ description: 'Default hook timeout in milliseconds (default: 10000)',
+ argument: '',
+ },
bail: {
description: 'Stop test execution when given number of tests have failed (default: 0)',
argument: '',
@@ -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: '',
},
- // slowTestThreshold: {
- // description: 'Threshold in milliseconds for a test to be considered slow (default: 300)',
- // argument: '',
- // },
- // teardownTimeout: {
- // description: 'Default timeout of a teardown function in milliseconds (default: 10000)',
- // argument: '',
- // },
+ slowTestThreshold: {
+ description: 'Threshold in milliseconds for a test to be considered slow (default: 300)',
+ argument: '',
+ },
+ teardownTimeout: {
+ description: 'Default timeout of a teardown function in milliseconds (default: 10000)',
+ argument: '',
+ },
+ cache: {
+ description: 'Enable cache',
+ argument: '', // allow only boolean
+ subcommands: {
+ dir: {
+ description: 'Path to the cache directory',
+ argument: '',
+ 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: '',
+ },
// CLI only options
run: {
@@ -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,
}
diff --git a/test/core/test/cli-test.test.ts b/test/core/test/cli-test.test.ts
index d7ab84962037..774b846b4eca 100644
--- a/test/core/test/cli-test.test.ts
+++ b/test/core/test/cli-test.test.ts
@@ -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'],
@@ -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],
+ },
})
})
@@ -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 "]`)
+ .toThrowErrorMatchingInlineSnapshot(`[Error: Expected a single value for option "--coverage.provider ", received ["v8", "istanbul"]]`)
})
test('even if coverage is boolean, don\'t fail', () => {
@@ -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": [
@@ -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' },
+ })
+})