@cldmv/vitest-runner 1.1.0 → 1.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,36 +1,46 @@
1
1
  {
2
2
  "name": "@cldmv/vitest-runner",
3
- "version": "1.1.0",
3
+ "version": "1.4.2",
4
4
  "description": "Sequential Vitest runner to avoid OOM issues with large test suites",
5
5
  "type": "module",
6
- "main": "index.cjs",
7
- "module": "index.mjs",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.mjs",
8
8
  "types": "./types/index.d.mts",
9
9
  "exports": {
10
10
  ".": {
11
+ "vitest-runner-dev": {
12
+ "types": "./types/index.d.mts",
13
+ "import": "./src/runner.mjs"
14
+ },
11
15
  "types": "./types/index.d.mts",
12
- "import": "./index.mjs",
13
- "require": "./index.cjs"
16
+ "import": "./dist/index.mjs",
17
+ "require": "./dist/index.cjs"
14
18
  }
15
19
  },
16
20
  "bin": {
17
- "vitest-runner": "./bin/vitest-runner.mjs"
21
+ "vitest-runner": "bin/vitest-runner.mjs"
18
22
  },
19
23
  "files": [
20
- "index.mjs",
21
- "index.cjs",
24
+ "dist/",
25
+ "!dist/**/*.map",
22
26
  "types/",
23
- "src/",
24
- "bin/"
27
+ "bin/",
28
+ "!bin/**/*.map"
25
29
  ],
26
30
  "scripts": {
27
- "lint": "eslint src/ bin/ index.mjs",
31
+ "lint": "eslint --config .configs/eslint.config.mjs .",
32
+ "format": "prettier --write . --config .configs/.prettierrc",
33
+ "format:check": "prettier --check . --config .configs/.prettierrc",
28
34
  "test": "vitest run --config .configs/vitest.config.mjs",
29
35
  "test:watch": "vitest --config .configs/vitest.config.mjs",
30
36
  "test:coverage": "vitest run --coverage --config .configs/vitest.config.mjs",
31
37
  "ci:coverage": "vitest run --coverage --reporter=dot --maxWorkers=1 --config .configs/vitest.config.mjs",
32
38
  "types:build": "tsc -p .configs/tsconfig.json",
33
- "types:check": "tsc -p .configs/tsconfig.json --noEmit"
39
+ "types:check": "tsc -p .configs/tsconfig.json --noEmit",
40
+ "build": "tsup",
41
+ "build:ci": "npm run lint && npm run format:check && npm run types:build && npm run build",
42
+ "prepack": "node -e \"const fs=require('node:fs');const hasTsup=fs.existsSync('node_modules/.bin/tsup')||fs.existsSync('node_modules/.bin/tsup.cmd');if(hasTsup){require('node:child_process').execSync('npm run build',{stdio:'inherit'})}else if(!fs.existsSync('dist/index.mjs')){throw new Error('dist/ is missing and tsup is unavailable to build it (expected in a bare package-contents publish dir with a prebuilt dist/; unexpected anywhere else)')}\"",
43
+ "fix:headers": "node tools/fix-headers.mjs"
34
44
  },
35
45
  "keywords": [
36
46
  "vitest",
@@ -39,10 +49,18 @@
39
49
  "oom"
40
50
  ],
41
51
  "devDependencies": {
52
+ "@cldmv/fix-headers": "^1.3.12",
53
+ "@eslint/js": "^10.0.1",
54
+ "@eslint/json": "^2.0.0",
55
+ "@eslint/markdown": "^8.0.2",
42
56
  "@types/node": "^25.3.0",
43
- "@vitest/coverage-v8": "^4.0.18",
57
+ "@vitest/coverage-v8": "^5.0.2",
58
+ "eslint": "^10.5.0",
59
+ "globals": "^17.6.0",
60
+ "prettier": "^3.8.4",
61
+ "tsup": "^8.5.1",
44
62
  "typescript": "^5.9.3",
45
- "vitest": "^4.0.18"
63
+ "vitest": "^5.0.1"
46
64
  },
47
65
  "dependencies": {
48
66
  "chalk": "^5.4.1"
@@ -51,10 +69,18 @@
51
69
  "vitest": ">=1.0.0"
52
70
  },
53
71
  "engines": {
54
- "node": ">=18.0.0"
72
+ "node": ">=20.19.0"
55
73
  },
56
74
  "publishConfig": {
57
75
  "access": "public"
58
76
  },
77
+ "repository": {
78
+ "type": "git",
79
+ "url": "git+https://github.com/CLDMV/vitest-runner.git"
80
+ },
81
+ "bugs": {
82
+ "url": "https://github.com/CLDMV/vitest-runner/issues"
83
+ },
84
+ "homepage": "https://github.com/CLDMV/vitest-runner#readme",
59
85
  "license": "MIT"
60
86
  }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -45,6 +45,14 @@ export type ParsedArgs = {
45
45
  * - Emit a JSON run report instead of text output (`--json`).
46
46
  */
47
47
  json: boolean;
48
+ /**
49
+ * - Directory for per-file coverage blobs (`--blobs-dir`); defaults to `<cwd>/.vitest-coverage-blobs`.
50
+ */
51
+ blobsDir: string | undefined;
52
+ /**
53
+ * - `false` when `--no-merge-reports` was passed; leaves blobs in `blobsDir` without merging.
54
+ */
55
+ mergeReports: boolean;
48
56
  /**
49
57
  * - Whether `--help` / `-h` was passed.
50
58
  */
@@ -69,4 +77,12 @@ export type ParsedArgs = {
69
77
  * - Non-flag positional arguments (file / folder patterns).
70
78
  */
71
79
  testPatterns: string[];
80
+ /**
81
+ * - Keep the run's scratch directory instead of removing it on completion (`--keep-tmp`).
82
+ */
83
+ keepTmp: boolean;
84
+ /**
85
+ * - Per-run scratch root, relative to `cwd` (`--scratch-dir`); defaults to `tmp/vitest-runner`.
86
+ */
87
+ scratchDir: string | undefined;
72
88
  };
@@ -21,6 +21,29 @@ export function discoverFilesInDir(dir: string, cwd: string, pattern?: RegExp):
21
21
  * sortWithPriority(files, ['listener-cleanup/']);
22
22
  */
23
23
  export function sortWithPriority(files: string[], earlyRunPatterns?: string[]): string[];
24
+ /**
25
+ * Compute, for every file in `files`, the set of *other* files that Vitest's
26
+ * own CLI filter would spuriously also match when that file's path is passed
27
+ * as the filter argument.
28
+ *
29
+ * Vitest's `vitest run <filter>` matches any discovered test file whose path
30
+ * *contains* `<filter>` as a substring — not just an exact-path match. Two
31
+ * files that share the same basename (and immediate parent directory) at
32
+ * different depths — e.g. `tests/contract.test.vitest.mjs` and
33
+ * `packages/a/tests/contract.test.vitest.mjs` — collide because the shorter
34
+ * path is a trailing substring of the longer one, so filtering on the shorter
35
+ * path's exact string also matches the longer path's file. Passing an
36
+ * absolute path does not help: Vitest normalises to a root-relative path
37
+ * before matching.
38
+ *
39
+ * @param {string[]} files - File paths relative to the project root, as returned by discovery.
40
+ * @returns {Map<string, string[]>} Map from each file to the other files it would spuriously match (empty array when unambiguous).
41
+ * @example
42
+ * const conflicts = computeFilterConflicts(["tests/a.mjs", "pkg/tests/a.mjs"]);
43
+ * conflicts.get("tests/a.mjs"); // ["pkg/tests/a.mjs"]
44
+ * conflicts.get("pkg/tests/a.mjs"); // []
45
+ */
46
+ export function computeFilterConflicts(files: string[]): Map<string, string[]>;
24
47
  /**
25
48
  * @typedef {Object} DiscoverOptions
26
49
  * @property {string} cwd - Project root directory.
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Check whether a process is still alive.
3
+ *
4
+ * @param {number} pid
5
+ * @returns {boolean}
6
+ */
7
+ export function isPidAlive(pid: number): boolean;
8
+ /**
9
+ * Remove scratch roots left behind by runs whose owning process is no longer alive
10
+ * (a crash or `kill -9` skips the normal exit-time cleanup).
11
+ *
12
+ * @param {string} cwd - Project root.
13
+ * @param {string} scratchDir - Scratch base directory, relative to `cwd` (or absolute).
14
+ * @returns {Promise<void>}
15
+ */
16
+ export function sweepStaleScratchRoots(cwd: string, scratchDir: string): Promise<void>;
17
+ /**
18
+ * Create this run's scratch root: `<cwd>/<scratchDir>/<pid>-<timestamp>/`.
19
+ *
20
+ * @param {string} cwd - Project root.
21
+ * @param {string} scratchDir - Scratch base directory, relative to `cwd` (or absolute).
22
+ * @returns {Promise<string>} Absolute path to the created root.
23
+ */
24
+ export function createRunScratchRoot(cwd: string, scratchDir: string): Promise<string>;
25
+ /**
26
+ * Create a scratch subdirectory under the run root for one file invocation.
27
+ *
28
+ * @param {string} runRoot - This run's scratch root, from `createRunScratchRoot`.
29
+ * @param {number} index - A unique index for this invocation within the run.
30
+ * @returns {Promise<string>} Absolute path to the created directory.
31
+ */
32
+ export function createFileScratchDir(runRoot: string, index: number): Promise<string>;
33
+ /**
34
+ * Remove a run's scratch root (async, best-effort).
35
+ *
36
+ * @param {string} root
37
+ * @returns {Promise<void>}
38
+ */
39
+ export function removeScratchRoot(root: string): Promise<void>;
40
+ /**
41
+ * Remove a run's scratch root synchronously (best-effort) — used from a signal
42
+ * handler right before `process.exit()`, where async cleanup can't be awaited.
43
+ *
44
+ * @param {string} root
45
+ * @returns {void}
46
+ */
47
+ export function removeScratchRootSync(root: string): void;
48
+ /**
49
+ * Create a fresh, uniquely-named scratch subdirectory for the calling test file.
50
+ *
51
+ * Reads the run's scratch directory from `process.env.VITEST_RUNNER_TMP`, which
52
+ * vitest-runner sets in every spawned child. Call this from a test file to get
53
+ * isolated scratch space per test case without managing your own `mkdtemp` base.
54
+ *
55
+ * @param {string} label - A short, human-readable label used as the directory name prefix.
56
+ * @returns {string} Absolute path to the newly created directory.
57
+ * @throws {Error} When `VITEST_RUNNER_TMP` is not set (not running under vitest-runner).
58
+ * @example
59
+ * import { makeRunTmpDir } from "@cldmv/vitest-runner";
60
+ * const dir = makeRunTmpDir("my-fixture");
61
+ */
62
+ export function makeRunTmpDir(label: string): string;
63
+ /** Default scratch root, relative to `cwd`. */
64
+ export const DEFAULT_SCRATCH_DIR: "tmp/vitest-runner";
@@ -16,7 +16,7 @@
16
16
  * Run a single Vitest test file in a child process and return parsed results.
17
17
  *
18
18
  * @param {string} filePath - Test file path (relative to `cwd` or absolute).
19
- * @param {SpawnBaseOptions & { vitestArgs?: string[], streamOutput?: boolean }} opts
19
+ * @param {SpawnBaseOptions & { vitestArgs?: string[], streamOutput?: boolean, excludePaths?: string[], extraEnv?: NodeJS.ProcessEnv }} opts
20
20
  * @returns {Promise<SingleFileResult>}
21
21
  * @example
22
22
  * const result = await runSingleFile('src/tests/foo.test.vitest.mjs', {
@@ -28,6 +28,8 @@
28
28
  export function runSingleFile(filePath: string, opts: SpawnBaseOptions & {
29
29
  vitestArgs?: string[];
30
30
  streamOutput?: boolean;
31
+ excludePaths?: string[];
32
+ extraEnv?: NodeJS.ProcessEnv;
31
33
  }): Promise<SingleFileResult>;
32
34
  /**
33
35
  * Run Vitest directly (all files in one process) with inherited stdio.
@@ -2,12 +2,19 @@
2
2
  * Run all discovered Vitest test files sequentially (with a configurable worker
3
3
  * pool for the non-solo phase) and return an exit code.
4
4
  *
5
+ * Owns the run's scratch directory lifecycle (`scratchDir`/`keepTmp`): sweeps stale
6
+ * roots from dead prior runs, creates this run's root, and removes it on every exit
7
+ * path — normal completion, a thrown error, or SIGINT/SIGTERM — unless `keepTmp` is
8
+ * set. The actual run logic lives in {@link runImpl}; this wrapper only exists to
9
+ * guarantee that cleanup regardless of how `runImpl` returns or throws.
10
+ *
5
11
  * @param {RunOptions} opts
6
12
  * @returns {Promise<number|object>} `0`/`1` by default; JSON report object when `opts.json` is true.
7
13
  */
8
14
  export function run(opts: RunOptions): Promise<number | object>;
9
15
  export { formatDuration } from "./utils/duration.mjs";
10
16
  export { buildNodeOptions } from "./utils/env.mjs";
17
+ export { makeRunTmpDir } from "./core/scratch.mjs";
11
18
  export type PerFileHeapOverride = {
12
19
  /**
13
20
  * - Substring matched against the normalised file path.
@@ -79,6 +86,14 @@ export type RunOptions = {
79
86
  * - Rows in the worst-coverage table (0 = disable).
80
87
  */
81
88
  worstCoverageCount?: number;
89
+ /**
90
+ * - Directory for per-file coverage blobs (default `<cwd>/.vitest-coverage-blobs`). Relative paths resolve against `cwd`. Always cleared at the start of a coverage run.
91
+ */
92
+ blobsDir?: string;
93
+ /**
94
+ * - When `true`, blobs are merged via `vitest --mergeReports`, the coverage summary is printed, and `blobsDir` is deleted at the end. When `false`, the run stops after producing blobs: no merge, no summary, and `blobsDir` is left populated for an external merge step.
95
+ */
96
+ mergeReports?: boolean;
82
97
  /**
83
98
  * - Global `--max-old-space-size` ceiling; per-file overrides may raise it.
84
99
  */
@@ -99,6 +114,14 @@ export type RunOptions = {
99
114
  * - Value for `NODE_ENV` in child processes.
100
115
  */
101
116
  nodeEnv?: string;
117
+ /**
118
+ * - Per-run scratch root, relative to `cwd` (or absolute). A subdirectory is created per file invocation and exposed to it via `VITEST_RUNNER_TMP`.
119
+ */
120
+ scratchDir?: string;
121
+ /**
122
+ * - Keep the run's scratch root instead of removing it on completion (normal exit, failure, or SIGINT/SIGTERM).
123
+ */
124
+ keepTmp?: boolean;
102
125
  /**
103
126
  * -
104
127
  */
@@ -1,3 +1,15 @@
1
+ /**
2
+ * @Project: @cldmv/vitest-runner
3
+ * @Filename: /src/utils/ansi.mjs
4
+ * @Date: 2026-02-24T22:33:55-08:00 (1772001235)
5
+ * @Author: Shinrai <CLDMV>
6
+ * @Email: <Shinrai@users.noreply.github.com>
7
+ * -----
8
+ * @Last modified by: Shinrai <CLDMV> (Shinrai@users.noreply.github.com)
9
+ * @Last modified time: 2026-09-27 08:51:31 -07:00 (1790524291)
10
+ * -----
11
+ * @Copyright: Copyright (c) 2013-2026 Catalyzed Motivation Inc. All rights reserved.
12
+ */
1
13
  /**
2
14
  * @fileoverview ANSI escape-code helpers.
3
15
  * @module vitest-runner/src/utils/ansi
@@ -1,3 +1,15 @@
1
+ /**
2
+ * @Project: @cldmv/vitest-runner
3
+ * @Filename: /src/utils/duration.mjs
4
+ * @Date: 2026-02-24T22:33:55-08:00 (1772001235)
5
+ * @Author: Shinrai <CLDMV>
6
+ * @Email: <Shinrai@users.noreply.github.com>
7
+ * -----
8
+ * @Last modified by: Shinrai <CLDMV> (Shinrai@users.noreply.github.com)
9
+ * @Last modified time: 2026-09-27 08:51:31 -07:00 (1790524291)
10
+ * -----
11
+ * @Copyright: Copyright (c) 2013-2026 Catalyzed Motivation Inc. All rights reserved.
12
+ */
1
13
  /**
2
14
  * @fileoverview Duration formatting utilities.
3
15
  * @module vitest-runner/src/utils/duration
@@ -1,3 +1,15 @@
1
+ /**
2
+ * @Project: @cldmv/vitest-runner
3
+ * @Filename: /src/utils/env.mjs
4
+ * @Date: 2026-02-24T22:33:55-08:00 (1772001235)
5
+ * @Author: Shinrai <CLDMV>
6
+ * @Email: <Shinrai@users.noreply.github.com>
7
+ * -----
8
+ * @Last modified by: Shinrai <CLDMV> (Shinrai@users.noreply.github.com)
9
+ * @Last modified time: 2026-09-27 08:51:31 -07:00 (1790524291)
10
+ * -----
11
+ * @Copyright: Copyright (c) 2013-2026 Catalyzed Motivation Inc. All rights reserved.
12
+ */
1
13
  /**
2
14
  * @fileoverview NODE_OPTIONS / environment helpers.
3
15
  * @module vitest-runner/src/utils/env
package/index.cjs DELETED
@@ -1,17 +0,0 @@
1
- /**
2
- * @fileoverview CJS shim — dynamically imports the ESM entry point so that
3
- * CommonJS callers can `require('vitest-runner')`.
4
- *
5
- * Because the package is pure ESM (`"type": "module"`) we cannot use `module.exports =`
6
- * directly; instead we export a promise and re-attach named exports once resolved.
7
- *
8
- * @example
9
- * // CommonJS usage
10
- * const { run } = await require('vitest-runner');
11
- */
12
-
13
- "use strict";
14
-
15
- // Async shim: re-export everything from the ESM module.
16
- // Callers must await the result or use .then().
17
- module.exports = import("./index.mjs");
package/index.mjs DELETED
@@ -1,5 +0,0 @@
1
- /**
2
- * @fileoverview ESM entry-point — re-exports the public API from src/runner.mjs.
3
- * @module vitest-runner
4
- */
5
- export * from "./src/runner.mjs";
package/src/cli/args.mjs DELETED
@@ -1,134 +0,0 @@
1
- /**
2
- * @fileoverview CLI argument parsing for the vitest-runner binary.
3
- * @module vitest-runner/src/cli/args
4
- */
5
-
6
- /**
7
- * @typedef {Object} ParsedArgs
8
- * @property {string|undefined} testListFile - Path to a JSON file of test paths to run (`--test-list`).
9
- * @property {boolean} showErrorDetails - `false` when `--no-error-details` was passed.
10
- * @property {boolean} coverageQuiet - Whether `--coverage-quiet` was passed.
11
- * @property {string|undefined} logFile - Path for the coverage run log (`--log-file`); defaults to `coverage/coverage-run.log`.
12
- * @property {boolean} suppressFileOutput - Suppress per-file runner output blocks (`--suppress-file-output`).
13
- * @property {boolean} suppressPassingFiles - Suppress the passed-files section in the final summary (`--suppress-passing-files`).
14
- * @property {boolean} topSummary - Show top-summary sections for memory and duration (`true` by default, disabled by `--no-top-summary`).
15
- * @property {boolean} json - Emit a JSON run report instead of text output (`--json`).
16
- * @property {boolean} help - Whether `--help` / `-h` was passed.
17
- * @property {number|undefined} workers - Worker count from `--workers <n>`, or undefined.
18
- * @property {string[]} soloPatterns - Path substrings from `--solo-pattern <pattern>` (repeatable).
19
- * @property {RegExp|undefined} testFilePattern - Compiled regex from `--file-pattern <regex>`, or undefined.
20
- * @property {string[]} vitestPassthroughArgs - Flags forwarded verbatim to vitest.
21
- * @property {string[]} testPatterns - Non-flag positional arguments (file / folder patterns).
22
- */
23
-
24
- /** Runner-owned flags that must not be forwarded to vitest. */
25
- const RUNNER_FLAGS = new Set([
26
- "--test-list",
27
- "--no-error-details",
28
- "--coverage-quiet",
29
- "--log-file",
30
- "--suppress-file-output",
31
- "--suppress-passing-files",
32
- "--no-top-summary",
33
- "--json",
34
- "--workers",
35
- "--solo-pattern",
36
- "--file-pattern",
37
- "--help",
38
- "-h"
39
- ]);
40
-
41
- /**
42
- * Parse raw CLI arguments into structured runner options.
43
- *
44
- * Runner-specific flags are extracted; everything else (flags and their
45
- * optional values) is forwarded to vitest as passthrough args.
46
- * A flag that takes a value (where the next token does not start with `-`)
47
- * consumes that token too.
48
- *
49
- * @param {string[]} args - Raw argument array (typically `process.argv.slice(2)`).
50
- * @returns {ParsedArgs}
51
- * @example
52
- * parseArguments(['--test-list', 'tests.json', '--workers', '2', '--reporter=verbose']);
53
- */
54
- export function parseArguments(args) {
55
- const vitestPassthroughArgs = [];
56
- const testPatterns = [];
57
- const soloPatterns = [];
58
- let testListFile;
59
- let showErrorDetails = true;
60
- let coverageQuiet = false;
61
- let logFile;
62
- let suppressFileOutput = false;
63
- let suppressPassingFiles = false;
64
- let topSummary = true;
65
- let json = false;
66
- let workers;
67
- let help = false;
68
- let testFilePattern;
69
- for (let i = 0; i < args.length; i++) {
70
- const arg = args[i];
71
-
72
- if (arg === "--test-list") {
73
- testListFile = args[++i];
74
- } else if (arg.startsWith("--test-list=")) {
75
- testListFile = arg.slice("--test-list=".length);
76
- } else if (arg === "--no-error-details") {
77
- showErrorDetails = false;
78
- } else if (arg === "--coverage-quiet") {
79
- coverageQuiet = true;
80
- } else if (arg === "--log-file") {
81
- logFile = args[++i];
82
- } else if (arg.startsWith("--log-file=")) {
83
- logFile = arg.slice("--log-file=".length);
84
- } else if (arg === "--suppress-file-output") {
85
- suppressFileOutput = true;
86
- } else if (arg === "--suppress-passing-files") {
87
- suppressPassingFiles = true;
88
- } else if (arg === "--no-top-summary") {
89
- topSummary = false;
90
- } else if (arg === "--json") {
91
- json = true;
92
- } else if (arg === "--workers") {
93
- workers = parseInt(args[++i], 10);
94
- } else if (arg.startsWith("--workers=")) {
95
- workers = parseInt(arg.slice("--workers=".length), 10);
96
- } else if (arg === "--solo-pattern") {
97
- soloPatterns.push(args[++i]);
98
- } else if (arg.startsWith("--solo-pattern=")) {
99
- soloPatterns.push(arg.slice("--solo-pattern=".length));
100
- } else if (arg === "--file-pattern") {
101
- testFilePattern = new RegExp(args[++i], "i");
102
- } else if (arg.startsWith("--file-pattern=")) {
103
- testFilePattern = new RegExp(arg.slice("--file-pattern=".length), "i");
104
- } else if (arg === "--help" || arg === "-h") {
105
- help = true;
106
- } else if ((arg.startsWith("--") || arg.startsWith("-")) && !RUNNER_FLAGS.has(arg)) {
107
- vitestPassthroughArgs.push(arg);
108
- // Consume the next token if it looks like a value (not another flag)
109
- if (i + 1 < args.length && !args[i + 1].startsWith("-")) {
110
- vitestPassthroughArgs.push(args[++i]);
111
- }
112
- } else {
113
- // Any remaining token (cannot start with '-'; those are caught above)
114
- testPatterns.push(arg);
115
- }
116
- }
117
-
118
- return {
119
- testListFile,
120
- showErrorDetails,
121
- coverageQuiet,
122
- logFile,
123
- suppressFileOutput,
124
- suppressPassingFiles,
125
- topSummary,
126
- json,
127
- help,
128
- workers,
129
- soloPatterns,
130
- testFilePattern,
131
- vitestPassthroughArgs,
132
- testPatterns
133
- };
134
- }
package/src/cli/help.mjs DELETED
@@ -1,84 +0,0 @@
1
- /**
2
- * @fileoverview CLI help text for the vitest-runner binary.
3
- * @module vitest-runner/src/cli/help
4
- */
5
-
6
- import chalk from "chalk";
7
-
8
- /**
9
- * Print the full CLI help message to stdout.
10
- * @returns {void}
11
- * @example
12
- * showHelp();
13
- */
14
- export function showHelp() {
15
- console.log(`
16
- ${chalk.bold("Vitest Sequential Runner")}
17
- Runs each test file in its own Vitest process to avoid OOM issues.
18
-
19
- ${chalk.bold("USAGE:")}
20
- vitest-runner [OPTIONS] [PATTERNS]
21
-
22
- ${chalk.bold("SPECIAL FLAGS:")}
23
- --test-list <file> Run only the files listed in a JSON array file
24
- --file-pattern <regex> Override the file discovery regex (default: \.test\.vitest\.(?:js|mjs|cjs)$)
25
- --workers <n> Number of parallel workers (default: 4 or VITEST_WORKERS)
26
- --solo-pattern <pat> Run files matching this path substring solo first (repeatable)
27
- --no-error-details Hide detailed error output (show only counts)
28
- --coverage-quiet Implies --coverage; show progress bar + final summaries only
29
- --log-file <path> Path for mirrored runner output (default: coverage/coverage-run.log with --coverage-quiet)
30
- --suppress-file-output Suppress per-file runner output blocks
31
- --suppress-passing-files Hide the PASSED TEST FILES section in the final summary
32
- --no-top-summary Hide TOP MEMORY USERS and TOP DURATION sections
33
- --json Emit JSON summary output instead of text logs
34
- --help, -h Show this help message
35
-
36
- ${chalk.bold("TEST PATTERNS:")}
37
- [file] Run a specific test file (supports partial paths)
38
- [folder] Run all tests in a folder
39
-
40
- Examples:
41
- src/tests/config/background.test.vitest.mjs
42
- src/tests/metadata
43
- background.test.vitest.mjs
44
-
45
- ${chalk.bold("VITEST FLAGS:")}
46
- All standard Vitest CLI flags are supported and passed through:
47
- -t, --testNamePattern Filter tests by name pattern (regex)
48
- --reporter Change reporter (verbose, dot, json, etc.)
49
- --coverage Run full-suite coverage (blob-per-file + mergeReports)
50
- --bail Stop on first failure
51
-
52
- See the Vitest documentation for the full list.
53
-
54
- ${chalk.bold("ENVIRONMENT VARIABLES:")}
55
- VITEST_HEAP_MB Set max heap size per test (default: Node.js default)
56
- VITEST_WORKERS Number of parallel workers (default: 4, overridden by --workers)
57
- # Run all tests
58
- vitest-runner
59
-
60
- # Run a specific file (partial path ok)
61
- vitest-runner src/tests/config/background.test.vitest.mjs
62
-
63
- # Run only the files listed in a JSON file
64
- vitest-runner --test-list my-tests.json
65
-
66
- # Filter by test name
67
- vitest-runner src/tests/metadata -t "lazy materialization"
68
-
69
- # Run with 2 workers
70
- vitest-runner --workers 2
71
-
72
- # Run files matching a pattern solo first, then the rest in parallel
73
- vitest-runner --solo-pattern listener-cleanup/ --solo-pattern heavy/
74
-
75
- # Hide detailed errors
76
- vitest-runner --no-error-details
77
-
78
- # Coverage with quiet output + progress bar
79
- vitest-runner --coverage --coverage-quiet
80
-
81
- # Custom heap and workers
82
- VITEST_HEAP_MB=8192 vitest-runner --workers 2 src/tests/heavy
83
- `);
84
- }