vitest 3.0.8 → 3.0.9
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/dist/browser.d.ts +12 -23
- package/dist/browser.js +2 -2
- package/dist/chunks/{base.XvKTsMeK.js → base.DV59CbtV.js} +1 -1
- package/dist/chunks/{benchmark.Cdu9hjj4.js → benchmark.DL72EVN-.js} +1 -1
- package/dist/chunks/{benchmark.CFFwLv-O.d.ts → benchmark.d.BwvBVTda.d.ts} +11 -11
- package/dist/chunks/{cac.VN5q-TPC.js → cac.CeVHgzve.js} +5 -5
- package/dist/chunks/{cli-api.Dis64jtY.js → cli-api.Ckwz_xSb.js} +13 -8
- package/dist/chunks/config.d.DevWltVl.d.ts +218 -0
- package/dist/chunks/{constants.fzPh7AOq.js → constants.DTYd6dNH.js} +1 -1
- package/dist/chunks/{coverage.DnNIv-kJ.js → coverage.A3sS5-Wm.js} +1 -29
- package/dist/chunks/coverage.d.S9RMNXIe.d.ts +35 -0
- package/dist/chunks/{resolveConfig.L1_HR0_0.js → coverage.gV8doR2Y.js} +496 -127
- package/dist/chunks/{creator.2CFRE1Yx.js → creator.BsBnpTzI.js} +1 -1
- package/dist/chunks/defaults.C2Ndd9wx.js +119 -0
- package/dist/chunks/env.D4Lgay0q.js +8 -0
- package/dist/chunks/environment.d.C8UItCbf.d.ts +170 -0
- package/dist/chunks/global.d.Cg2sEPIm.d.ts +127 -0
- package/dist/chunks/{globals.CydvVTgC.js → globals.BEpDe-k3.js} +4 -4
- package/dist/chunks/{index.B7vJpkTD.js → index.B8tIoLPT.js} +6 -1
- package/dist/chunks/{index.CNRemkXW.js → index.D7Ny8f_s.js} +2 -2
- package/dist/chunks/{index.BmFgJtkv.js → index.uXkkC4xl.js} +1 -2
- package/dist/chunks/{mocker.cRtM890J.d.ts → mocker.d.BE_2ls6u.d.ts} +6 -6
- package/dist/chunks/reporters.d.CqBhtcTq.d.ts +3006 -0
- package/dist/chunks/{runBaseTests.DnaAUBKD.js → runBaseTests.BVrL_ow3.js} +8 -8
- package/dist/chunks/{setup-common.Uaw6Zgv9.js → setup-common.CPvtqi8q.js} +25 -2
- package/dist/chunks/{suite.qtkXWc6R.d.ts → suite.d.FvehnV49.d.ts} +1 -1
- package/dist/chunks/{typechecker.cZ0LjdSi.js → typechecker.BlF3eHsb.js} +2 -7
- package/dist/chunks/{vi.B5EKKJdE.js → vi.nSCvwQ7l.js} +3 -3
- package/dist/chunks/vite.d.BUZTGxQ3.d.ts +11 -0
- package/dist/chunks/{worker.BmVno_ab.d.ts → worker.d.C58isfFm.d.ts} +62 -62
- package/dist/chunks/{worker.BT4v-DKx.d.ts → worker.d.CSFlSYJg.d.ts} +2 -2
- package/dist/cli.js +2 -2
- package/dist/config.d.ts +48 -45
- package/dist/config.js +6 -123
- package/dist/coverage.d.ts +82 -79
- package/dist/coverage.js +19 -469
- package/dist/environments.d.ts +11 -11
- package/dist/execute.d.ts +109 -109
- package/dist/index.d.ts +414 -412
- package/dist/index.js +3 -3
- package/dist/node.d.ts +51 -48
- package/dist/node.js +13 -10
- package/dist/reporters.d.ts +7 -4
- package/dist/reporters.js +3 -2
- package/dist/runners.d.ts +28 -28
- package/dist/runners.js +2 -3
- package/dist/snapshot.d.ts +2 -2
- package/dist/suite.d.ts +2 -2
- package/dist/suite.js +1 -1
- package/dist/workers/forks.js +1 -1
- package/dist/workers/runVmTests.js +8 -8
- package/dist/workers/threads.js +1 -1
- package/dist/workers.d.ts +13 -13
- package/dist/workers.js +1 -1
- package/package.json +11 -11
- package/dist/chunks/config.BCv-fVdT.d.ts +0 -215
- package/dist/chunks/environment.d8YfPkTm.d.ts +0 -173
- package/dist/chunks/global.CnI8_G5V.d.ts +0 -133
- package/dist/chunks/reporters.66aFHiyX.d.ts +0 -3051
- package/dist/chunks/vite.BCQa3xFG.d.ts +0 -11
package/dist/coverage.d.ts
CHANGED
|
@@ -1,102 +1,105 @@
|
|
|
1
|
-
import { R as ResolvedCoverageOptions, V as Vitest, C as CoverageMap, a as ReportContext } from './chunks/reporters.
|
|
1
|
+
import { R as ResolvedCoverageOptions, V as Vitest, C as CoverageMap, a as ReportContext } from './chunks/reporters.d.CqBhtcTq.js';
|
|
2
2
|
import { TransformResult } from 'vite';
|
|
3
|
-
import { A as AfterSuiteRunMeta } from './chunks/environment.
|
|
3
|
+
import { A as AfterSuiteRunMeta } from './chunks/environment.d.C8UItCbf.js';
|
|
4
4
|
import '@vitest/runner';
|
|
5
5
|
import '@vitest/utils';
|
|
6
6
|
import 'node:stream';
|
|
7
|
+
import 'node:console';
|
|
7
8
|
import '@vitest/utils/source-map';
|
|
8
|
-
import './chunks/config.
|
|
9
|
+
import './chunks/config.d.DevWltVl.js';
|
|
9
10
|
import '@vitest/pretty-format';
|
|
10
11
|
import '@vitest/snapshot';
|
|
11
12
|
import '@vitest/snapshot/environment';
|
|
12
13
|
import '@vitest/utils/diff';
|
|
13
14
|
import 'vite-node';
|
|
14
15
|
import 'chai';
|
|
15
|
-
import './chunks/benchmark.
|
|
16
|
+
import './chunks/benchmark.d.BwvBVTda.js';
|
|
16
17
|
import '@vitest/runner/utils';
|
|
17
18
|
import 'tinybench';
|
|
19
|
+
import './chunks/coverage.d.S9RMNXIe.js';
|
|
20
|
+
import 'vite-node/client';
|
|
18
21
|
import '@vitest/snapshot/manager';
|
|
19
22
|
import 'node:fs';
|
|
20
23
|
|
|
21
|
-
type Threshold =
|
|
24
|
+
type Threshold = "lines" | "functions" | "statements" | "branches";
|
|
22
25
|
interface ResolvedThreshold {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
+
coverageMap: CoverageMap;
|
|
27
|
+
name: string;
|
|
28
|
+
thresholds: Partial<Record<Threshold, number | undefined>>;
|
|
26
29
|
}
|
|
27
30
|
/**
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
type CoverageFiles = Map<NonNullable<AfterSuiteRunMeta[
|
|
44
|
-
|
|
31
|
+
* Holds info about raw coverage results that are stored on file system:
|
|
32
|
+
*
|
|
33
|
+
* ```json
|
|
34
|
+
* "project-a": {
|
|
35
|
+
* "web": {
|
|
36
|
+
* "tests/math.test.ts": "coverage-1.json",
|
|
37
|
+
* "tests/utils.test.ts": "coverage-2.json",
|
|
38
|
+
* // ^^^^^^^^^^^^^^^ Raw coverage on file system
|
|
39
|
+
* },
|
|
40
|
+
* "ssr": { ... },
|
|
41
|
+
* "browser": { ... },
|
|
42
|
+
* },
|
|
43
|
+
* "project-b": ...
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
type CoverageFiles = Map<NonNullable<AfterSuiteRunMeta["projectName"]> | symbol, Record<AfterSuiteRunMeta["transformMode"], {
|
|
47
|
+
[TestFilenames: string]: string
|
|
45
48
|
}>>;
|
|
46
|
-
declare class BaseCoverageProvider<Options extends ResolvedCoverageOptions<
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
49
|
+
declare class BaseCoverageProvider<Options extends ResolvedCoverageOptions<"istanbul" | "v8">> {
|
|
50
|
+
ctx: Vitest;
|
|
51
|
+
readonly name: "v8" | "istanbul";
|
|
52
|
+
version: string;
|
|
53
|
+
options: Options;
|
|
54
|
+
coverageFiles: CoverageFiles;
|
|
55
|
+
pendingPromises: Promise<void>[];
|
|
56
|
+
coverageFilesDirectory: string;
|
|
57
|
+
_initialize(ctx: Vitest): void;
|
|
58
|
+
createCoverageMap(): CoverageMap;
|
|
59
|
+
generateReports(_: CoverageMap, __: boolean | undefined): Promise<void>;
|
|
60
|
+
parseConfigModule(_: string): Promise<{
|
|
61
|
+
generate: () => {
|
|
62
|
+
code: string
|
|
63
|
+
}
|
|
64
|
+
}>;
|
|
65
|
+
resolveOptions(): Options;
|
|
66
|
+
clean(clean?: boolean): Promise<void>;
|
|
67
|
+
onAfterSuiteRun({ coverage, transformMode, projectName, testFiles }: AfterSuiteRunMeta): void;
|
|
68
|
+
readCoverageFiles<CoverageType>({ onFileRead, onFinished, onDebug }: {
|
|
69
|
+
/** Callback invoked with a single coverage result */
|
|
70
|
+
onFileRead: (data: CoverageType) => void
|
|
71
|
+
/** Callback invoked once all results of a project for specific transform mode are read */
|
|
72
|
+
onFinished: (project: Vitest["projects"][number], transformMode: AfterSuiteRunMeta["transformMode"]) => Promise<void>
|
|
73
|
+
onDebug: ((...logs: any[]) => void) & {
|
|
74
|
+
enabled: boolean
|
|
75
|
+
}
|
|
76
|
+
}): Promise<void>;
|
|
77
|
+
cleanAfterRun(): Promise<void>;
|
|
78
|
+
onTestFailure(): Promise<void>;
|
|
79
|
+
reportCoverage(coverageMap: unknown, { allTestsRun }: ReportContext): Promise<void>;
|
|
80
|
+
reportThresholds(coverageMap: CoverageMap, allTestsRun: boolean | undefined): Promise<void>;
|
|
81
|
+
/**
|
|
82
|
+
* Constructs collected coverage and users' threshold options into separate sets
|
|
83
|
+
* where each threshold set holds their own coverage maps. Threshold set is either
|
|
84
|
+
* for specific files defined by glob pattern or global for all other files.
|
|
85
|
+
*/
|
|
86
|
+
private resolveThresholds;
|
|
87
|
+
/**
|
|
88
|
+
* Check collected coverage against configured thresholds. Sets exit code to 1 when thresholds not reached.
|
|
89
|
+
*/
|
|
90
|
+
private checkThresholds;
|
|
91
|
+
/**
|
|
92
|
+
* Check if current coverage is above configured thresholds and bump the thresholds if needed
|
|
93
|
+
*/
|
|
94
|
+
updateThresholds({ thresholds: allThresholds, onUpdate, configurationFile }: {
|
|
95
|
+
thresholds: ResolvedThreshold[]
|
|
96
|
+
configurationFile: unknown
|
|
97
|
+
onUpdate: () => void
|
|
98
|
+
}): Promise<void>;
|
|
99
|
+
mergeReports(coverageMaps: unknown[]): Promise<void>;
|
|
100
|
+
hasTerminalReporter(reporters: ResolvedCoverageOptions["reporter"]): boolean;
|
|
101
|
+
toSlices<T>(array: T[], size: number): T[][];
|
|
102
|
+
createUncoveredFileTransformer(ctx: Vitest): (filename: string) => Promise<TransformResult | null | undefined>;
|
|
100
103
|
}
|
|
101
104
|
|
|
102
105
|
export { BaseCoverageProvider };
|
package/dist/coverage.js
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
1
|
+
export { B as BaseCoverageProvider } from './chunks/coverage.gV8doR2Y.js';
|
|
2
|
+
import 'node:fs';
|
|
3
|
+
import './chunks/_commonjsHelpers.BFTU3MAI.js';
|
|
4
|
+
import 'util';
|
|
5
|
+
import 'path';
|
|
6
|
+
import 'pathe';
|
|
7
|
+
import 'tinyrainbow';
|
|
8
|
+
import './chunks/defaults.C2Ndd9wx.js';
|
|
9
|
+
import 'node:os';
|
|
10
|
+
import './chunks/env.D4Lgay0q.js';
|
|
11
|
+
import 'std-env';
|
|
5
12
|
import 'node:crypto';
|
|
6
13
|
import '@vitest/utils';
|
|
7
14
|
import 'node:fs/promises';
|
|
@@ -12,476 +19,19 @@ import 'node:url';
|
|
|
12
19
|
import 'node:assert';
|
|
13
20
|
import 'node:v8';
|
|
14
21
|
import 'node:util';
|
|
15
|
-
import './chunks/constants.
|
|
16
|
-
import 'node:
|
|
17
|
-
import '
|
|
18
|
-
import '
|
|
22
|
+
import './chunks/constants.DTYd6dNH.js';
|
|
23
|
+
import 'node:tty';
|
|
24
|
+
import 'vite';
|
|
25
|
+
import 'node:events';
|
|
26
|
+
import './chunks/index.68735LiX.js';
|
|
27
|
+
import 'tinypool';
|
|
28
|
+
import './chunks/typechecker.BlF3eHsb.js';
|
|
19
29
|
import 'node:perf_hooks';
|
|
20
30
|
import '@vitest/utils/source-map';
|
|
21
31
|
import 'tinyexec';
|
|
22
32
|
import '@vitest/runner/utils';
|
|
23
|
-
import 'vite';
|
|
24
33
|
import 'fs';
|
|
25
|
-
import 'node:tty';
|
|
26
|
-
import './chunks/_commonjsHelpers.BFTU3MAI.js';
|
|
27
|
-
import 'util';
|
|
28
|
-
import 'path';
|
|
29
|
-
import 'node:events';
|
|
30
|
-
import './chunks/index.68735LiX.js';
|
|
31
|
-
import 'tinypool';
|
|
32
34
|
import 'node:worker_threads';
|
|
33
35
|
import './path.js';
|
|
34
36
|
import 'vite-node/utils';
|
|
35
|
-
|
|
36
|
-
const THRESHOLD_KEYS = [
|
|
37
|
-
"lines",
|
|
38
|
-
"functions",
|
|
39
|
-
"statements",
|
|
40
|
-
"branches"
|
|
41
|
-
];
|
|
42
|
-
const GLOBAL_THRESHOLDS_KEY = "global";
|
|
43
|
-
const DEFAULT_PROJECT = Symbol.for("default-project");
|
|
44
|
-
let uniqueId = 0;
|
|
45
|
-
class BaseCoverageProvider {
|
|
46
|
-
ctx;
|
|
47
|
-
name;
|
|
48
|
-
version;
|
|
49
|
-
options;
|
|
50
|
-
coverageFiles = /* @__PURE__ */ new Map();
|
|
51
|
-
pendingPromises = [];
|
|
52
|
-
coverageFilesDirectory;
|
|
53
|
-
_initialize(ctx) {
|
|
54
|
-
this.ctx = ctx;
|
|
55
|
-
if (ctx.version !== this.version) {
|
|
56
|
-
ctx.logger.warn(
|
|
57
|
-
c.yellow(
|
|
58
|
-
`Loaded ${c.inverse(c.yellow(` vitest@${ctx.version} `))} and ${c.inverse(c.yellow(` @vitest/coverage-${this.name}@${this.version} `))}.
|
|
59
|
-
Running mixed versions is not supported and may lead into bugs
|
|
60
|
-
Update your dependencies and make sure the versions match.`
|
|
61
|
-
)
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
const config = ctx.config.coverage;
|
|
65
|
-
this.options = {
|
|
66
|
-
...coverageConfigDefaults,
|
|
67
|
-
// User's options
|
|
68
|
-
...config,
|
|
69
|
-
// Resolved fields
|
|
70
|
-
provider: this.name,
|
|
71
|
-
reportsDirectory: resolve(
|
|
72
|
-
ctx.config.root,
|
|
73
|
-
config.reportsDirectory || coverageConfigDefaults.reportsDirectory
|
|
74
|
-
),
|
|
75
|
-
reporter: resolveCoverageReporters(
|
|
76
|
-
config.reporter || coverageConfigDefaults.reporter
|
|
77
|
-
),
|
|
78
|
-
thresholds: config.thresholds && {
|
|
79
|
-
...config.thresholds,
|
|
80
|
-
lines: config.thresholds["100"] ? 100 : config.thresholds.lines,
|
|
81
|
-
branches: config.thresholds["100"] ? 100 : config.thresholds.branches,
|
|
82
|
-
functions: config.thresholds["100"] ? 100 : config.thresholds.functions,
|
|
83
|
-
statements: config.thresholds["100"] ? 100 : config.thresholds.statements
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
|
-
const shard = this.ctx.config.shard;
|
|
87
|
-
const tempDirectory = `.tmp${shard ? `-${shard.index}-${shard.count}` : ""}`;
|
|
88
|
-
this.coverageFilesDirectory = resolve(
|
|
89
|
-
this.options.reportsDirectory,
|
|
90
|
-
tempDirectory
|
|
91
|
-
);
|
|
92
|
-
}
|
|
93
|
-
createCoverageMap() {
|
|
94
|
-
throw new Error("BaseReporter's createCoverageMap was not overwritten");
|
|
95
|
-
}
|
|
96
|
-
async generateReports(_, __) {
|
|
97
|
-
throw new Error("BaseReporter's generateReports was not overwritten");
|
|
98
|
-
}
|
|
99
|
-
async parseConfigModule(_) {
|
|
100
|
-
throw new Error("BaseReporter's parseConfigModule was not overwritten");
|
|
101
|
-
}
|
|
102
|
-
resolveOptions() {
|
|
103
|
-
return this.options;
|
|
104
|
-
}
|
|
105
|
-
async clean(clean = true) {
|
|
106
|
-
if (clean && existsSync(this.options.reportsDirectory)) {
|
|
107
|
-
await promises.rm(this.options.reportsDirectory, {
|
|
108
|
-
recursive: true,
|
|
109
|
-
force: true,
|
|
110
|
-
maxRetries: 10
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
if (existsSync(this.coverageFilesDirectory)) {
|
|
114
|
-
await promises.rm(this.coverageFilesDirectory, {
|
|
115
|
-
recursive: true,
|
|
116
|
-
force: true,
|
|
117
|
-
maxRetries: 10
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
await promises.mkdir(this.coverageFilesDirectory, { recursive: true });
|
|
121
|
-
this.coverageFiles = /* @__PURE__ */ new Map();
|
|
122
|
-
this.pendingPromises = [];
|
|
123
|
-
}
|
|
124
|
-
onAfterSuiteRun({ coverage, transformMode, projectName, testFiles }) {
|
|
125
|
-
if (!coverage) {
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
if (transformMode !== "web" && transformMode !== "ssr" && transformMode !== "browser") {
|
|
129
|
-
throw new Error(`Invalid transform mode: ${transformMode}`);
|
|
130
|
-
}
|
|
131
|
-
let entry = this.coverageFiles.get(projectName || DEFAULT_PROJECT);
|
|
132
|
-
if (!entry) {
|
|
133
|
-
entry = { web: {}, ssr: {}, browser: {} };
|
|
134
|
-
this.coverageFiles.set(projectName || DEFAULT_PROJECT, entry);
|
|
135
|
-
}
|
|
136
|
-
const testFilenames = testFiles.join();
|
|
137
|
-
const filename = resolve(
|
|
138
|
-
this.coverageFilesDirectory,
|
|
139
|
-
`coverage-${uniqueId++}.json`
|
|
140
|
-
);
|
|
141
|
-
entry[transformMode][testFilenames] = filename;
|
|
142
|
-
const promise = promises.writeFile(filename, JSON.stringify(coverage), "utf-8");
|
|
143
|
-
this.pendingPromises.push(promise);
|
|
144
|
-
}
|
|
145
|
-
async readCoverageFiles({ onFileRead, onFinished, onDebug }) {
|
|
146
|
-
let index = 0;
|
|
147
|
-
const total = this.pendingPromises.length;
|
|
148
|
-
await Promise.all(this.pendingPromises);
|
|
149
|
-
this.pendingPromises = [];
|
|
150
|
-
for (const [projectName, coveragePerProject] of this.coverageFiles.entries()) {
|
|
151
|
-
for (const [transformMode, coverageByTestfiles] of Object.entries(coveragePerProject)) {
|
|
152
|
-
const filenames = Object.values(coverageByTestfiles);
|
|
153
|
-
const project = this.ctx.getProjectByName(projectName);
|
|
154
|
-
for (const chunk of this.toSlices(filenames, this.options.processingConcurrency)) {
|
|
155
|
-
if (onDebug.enabled) {
|
|
156
|
-
index += chunk.length;
|
|
157
|
-
onDebug("Covered files %d/%d", index, total);
|
|
158
|
-
}
|
|
159
|
-
await Promise.all(
|
|
160
|
-
chunk.map(async (filename) => {
|
|
161
|
-
const contents = await promises.readFile(filename, "utf-8");
|
|
162
|
-
const coverage = JSON.parse(contents);
|
|
163
|
-
onFileRead(coverage);
|
|
164
|
-
})
|
|
165
|
-
);
|
|
166
|
-
}
|
|
167
|
-
await onFinished(project, transformMode);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
async cleanAfterRun() {
|
|
172
|
-
this.coverageFiles = /* @__PURE__ */ new Map();
|
|
173
|
-
await promises.rm(this.coverageFilesDirectory, { recursive: true });
|
|
174
|
-
if (readdirSync(this.options.reportsDirectory).length === 0) {
|
|
175
|
-
await promises.rm(this.options.reportsDirectory, { recursive: true });
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
async onTestFailure() {
|
|
179
|
-
if (!this.options.reportOnFailure) {
|
|
180
|
-
await this.cleanAfterRun();
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
async reportCoverage(coverageMap, { allTestsRun }) {
|
|
184
|
-
await this.generateReports(
|
|
185
|
-
coverageMap || this.createCoverageMap(),
|
|
186
|
-
allTestsRun
|
|
187
|
-
);
|
|
188
|
-
const keepResults = !this.options.cleanOnRerun && this.ctx.config.watch;
|
|
189
|
-
if (!keepResults) {
|
|
190
|
-
await this.cleanAfterRun();
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
async reportThresholds(coverageMap, allTestsRun) {
|
|
194
|
-
const resolvedThresholds = this.resolveThresholds(coverageMap);
|
|
195
|
-
this.checkThresholds(resolvedThresholds);
|
|
196
|
-
if (this.options.thresholds?.autoUpdate && allTestsRun) {
|
|
197
|
-
if (!this.ctx.server.config.configFile) {
|
|
198
|
-
throw new Error(
|
|
199
|
-
'Missing configurationFile. The "coverage.thresholds.autoUpdate" can only be enabled when configuration file is used.'
|
|
200
|
-
);
|
|
201
|
-
}
|
|
202
|
-
const configFilePath = this.ctx.server.config.configFile;
|
|
203
|
-
const configModule = await this.parseConfigModule(configFilePath);
|
|
204
|
-
await this.updateThresholds({
|
|
205
|
-
thresholds: resolvedThresholds,
|
|
206
|
-
configurationFile: configModule,
|
|
207
|
-
onUpdate: () => writeFileSync(
|
|
208
|
-
configFilePath,
|
|
209
|
-
configModule.generate().code,
|
|
210
|
-
"utf-8"
|
|
211
|
-
)
|
|
212
|
-
});
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
/**
|
|
216
|
-
* Constructs collected coverage and users' threshold options into separate sets
|
|
217
|
-
* where each threshold set holds their own coverage maps. Threshold set is either
|
|
218
|
-
* for specific files defined by glob pattern or global for all other files.
|
|
219
|
-
*/
|
|
220
|
-
resolveThresholds(coverageMap) {
|
|
221
|
-
const resolvedThresholds = [];
|
|
222
|
-
const files = coverageMap.files();
|
|
223
|
-
const globalCoverageMap = this.createCoverageMap();
|
|
224
|
-
for (const key of Object.keys(this.options.thresholds)) {
|
|
225
|
-
if (key === "perFile" || key === "autoUpdate" || key === "100" || THRESHOLD_KEYS.includes(key)) {
|
|
226
|
-
continue;
|
|
227
|
-
}
|
|
228
|
-
const glob = key;
|
|
229
|
-
const globThresholds = resolveGlobThresholds(this.options.thresholds[glob]);
|
|
230
|
-
const globCoverageMap = this.createCoverageMap();
|
|
231
|
-
const matchingFiles = files.filter(
|
|
232
|
-
(file) => mm.isMatch(relative(this.ctx.config.root, file), glob)
|
|
233
|
-
);
|
|
234
|
-
for (const file of matchingFiles) {
|
|
235
|
-
const fileCoverage = coverageMap.fileCoverageFor(file);
|
|
236
|
-
globCoverageMap.addFileCoverage(fileCoverage);
|
|
237
|
-
}
|
|
238
|
-
resolvedThresholds.push({
|
|
239
|
-
name: glob,
|
|
240
|
-
coverageMap: globCoverageMap,
|
|
241
|
-
thresholds: globThresholds
|
|
242
|
-
});
|
|
243
|
-
}
|
|
244
|
-
for (const file of files) {
|
|
245
|
-
const fileCoverage = coverageMap.fileCoverageFor(file);
|
|
246
|
-
globalCoverageMap.addFileCoverage(fileCoverage);
|
|
247
|
-
}
|
|
248
|
-
resolvedThresholds.unshift({
|
|
249
|
-
name: GLOBAL_THRESHOLDS_KEY,
|
|
250
|
-
coverageMap: globalCoverageMap,
|
|
251
|
-
thresholds: {
|
|
252
|
-
branches: this.options.thresholds?.branches,
|
|
253
|
-
functions: this.options.thresholds?.functions,
|
|
254
|
-
lines: this.options.thresholds?.lines,
|
|
255
|
-
statements: this.options.thresholds?.statements
|
|
256
|
-
}
|
|
257
|
-
});
|
|
258
|
-
return resolvedThresholds;
|
|
259
|
-
}
|
|
260
|
-
/**
|
|
261
|
-
* Check collected coverage against configured thresholds. Sets exit code to 1 when thresholds not reached.
|
|
262
|
-
*/
|
|
263
|
-
checkThresholds(allThresholds) {
|
|
264
|
-
for (const { coverageMap, thresholds, name } of allThresholds) {
|
|
265
|
-
if (thresholds.branches === void 0 && thresholds.functions === void 0 && thresholds.lines === void 0 && thresholds.statements === void 0) {
|
|
266
|
-
continue;
|
|
267
|
-
}
|
|
268
|
-
const summaries = this.options.thresholds?.perFile ? coverageMap.files().map((file) => ({
|
|
269
|
-
file,
|
|
270
|
-
summary: coverageMap.fileCoverageFor(file).toSummary()
|
|
271
|
-
})) : [{ file: null, summary: coverageMap.getCoverageSummary() }];
|
|
272
|
-
for (const { summary, file } of summaries) {
|
|
273
|
-
for (const thresholdKey of THRESHOLD_KEYS) {
|
|
274
|
-
const threshold = thresholds[thresholdKey];
|
|
275
|
-
if (threshold === void 0) {
|
|
276
|
-
continue;
|
|
277
|
-
}
|
|
278
|
-
if (threshold >= 0) {
|
|
279
|
-
const coverage = summary.data[thresholdKey].pct;
|
|
280
|
-
if (coverage < threshold) {
|
|
281
|
-
process.exitCode = 1;
|
|
282
|
-
let errorMessage = `ERROR: Coverage for ${thresholdKey} (${coverage}%) does not meet ${name === GLOBAL_THRESHOLDS_KEY ? name : `"${name}"`} threshold (${threshold}%)`;
|
|
283
|
-
if (this.options.thresholds?.perFile && file) {
|
|
284
|
-
errorMessage += ` for ${relative("./", file).replace(/\\/g, "/")}`;
|
|
285
|
-
}
|
|
286
|
-
this.ctx.logger.error(errorMessage);
|
|
287
|
-
}
|
|
288
|
-
} else {
|
|
289
|
-
const uncovered = summary.data[thresholdKey].total - summary.data[thresholdKey].covered;
|
|
290
|
-
const absoluteThreshold = threshold * -1;
|
|
291
|
-
if (uncovered > absoluteThreshold) {
|
|
292
|
-
process.exitCode = 1;
|
|
293
|
-
let errorMessage = `ERROR: Uncovered ${thresholdKey} (${uncovered}) exceed ${name === GLOBAL_THRESHOLDS_KEY ? name : `"${name}"`} threshold (${absoluteThreshold})`;
|
|
294
|
-
if (this.options.thresholds?.perFile && file) {
|
|
295
|
-
errorMessage += ` for ${relative("./", file).replace(/\\/g, "/")}`;
|
|
296
|
-
}
|
|
297
|
-
this.ctx.logger.error(errorMessage);
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
/**
|
|
305
|
-
* Check if current coverage is above configured thresholds and bump the thresholds if needed
|
|
306
|
-
*/
|
|
307
|
-
async updateThresholds({ thresholds: allThresholds, onUpdate, configurationFile }) {
|
|
308
|
-
let updatedThresholds = false;
|
|
309
|
-
const config = resolveConfig(configurationFile);
|
|
310
|
-
assertConfigurationModule(config);
|
|
311
|
-
for (const { coverageMap, thresholds, name } of allThresholds) {
|
|
312
|
-
const summaries = this.options.thresholds?.perFile ? coverageMap.files().map(
|
|
313
|
-
(file) => coverageMap.fileCoverageFor(file).toSummary()
|
|
314
|
-
) : [coverageMap.getCoverageSummary()];
|
|
315
|
-
const thresholdsToUpdate = [];
|
|
316
|
-
for (const key of THRESHOLD_KEYS) {
|
|
317
|
-
const threshold = thresholds[key] ?? 100;
|
|
318
|
-
if (threshold >= 0) {
|
|
319
|
-
const actual = Math.min(
|
|
320
|
-
...summaries.map((summary) => summary[key].pct)
|
|
321
|
-
);
|
|
322
|
-
if (actual > threshold) {
|
|
323
|
-
thresholdsToUpdate.push([key, actual]);
|
|
324
|
-
}
|
|
325
|
-
} else {
|
|
326
|
-
const absoluteThreshold = threshold * -1;
|
|
327
|
-
const actual = Math.max(
|
|
328
|
-
...summaries.map((summary) => summary[key].total - summary[key].covered)
|
|
329
|
-
);
|
|
330
|
-
if (actual < absoluteThreshold) {
|
|
331
|
-
const updatedThreshold = actual === 0 ? 100 : actual * -1;
|
|
332
|
-
thresholdsToUpdate.push([key, updatedThreshold]);
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
if (thresholdsToUpdate.length === 0) {
|
|
337
|
-
continue;
|
|
338
|
-
}
|
|
339
|
-
updatedThresholds = true;
|
|
340
|
-
for (const [threshold, newValue] of thresholdsToUpdate) {
|
|
341
|
-
if (name === GLOBAL_THRESHOLDS_KEY) {
|
|
342
|
-
config.test.coverage.thresholds[threshold] = newValue;
|
|
343
|
-
} else {
|
|
344
|
-
const glob = config.test.coverage.thresholds[name];
|
|
345
|
-
glob[threshold] = newValue;
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
if (updatedThresholds) {
|
|
350
|
-
this.ctx.logger.log("Updating thresholds to configuration file. You may want to push with updated coverage thresholds.");
|
|
351
|
-
onUpdate();
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
async mergeReports(coverageMaps) {
|
|
355
|
-
const coverageMap = this.createCoverageMap();
|
|
356
|
-
for (const coverage of coverageMaps) {
|
|
357
|
-
coverageMap.merge(coverage);
|
|
358
|
-
}
|
|
359
|
-
await this.generateReports(coverageMap, true);
|
|
360
|
-
}
|
|
361
|
-
hasTerminalReporter(reporters) {
|
|
362
|
-
return reporters.some(
|
|
363
|
-
([reporter]) => reporter === "text" || reporter === "text-summary" || reporter === "text-lcov" || reporter === "teamcity"
|
|
364
|
-
);
|
|
365
|
-
}
|
|
366
|
-
toSlices(array, size) {
|
|
367
|
-
return array.reduce((chunks, item) => {
|
|
368
|
-
const index = Math.max(0, chunks.length - 1);
|
|
369
|
-
const lastChunk = chunks[index] || [];
|
|
370
|
-
chunks[index] = lastChunk;
|
|
371
|
-
if (lastChunk.length >= size) {
|
|
372
|
-
chunks.push([item]);
|
|
373
|
-
} else {
|
|
374
|
-
lastChunk.push(item);
|
|
375
|
-
}
|
|
376
|
-
return chunks;
|
|
377
|
-
}, []);
|
|
378
|
-
}
|
|
379
|
-
createUncoveredFileTransformer(ctx) {
|
|
380
|
-
const servers = [
|
|
381
|
-
...ctx.projects.map((project) => ({
|
|
382
|
-
root: project.config.root,
|
|
383
|
-
vitenode: project.vitenode
|
|
384
|
-
})),
|
|
385
|
-
// Check core last as it will match all files anyway
|
|
386
|
-
{ root: ctx.config.root, vitenode: ctx.vitenode }
|
|
387
|
-
];
|
|
388
|
-
return async function transformFile(filename) {
|
|
389
|
-
let lastError;
|
|
390
|
-
for (const { root, vitenode } of servers) {
|
|
391
|
-
if (!filename.startsWith(root)) {
|
|
392
|
-
continue;
|
|
393
|
-
}
|
|
394
|
-
try {
|
|
395
|
-
return await vitenode.transformRequest(filename);
|
|
396
|
-
} catch (error) {
|
|
397
|
-
lastError = error;
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
throw lastError;
|
|
401
|
-
};
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
function resolveGlobThresholds(thresholds) {
|
|
405
|
-
if (!thresholds || typeof thresholds !== "object") {
|
|
406
|
-
return {};
|
|
407
|
-
}
|
|
408
|
-
if (100 in thresholds && thresholds[100] === true) {
|
|
409
|
-
return {
|
|
410
|
-
lines: 100,
|
|
411
|
-
branches: 100,
|
|
412
|
-
functions: 100,
|
|
413
|
-
statements: 100
|
|
414
|
-
};
|
|
415
|
-
}
|
|
416
|
-
return {
|
|
417
|
-
lines: "lines" in thresholds && typeof thresholds.lines === "number" ? thresholds.lines : void 0,
|
|
418
|
-
branches: "branches" in thresholds && typeof thresholds.branches === "number" ? thresholds.branches : void 0,
|
|
419
|
-
functions: "functions" in thresholds && typeof thresholds.functions === "number" ? thresholds.functions : void 0,
|
|
420
|
-
statements: "statements" in thresholds && typeof thresholds.statements === "number" ? thresholds.statements : void 0
|
|
421
|
-
};
|
|
422
|
-
}
|
|
423
|
-
function assertConfigurationModule(config) {
|
|
424
|
-
try {
|
|
425
|
-
if (typeof config.test.coverage.thresholds !== "object") {
|
|
426
|
-
throw new TypeError(
|
|
427
|
-
"Expected config.test.coverage.thresholds to be an object"
|
|
428
|
-
);
|
|
429
|
-
}
|
|
430
|
-
} catch (error) {
|
|
431
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
432
|
-
throw new Error(
|
|
433
|
-
`Unable to parse thresholds from configuration file: ${message}`
|
|
434
|
-
);
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
function resolveConfig(configModule) {
|
|
438
|
-
const mod = configModule.exports.default;
|
|
439
|
-
try {
|
|
440
|
-
if (mod.$type === "object") {
|
|
441
|
-
return mod;
|
|
442
|
-
}
|
|
443
|
-
let config = resolveDefineConfig(mod);
|
|
444
|
-
if (config) {
|
|
445
|
-
return config;
|
|
446
|
-
}
|
|
447
|
-
if (mod.$type === "function-call" && mod.$callee === "mergeConfig") {
|
|
448
|
-
config = resolveMergeConfig(mod);
|
|
449
|
-
if (config) {
|
|
450
|
-
return config;
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
} catch (error) {
|
|
454
|
-
throw new Error(error instanceof Error ? error.message : String(error));
|
|
455
|
-
}
|
|
456
|
-
throw new Error(
|
|
457
|
-
"Failed to update coverage thresholds. Configuration file is too complex."
|
|
458
|
-
);
|
|
459
|
-
}
|
|
460
|
-
function resolveDefineConfig(mod) {
|
|
461
|
-
if (mod.$type === "function-call" && mod.$callee === "defineConfig") {
|
|
462
|
-
if (mod.$args[0].$type === "object") {
|
|
463
|
-
return mod.$args[0];
|
|
464
|
-
}
|
|
465
|
-
if (mod.$args[0].$type === "arrow-function-expression") {
|
|
466
|
-
if (mod.$args[0].$body.$type === "object") {
|
|
467
|
-
return mod.$args[0].$body;
|
|
468
|
-
}
|
|
469
|
-
const config = resolveMergeConfig(mod.$args[0].$body);
|
|
470
|
-
if (config) {
|
|
471
|
-
return config;
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
function resolveMergeConfig(mod) {
|
|
477
|
-
if (mod.$type === "function-call" && mod.$callee === "mergeConfig") {
|
|
478
|
-
for (const arg of mod.$args) {
|
|
479
|
-
const config = resolveDefineConfig(arg);
|
|
480
|
-
if (config) {
|
|
481
|
-
return config;
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
export { BaseCoverageProvider };
|
|
37
|
+
import './chunks/coverage.A3sS5-Wm.js';
|