vitest 2.1.0-beta.5 → 2.1.0-beta.7
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/LICENSE.md +59 -320
- package/dist/browser.d.ts +6 -3
- package/dist/browser.js +2 -2
- package/dist/chunks/{RandomSequencer.B4M2ux5b.js → RandomSequencer.Bh5-tlNJ.js} +77 -58
- package/dist/chunks/{base.BH-FAiX7.js → base.BlXpj3e_.js} +1 -29
- package/dist/chunks/{base.BYvKfYzm.js → base.CchlWrnV.js} +2 -4
- package/dist/chunks/{cac.DosbLiJg.js → cac.B5XYKv2_.js} +26 -17
- package/dist/chunks/{cli-api.D8zgNrBU.js → cli-api.ByZPnilx.js} +7419 -7959
- package/dist/chunks/{constants.CaAN7icJ.js → constants.fzPh7AOq.js} +1 -1
- package/dist/chunks/{coverage.CqfT4xaf.js → coverage.zlNdAMHK.js} +5 -3
- package/dist/chunks/{creator.COdKw_ZN.js → creator.zfBZSJzo.js} +9 -9
- package/dist/chunks/{environment.0M5R1SX_.d.ts → environment.C5eAp3K6.d.ts} +1 -1
- package/dist/chunks/{execute.DT9BA6zp.js → execute._eQQfgI8.js} +322 -232
- package/dist/chunks/{git.ZtkbKc8u.js → git.B5SDxu-n.js} +5 -5
- package/dist/chunks/{globals.DRPLtPOv.js → globals.jM7MxN2t.js} +4 -4
- package/dist/chunks/{index.CM5UI-4O.js → index.Bn75ITYg.js} +3 -3
- package/dist/chunks/index.CPD77dLA.js +133 -0
- package/dist/chunks/{index.CxWPpGJz.js → index.CSjyR2-v.js} +2 -2
- package/dist/chunks/{index.Dx3f477d.js → index.DpJO1tkB.js} +1110 -1104
- package/dist/chunks/{index.CNZXZ9PJ.js → index.xm8OIiKD.js} +1 -1
- package/dist/chunks/mocker.cRtM890J.d.ts +17 -0
- package/dist/chunks/{reporters.DbwOGCsU.d.ts → reporters.WnPwkmgA.d.ts} +154 -129
- package/dist/chunks/{resolveConfig.RHsAM2_Q.js → resolveConfig.-K5hHm0S.js} +56 -34
- package/dist/chunks/{runBaseTests.BAhL8UH_.js → runBaseTests.Cztfoflv.js} +7 -7
- package/dist/chunks/{setup-common.KBrCO5LJ.js → setup-common.fGBFoQKJ.js} +1 -1
- package/dist/chunks/{utils.C3_cBsyn.js → utils.Cn0zI1t3.js} +16 -3
- package/dist/chunks/{utils.DO38lwfj.js → utils.Dbnmsfq1.js} +1 -1
- package/dist/chunks/{vi.B6QZ938s.js → vi.DGgiNzJE.js} +46 -37
- package/dist/chunks/vite.D2yAwzwa.d.ts +11 -0
- package/dist/chunks/{vm.kl9T_5ai.js → vm.CPXwWp4C.js} +1 -2
- package/dist/chunks/{worker.Cx2xE71X.d.ts → worker.Bws9Zuxu.d.ts} +1 -1
- package/dist/chunks/{worker.BANO5ak1.d.ts → worker.CmPmTxgH.d.ts} +2 -14
- package/dist/cli.js +3 -3
- package/dist/config.cjs +1 -0
- package/dist/config.d.ts +70 -2
- package/dist/config.js +1 -0
- package/dist/coverage.d.ts +4 -3
- package/dist/coverage.js +29 -5
- package/dist/environments.d.ts +2 -2
- package/dist/execute.d.ts +13 -14
- package/dist/execute.js +3 -2
- package/dist/index.d.ts +23 -16
- package/dist/index.js +4 -4
- package/dist/mocker.d.ts +1 -0
- package/dist/mocker.js +1 -0
- package/dist/node.d.ts +27 -9
- package/dist/node.js +44 -39
- package/dist/reporters.d.ts +2 -2
- package/dist/reporters.js +8 -8
- package/dist/runners.js +2 -2
- package/dist/utils.d.ts +1 -0
- package/dist/worker.js +3 -2
- package/dist/workers/forks.js +5 -4
- package/dist/workers/runVmTests.js +6 -6
- package/dist/workers/threads.js +5 -4
- package/dist/workers/vmForks.js +4 -4
- package/dist/workers/vmThreads.js +4 -4
- package/dist/workers.d.ts +4 -16
- package/dist/workers.js +6 -5
- package/mocker.d.ts +1 -0
- package/package.json +22 -17
- package/dist/chunks/index.DNUmWFkO.js +0 -319
|
@@ -1,287 +1,667 @@
|
|
|
1
|
-
import { g as getTestName, h as hasFailedSnapshot, a as getFullName } from './tasks.BZnCS9aT.js';
|
|
2
1
|
import fs, { existsSync, promises, readFileSync } from 'node:fs';
|
|
3
2
|
import c from 'tinyrainbow';
|
|
4
3
|
import * as pathe from 'pathe';
|
|
5
4
|
import { relative, resolve, dirname, extname, normalize } from 'pathe';
|
|
5
|
+
import { g as getTestName, h as hasFailedSnapshot, a as getFullName } from './tasks.BZnCS9aT.js';
|
|
6
6
|
import { notNullish, highlight, inspect, positionToOffset, lineSplitRE } from '@vitest/utils';
|
|
7
7
|
import { a as isNode, b as isDeno } from './env.CmHVDJnw.js';
|
|
8
|
-
import { g as getStateSymbol, f as formatProjectName, t as taskFail, F as F_RIGHT, a as F_POINTER, r as renderSnapshotSummary, b as getStateString, c as formatTimeString, d as countTestErrors, e as divider, s as stripAnsi, h as getCols, i as getHookStateSymbol } from './utils.
|
|
8
|
+
import { g as getStateSymbol, f as formatProjectName, t as taskFail, F as F_RIGHT, a as F_POINTER, r as renderSnapshotSummary, b as getStateString, c as formatTimeString, d as countTestErrors, e as divider, s as stripAnsi, h as getCols, i as getHookStateSymbol } from './utils.Dbnmsfq1.js';
|
|
9
9
|
import { getTests, hasFailed, getSuites, getTasks } from '@vitest/runner/utils';
|
|
10
10
|
import { performance } from 'node:perf_hooks';
|
|
11
11
|
import { parseStacktrace, parseErrorStacktrace } from '@vitest/utils/source-map';
|
|
12
12
|
import { r as relativePath } from './index.CxRxs566.js';
|
|
13
|
-
import { t as toArray,
|
|
13
|
+
import { t as toArray, b as isPrimitive } from './base.BlXpj3e_.js';
|
|
14
14
|
import { isCI } from 'std-env';
|
|
15
|
-
import { g as getOutputFile, R as RandomSequencer, a as TypeCheckError } from './RandomSequencer.
|
|
15
|
+
import { g as getOutputFile, R as RandomSequencer, a as TypeCheckError } from './RandomSequencer.Bh5-tlNJ.js';
|
|
16
16
|
import { hostname } from 'node:os';
|
|
17
17
|
import { Writable } from 'node:stream';
|
|
18
18
|
import { Console } from 'node:console';
|
|
19
19
|
import process$2 from 'node:process';
|
|
20
20
|
import { g as getDefaultExportFromCjs, c as commonjsGlobal } from './_commonjsHelpers.BFTU3MAI.js';
|
|
21
|
-
import require$$0
|
|
22
|
-
import require$$
|
|
21
|
+
import require$$0 from 'assert';
|
|
22
|
+
import require$$2 from 'events';
|
|
23
23
|
import { createRequire } from 'node:module';
|
|
24
24
|
import { mkdir, writeFile, readdir, stat, readFile } from 'node:fs/promises';
|
|
25
|
-
import { cleanUrl } from 'vite-node/utils';
|
|
26
|
-
|
|
27
|
-
/// <reference types="../types/index.d.ts" />
|
|
28
|
-
|
|
29
|
-
// (c) 2020-present Andrea Giammarchi
|
|
30
|
-
|
|
31
|
-
const {parse: $parse, stringify: $stringify} = JSON;
|
|
32
|
-
const {keys} = Object;
|
|
33
|
-
|
|
34
|
-
const Primitive = String; // it could be Number
|
|
35
|
-
const primitive = 'string'; // it could be 'number'
|
|
36
|
-
|
|
37
|
-
const ignore = {};
|
|
38
|
-
const object = 'object';
|
|
39
|
-
|
|
40
|
-
const noop = (_, value) => value;
|
|
41
|
-
|
|
42
|
-
const primitives = value => (
|
|
43
|
-
value instanceof Primitive ? Primitive(value) : value
|
|
44
|
-
);
|
|
45
|
-
|
|
46
|
-
const Primitives = (_, value) => (
|
|
47
|
-
typeof value === primitive ? new Primitive(value) : value
|
|
48
|
-
);
|
|
49
25
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
26
|
+
class TestProject {
|
|
27
|
+
/**
|
|
28
|
+
* The global vitest instance.
|
|
29
|
+
* @experimental The public Vitest API is experimental and does not follow semver.
|
|
30
|
+
*/
|
|
31
|
+
vitest;
|
|
32
|
+
/**
|
|
33
|
+
* The workspace project this test project is associated with.
|
|
34
|
+
* @experimental The public Vitest API is experimental and does not follow semver.
|
|
35
|
+
*/
|
|
36
|
+
workspaceProject;
|
|
37
|
+
/**
|
|
38
|
+
* Resolved project configuration.
|
|
39
|
+
*/
|
|
40
|
+
config;
|
|
41
|
+
/**
|
|
42
|
+
* Resolved global configuration. If there are no workspace projects, this will be the same as `config`.
|
|
43
|
+
*/
|
|
44
|
+
globalConfig;
|
|
45
|
+
/**
|
|
46
|
+
* The name of the project or an empty string if not set.
|
|
47
|
+
*/
|
|
48
|
+
name;
|
|
49
|
+
constructor(workspaceProject) {
|
|
50
|
+
this.workspaceProject = workspaceProject;
|
|
51
|
+
this.vitest = workspaceProject.ctx;
|
|
52
|
+
this.globalConfig = workspaceProject.ctx.config;
|
|
53
|
+
this.config = workspaceProject.config;
|
|
54
|
+
this.name = workspaceProject.getName();
|
|
67
55
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
56
|
+
/**
|
|
57
|
+
* Serialized project configuration. This is the config that tests receive.
|
|
58
|
+
*/
|
|
59
|
+
get serializedConfig() {
|
|
60
|
+
return this.workspaceProject.getSerializableConfig();
|
|
71
61
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
known.set(value, index);
|
|
78
|
-
return index;
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Converts a specialized flatted string into a JS value.
|
|
83
|
-
* @param {string} text
|
|
84
|
-
* @param {(this: any, key: string, value: any) => any} [reviver]
|
|
85
|
-
* @returns {any}
|
|
86
|
-
*/
|
|
87
|
-
const parse = (text, reviver) => {
|
|
88
|
-
const input = $parse(text, Primitives).map(primitives);
|
|
89
|
-
const value = input[0];
|
|
90
|
-
const $ = reviver || noop;
|
|
91
|
-
const tmp = typeof value === object && value ?
|
|
92
|
-
revive(input, new Set, value, $) :
|
|
93
|
-
value;
|
|
94
|
-
return $.call({'': tmp}, '', tmp);
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Converts a JS value into a specialized flatted string.
|
|
99
|
-
* @param {any} value
|
|
100
|
-
* @param {((this: any, key: string, value: any) => any) | (string | number)[] | null | undefined} [replacer]
|
|
101
|
-
* @param {string | number | undefined} [space]
|
|
102
|
-
* @returns {string}
|
|
103
|
-
*/
|
|
104
|
-
const stringify = (value, replacer, space) => {
|
|
105
|
-
const $ = replacer && typeof replacer === object ?
|
|
106
|
-
(k, v) => (k === '' || -1 < replacer.indexOf(k) ? v : void 0) :
|
|
107
|
-
(replacer || noop);
|
|
108
|
-
const known = new Map;
|
|
109
|
-
const input = [];
|
|
110
|
-
const output = [];
|
|
111
|
-
let i = +set(known, input, $.call({'': value}, '', value));
|
|
112
|
-
let firstRun = !i;
|
|
113
|
-
while (i < input.length) {
|
|
114
|
-
firstRun = true;
|
|
115
|
-
output[i] = $stringify(input[i++], replace, space);
|
|
62
|
+
/**
|
|
63
|
+
* Custom context provided to the project.
|
|
64
|
+
*/
|
|
65
|
+
context() {
|
|
66
|
+
return this.workspaceProject.getProvidedContext();
|
|
116
67
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
}
|
|
123
|
-
const after = $.call(this, key, value);
|
|
124
|
-
switch (typeof after) {
|
|
125
|
-
case object:
|
|
126
|
-
if (after === null) return after;
|
|
127
|
-
case primitive:
|
|
128
|
-
return known.get(after) || set(known, input, after);
|
|
129
|
-
}
|
|
130
|
-
return after;
|
|
68
|
+
/**
|
|
69
|
+
* Provide a custom serializable context to the project. This context will be available for tests once they run.
|
|
70
|
+
*/
|
|
71
|
+
provide(key, value) {
|
|
72
|
+
this.workspaceProject.provide(key, value);
|
|
131
73
|
}
|
|
132
|
-
|
|
74
|
+
toJSON() {
|
|
75
|
+
return {
|
|
76
|
+
name: this.name,
|
|
77
|
+
serializedConfig: this.serializedConfig,
|
|
78
|
+
context: this.context()
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
}
|
|
133
82
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
_filesInWatchMode = /* @__PURE__ */ new Map();
|
|
160
|
-
_lastRunTimeout = 0;
|
|
161
|
-
_lastRunTimer;
|
|
162
|
-
_lastRunCount = 0;
|
|
163
|
-
_timeStart = /* @__PURE__ */ new Date();
|
|
164
|
-
_offUnhandledRejection;
|
|
165
|
-
constructor(options = {}) {
|
|
166
|
-
this.isTTY = options.isTTY ?? ((isNode || isDeno) && process.stdout?.isTTY && !isCI);
|
|
167
|
-
this.registerUnhandledRejection();
|
|
83
|
+
class ReportedTaskImplementation {
|
|
84
|
+
/**
|
|
85
|
+
* Task instance.
|
|
86
|
+
* @experimental Public runner task API is experimental and does not follow semver.
|
|
87
|
+
*/
|
|
88
|
+
task;
|
|
89
|
+
/**
|
|
90
|
+
* The project assosiacted with the test or suite.
|
|
91
|
+
*/
|
|
92
|
+
project;
|
|
93
|
+
/**
|
|
94
|
+
* Unique identifier.
|
|
95
|
+
* This ID is deterministic and will be the same for the same test across multiple runs.
|
|
96
|
+
* The ID is based on the project name, module url and test position.
|
|
97
|
+
*/
|
|
98
|
+
id;
|
|
99
|
+
/**
|
|
100
|
+
* Location in the module where the test or suite is defined.
|
|
101
|
+
*/
|
|
102
|
+
location;
|
|
103
|
+
constructor(task, project) {
|
|
104
|
+
this.task = task;
|
|
105
|
+
this.project = project.testProject || (project.testProject = new TestProject(project));
|
|
106
|
+
this.id = task.id;
|
|
107
|
+
this.location = task.location;
|
|
168
108
|
}
|
|
169
|
-
|
|
170
|
-
|
|
109
|
+
/**
|
|
110
|
+
* Creates a new reported task instance and stores it in the project's state for future use.
|
|
111
|
+
*/
|
|
112
|
+
static register(task, project) {
|
|
113
|
+
const state = new this(task, project);
|
|
114
|
+
storeTask(project, task, state);
|
|
115
|
+
return state;
|
|
171
116
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
117
|
+
}
|
|
118
|
+
class TestCase extends ReportedTaskImplementation {
|
|
119
|
+
#fullName;
|
|
120
|
+
type = "test";
|
|
121
|
+
/**
|
|
122
|
+
* Direct reference to the test module where the test or suite is defined.
|
|
123
|
+
*/
|
|
124
|
+
module;
|
|
125
|
+
/**
|
|
126
|
+
* Name of the test.
|
|
127
|
+
*/
|
|
128
|
+
name;
|
|
129
|
+
/**
|
|
130
|
+
* Options that the test was initiated with.
|
|
131
|
+
*/
|
|
132
|
+
options;
|
|
133
|
+
/**
|
|
134
|
+
* Parent suite. If the test was called directly inside the module, the parent will be the module itself.
|
|
135
|
+
*/
|
|
136
|
+
parent;
|
|
137
|
+
constructor(task, project) {
|
|
138
|
+
super(task, project);
|
|
139
|
+
this.name = task.name;
|
|
140
|
+
this.module = getReportedTask(project, task.file);
|
|
141
|
+
const suite = this.task.suite;
|
|
142
|
+
if (suite) {
|
|
143
|
+
this.parent = getReportedTask(project, suite);
|
|
144
|
+
} else {
|
|
145
|
+
this.parent = this.module;
|
|
146
|
+
}
|
|
147
|
+
this.options = buildOptions(task);
|
|
179
148
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
this
|
|
185
|
-
|
|
186
|
-
if (errors.length) {
|
|
187
|
-
if (!this.ctx.config.dangerouslyIgnoreUnhandledErrors) {
|
|
188
|
-
process.exitCode = 1;
|
|
189
|
-
}
|
|
149
|
+
/**
|
|
150
|
+
* Full name of the test including all parent suites separated with `>`.
|
|
151
|
+
*/
|
|
152
|
+
get fullName() {
|
|
153
|
+
if (this.#fullName === void 0) {
|
|
154
|
+
this.#fullName = getTestName(this.task, " > ");
|
|
190
155
|
}
|
|
156
|
+
return this.#fullName;
|
|
191
157
|
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
this.printTask(task);
|
|
200
|
-
}
|
|
158
|
+
/**
|
|
159
|
+
* Test results. Will be `undefined` if test is not finished yet or was just collected.
|
|
160
|
+
*/
|
|
161
|
+
result() {
|
|
162
|
+
const result = this.task.result;
|
|
163
|
+
if (!result || result.state === "run") {
|
|
164
|
+
return void 0;
|
|
201
165
|
}
|
|
166
|
+
const state = result.state === "fail" ? "failed" : result.state === "pass" ? "passed" : "skipped";
|
|
167
|
+
return {
|
|
168
|
+
state,
|
|
169
|
+
errors: result.errors
|
|
170
|
+
};
|
|
202
171
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
172
|
+
/**
|
|
173
|
+
* Checks if the test did not fail the suite.
|
|
174
|
+
* If the test is not finished yet or was skipped, it will return `true`.
|
|
175
|
+
*/
|
|
176
|
+
ok() {
|
|
177
|
+
const result = this.result();
|
|
178
|
+
return !result || result.state !== "failed";
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Custom metadata that was attached to the test during its execution.
|
|
182
|
+
*/
|
|
183
|
+
meta() {
|
|
184
|
+
return this.task.meta;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Useful information about the test like duration, memory usage, etc.
|
|
188
|
+
* Diagnostic is only available after the test has finished.
|
|
189
|
+
*/
|
|
190
|
+
diagnostic() {
|
|
191
|
+
const result = this.task.result;
|
|
192
|
+
if (!result || result.state === "run" || !result.startTime) {
|
|
193
|
+
return void 0;
|
|
216
194
|
}
|
|
217
|
-
|
|
218
|
-
|
|
195
|
+
return {
|
|
196
|
+
heap: result.heap,
|
|
197
|
+
duration: result.duration,
|
|
198
|
+
startTime: result.startTime,
|
|
199
|
+
retryCount: result.retryCount ?? 0,
|
|
200
|
+
repeatCount: result.repeatCount ?? 0,
|
|
201
|
+
flaky: !!result.retryCount && result.state === "pass" && result.retryCount > 0
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
class TestCollection {
|
|
206
|
+
#task;
|
|
207
|
+
#project;
|
|
208
|
+
constructor(task, project) {
|
|
209
|
+
this.#task = task;
|
|
210
|
+
this.#project = project;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Returns the test or suite at a specific index in the array.
|
|
214
|
+
*/
|
|
215
|
+
at(index) {
|
|
216
|
+
if (index < 0) {
|
|
217
|
+
index = this.size + index;
|
|
219
218
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
219
|
+
return getReportedTask(this.#project, this.#task.tasks[index]);
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* The number of tests and suites in the collection.
|
|
223
|
+
*/
|
|
224
|
+
get size() {
|
|
225
|
+
return this.#task.tasks.length;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Returns the collection in array form for easier manipulation.
|
|
229
|
+
*/
|
|
230
|
+
array() {
|
|
231
|
+
return Array.from(this);
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Filters all tests that are part of this collection and its children.
|
|
235
|
+
*/
|
|
236
|
+
*allTests(state) {
|
|
237
|
+
for (const child of this) {
|
|
238
|
+
if (child.type === "suite") {
|
|
239
|
+
yield* child.children.allTests(state);
|
|
240
|
+
} else if (state) {
|
|
241
|
+
const testState = getTestState(child);
|
|
242
|
+
if (state === testState) {
|
|
243
|
+
yield child;
|
|
244
|
+
}
|
|
245
|
+
} else {
|
|
246
|
+
yield child;
|
|
247
|
+
}
|
|
224
248
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Filters only the tests that are part of this collection.
|
|
252
|
+
*/
|
|
253
|
+
*tests(state) {
|
|
254
|
+
for (const child of this) {
|
|
255
|
+
if (child.type !== "test") {
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
if (state) {
|
|
259
|
+
const testState = getTestState(child);
|
|
260
|
+
if (state === testState) {
|
|
261
|
+
yield child;
|
|
262
|
+
}
|
|
263
|
+
} else {
|
|
264
|
+
yield child;
|
|
265
|
+
}
|
|
229
266
|
}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Filters only the suites that are part of this collection.
|
|
270
|
+
*/
|
|
271
|
+
*suites() {
|
|
272
|
+
for (const child of this) {
|
|
273
|
+
if (child.type === "suite") {
|
|
274
|
+
yield child;
|
|
275
|
+
}
|
|
233
276
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Filters all suites that are part of this collection and its children.
|
|
280
|
+
*/
|
|
281
|
+
*allSuites() {
|
|
282
|
+
for (const child of this) {
|
|
283
|
+
if (child.type === "suite") {
|
|
284
|
+
yield child;
|
|
285
|
+
yield* child.children.allSuites();
|
|
286
|
+
}
|
|
241
287
|
}
|
|
242
288
|
}
|
|
243
|
-
|
|
244
|
-
this.
|
|
245
|
-
|
|
246
|
-
const failedSnap = hasFailedSnapshot(files);
|
|
247
|
-
const cancelled = this.ctx.isCancelling;
|
|
248
|
-
if (failed) {
|
|
249
|
-
this.ctx.logger.log(WAIT_FOR_CHANGE_FAIL);
|
|
250
|
-
} else if (cancelled) {
|
|
251
|
-
this.ctx.logger.log(WAIT_FOR_CHANGE_CANCELLED);
|
|
252
|
-
} else {
|
|
253
|
-
this.ctx.logger.log(WAIT_FOR_CHANGE_PASS);
|
|
289
|
+
*[Symbol.iterator]() {
|
|
290
|
+
for (const task of this.#task.tasks) {
|
|
291
|
+
yield getReportedTask(this.#project, task);
|
|
254
292
|
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
class SuiteImplementation extends ReportedTaskImplementation {
|
|
296
|
+
/**
|
|
297
|
+
* Collection of suites and tests that are part of this suite.
|
|
298
|
+
*/
|
|
299
|
+
children;
|
|
300
|
+
constructor(task, project) {
|
|
301
|
+
super(task, project);
|
|
302
|
+
this.children = new TestCollection(task, project);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
class TestSuite extends SuiteImplementation {
|
|
306
|
+
#fullName;
|
|
307
|
+
type = "suite";
|
|
308
|
+
/**
|
|
309
|
+
* Name of the test or the suite.
|
|
310
|
+
*/
|
|
311
|
+
name;
|
|
312
|
+
/**
|
|
313
|
+
* Direct reference to the test module where the test or suite is defined.
|
|
314
|
+
*/
|
|
315
|
+
module;
|
|
316
|
+
/**
|
|
317
|
+
* Parent suite. If suite was called directly inside the module, the parent will be the module itself.
|
|
318
|
+
*/
|
|
319
|
+
parent;
|
|
320
|
+
/**
|
|
321
|
+
* Options that suite was initiated with.
|
|
322
|
+
*/
|
|
323
|
+
options;
|
|
324
|
+
constructor(task, project) {
|
|
325
|
+
super(task, project);
|
|
326
|
+
this.name = task.name;
|
|
327
|
+
this.module = getReportedTask(project, task.file);
|
|
328
|
+
const suite = this.task.suite;
|
|
329
|
+
if (suite) {
|
|
330
|
+
this.parent = getReportedTask(project, suite);
|
|
259
331
|
} else {
|
|
260
|
-
|
|
261
|
-
}
|
|
262
|
-
this.ctx.logger.log(BADGE_PADDING + hints.join(c.dim(", ")));
|
|
263
|
-
if (this._lastRunCount) {
|
|
264
|
-
const LAST_RUN_TEXT = `rerun x${this._lastRunCount}`;
|
|
265
|
-
const LAST_RUN_TEXTS = [
|
|
266
|
-
c.blue(LAST_RUN_TEXT),
|
|
267
|
-
c.gray(LAST_RUN_TEXT),
|
|
268
|
-
c.dim(c.gray(LAST_RUN_TEXT))
|
|
269
|
-
];
|
|
270
|
-
this.ctx.logger.logUpdate(BADGE_PADDING + LAST_RUN_TEXTS[0]);
|
|
271
|
-
this._lastRunTimeout = 0;
|
|
272
|
-
this._lastRunTimer = setInterval(() => {
|
|
273
|
-
this._lastRunTimeout += 1;
|
|
274
|
-
if (this._lastRunTimeout >= LAST_RUN_TEXTS.length) {
|
|
275
|
-
this.resetLastRunLog();
|
|
276
|
-
} else {
|
|
277
|
-
this.ctx.logger.logUpdate(
|
|
278
|
-
BADGE_PADDING + LAST_RUN_TEXTS[this._lastRunTimeout]
|
|
279
|
-
);
|
|
280
|
-
}
|
|
281
|
-
}, LAST_RUN_LOG_TIMEOUT / LAST_RUN_TEXTS.length);
|
|
332
|
+
this.parent = this.module;
|
|
282
333
|
}
|
|
334
|
+
this.options = buildOptions(task);
|
|
283
335
|
}
|
|
284
|
-
|
|
336
|
+
/**
|
|
337
|
+
* Full name of the suite including all parent suites separated with `>`.
|
|
338
|
+
*/
|
|
339
|
+
get fullName() {
|
|
340
|
+
if (this.#fullName === void 0) {
|
|
341
|
+
this.#fullName = getTestName(this.task, " > ");
|
|
342
|
+
}
|
|
343
|
+
return this.#fullName;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
class TestModule extends SuiteImplementation {
|
|
347
|
+
type = "module";
|
|
348
|
+
/**
|
|
349
|
+
* This is usually an absolute UNIX file path.
|
|
350
|
+
* It can be a virtual id if the file is not on the disk.
|
|
351
|
+
* This value corresponds to Vite's `ModuleGraph` id.
|
|
352
|
+
*/
|
|
353
|
+
moduleId;
|
|
354
|
+
constructor(task, project) {
|
|
355
|
+
super(task, project);
|
|
356
|
+
this.moduleId = task.filepath;
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Useful information about the module like duration, memory usage, etc.
|
|
360
|
+
* If the module was not executed yet, all diagnostic values will return `0`.
|
|
361
|
+
*/
|
|
362
|
+
diagnostic() {
|
|
363
|
+
const setupDuration = this.task.setupDuration || 0;
|
|
364
|
+
const collectDuration = this.task.collectDuration || 0;
|
|
365
|
+
const prepareDuration = this.task.prepareDuration || 0;
|
|
366
|
+
const environmentSetupDuration = this.task.environmentLoad || 0;
|
|
367
|
+
const duration = this.task.result?.duration || 0;
|
|
368
|
+
return {
|
|
369
|
+
environmentSetupDuration,
|
|
370
|
+
prepareDuration,
|
|
371
|
+
collectDuration,
|
|
372
|
+
setupDuration,
|
|
373
|
+
duration
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
function buildOptions(task) {
|
|
378
|
+
return {
|
|
379
|
+
each: task.each,
|
|
380
|
+
concurrent: task.concurrent,
|
|
381
|
+
shuffle: task.shuffle,
|
|
382
|
+
retry: task.retry,
|
|
383
|
+
repeats: task.repeats,
|
|
384
|
+
mode: task.mode
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
function getTestState(test) {
|
|
388
|
+
const result = test.result();
|
|
389
|
+
return result ? result.state : "running";
|
|
390
|
+
}
|
|
391
|
+
function storeTask(project, runnerTask, reportedTask) {
|
|
392
|
+
project.ctx.state.reportedTasksMap.set(runnerTask, reportedTask);
|
|
393
|
+
}
|
|
394
|
+
function getReportedTask(project, runnerTask) {
|
|
395
|
+
const reportedTask = project.ctx.state.getReportedEntity(runnerTask);
|
|
396
|
+
if (!reportedTask) {
|
|
397
|
+
throw new Error(
|
|
398
|
+
`Task instance was not found for ${runnerTask.type} "${runnerTask.name}"`
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
return reportedTask;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/// <reference types="../types/index.d.ts" />
|
|
405
|
+
|
|
406
|
+
// (c) 2020-present Andrea Giammarchi
|
|
407
|
+
|
|
408
|
+
const {parse: $parse, stringify: $stringify} = JSON;
|
|
409
|
+
const {keys} = Object;
|
|
410
|
+
|
|
411
|
+
const Primitive = String; // it could be Number
|
|
412
|
+
const primitive = 'string'; // it could be 'number'
|
|
413
|
+
|
|
414
|
+
const ignore = {};
|
|
415
|
+
const object = 'object';
|
|
416
|
+
|
|
417
|
+
const noop = (_, value) => value;
|
|
418
|
+
|
|
419
|
+
const primitives = value => (
|
|
420
|
+
value instanceof Primitive ? Primitive(value) : value
|
|
421
|
+
);
|
|
422
|
+
|
|
423
|
+
const Primitives = (_, value) => (
|
|
424
|
+
typeof value === primitive ? new Primitive(value) : value
|
|
425
|
+
);
|
|
426
|
+
|
|
427
|
+
const revive = (input, parsed, output, $) => {
|
|
428
|
+
const lazy = [];
|
|
429
|
+
for (let ke = keys(output), {length} = ke, y = 0; y < length; y++) {
|
|
430
|
+
const k = ke[y];
|
|
431
|
+
const value = output[k];
|
|
432
|
+
if (value instanceof Primitive) {
|
|
433
|
+
const tmp = input[value];
|
|
434
|
+
if (typeof tmp === object && !parsed.has(tmp)) {
|
|
435
|
+
parsed.add(tmp);
|
|
436
|
+
output[k] = ignore;
|
|
437
|
+
lazy.push({k, a: [input, parsed, tmp, $]});
|
|
438
|
+
}
|
|
439
|
+
else
|
|
440
|
+
output[k] = $.call(output, k, tmp);
|
|
441
|
+
}
|
|
442
|
+
else if (output[k] !== ignore)
|
|
443
|
+
output[k] = $.call(output, k, value);
|
|
444
|
+
}
|
|
445
|
+
for (let {length} = lazy, i = 0; i < length; i++) {
|
|
446
|
+
const {k, a} = lazy[i];
|
|
447
|
+
output[k] = $.call(output, k, revive.apply(null, a));
|
|
448
|
+
}
|
|
449
|
+
return output;
|
|
450
|
+
};
|
|
451
|
+
|
|
452
|
+
const set = (known, input, value) => {
|
|
453
|
+
const index = Primitive(input.push(value) - 1);
|
|
454
|
+
known.set(value, index);
|
|
455
|
+
return index;
|
|
456
|
+
};
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* Converts a specialized flatted string into a JS value.
|
|
460
|
+
* @param {string} text
|
|
461
|
+
* @param {(this: any, key: string, value: any) => any} [reviver]
|
|
462
|
+
* @returns {any}
|
|
463
|
+
*/
|
|
464
|
+
const parse = (text, reviver) => {
|
|
465
|
+
const input = $parse(text, Primitives).map(primitives);
|
|
466
|
+
const value = input[0];
|
|
467
|
+
const $ = reviver || noop;
|
|
468
|
+
const tmp = typeof value === object && value ?
|
|
469
|
+
revive(input, new Set, value, $) :
|
|
470
|
+
value;
|
|
471
|
+
return $.call({'': tmp}, '', tmp);
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
/**
|
|
475
|
+
* Converts a JS value into a specialized flatted string.
|
|
476
|
+
* @param {any} value
|
|
477
|
+
* @param {((this: any, key: string, value: any) => any) | (string | number)[] | null | undefined} [replacer]
|
|
478
|
+
* @param {string | number | undefined} [space]
|
|
479
|
+
* @returns {string}
|
|
480
|
+
*/
|
|
481
|
+
const stringify = (value, replacer, space) => {
|
|
482
|
+
const $ = replacer && typeof replacer === object ?
|
|
483
|
+
(k, v) => (k === '' || -1 < replacer.indexOf(k) ? v : void 0) :
|
|
484
|
+
(replacer || noop);
|
|
485
|
+
const known = new Map;
|
|
486
|
+
const input = [];
|
|
487
|
+
const output = [];
|
|
488
|
+
let i = +set(known, input, $.call({'': value}, '', value));
|
|
489
|
+
let firstRun = !i;
|
|
490
|
+
while (i < input.length) {
|
|
491
|
+
firstRun = true;
|
|
492
|
+
output[i] = $stringify(input[i++], replace, space);
|
|
493
|
+
}
|
|
494
|
+
return '[' + output.join(',') + ']';
|
|
495
|
+
function replace(key, value) {
|
|
496
|
+
if (firstRun) {
|
|
497
|
+
firstRun = !firstRun;
|
|
498
|
+
return value;
|
|
499
|
+
}
|
|
500
|
+
const after = $.call(this, key, value);
|
|
501
|
+
switch (typeof after) {
|
|
502
|
+
case object:
|
|
503
|
+
if (after === null) return after;
|
|
504
|
+
case primitive:
|
|
505
|
+
return known.get(after) || set(known, input, after);
|
|
506
|
+
}
|
|
507
|
+
return after;
|
|
508
|
+
}
|
|
509
|
+
};
|
|
510
|
+
|
|
511
|
+
const BADGE_PADDING = " ";
|
|
512
|
+
const HELP_HINT = `${c.dim("press ")}${c.bold("h")}${c.dim(" to show help")}`;
|
|
513
|
+
const HELP_UPDATE_SNAP = c.dim("press ") + c.bold(c.yellow("u")) + c.dim(" to update snapshot");
|
|
514
|
+
const HELP_QUITE = `${c.dim("press ")}${c.bold("q")}${c.dim(" to quit")}`;
|
|
515
|
+
const WAIT_FOR_CHANGE_PASS = `
|
|
516
|
+
${c.bold(
|
|
517
|
+
c.inverse(c.green(" PASS "))
|
|
518
|
+
)}${c.green(" Waiting for file changes...")}`;
|
|
519
|
+
const WAIT_FOR_CHANGE_FAIL = `
|
|
520
|
+
${c.bold(c.inverse(c.red(" FAIL ")))}${c.red(
|
|
521
|
+
" Tests failed. Watching for file changes..."
|
|
522
|
+
)}`;
|
|
523
|
+
const WAIT_FOR_CHANGE_CANCELLED = `
|
|
524
|
+
${c.bold(
|
|
525
|
+
c.inverse(c.red(" CANCELLED "))
|
|
526
|
+
)}${c.red(" Test run cancelled. Watching for file changes...")}`;
|
|
527
|
+
const LAST_RUN_LOG_TIMEOUT = 1500;
|
|
528
|
+
class BaseReporter {
|
|
529
|
+
start = 0;
|
|
530
|
+
end = 0;
|
|
531
|
+
watchFilters;
|
|
532
|
+
failedUnwatchedFiles = [];
|
|
533
|
+
isTTY;
|
|
534
|
+
ctx = void 0;
|
|
535
|
+
verbose = false;
|
|
536
|
+
_filesInWatchMode = /* @__PURE__ */ new Map();
|
|
537
|
+
_lastRunTimeout = 0;
|
|
538
|
+
_lastRunTimer;
|
|
539
|
+
_lastRunCount = 0;
|
|
540
|
+
_timeStart = /* @__PURE__ */ new Date();
|
|
541
|
+
_offUnhandledRejection;
|
|
542
|
+
constructor(options = {}) {
|
|
543
|
+
this.isTTY = options.isTTY ?? ((isNode || isDeno) && process.stdout?.isTTY && !isCI);
|
|
544
|
+
this.registerUnhandledRejection();
|
|
545
|
+
}
|
|
546
|
+
get mode() {
|
|
547
|
+
return this.ctx.config.mode;
|
|
548
|
+
}
|
|
549
|
+
onInit(ctx) {
|
|
550
|
+
this.ctx = ctx;
|
|
551
|
+
ctx.onClose(() => {
|
|
552
|
+
this._offUnhandledRejection?.();
|
|
553
|
+
});
|
|
554
|
+
ctx.logger.printBanner();
|
|
555
|
+
this.start = performance.now();
|
|
556
|
+
}
|
|
557
|
+
relative(path) {
|
|
558
|
+
return relativePath(this.ctx.config.root, path);
|
|
559
|
+
}
|
|
560
|
+
onFinished(files = this.ctx.state.getFiles(), errors = this.ctx.state.getUnhandledErrors()) {
|
|
561
|
+
this.end = performance.now();
|
|
562
|
+
this.reportSummary(files, errors);
|
|
563
|
+
if (errors.length) {
|
|
564
|
+
if (!this.ctx.config.dangerouslyIgnoreUnhandledErrors) {
|
|
565
|
+
process.exitCode = 1;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
onTaskUpdate(packs) {
|
|
570
|
+
if (this.isTTY) {
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
for (const pack of packs) {
|
|
574
|
+
const task = this.ctx.state.idMap.get(pack[0]);
|
|
575
|
+
if (task) {
|
|
576
|
+
this.printTask(task);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
printTask(task) {
|
|
581
|
+
if (!("filepath" in task) || !task.result?.state || task.result?.state === "run") {
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
const logger = this.ctx.logger;
|
|
585
|
+
const tests = getTests(task);
|
|
586
|
+
const failed = tests.filter((t) => t.result?.state === "fail");
|
|
587
|
+
const skipped = tests.filter(
|
|
588
|
+
(t) => t.mode === "skip" || t.mode === "todo"
|
|
589
|
+
);
|
|
590
|
+
let state = c.dim(`${tests.length} test${tests.length > 1 ? "s" : ""}`);
|
|
591
|
+
if (failed.length) {
|
|
592
|
+
state += ` ${c.dim("|")} ${c.red(`${failed.length} failed`)}`;
|
|
593
|
+
}
|
|
594
|
+
if (skipped.length) {
|
|
595
|
+
state += ` ${c.dim("|")} ${c.yellow(`${skipped.length} skipped`)}`;
|
|
596
|
+
}
|
|
597
|
+
let suffix = c.dim(" (") + state + c.dim(")");
|
|
598
|
+
if (task.result.duration) {
|
|
599
|
+
const color = task.result.duration > this.ctx.config.slowTestThreshold ? c.yellow : c.gray;
|
|
600
|
+
suffix += color(` ${Math.round(task.result.duration)}${c.dim("ms")}`);
|
|
601
|
+
}
|
|
602
|
+
if (this.ctx.config.logHeapUsage && task.result.heap != null) {
|
|
603
|
+
suffix += c.magenta(
|
|
604
|
+
` ${Math.floor(task.result.heap / 1024 / 1024)} MB heap used`
|
|
605
|
+
);
|
|
606
|
+
}
|
|
607
|
+
let title = ` ${getStateSymbol(task)} `;
|
|
608
|
+
if (task.meta.typecheck) {
|
|
609
|
+
title += `${c.bgBlue(c.bold(" TS "))} `;
|
|
610
|
+
}
|
|
611
|
+
if (task.projectName) {
|
|
612
|
+
title += formatProjectName(task.projectName);
|
|
613
|
+
}
|
|
614
|
+
title += `${task.name} ${suffix}`;
|
|
615
|
+
logger.log(title);
|
|
616
|
+
for (const test of failed) {
|
|
617
|
+
logger.log(c.red(` ${taskFail} ${getTestName(test, c.dim(" > "))}`));
|
|
618
|
+
test.result?.errors?.forEach((e) => {
|
|
619
|
+
logger.log(c.red(` ${F_RIGHT} ${e?.message}`));
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
onWatcherStart(files = this.ctx.state.getFiles(), errors = this.ctx.state.getUnhandledErrors()) {
|
|
624
|
+
this.resetLastRunLog();
|
|
625
|
+
const failed = errors.length > 0 || hasFailed(files);
|
|
626
|
+
const failedSnap = hasFailedSnapshot(files);
|
|
627
|
+
const cancelled = this.ctx.isCancelling;
|
|
628
|
+
if (failed) {
|
|
629
|
+
this.ctx.logger.log(WAIT_FOR_CHANGE_FAIL);
|
|
630
|
+
} else if (cancelled) {
|
|
631
|
+
this.ctx.logger.log(WAIT_FOR_CHANGE_CANCELLED);
|
|
632
|
+
} else {
|
|
633
|
+
this.ctx.logger.log(WAIT_FOR_CHANGE_PASS);
|
|
634
|
+
}
|
|
635
|
+
const hints = [];
|
|
636
|
+
hints.push(HELP_HINT);
|
|
637
|
+
if (failedSnap) {
|
|
638
|
+
hints.unshift(HELP_UPDATE_SNAP);
|
|
639
|
+
} else {
|
|
640
|
+
hints.push(HELP_QUITE);
|
|
641
|
+
}
|
|
642
|
+
this.ctx.logger.log(BADGE_PADDING + hints.join(c.dim(", ")));
|
|
643
|
+
if (this._lastRunCount) {
|
|
644
|
+
const LAST_RUN_TEXT = `rerun x${this._lastRunCount}`;
|
|
645
|
+
const LAST_RUN_TEXTS = [
|
|
646
|
+
c.blue(LAST_RUN_TEXT),
|
|
647
|
+
c.gray(LAST_RUN_TEXT),
|
|
648
|
+
c.dim(c.gray(LAST_RUN_TEXT))
|
|
649
|
+
];
|
|
650
|
+
this.ctx.logger.logUpdate(BADGE_PADDING + LAST_RUN_TEXTS[0]);
|
|
651
|
+
this._lastRunTimeout = 0;
|
|
652
|
+
this._lastRunTimer = setInterval(() => {
|
|
653
|
+
this._lastRunTimeout += 1;
|
|
654
|
+
if (this._lastRunTimeout >= LAST_RUN_TEXTS.length) {
|
|
655
|
+
this.resetLastRunLog();
|
|
656
|
+
} else {
|
|
657
|
+
this.ctx.logger.logUpdate(
|
|
658
|
+
BADGE_PADDING + LAST_RUN_TEXTS[this._lastRunTimeout]
|
|
659
|
+
);
|
|
660
|
+
}
|
|
661
|
+
}, LAST_RUN_LOG_TIMEOUT / LAST_RUN_TEXTS.length);
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
resetLastRunLog() {
|
|
285
665
|
clearInterval(this._lastRunTimer);
|
|
286
666
|
this._lastRunTimer = void 0;
|
|
287
667
|
this.ctx.logger.logUpdate.clear();
|
|
@@ -430,13 +810,6 @@ ${log.content}`);
|
|
|
430
810
|
0
|
|
431
811
|
);
|
|
432
812
|
const threadTime = collectTime + testsTime + setupTime;
|
|
433
|
-
const padTitle = (str) => c.dim(`${str.padStart(11)} `);
|
|
434
|
-
const time = (time2) => {
|
|
435
|
-
if (time2 > 1e3) {
|
|
436
|
-
return `${(time2 / 1e3).toFixed(2)}s`;
|
|
437
|
-
}
|
|
438
|
-
return `${Math.round(time2)}ms`;
|
|
439
|
-
};
|
|
440
813
|
const snapshotOutput = renderSnapshotSummary(
|
|
441
814
|
this.ctx.config.root,
|
|
442
815
|
this.ctx.snapshot.summary
|
|
@@ -620,6 +993,15 @@ ${c.cyan(c.inverse(c.bold(" BENCH ")))} ${c.cyan("Summary")}
|
|
|
620
993
|
};
|
|
621
994
|
}
|
|
622
995
|
}
|
|
996
|
+
function padTitle(str) {
|
|
997
|
+
return c.dim(`${str.padStart(11)} `);
|
|
998
|
+
}
|
|
999
|
+
function time(time2) {
|
|
1000
|
+
if (time2 > 1e3) {
|
|
1001
|
+
return `${(time2 / 1e3).toFixed(2)}s`;
|
|
1002
|
+
}
|
|
1003
|
+
return `${Math.round(time2)}ms`;
|
|
1004
|
+
}
|
|
623
1005
|
|
|
624
1006
|
class BasicReporter extends BaseReporter {
|
|
625
1007
|
constructor() {
|
|
@@ -1593,6 +1975,10 @@ function renderTree$1(tasks, options, level = 0, maxRows) {
|
|
|
1593
1975
|
if (level === 0 && task.type === "suite" && "projectName" in task) {
|
|
1594
1976
|
prefix += formatProjectName(task.projectName);
|
|
1595
1977
|
}
|
|
1978
|
+
if (level === 0 && task.type === "suite" && task.meta.typecheck) {
|
|
1979
|
+
prefix += c.bgBlue(c.bold(" TS "));
|
|
1980
|
+
prefix += " ";
|
|
1981
|
+
}
|
|
1596
1982
|
if (task.type === "test" && task.result?.retryCount && task.result.retryCount > 0) {
|
|
1597
1983
|
suffix += c.yellow(` (retry x${task.result.retryCount})`);
|
|
1598
1984
|
}
|
|
@@ -2519,11 +2905,11 @@ if (!processOk(process$1)) {
|
|
|
2519
2905
|
return function () {}
|
|
2520
2906
|
};
|
|
2521
2907
|
} else {
|
|
2522
|
-
var assert = require$$0
|
|
2908
|
+
var assert = require$$0;
|
|
2523
2909
|
var signals = requireSignals();
|
|
2524
2910
|
var isWin = /^win/i.test(process$1.platform);
|
|
2525
2911
|
|
|
2526
|
-
var EE = require$$
|
|
2912
|
+
var EE = require$$2;
|
|
2527
2913
|
/* istanbul ignore if */
|
|
2528
2914
|
if (typeof EE !== 'function') {
|
|
2529
2915
|
EE = EE.EventEmitter;
|
|
@@ -3908,326 +4294,77 @@ function printStack(logger, project, stack, highlight, errorProperties, onStack)
|
|
|
3908
4294
|
].filter(Boolean).join(" ")}`
|
|
3909
4295
|
)
|
|
3910
4296
|
);
|
|
3911
|
-
onStack?.(frame);
|
|
3912
|
-
}
|
|
3913
|
-
if (stack.length) {
|
|
3914
|
-
logger.error();
|
|
3915
|
-
}
|
|
3916
|
-
if (hasProperties(errorProperties)) {
|
|
3917
|
-
logger.error(c.red(c.dim(divider())));
|
|
3918
|
-
const propertiesString = inspect(errorProperties);
|
|
3919
|
-
logger.error(c.red(c.bold("Serialized Error:")), c.gray(propertiesString));
|
|
3920
|
-
}
|
|
3921
|
-
}
|
|
3922
|
-
function hasProperties(obj) {
|
|
3923
|
-
for (const _key in obj) {
|
|
3924
|
-
return true;
|
|
3925
|
-
}
|
|
3926
|
-
return false;
|
|
3927
|
-
}
|
|
3928
|
-
function generateCodeFrame(source, indent = 0, loc, range = 2) {
|
|
3929
|
-
const start = typeof loc === "object" ? positionToOffset(source, loc.line, loc.column) : loc;
|
|
3930
|
-
const end = start;
|
|
3931
|
-
const lines = source.split(lineSplitRE);
|
|
3932
|
-
const nl = /\r\n/.test(source) ? 2 : 1;
|
|
3933
|
-
let count = 0;
|
|
3934
|
-
let res = [];
|
|
3935
|
-
const columns = process.stdout?.columns || 80;
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
for (let j = i - range; j <= i + range || end > count; j++) {
|
|
3943
|
-
if (j < 0 || j >= lines.length) {
|
|
3944
|
-
continue;
|
|
3945
|
-
}
|
|
3946
|
-
const lineLength = lines[j].length;
|
|
3947
|
-
if (stripAnsi(lines[j]).length > 200) {
|
|
3948
|
-
return "";
|
|
3949
|
-
}
|
|
3950
|
-
res.push(
|
|
3951
|
-
lineNo(j + 1) + cliTruncate(lines[j].replace(/\t/g, " "), columns - 5 - indent)
|
|
3952
|
-
);
|
|
3953
|
-
if (j === i) {
|
|
3954
|
-
const pad = start - (count - lineLength) + (nl - 1);
|
|
3955
|
-
const length = Math.max(
|
|
3956
|
-
1,
|
|
3957
|
-
end > count ? lineLength - pad : end - start
|
|
3958
|
-
);
|
|
3959
|
-
res.push(lineNo() + " ".repeat(pad) + c.red("^".repeat(length)));
|
|
3960
|
-
} else if (j > i) {
|
|
3961
|
-
if (end > count) {
|
|
3962
|
-
const length = Math.max(1, Math.min(end - count, lineLength));
|
|
3963
|
-
res.push(lineNo() + c.red("^".repeat(length)));
|
|
3964
|
-
}
|
|
3965
|
-
count += lineLength + 1;
|
|
3966
|
-
}
|
|
3967
|
-
}
|
|
3968
|
-
break;
|
|
3969
|
-
}
|
|
3970
|
-
}
|
|
3971
|
-
if (indent) {
|
|
3972
|
-
res = res.map((line) => " ".repeat(indent) + line);
|
|
3973
|
-
}
|
|
3974
|
-
return res.join("\n");
|
|
3975
|
-
}
|
|
3976
|
-
|
|
3977
|
-
function flattenTasks$1(task, baseName = "") {
|
|
3978
|
-
const base = baseName ? `${baseName} > ` : "";
|
|
3979
|
-
if (task.type === "suite") {
|
|
3980
|
-
return task.tasks.flatMap(
|
|
3981
|
-
(child) => flattenTasks$1(child, `${base}${task.name}`)
|
|
3982
|
-
);
|
|
3983
|
-
} else {
|
|
3984
|
-
return [
|
|
3985
|
-
{
|
|
3986
|
-
...task,
|
|
3987
|
-
name: `${base}${task.name}`
|
|
3988
|
-
}
|
|
3989
|
-
];
|
|
3990
|
-
}
|
|
3991
|
-
}
|
|
3992
|
-
function removeInvalidXMLCharacters(value, removeDiscouragedChars) {
|
|
3993
|
-
let regex = /([\0-\x08\v\f\x0E-\x1F\uFFFD\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])/g;
|
|
3994
|
-
value = String(value || "").replace(regex, "");
|
|
3995
|
-
{
|
|
3996
|
-
regex = new RegExp(
|
|
3997
|
-
/* eslint-disable regexp/prefer-character-class, regexp/no-obscure-range, regexp/no-useless-non-capturing-group */
|
|
3998
|
-
"([\\x7F-\\x84]|[\\x86-\\x9F]|[\\uFDD0-\\uFDEF]|\\uD83F[\\uDFFE\\uDFFF]|(?:\\uD87F[\\uDFFE\\uDFFF])|\\uD8BF[\\uDFFE\\uDFFF]|\\uD8FF[\\uDFFE\\uDFFF]|(?:\\uD93F[\\uDFFE\\uDFFF])|\\uD97F[\\uDFFE\\uDFFF]|\\uD9BF[\\uDFFE\\uDFFF]|\\uD9FF[\\uDFFE\\uDFFF]|\\uDA3F[\\uDFFE\\uDFFF]|\\uDA7F[\\uDFFE\\uDFFF]|\\uDABF[\\uDFFE\\uDFFF]|(?:\\uDAFF[\\uDFFE\\uDFFF])|\\uDB3F[\\uDFFE\\uDFFF]|\\uDB7F[\\uDFFE\\uDFFF]|(?:\\uDBBF[\\uDFFE\\uDFFF])|\\uDBFF[\\uDFFE\\uDFFF](?:[\\0-\\t\\v\\f\\x0E-\\u2027\\u202A-\\uD7FF\\uE000-\\uFFFF]|[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]|[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?:[^\\uD800-\\uDBFF]|^)[\\uDC00-\\uDFFF]))",
|
|
3999
|
-
"g"
|
|
4000
|
-
/* eslint-enable */
|
|
4001
|
-
);
|
|
4002
|
-
value = value.replace(regex, "");
|
|
4003
|
-
}
|
|
4004
|
-
return value;
|
|
4005
|
-
}
|
|
4006
|
-
function escapeXML(value) {
|
|
4007
|
-
return removeInvalidXMLCharacters(
|
|
4008
|
-
String(value).replace(/&/g, "&").replace(/"/g, """).replace(/'/g, "'").replace(/</g, "<").replace(/>/g, ">"));
|
|
4009
|
-
}
|
|
4010
|
-
function executionTime(durationMS) {
|
|
4011
|
-
return (durationMS / 1e3).toLocaleString("en-US", {
|
|
4012
|
-
useGrouping: false,
|
|
4013
|
-
maximumFractionDigits: 10
|
|
4014
|
-
});
|
|
4015
|
-
}
|
|
4016
|
-
function getDuration(task) {
|
|
4017
|
-
const duration = task.result?.duration ?? 0;
|
|
4018
|
-
return executionTime(duration);
|
|
4019
|
-
}
|
|
4020
|
-
class JUnitReporter {
|
|
4021
|
-
ctx;
|
|
4022
|
-
reportFile;
|
|
4023
|
-
baseLog;
|
|
4024
|
-
logger;
|
|
4025
|
-
_timeStart = /* @__PURE__ */ new Date();
|
|
4026
|
-
fileFd;
|
|
4027
|
-
options;
|
|
4028
|
-
constructor(options) {
|
|
4029
|
-
this.options = { ...options };
|
|
4030
|
-
this.options.includeConsoleOutput ??= true;
|
|
4031
|
-
}
|
|
4032
|
-
async onInit(ctx) {
|
|
4033
|
-
this.ctx = ctx;
|
|
4034
|
-
const outputFile = this.options.outputFile ?? getOutputFile(this.ctx.config, "junit");
|
|
4035
|
-
if (outputFile) {
|
|
4036
|
-
this.reportFile = resolve(this.ctx.config.root, outputFile);
|
|
4037
|
-
const outputDirectory = dirname(this.reportFile);
|
|
4038
|
-
if (!existsSync(outputDirectory)) {
|
|
4039
|
-
await promises.mkdir(outputDirectory, { recursive: true });
|
|
4040
|
-
}
|
|
4041
|
-
const fileFd = await promises.open(this.reportFile, "w+");
|
|
4042
|
-
this.fileFd = fileFd;
|
|
4043
|
-
this.baseLog = async (text) => {
|
|
4044
|
-
if (!this.fileFd) {
|
|
4045
|
-
this.fileFd = await promises.open(this.reportFile, "w+");
|
|
4046
|
-
}
|
|
4047
|
-
await promises.writeFile(this.fileFd, `${text}
|
|
4048
|
-
`);
|
|
4049
|
-
};
|
|
4050
|
-
} else {
|
|
4051
|
-
this.baseLog = async (text) => this.ctx.logger.log(text);
|
|
4052
|
-
}
|
|
4053
|
-
this._timeStart = /* @__PURE__ */ new Date();
|
|
4054
|
-
this.logger = new IndentedLogger(this.baseLog);
|
|
4055
|
-
}
|
|
4056
|
-
async writeElement(name, attrs, children) {
|
|
4057
|
-
const pairs = [];
|
|
4058
|
-
for (const key in attrs) {
|
|
4059
|
-
const attr = attrs[key];
|
|
4060
|
-
if (attr === void 0) {
|
|
4061
|
-
continue;
|
|
4062
|
-
}
|
|
4063
|
-
pairs.push(`${key}="${escapeXML(attr)}"`);
|
|
4064
|
-
}
|
|
4065
|
-
await this.logger.log(
|
|
4066
|
-
`<${name}${pairs.length ? ` ${pairs.join(" ")}` : ""}>`
|
|
4067
|
-
);
|
|
4068
|
-
this.logger.indent();
|
|
4069
|
-
await children.call(this);
|
|
4070
|
-
this.logger.unindent();
|
|
4071
|
-
await this.logger.log(`</${name}>`);
|
|
4072
|
-
}
|
|
4073
|
-
async writeLogs(task, type) {
|
|
4074
|
-
if (task.logs == null || task.logs.length === 0) {
|
|
4075
|
-
return;
|
|
4076
|
-
}
|
|
4077
|
-
const logType = type === "err" ? "stderr" : "stdout";
|
|
4078
|
-
const logs = task.logs.filter((log) => log.type === logType);
|
|
4079
|
-
if (logs.length === 0) {
|
|
4080
|
-
return;
|
|
4081
|
-
}
|
|
4082
|
-
await this.writeElement(`system-${type}`, {}, async () => {
|
|
4083
|
-
for (const log of logs) {
|
|
4084
|
-
await this.baseLog(escapeXML(log.content));
|
|
4085
|
-
}
|
|
4086
|
-
});
|
|
4087
|
-
}
|
|
4088
|
-
async writeTasks(tasks, filename) {
|
|
4089
|
-
for (const task of tasks) {
|
|
4090
|
-
await this.writeElement(
|
|
4091
|
-
"testcase",
|
|
4092
|
-
{
|
|
4093
|
-
classname: this.options.classname ?? filename,
|
|
4094
|
-
file: this.options.addFileAttribute ? filename : void 0,
|
|
4095
|
-
name: task.name,
|
|
4096
|
-
time: getDuration(task)
|
|
4097
|
-
},
|
|
4098
|
-
async () => {
|
|
4099
|
-
if (this.options.includeConsoleOutput) {
|
|
4100
|
-
await this.writeLogs(task, "out");
|
|
4101
|
-
await this.writeLogs(task, "err");
|
|
4102
|
-
}
|
|
4103
|
-
if (task.mode === "skip" || task.mode === "todo") {
|
|
4104
|
-
await this.logger.log("<skipped/>");
|
|
4105
|
-
}
|
|
4106
|
-
if (task.result?.state === "fail") {
|
|
4107
|
-
const errors = task.result.errors || [];
|
|
4108
|
-
for (const error of errors) {
|
|
4109
|
-
await this.writeElement(
|
|
4110
|
-
"failure",
|
|
4111
|
-
{
|
|
4112
|
-
message: error?.message,
|
|
4113
|
-
type: error?.name ?? error?.nameStr
|
|
4114
|
-
},
|
|
4115
|
-
async () => {
|
|
4116
|
-
if (!error) {
|
|
4117
|
-
return;
|
|
4118
|
-
}
|
|
4119
|
-
const result = capturePrintError(
|
|
4120
|
-
error,
|
|
4121
|
-
this.ctx,
|
|
4122
|
-
{ project: this.ctx.getProjectByTaskId(task.id), task }
|
|
4123
|
-
);
|
|
4124
|
-
await this.baseLog(
|
|
4125
|
-
escapeXML(stripAnsi(result.output.trim()))
|
|
4126
|
-
);
|
|
4127
|
-
}
|
|
4128
|
-
);
|
|
4129
|
-
}
|
|
4130
|
-
}
|
|
4131
|
-
}
|
|
4132
|
-
);
|
|
4133
|
-
}
|
|
4134
|
-
}
|
|
4135
|
-
async onFinished(files = this.ctx.state.getFiles()) {
|
|
4136
|
-
await this.logger.log('<?xml version="1.0" encoding="UTF-8" ?>');
|
|
4137
|
-
const transformed = files.map((file) => {
|
|
4138
|
-
const tasks = file.tasks.flatMap((task) => flattenTasks$1(task));
|
|
4139
|
-
const stats2 = tasks.reduce(
|
|
4140
|
-
(stats3, task) => {
|
|
4141
|
-
return {
|
|
4142
|
-
passed: stats3.passed + Number(task.result?.state === "pass"),
|
|
4143
|
-
failures: stats3.failures + Number(task.result?.state === "fail"),
|
|
4144
|
-
skipped: stats3.skipped + Number(task.mode === "skip" || task.mode === "todo")
|
|
4145
|
-
};
|
|
4146
|
-
},
|
|
4147
|
-
{
|
|
4148
|
-
passed: 0,
|
|
4149
|
-
failures: 0,
|
|
4150
|
-
skipped: 0
|
|
4297
|
+
onStack?.(frame);
|
|
4298
|
+
}
|
|
4299
|
+
if (stack.length) {
|
|
4300
|
+
logger.error();
|
|
4301
|
+
}
|
|
4302
|
+
if (hasProperties(errorProperties)) {
|
|
4303
|
+
logger.error(c.red(c.dim(divider())));
|
|
4304
|
+
const propertiesString = inspect(errorProperties);
|
|
4305
|
+
logger.error(c.red(c.bold("Serialized Error:")), c.gray(propertiesString));
|
|
4306
|
+
}
|
|
4307
|
+
}
|
|
4308
|
+
function hasProperties(obj) {
|
|
4309
|
+
for (const _key in obj) {
|
|
4310
|
+
return true;
|
|
4311
|
+
}
|
|
4312
|
+
return false;
|
|
4313
|
+
}
|
|
4314
|
+
function generateCodeFrame(source, indent = 0, loc, range = 2) {
|
|
4315
|
+
const start = typeof loc === "object" ? positionToOffset(source, loc.line, loc.column) : loc;
|
|
4316
|
+
const end = start;
|
|
4317
|
+
const lines = source.split(lineSplitRE);
|
|
4318
|
+
const nl = /\r\n/.test(source) ? 2 : 1;
|
|
4319
|
+
let count = 0;
|
|
4320
|
+
let res = [];
|
|
4321
|
+
const columns = process.stdout?.columns || 80;
|
|
4322
|
+
for (let i = 0; i < lines.length; i++) {
|
|
4323
|
+
count += lines[i].length + nl;
|
|
4324
|
+
if (count >= start) {
|
|
4325
|
+
for (let j = i - range; j <= i + range || end > count; j++) {
|
|
4326
|
+
if (j < 0 || j >= lines.length) {
|
|
4327
|
+
continue;
|
|
4151
4328
|
}
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
if (suite.result?.errors) {
|
|
4156
|
-
tasks.push(suite);
|
|
4157
|
-
stats2.failures += 1;
|
|
4329
|
+
const lineLength = lines[j].length;
|
|
4330
|
+
if (stripAnsi(lines[j]).length > 200) {
|
|
4331
|
+
return "";
|
|
4158
4332
|
}
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
stats2.failures = 1;
|
|
4162
|
-
tasks.push({
|
|
4163
|
-
id: file.id,
|
|
4164
|
-
type: "test",
|
|
4165
|
-
name: file.name,
|
|
4166
|
-
mode: "run",
|
|
4167
|
-
result: file.result,
|
|
4168
|
-
meta: {},
|
|
4169
|
-
// NOTE: not used in JUnitReporter
|
|
4170
|
-
context: null,
|
|
4171
|
-
suite: null,
|
|
4172
|
-
file: null
|
|
4173
|
-
});
|
|
4174
|
-
}
|
|
4175
|
-
return {
|
|
4176
|
-
...file,
|
|
4177
|
-
tasks,
|
|
4178
|
-
stats: stats2
|
|
4179
|
-
};
|
|
4180
|
-
});
|
|
4181
|
-
const stats = transformed.reduce(
|
|
4182
|
-
(stats2, file) => {
|
|
4183
|
-
stats2.tests += file.tasks.length;
|
|
4184
|
-
stats2.failures += file.stats.failures;
|
|
4185
|
-
return stats2;
|
|
4186
|
-
},
|
|
4187
|
-
{
|
|
4188
|
-
name: this.options.suiteName || "vitest tests",
|
|
4189
|
-
tests: 0,
|
|
4190
|
-
failures: 0,
|
|
4191
|
-
errors: 0,
|
|
4192
|
-
// we cannot detect those
|
|
4193
|
-
time: executionTime((/* @__PURE__ */ new Date()).getTime() - this._timeStart.getTime())
|
|
4194
|
-
}
|
|
4195
|
-
);
|
|
4196
|
-
await this.writeElement("testsuites", stats, async () => {
|
|
4197
|
-
for (const file of transformed) {
|
|
4198
|
-
const filename = relative(this.ctx.config.root, file.filepath);
|
|
4199
|
-
await this.writeElement(
|
|
4200
|
-
"testsuite",
|
|
4201
|
-
{
|
|
4202
|
-
name: filename,
|
|
4203
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4204
|
-
hostname: hostname(),
|
|
4205
|
-
tests: file.tasks.length,
|
|
4206
|
-
failures: file.stats.failures,
|
|
4207
|
-
errors: 0,
|
|
4208
|
-
// An errored test is one that had an unanticipated problem. We cannot detect those.
|
|
4209
|
-
skipped: file.stats.skipped,
|
|
4210
|
-
time: getDuration(file)
|
|
4211
|
-
},
|
|
4212
|
-
async () => {
|
|
4213
|
-
await this.writeTasks(file.tasks, filename);
|
|
4214
|
-
}
|
|
4333
|
+
res.push(
|
|
4334
|
+
lineNo(j + 1) + cliTruncate(lines[j].replace(/\t/g, " "), columns - 5 - indent)
|
|
4215
4335
|
);
|
|
4336
|
+
if (j === i) {
|
|
4337
|
+
const pad = start - (count - lineLength) + (nl - 1);
|
|
4338
|
+
const length = Math.max(
|
|
4339
|
+
1,
|
|
4340
|
+
end > count ? lineLength - pad : end - start
|
|
4341
|
+
);
|
|
4342
|
+
res.push(lineNo() + " ".repeat(pad) + c.red("^".repeat(length)));
|
|
4343
|
+
} else if (j > i) {
|
|
4344
|
+
if (end > count) {
|
|
4345
|
+
const length = Math.max(1, Math.min(end - count, lineLength));
|
|
4346
|
+
res.push(lineNo() + c.red("^".repeat(length)));
|
|
4347
|
+
}
|
|
4348
|
+
count += lineLength + 1;
|
|
4349
|
+
}
|
|
4216
4350
|
}
|
|
4217
|
-
|
|
4218
|
-
if (this.reportFile) {
|
|
4219
|
-
this.ctx.logger.log(`JUNIT report written to ${this.reportFile}`);
|
|
4351
|
+
break;
|
|
4220
4352
|
}
|
|
4221
|
-
await this.fileFd?.close();
|
|
4222
|
-
this.fileFd = void 0;
|
|
4223
4353
|
}
|
|
4354
|
+
if (indent) {
|
|
4355
|
+
res = res.map((line) => " ".repeat(indent) + line);
|
|
4356
|
+
}
|
|
4357
|
+
return res.join("\n");
|
|
4358
|
+
}
|
|
4359
|
+
function lineNo(no = "") {
|
|
4360
|
+
return c.gray(`${String(no).padStart(3, " ")}| `);
|
|
4224
4361
|
}
|
|
4225
4362
|
|
|
4226
|
-
function flattenTasks(task, baseName = "") {
|
|
4363
|
+
function flattenTasks$1(task, baseName = "") {
|
|
4227
4364
|
const base = baseName ? `${baseName} > ` : "";
|
|
4228
|
-
if (task.type === "suite"
|
|
4365
|
+
if (task.type === "suite") {
|
|
4229
4366
|
return task.tasks.flatMap(
|
|
4230
|
-
(child) => flattenTasks(child, `${base}${task.name}`)
|
|
4367
|
+
(child) => flattenTasks$1(child, `${base}${task.name}`)
|
|
4231
4368
|
);
|
|
4232
4369
|
} else {
|
|
4233
4370
|
return [
|
|
@@ -4238,600 +4375,468 @@ function flattenTasks(task, baseName = "") {
|
|
|
4238
4375
|
];
|
|
4239
4376
|
}
|
|
4240
4377
|
}
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
class HangingProcessReporter {
|
|
4253
|
-
whyRunning;
|
|
4254
|
-
onInit() {
|
|
4255
|
-
const _require = createRequire(import.meta.url);
|
|
4256
|
-
this.whyRunning = _require("why-is-node-running");
|
|
4257
|
-
}
|
|
4258
|
-
onProcessTimeout() {
|
|
4259
|
-
this.whyRunning?.();
|
|
4378
|
+
function removeInvalidXMLCharacters(value, removeDiscouragedChars) {
|
|
4379
|
+
let regex = /([\0-\x08\v\f\x0E-\x1F\uFFFD\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])/g;
|
|
4380
|
+
value = String(value || "").replace(regex, "");
|
|
4381
|
+
{
|
|
4382
|
+
regex = new RegExp(
|
|
4383
|
+
/* eslint-disable regexp/prefer-character-class, regexp/no-obscure-range, regexp/no-useless-non-capturing-group */
|
|
4384
|
+
"([\\x7F-\\x84]|[\\x86-\\x9F]|[\\uFDD0-\\uFDEF]|\\uD83F[\\uDFFE\\uDFFF]|(?:\\uD87F[\\uDFFE\\uDFFF])|\\uD8BF[\\uDFFE\\uDFFF]|\\uD8FF[\\uDFFE\\uDFFF]|(?:\\uD93F[\\uDFFE\\uDFFF])|\\uD97F[\\uDFFE\\uDFFF]|\\uD9BF[\\uDFFE\\uDFFF]|\\uD9FF[\\uDFFE\\uDFFF]|\\uDA3F[\\uDFFE\\uDFFF]|\\uDA7F[\\uDFFE\\uDFFF]|\\uDABF[\\uDFFE\\uDFFF]|(?:\\uDAFF[\\uDFFE\\uDFFF])|\\uDB3F[\\uDFFE\\uDFFF]|\\uDB7F[\\uDFFE\\uDFFF]|(?:\\uDBBF[\\uDFFE\\uDFFF])|\\uDBFF[\\uDFFE\\uDFFF](?:[\\0-\\t\\v\\f\\x0E-\\u2027\\u202A-\\uD7FF\\uE000-\\uFFFF]|[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]|[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?:[^\\uD800-\\uDBFF]|^)[\\uDC00-\\uDFFF]))",
|
|
4385
|
+
"g"
|
|
4386
|
+
/* eslint-enable */
|
|
4387
|
+
);
|
|
4388
|
+
value = value.replace(regex, "");
|
|
4260
4389
|
}
|
|
4390
|
+
return value;
|
|
4261
4391
|
}
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
onInit(ctx) {
|
|
4266
|
-
this.ctx = ctx;
|
|
4267
|
-
}
|
|
4268
|
-
onFinished(files = [], errors = []) {
|
|
4269
|
-
const projectErrors = new Array();
|
|
4270
|
-
for (const error of errors) {
|
|
4271
|
-
projectErrors.push({
|
|
4272
|
-
project: this.ctx.getCoreWorkspaceProject(),
|
|
4273
|
-
title: "Unhandled error",
|
|
4274
|
-
error
|
|
4275
|
-
});
|
|
4276
|
-
}
|
|
4277
|
-
for (const file of files) {
|
|
4278
|
-
const tasks = getTasks(file);
|
|
4279
|
-
const project = this.ctx.getProjectByTaskId(file.id);
|
|
4280
|
-
for (const task of tasks) {
|
|
4281
|
-
if (task.result?.state !== "fail") {
|
|
4282
|
-
continue;
|
|
4283
|
-
}
|
|
4284
|
-
const title = getFullName(task, " > ");
|
|
4285
|
-
for (const error of task.result?.errors ?? []) {
|
|
4286
|
-
projectErrors.push({
|
|
4287
|
-
project,
|
|
4288
|
-
title,
|
|
4289
|
-
error,
|
|
4290
|
-
file
|
|
4291
|
-
});
|
|
4292
|
-
}
|
|
4293
|
-
}
|
|
4294
|
-
}
|
|
4295
|
-
for (const { project, title, error, file } of projectErrors) {
|
|
4296
|
-
const result = capturePrintError(error, this.ctx, { project, task: file });
|
|
4297
|
-
const stack = result?.nearest;
|
|
4298
|
-
if (!stack) {
|
|
4299
|
-
continue;
|
|
4300
|
-
}
|
|
4301
|
-
const formatted = formatMessage({
|
|
4302
|
-
command: "error",
|
|
4303
|
-
properties: {
|
|
4304
|
-
file: stack.file,
|
|
4305
|
-
title,
|
|
4306
|
-
line: String(stack.line),
|
|
4307
|
-
column: String(stack.column)
|
|
4308
|
-
},
|
|
4309
|
-
message: stripAnsi(result.output)
|
|
4310
|
-
});
|
|
4311
|
-
this.ctx.logger.log(`
|
|
4312
|
-
${formatted}`);
|
|
4313
|
-
}
|
|
4314
|
-
}
|
|
4392
|
+
function escapeXML(value) {
|
|
4393
|
+
return removeInvalidXMLCharacters(
|
|
4394
|
+
String(value).replace(/&/g, "&").replace(/"/g, """).replace(/'/g, "'").replace(/</g, "<").replace(/>/g, ">"));
|
|
4315
4395
|
}
|
|
4316
|
-
function
|
|
4317
|
-
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
}) {
|
|
4321
|
-
let result = `::${command}`;
|
|
4322
|
-
Object.entries(properties).forEach(([k, v], i) => {
|
|
4323
|
-
result += i === 0 ? " " : ",";
|
|
4324
|
-
result += `${k}=${escapeProperty(v)}`;
|
|
4396
|
+
function executionTime(durationMS) {
|
|
4397
|
+
return (durationMS / 1e3).toLocaleString("en-US", {
|
|
4398
|
+
useGrouping: false,
|
|
4399
|
+
maximumFractionDigits: 10
|
|
4325
4400
|
});
|
|
4326
|
-
result += `::${escapeData(message)}`;
|
|
4327
|
-
return result;
|
|
4328
|
-
}
|
|
4329
|
-
function escapeData(s) {
|
|
4330
|
-
return s.replace(/%/g, "%25").replace(/\r/g, "%0D").replace(/\n/g, "%0A");
|
|
4331
4401
|
}
|
|
4332
|
-
function
|
|
4333
|
-
|
|
4402
|
+
function getDuration(task) {
|
|
4403
|
+
const duration = task.result?.duration ?? 0;
|
|
4404
|
+
return executionTime(duration);
|
|
4334
4405
|
}
|
|
4335
|
-
|
|
4336
|
-
class BlobReporter {
|
|
4406
|
+
class JUnitReporter {
|
|
4337
4407
|
ctx;
|
|
4408
|
+
reportFile;
|
|
4409
|
+
baseLog;
|
|
4410
|
+
logger;
|
|
4411
|
+
_timeStart = /* @__PURE__ */ new Date();
|
|
4412
|
+
fileFd;
|
|
4338
4413
|
options;
|
|
4339
4414
|
constructor(options) {
|
|
4340
|
-
this.options = options;
|
|
4341
|
-
|
|
4342
|
-
onInit(ctx) {
|
|
4343
|
-
if (ctx.config.watch) {
|
|
4344
|
-
throw new Error("Blob reporter is not supported in watch mode");
|
|
4345
|
-
}
|
|
4346
|
-
this.ctx = ctx;
|
|
4415
|
+
this.options = { ...options };
|
|
4416
|
+
this.options.includeConsoleOutput ??= true;
|
|
4347
4417
|
}
|
|
4348
|
-
async
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
return [
|
|
4357
|
-
project.getName(),
|
|
4358
|
-
[...project.server.moduleGraph.idToModuleMap.keys()]
|
|
4359
|
-
];
|
|
4418
|
+
async onInit(ctx) {
|
|
4419
|
+
this.ctx = ctx;
|
|
4420
|
+
const outputFile = this.options.outputFile ?? getOutputFile(this.ctx.config, "junit");
|
|
4421
|
+
if (outputFile) {
|
|
4422
|
+
this.reportFile = resolve(this.ctx.config.root, outputFile);
|
|
4423
|
+
const outputDirectory = dirname(this.reportFile);
|
|
4424
|
+
if (!existsSync(outputDirectory)) {
|
|
4425
|
+
await promises.mkdir(outputDirectory, { recursive: true });
|
|
4360
4426
|
}
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
this.
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
await mkdir(dir, { recursive: true });
|
|
4427
|
+
const fileFd = await promises.open(this.reportFile, "w+");
|
|
4428
|
+
this.fileFd = fileFd;
|
|
4429
|
+
this.baseLog = async (text) => {
|
|
4430
|
+
if (!this.fileFd) {
|
|
4431
|
+
this.fileFd = await promises.open(this.reportFile, "w+");
|
|
4432
|
+
}
|
|
4433
|
+
await promises.writeFile(this.fileFd, `${text}
|
|
4434
|
+
`);
|
|
4435
|
+
};
|
|
4436
|
+
} else {
|
|
4437
|
+
this.baseLog = async (text) => this.ctx.logger.log(text);
|
|
4373
4438
|
}
|
|
4374
|
-
|
|
4375
|
-
this.
|
|
4439
|
+
this._timeStart = /* @__PURE__ */ new Date();
|
|
4440
|
+
this.logger = new IndentedLogger(this.baseLog);
|
|
4376
4441
|
}
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
throw new TypeError(
|
|
4386
|
-
`vitest.mergeReports() expects all paths in "${blobsDirectory}" to be files generated by the blob reporter, but "${filename}" is not a file`
|
|
4387
|
-
);
|
|
4388
|
-
}
|
|
4389
|
-
const content = await readFile(fullPath, "utf-8");
|
|
4390
|
-
const [version, files2, errors2, moduleKeys, coverage] = parse(
|
|
4391
|
-
content
|
|
4392
|
-
);
|
|
4393
|
-
if (!version) {
|
|
4394
|
-
throw new TypeError(
|
|
4395
|
-
`vitest.mergeReports() expects all paths in "${blobsDirectory}" to be files generated by the blob reporter, but "${filename}" is not a valid blob file`
|
|
4396
|
-
);
|
|
4442
|
+
async writeElement(name, attrs, children) {
|
|
4443
|
+
const pairs = [];
|
|
4444
|
+
for (const key in attrs) {
|
|
4445
|
+
const attr = attrs[key];
|
|
4446
|
+
if (attr === void 0) {
|
|
4447
|
+
continue;
|
|
4448
|
+
}
|
|
4449
|
+
pairs.push(`${key}="${escapeXML(attr)}"`);
|
|
4397
4450
|
}
|
|
4398
|
-
|
|
4399
|
-
|
|
4400
|
-
const blobs = await Promise.all(promises);
|
|
4401
|
-
if (!blobs.length) {
|
|
4402
|
-
throw new Error(
|
|
4403
|
-
`vitest.mergeReports() requires at least one blob file in "${blobsDirectory}" directory, but none were found`
|
|
4404
|
-
);
|
|
4405
|
-
}
|
|
4406
|
-
const versions = new Set(blobs.map((blob) => blob.version));
|
|
4407
|
-
if (versions.size > 1) {
|
|
4408
|
-
throw new Error(
|
|
4409
|
-
`vitest.mergeReports() requires all blob files to be generated by the same Vitest version, received
|
|
4410
|
-
|
|
4411
|
-
${blobs.map((b) => `- "${b.file}" uses v${b.version}`).join("\n")}`
|
|
4451
|
+
await this.logger.log(
|
|
4452
|
+
`<${name}${pairs.length ? ` ${pairs.join(" ")}` : ""}>`
|
|
4412
4453
|
);
|
|
4454
|
+
this.logger.indent();
|
|
4455
|
+
await children.call(this);
|
|
4456
|
+
this.logger.unindent();
|
|
4457
|
+
await this.logger.log(`</${name}>`);
|
|
4413
4458
|
}
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
4459
|
+
async writeLogs(task, type) {
|
|
4460
|
+
if (task.logs == null || task.logs.length === 0) {
|
|
4461
|
+
return;
|
|
4462
|
+
}
|
|
4463
|
+
const logType = type === "err" ? "stderr" : "stdout";
|
|
4464
|
+
const logs = task.logs.filter((log) => log.type === logType);
|
|
4465
|
+
if (logs.length === 0) {
|
|
4466
|
+
return;
|
|
4467
|
+
}
|
|
4468
|
+
await this.writeElement(`system-${type}`, {}, async () => {
|
|
4469
|
+
for (const log of logs) {
|
|
4470
|
+
await this.baseLog(escapeXML(log.content));
|
|
4422
4471
|
}
|
|
4423
|
-
moduleIds.forEach((moduleId) => {
|
|
4424
|
-
project.server.moduleGraph.idToModuleMap.set(moduleId, {
|
|
4425
|
-
id: moduleId,
|
|
4426
|
-
url: moduleId,
|
|
4427
|
-
file: cleanUrl(moduleId),
|
|
4428
|
-
ssrTransformResult: null,
|
|
4429
|
-
transformResult: null,
|
|
4430
|
-
importedBindings: null,
|
|
4431
|
-
importedModules: /* @__PURE__ */ new Set(),
|
|
4432
|
-
importers: /* @__PURE__ */ new Set(),
|
|
4433
|
-
type: "js",
|
|
4434
|
-
clientImportedModules: /* @__PURE__ */ new Set(),
|
|
4435
|
-
ssrError: null,
|
|
4436
|
-
ssrImportedModules: /* @__PURE__ */ new Set(),
|
|
4437
|
-
ssrModule: null,
|
|
4438
|
-
acceptedHmrDeps: /* @__PURE__ */ new Set(),
|
|
4439
|
-
acceptedHmrExports: null,
|
|
4440
|
-
lastHMRTimestamp: 0,
|
|
4441
|
-
lastInvalidationTimestamp: 0
|
|
4442
|
-
});
|
|
4443
|
-
});
|
|
4444
4472
|
});
|
|
4445
|
-
});
|
|
4446
|
-
const files = blobs.flatMap((blob) => blob.files).sort((f1, f2) => {
|
|
4447
|
-
const time1 = f1.result?.startTime || 0;
|
|
4448
|
-
const time2 = f2.result?.startTime || 0;
|
|
4449
|
-
return time1 - time2;
|
|
4450
|
-
});
|
|
4451
|
-
const errors = blobs.flatMap((blob) => blob.errors);
|
|
4452
|
-
const coverages = blobs.map((blob) => blob.coverage);
|
|
4453
|
-
return {
|
|
4454
|
-
files,
|
|
4455
|
-
errors,
|
|
4456
|
-
coverages
|
|
4457
|
-
};
|
|
4458
|
-
}
|
|
4459
|
-
|
|
4460
|
-
class TestProject {
|
|
4461
|
-
/**
|
|
4462
|
-
* The global vitest instance.
|
|
4463
|
-
* @experimental The public Vitest API is experimental and does not follow semver.
|
|
4464
|
-
*/
|
|
4465
|
-
vitest;
|
|
4466
|
-
/**
|
|
4467
|
-
* The workspace project this test project is associated with.
|
|
4468
|
-
* @experimental The public Vitest API is experimental and does not follow semver.
|
|
4469
|
-
*/
|
|
4470
|
-
workspaceProject;
|
|
4471
|
-
/**
|
|
4472
|
-
* Resolved project configuration.
|
|
4473
|
-
*/
|
|
4474
|
-
config;
|
|
4475
|
-
/**
|
|
4476
|
-
* Resolved global configuration. If there are no workspace projects, this will be the same as `config`.
|
|
4477
|
-
*/
|
|
4478
|
-
globalConfig;
|
|
4479
|
-
/**
|
|
4480
|
-
* The name of the project or an empty string if not set.
|
|
4481
|
-
*/
|
|
4482
|
-
name;
|
|
4483
|
-
constructor(workspaceProject) {
|
|
4484
|
-
this.workspaceProject = workspaceProject;
|
|
4485
|
-
this.vitest = workspaceProject.ctx;
|
|
4486
|
-
this.globalConfig = workspaceProject.ctx.config;
|
|
4487
|
-
this.config = workspaceProject.config;
|
|
4488
|
-
this.name = workspaceProject.getName();
|
|
4489
|
-
}
|
|
4490
|
-
/**
|
|
4491
|
-
* Serialized project configuration. This is the config that tests receive.
|
|
4492
|
-
*/
|
|
4493
|
-
get serializedConfig() {
|
|
4494
|
-
return this.workspaceProject.getSerializableConfig();
|
|
4495
|
-
}
|
|
4496
|
-
/**
|
|
4497
|
-
* Custom context provided to the project.
|
|
4498
|
-
*/
|
|
4499
|
-
context() {
|
|
4500
|
-
return this.workspaceProject.getProvidedContext();
|
|
4501
4473
|
}
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
|
|
4474
|
+
async writeTasks(tasks, filename) {
|
|
4475
|
+
for (const task of tasks) {
|
|
4476
|
+
await this.writeElement(
|
|
4477
|
+
"testcase",
|
|
4478
|
+
{
|
|
4479
|
+
classname: this.options.classname ?? filename,
|
|
4480
|
+
file: this.options.addFileAttribute ? filename : void 0,
|
|
4481
|
+
name: task.name,
|
|
4482
|
+
time: getDuration(task)
|
|
4483
|
+
},
|
|
4484
|
+
async () => {
|
|
4485
|
+
if (this.options.includeConsoleOutput) {
|
|
4486
|
+
await this.writeLogs(task, "out");
|
|
4487
|
+
await this.writeLogs(task, "err");
|
|
4488
|
+
}
|
|
4489
|
+
if (task.mode === "skip" || task.mode === "todo") {
|
|
4490
|
+
await this.logger.log("<skipped/>");
|
|
4491
|
+
}
|
|
4492
|
+
if (task.result?.state === "fail") {
|
|
4493
|
+
const errors = task.result.errors || [];
|
|
4494
|
+
for (const error of errors) {
|
|
4495
|
+
await this.writeElement(
|
|
4496
|
+
"failure",
|
|
4497
|
+
{
|
|
4498
|
+
message: error?.message,
|
|
4499
|
+
type: error?.name ?? error?.nameStr
|
|
4500
|
+
},
|
|
4501
|
+
async () => {
|
|
4502
|
+
if (!error) {
|
|
4503
|
+
return;
|
|
4504
|
+
}
|
|
4505
|
+
const result = capturePrintError(
|
|
4506
|
+
error,
|
|
4507
|
+
this.ctx,
|
|
4508
|
+
{ project: this.ctx.getProjectByTaskId(task.id), task }
|
|
4509
|
+
);
|
|
4510
|
+
await this.baseLog(
|
|
4511
|
+
escapeXML(stripAnsi(result.output.trim()))
|
|
4512
|
+
);
|
|
4513
|
+
}
|
|
4514
|
+
);
|
|
4515
|
+
}
|
|
4516
|
+
}
|
|
4517
|
+
}
|
|
4518
|
+
);
|
|
4519
|
+
}
|
|
4507
4520
|
}
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4521
|
+
async onFinished(files = this.ctx.state.getFiles()) {
|
|
4522
|
+
await this.logger.log('<?xml version="1.0" encoding="UTF-8" ?>');
|
|
4523
|
+
const transformed = files.map((file) => {
|
|
4524
|
+
const tasks = file.tasks.flatMap((task) => flattenTasks$1(task));
|
|
4525
|
+
const stats2 = tasks.reduce(
|
|
4526
|
+
(stats3, task) => {
|
|
4527
|
+
return {
|
|
4528
|
+
passed: stats3.passed + Number(task.result?.state === "pass"),
|
|
4529
|
+
failures: stats3.failures + Number(task.result?.state === "fail"),
|
|
4530
|
+
skipped: stats3.skipped + Number(task.mode === "skip" || task.mode === "todo")
|
|
4531
|
+
};
|
|
4532
|
+
},
|
|
4533
|
+
{
|
|
4534
|
+
passed: 0,
|
|
4535
|
+
failures: 0,
|
|
4536
|
+
skipped: 0
|
|
4537
|
+
}
|
|
4538
|
+
);
|
|
4539
|
+
const suites = getSuites(file);
|
|
4540
|
+
for (const suite of suites) {
|
|
4541
|
+
if (suite.result?.errors) {
|
|
4542
|
+
tasks.push(suite);
|
|
4543
|
+
stats2.failures += 1;
|
|
4544
|
+
}
|
|
4545
|
+
}
|
|
4546
|
+
if (tasks.length === 0 && file.result?.state === "fail") {
|
|
4547
|
+
stats2.failures = 1;
|
|
4548
|
+
tasks.push({
|
|
4549
|
+
id: file.id,
|
|
4550
|
+
type: "test",
|
|
4551
|
+
name: file.name,
|
|
4552
|
+
mode: "run",
|
|
4553
|
+
result: file.result,
|
|
4554
|
+
meta: {},
|
|
4555
|
+
// NOTE: not used in JUnitReporter
|
|
4556
|
+
context: null,
|
|
4557
|
+
suite: null,
|
|
4558
|
+
file: null
|
|
4559
|
+
});
|
|
4560
|
+
}
|
|
4561
|
+
return {
|
|
4562
|
+
...file,
|
|
4563
|
+
tasks,
|
|
4564
|
+
stats: stats2
|
|
4565
|
+
};
|
|
4566
|
+
});
|
|
4567
|
+
const stats = transformed.reduce(
|
|
4568
|
+
(stats2, file) => {
|
|
4569
|
+
stats2.tests += file.tasks.length;
|
|
4570
|
+
stats2.failures += file.stats.failures;
|
|
4571
|
+
return stats2;
|
|
4572
|
+
},
|
|
4573
|
+
{
|
|
4574
|
+
name: this.options.suiteName || "vitest tests",
|
|
4575
|
+
tests: 0,
|
|
4576
|
+
failures: 0,
|
|
4577
|
+
errors: 0,
|
|
4578
|
+
// we cannot detect those
|
|
4579
|
+
time: executionTime((/* @__PURE__ */ new Date()).getTime() - this._timeStart.getTime())
|
|
4580
|
+
}
|
|
4581
|
+
);
|
|
4582
|
+
await this.writeElement("testsuites", stats, async () => {
|
|
4583
|
+
for (const file of transformed) {
|
|
4584
|
+
const filename = relative(this.ctx.config.root, file.filepath);
|
|
4585
|
+
await this.writeElement(
|
|
4586
|
+
"testsuite",
|
|
4587
|
+
{
|
|
4588
|
+
name: filename,
|
|
4589
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4590
|
+
hostname: hostname(),
|
|
4591
|
+
tests: file.tasks.length,
|
|
4592
|
+
failures: file.stats.failures,
|
|
4593
|
+
errors: 0,
|
|
4594
|
+
// An errored test is one that had an unanticipated problem. We cannot detect those.
|
|
4595
|
+
skipped: file.stats.skipped,
|
|
4596
|
+
time: getDuration(file)
|
|
4597
|
+
},
|
|
4598
|
+
async () => {
|
|
4599
|
+
await this.writeTasks(file.tasks, filename);
|
|
4600
|
+
}
|
|
4601
|
+
);
|
|
4602
|
+
}
|
|
4603
|
+
});
|
|
4604
|
+
if (this.reportFile) {
|
|
4605
|
+
this.ctx.logger.log(`JUNIT report written to ${this.reportFile}`);
|
|
4606
|
+
}
|
|
4607
|
+
await this.fileFd?.close();
|
|
4608
|
+
this.fileFd = void 0;
|
|
4514
4609
|
}
|
|
4515
4610
|
}
|
|
4516
4611
|
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
* The ID is based on the project name, file path and test position.
|
|
4531
|
-
*/
|
|
4532
|
-
id;
|
|
4533
|
-
/**
|
|
4534
|
-
* Location in the file where the test or suite is defined.
|
|
4535
|
-
*/
|
|
4536
|
-
location;
|
|
4537
|
-
constructor(task, project) {
|
|
4538
|
-
this.task = task;
|
|
4539
|
-
this.project = project.testProject || (project.testProject = new TestProject(project));
|
|
4540
|
-
this.id = task.id;
|
|
4541
|
-
this.location = task.location;
|
|
4542
|
-
}
|
|
4543
|
-
/**
|
|
4544
|
-
* Creates a new reported task instance and stores it in the project's state for future use.
|
|
4545
|
-
*/
|
|
4546
|
-
static register(task, project) {
|
|
4547
|
-
const state = new this(task, project);
|
|
4548
|
-
storeTask(project, task, state);
|
|
4549
|
-
return state;
|
|
4612
|
+
function flattenTasks(task, baseName = "") {
|
|
4613
|
+
const base = baseName ? `${baseName} > ` : "";
|
|
4614
|
+
if (task.type === "suite" && task.tasks.length > 0) {
|
|
4615
|
+
return task.tasks.flatMap(
|
|
4616
|
+
(child) => flattenTasks(child, `${base}${task.name}`)
|
|
4617
|
+
);
|
|
4618
|
+
} else {
|
|
4619
|
+
return [
|
|
4620
|
+
{
|
|
4621
|
+
...task,
|
|
4622
|
+
name: `${base}${task.name}`
|
|
4623
|
+
}
|
|
4624
|
+
];
|
|
4550
4625
|
}
|
|
4551
4626
|
}
|
|
4552
|
-
class
|
|
4553
|
-
|
|
4554
|
-
|
|
4555
|
-
/**
|
|
4556
|
-
* Direct reference to the test file where the test or suite is defined.
|
|
4557
|
-
*/
|
|
4558
|
-
file;
|
|
4559
|
-
/**
|
|
4560
|
-
* Name of the test.
|
|
4561
|
-
*/
|
|
4562
|
-
name;
|
|
4563
|
-
/**
|
|
4564
|
-
* Options that the test was initiated with.
|
|
4565
|
-
*/
|
|
4566
|
-
options;
|
|
4567
|
-
/**
|
|
4568
|
-
* Parent suite. If the test was called directly inside the file, the parent will be the file.
|
|
4569
|
-
*/
|
|
4570
|
-
parent;
|
|
4571
|
-
constructor(task, project) {
|
|
4572
|
-
super(task, project);
|
|
4573
|
-
this.name = task.name;
|
|
4574
|
-
this.file = getReportedTask(project, task.file);
|
|
4575
|
-
const suite = this.task.suite;
|
|
4576
|
-
if (suite) {
|
|
4577
|
-
this.parent = getReportedTask(project, suite);
|
|
4578
|
-
} else {
|
|
4579
|
-
this.parent = this.file;
|
|
4580
|
-
}
|
|
4581
|
-
this.options = buildOptions(task);
|
|
4582
|
-
}
|
|
4583
|
-
/**
|
|
4584
|
-
* Full name of the test including all parent suites separated with `>`.
|
|
4585
|
-
*/
|
|
4586
|
-
get fullName() {
|
|
4587
|
-
if (this.#fullName === void 0) {
|
|
4588
|
-
this.#fullName = getTestName(this.task, " > ");
|
|
4589
|
-
}
|
|
4590
|
-
return this.#fullName;
|
|
4591
|
-
}
|
|
4592
|
-
/**
|
|
4593
|
-
* Test results. Will be `undefined` if test is not finished yet or was just collected.
|
|
4594
|
-
*/
|
|
4595
|
-
result() {
|
|
4596
|
-
const result = this.task.result;
|
|
4597
|
-
if (!result || result.state === "run") {
|
|
4598
|
-
return void 0;
|
|
4599
|
-
}
|
|
4600
|
-
const state = result.state === "fail" ? "failed" : result.state === "pass" ? "passed" : "skipped";
|
|
4601
|
-
return {
|
|
4602
|
-
state,
|
|
4603
|
-
errors: result.errors
|
|
4604
|
-
};
|
|
4627
|
+
class TapFlatReporter extends TapReporter {
|
|
4628
|
+
onInit(ctx) {
|
|
4629
|
+
super.onInit(ctx);
|
|
4605
4630
|
}
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
|
|
4610
|
-
ok() {
|
|
4611
|
-
const result = this.result();
|
|
4612
|
-
return !result || result.state !== "failed";
|
|
4631
|
+
onFinished(files = this.ctx.state.getFiles()) {
|
|
4632
|
+
this.ctx.logger.log("TAP version 13");
|
|
4633
|
+
const flatTasks = files.flatMap((task) => flattenTasks(task));
|
|
4634
|
+
this.logTasks(flatTasks);
|
|
4613
4635
|
}
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
|
|
4636
|
+
}
|
|
4637
|
+
|
|
4638
|
+
class HangingProcessReporter {
|
|
4639
|
+
whyRunning;
|
|
4640
|
+
onInit() {
|
|
4641
|
+
const _require = createRequire(import.meta.url);
|
|
4642
|
+
this.whyRunning = _require("why-is-node-running");
|
|
4619
4643
|
}
|
|
4620
|
-
|
|
4621
|
-
|
|
4622
|
-
* Diagnostic is only available after the test has finished.
|
|
4623
|
-
*/
|
|
4624
|
-
diagnostic() {
|
|
4625
|
-
const result = this.task.result;
|
|
4626
|
-
if (!result || result.state === "run" || !result.startTime) {
|
|
4627
|
-
return void 0;
|
|
4628
|
-
}
|
|
4629
|
-
return {
|
|
4630
|
-
heap: result.heap,
|
|
4631
|
-
duration: result.duration,
|
|
4632
|
-
startTime: result.startTime,
|
|
4633
|
-
retryCount: result.retryCount ?? 0,
|
|
4634
|
-
repeatCount: result.repeatCount ?? 0,
|
|
4635
|
-
flaky: !!result.retryCount && result.state === "pass" && result.retryCount > 0
|
|
4636
|
-
};
|
|
4644
|
+
onProcessTimeout() {
|
|
4645
|
+
this.whyRunning?.();
|
|
4637
4646
|
}
|
|
4638
4647
|
}
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
|
|
4642
|
-
|
|
4643
|
-
this
|
|
4644
|
-
this.#project = project;
|
|
4648
|
+
|
|
4649
|
+
class GithubActionsReporter {
|
|
4650
|
+
ctx = void 0;
|
|
4651
|
+
onInit(ctx) {
|
|
4652
|
+
this.ctx = ctx;
|
|
4645
4653
|
}
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
4654
|
+
onFinished(files = [], errors = []) {
|
|
4655
|
+
const projectErrors = new Array();
|
|
4656
|
+
for (const error of errors) {
|
|
4657
|
+
projectErrors.push({
|
|
4658
|
+
project: this.ctx.getCoreWorkspaceProject(),
|
|
4659
|
+
title: "Unhandled error",
|
|
4660
|
+
error
|
|
4661
|
+
});
|
|
4652
4662
|
}
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
|
|
4664
|
-
|
|
4665
|
-
|
|
4666
|
-
|
|
4667
|
-
|
|
4668
|
-
* Filters all tests that are part of this collection and its children.
|
|
4669
|
-
*/
|
|
4670
|
-
*allTests(state) {
|
|
4671
|
-
for (const child of this) {
|
|
4672
|
-
if (child.type === "suite") {
|
|
4673
|
-
yield* child.children.allTests(state);
|
|
4674
|
-
} else if (state) {
|
|
4675
|
-
const testState = getTestState(child);
|
|
4676
|
-
if (state === testState) {
|
|
4677
|
-
yield child;
|
|
4663
|
+
for (const file of files) {
|
|
4664
|
+
const tasks = getTasks(file);
|
|
4665
|
+
const project = this.ctx.getProjectByTaskId(file.id);
|
|
4666
|
+
for (const task of tasks) {
|
|
4667
|
+
if (task.result?.state !== "fail") {
|
|
4668
|
+
continue;
|
|
4669
|
+
}
|
|
4670
|
+
const title = getFullName(task, " > ");
|
|
4671
|
+
for (const error of task.result?.errors ?? []) {
|
|
4672
|
+
projectErrors.push({
|
|
4673
|
+
project,
|
|
4674
|
+
title,
|
|
4675
|
+
error,
|
|
4676
|
+
file
|
|
4677
|
+
});
|
|
4678
4678
|
}
|
|
4679
|
-
} else {
|
|
4680
|
-
yield child;
|
|
4681
4679
|
}
|
|
4682
4680
|
}
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
*tests(state) {
|
|
4688
|
-
for (const child of this) {
|
|
4689
|
-
if (child.type !== "test") {
|
|
4681
|
+
for (const { project, title, error, file } of projectErrors) {
|
|
4682
|
+
const result = capturePrintError(error, this.ctx, { project, task: file });
|
|
4683
|
+
const stack = result?.nearest;
|
|
4684
|
+
if (!stack) {
|
|
4690
4685
|
continue;
|
|
4691
4686
|
}
|
|
4692
|
-
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
|
|
4699
|
-
|
|
4687
|
+
const formatted = formatMessage({
|
|
4688
|
+
command: "error",
|
|
4689
|
+
properties: {
|
|
4690
|
+
file: stack.file,
|
|
4691
|
+
title,
|
|
4692
|
+
line: String(stack.line),
|
|
4693
|
+
column: String(stack.column)
|
|
4694
|
+
},
|
|
4695
|
+
message: stripAnsi(result.output)
|
|
4696
|
+
});
|
|
4697
|
+
this.ctx.logger.log(`
|
|
4698
|
+
${formatted}`);
|
|
4700
4699
|
}
|
|
4701
4700
|
}
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
|
|
4708
|
-
|
|
4709
|
-
|
|
4710
|
-
|
|
4701
|
+
}
|
|
4702
|
+
function formatMessage({
|
|
4703
|
+
command,
|
|
4704
|
+
properties,
|
|
4705
|
+
message
|
|
4706
|
+
}) {
|
|
4707
|
+
let result = `::${command}`;
|
|
4708
|
+
Object.entries(properties).forEach(([k, v], i) => {
|
|
4709
|
+
result += i === 0 ? " " : ",";
|
|
4710
|
+
result += `${k}=${escapeProperty(v)}`;
|
|
4711
|
+
});
|
|
4712
|
+
result += `::${escapeData(message)}`;
|
|
4713
|
+
return result;
|
|
4714
|
+
}
|
|
4715
|
+
function escapeData(s) {
|
|
4716
|
+
return s.replace(/%/g, "%25").replace(/\r/g, "%0D").replace(/\n/g, "%0A");
|
|
4717
|
+
}
|
|
4718
|
+
function escapeProperty(s) {
|
|
4719
|
+
return s.replace(/%/g, "%25").replace(/\r/g, "%0D").replace(/\n/g, "%0A").replace(/:/g, "%3A").replace(/,/g, "%2C");
|
|
4720
|
+
}
|
|
4721
|
+
|
|
4722
|
+
class BlobReporter {
|
|
4723
|
+
ctx;
|
|
4724
|
+
options;
|
|
4725
|
+
constructor(options) {
|
|
4726
|
+
this.options = options;
|
|
4711
4727
|
}
|
|
4712
|
-
|
|
4713
|
-
|
|
4714
|
-
|
|
4715
|
-
*allSuites() {
|
|
4716
|
-
for (const child of this) {
|
|
4717
|
-
if (child.type === "suite") {
|
|
4718
|
-
yield child;
|
|
4719
|
-
yield* child.children.allSuites();
|
|
4720
|
-
}
|
|
4728
|
+
onInit(ctx) {
|
|
4729
|
+
if (ctx.config.watch) {
|
|
4730
|
+
throw new Error("Blob reporter is not supported in watch mode");
|
|
4721
4731
|
}
|
|
4732
|
+
this.ctx = ctx;
|
|
4722
4733
|
}
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
4734
|
+
async onFinished(files = [], errors = [], coverage) {
|
|
4735
|
+
let outputFile = this.options.outputFile ?? getOutputFile(this.ctx.config, "blob");
|
|
4736
|
+
if (!outputFile) {
|
|
4737
|
+
const shard = this.ctx.config.shard;
|
|
4738
|
+
outputFile = shard ? `.vitest-reports/blob-${shard.index}-${shard.count}.json` : ".vitest-reports/blob.json";
|
|
4726
4739
|
}
|
|
4740
|
+
const modules = this.ctx.projects.map(
|
|
4741
|
+
(project) => {
|
|
4742
|
+
return [
|
|
4743
|
+
project.getName(),
|
|
4744
|
+
[...project.server.moduleGraph.idToModuleMap.entries()].map((mod) => {
|
|
4745
|
+
if (!mod[1].file) {
|
|
4746
|
+
return null;
|
|
4747
|
+
}
|
|
4748
|
+
return [mod[0], mod[1].file, mod[1].url];
|
|
4749
|
+
}).filter((x) => x != null)
|
|
4750
|
+
];
|
|
4751
|
+
}
|
|
4752
|
+
);
|
|
4753
|
+
const report = stringify([
|
|
4754
|
+
this.ctx.version,
|
|
4755
|
+
files,
|
|
4756
|
+
errors,
|
|
4757
|
+
modules,
|
|
4758
|
+
coverage
|
|
4759
|
+
]);
|
|
4760
|
+
const reportFile = resolve(this.ctx.config.root, outputFile);
|
|
4761
|
+
const dir = dirname(reportFile);
|
|
4762
|
+
if (!existsSync(dir)) {
|
|
4763
|
+
await mkdir(dir, { recursive: true });
|
|
4764
|
+
}
|
|
4765
|
+
await writeFile(reportFile, report, "utf-8");
|
|
4766
|
+
this.ctx.logger.log("blob report written to", reportFile);
|
|
4727
4767
|
}
|
|
4728
4768
|
}
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
|
|
4737
|
-
|
|
4738
|
-
|
|
4739
|
-
class TestSuite extends SuiteImplementation {
|
|
4740
|
-
#fullName;
|
|
4741
|
-
type = "suite";
|
|
4742
|
-
/**
|
|
4743
|
-
* Name of the test or the suite.
|
|
4744
|
-
*/
|
|
4745
|
-
name;
|
|
4746
|
-
/**
|
|
4747
|
-
* Direct reference to the test file where the test or suite is defined.
|
|
4748
|
-
*/
|
|
4749
|
-
file;
|
|
4750
|
-
/**
|
|
4751
|
-
* Parent suite. If suite was called directly inside the file, the parent will be the file.
|
|
4752
|
-
*/
|
|
4753
|
-
parent;
|
|
4754
|
-
/**
|
|
4755
|
-
* Options that suite was initiated with.
|
|
4756
|
-
*/
|
|
4757
|
-
options;
|
|
4758
|
-
constructor(task, project) {
|
|
4759
|
-
super(task, project);
|
|
4760
|
-
this.name = task.name;
|
|
4761
|
-
this.file = getReportedTask(project, task.file);
|
|
4762
|
-
const suite = this.task.suite;
|
|
4763
|
-
if (suite) {
|
|
4764
|
-
this.parent = getReportedTask(project, suite);
|
|
4765
|
-
} else {
|
|
4766
|
-
this.parent = this.file;
|
|
4769
|
+
async function readBlobs(currentVersion, blobsDirectory, projectsArray) {
|
|
4770
|
+
const resolvedDir = resolve(process.cwd(), blobsDirectory);
|
|
4771
|
+
const blobsFiles = await readdir(resolvedDir);
|
|
4772
|
+
const promises = blobsFiles.map(async (filename) => {
|
|
4773
|
+
const fullPath = resolve(resolvedDir, filename);
|
|
4774
|
+
const stats = await stat(fullPath);
|
|
4775
|
+
if (!stats.isFile()) {
|
|
4776
|
+
throw new TypeError(
|
|
4777
|
+
`vitest.mergeReports() expects all paths in "${blobsDirectory}" to be files generated by the blob reporter, but "${filename}" is not a file`
|
|
4778
|
+
);
|
|
4767
4779
|
}
|
|
4768
|
-
|
|
4769
|
-
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
|
|
4773
|
-
|
|
4774
|
-
|
|
4775
|
-
|
|
4780
|
+
const content = await readFile(fullPath, "utf-8");
|
|
4781
|
+
const [version, files2, errors2, moduleKeys, coverage] = parse(
|
|
4782
|
+
content
|
|
4783
|
+
);
|
|
4784
|
+
if (!version) {
|
|
4785
|
+
throw new TypeError(
|
|
4786
|
+
`vitest.mergeReports() expects all paths in "${blobsDirectory}" to be files generated by the blob reporter, but "${filename}" is not a valid blob file`
|
|
4787
|
+
);
|
|
4776
4788
|
}
|
|
4777
|
-
return
|
|
4789
|
+
return { version, files: files2, errors: errors2, moduleKeys, coverage, file: filename };
|
|
4790
|
+
});
|
|
4791
|
+
const blobs = await Promise.all(promises);
|
|
4792
|
+
if (!blobs.length) {
|
|
4793
|
+
throw new Error(
|
|
4794
|
+
`vitest.mergeReports() requires at least one blob file in "${blobsDirectory}" directory, but none were found`
|
|
4795
|
+
);
|
|
4778
4796
|
}
|
|
4779
|
-
|
|
4780
|
-
|
|
4781
|
-
|
|
4782
|
-
|
|
4783
|
-
|
|
4784
|
-
|
|
4785
|
-
|
|
4786
|
-
*/
|
|
4787
|
-
moduleId;
|
|
4788
|
-
constructor(task, project) {
|
|
4789
|
-
super(task, project);
|
|
4790
|
-
this.moduleId = task.filepath;
|
|
4797
|
+
const versions = new Set(blobs.map((blob) => blob.version));
|
|
4798
|
+
if (versions.size > 1) {
|
|
4799
|
+
throw new Error(
|
|
4800
|
+
`vitest.mergeReports() requires all blob files to be generated by the same Vitest version, received
|
|
4801
|
+
|
|
4802
|
+
${blobs.map((b) => `- "${b.file}" uses v${b.version}`).join("\n")}`
|
|
4803
|
+
);
|
|
4791
4804
|
}
|
|
4792
|
-
|
|
4793
|
-
|
|
4794
|
-
|
|
4795
|
-
|
|
4796
|
-
diagnostic() {
|
|
4797
|
-
const setupDuration = this.task.setupDuration || 0;
|
|
4798
|
-
const collectDuration = this.task.collectDuration || 0;
|
|
4799
|
-
const prepareDuration = this.task.prepareDuration || 0;
|
|
4800
|
-
const environmentSetupDuration = this.task.environmentLoad || 0;
|
|
4801
|
-
const duration = this.task.result?.duration || 0;
|
|
4802
|
-
return {
|
|
4803
|
-
environmentSetupDuration,
|
|
4804
|
-
prepareDuration,
|
|
4805
|
-
collectDuration,
|
|
4806
|
-
setupDuration,
|
|
4807
|
-
duration
|
|
4808
|
-
};
|
|
4805
|
+
if (!versions.has(currentVersion)) {
|
|
4806
|
+
throw new Error(
|
|
4807
|
+
`the blobs in "${blobsDirectory}" were generated by a different version of Vitest. Expected v${currentVersion}, but received v${blobs[0].version}`
|
|
4808
|
+
);
|
|
4809
4809
|
}
|
|
4810
|
-
|
|
4811
|
-
|
|
4810
|
+
const projects = Object.fromEntries(
|
|
4811
|
+
projectsArray.map((p) => [p.getName(), p])
|
|
4812
|
+
);
|
|
4813
|
+
blobs.forEach((blob) => {
|
|
4814
|
+
blob.moduleKeys.forEach(([projectName, moduleIds]) => {
|
|
4815
|
+
const project = projects[projectName];
|
|
4816
|
+
if (!project) {
|
|
4817
|
+
return;
|
|
4818
|
+
}
|
|
4819
|
+
moduleIds.forEach(([moduleId, file, url]) => {
|
|
4820
|
+
const moduleNode = project.server.moduleGraph.createFileOnlyEntry(file);
|
|
4821
|
+
moduleNode.url = url;
|
|
4822
|
+
moduleNode.id = moduleId;
|
|
4823
|
+
project.server.moduleGraph.idToModuleMap.set(moduleId, moduleNode);
|
|
4824
|
+
});
|
|
4825
|
+
});
|
|
4826
|
+
});
|
|
4827
|
+
const files = blobs.flatMap((blob) => blob.files).sort((f1, f2) => {
|
|
4828
|
+
const time1 = f1.result?.startTime || 0;
|
|
4829
|
+
const time2 = f2.result?.startTime || 0;
|
|
4830
|
+
return time1 - time2;
|
|
4831
|
+
});
|
|
4832
|
+
const errors = blobs.flatMap((blob) => blob.errors);
|
|
4833
|
+
const coverages = blobs.map((blob) => blob.coverage);
|
|
4812
4834
|
return {
|
|
4813
|
-
|
|
4814
|
-
|
|
4815
|
-
|
|
4816
|
-
retry: task.retry,
|
|
4817
|
-
repeats: task.repeats,
|
|
4818
|
-
mode: task.mode
|
|
4835
|
+
files,
|
|
4836
|
+
errors,
|
|
4837
|
+
coverages
|
|
4819
4838
|
};
|
|
4820
4839
|
}
|
|
4821
|
-
function getTestState(test) {
|
|
4822
|
-
const result = test.result();
|
|
4823
|
-
return result ? result.state : "running";
|
|
4824
|
-
}
|
|
4825
|
-
function storeTask(project, runnerTask, reportedTask) {
|
|
4826
|
-
project.ctx.state.reportedTasksMap.set(runnerTask, reportedTask);
|
|
4827
|
-
}
|
|
4828
|
-
function getReportedTask(project, runnerTask) {
|
|
4829
|
-
const reportedTask = project.ctx.state.getReportedEntity(runnerTask);
|
|
4830
|
-
if (!reportedTask) {
|
|
4831
|
-
throw new Error(`Task instance was not found for ${runnerTask.type} "${runnerTask.name}"`);
|
|
4832
|
-
}
|
|
4833
|
-
return reportedTask;
|
|
4834
|
-
}
|
|
4835
4840
|
|
|
4836
4841
|
const outputMap = /* @__PURE__ */ new WeakMap();
|
|
4837
4842
|
function formatFilepath(path) {
|
|
@@ -4928,7 +4933,7 @@ function renderTree(tasks, options, level = 0, shallow = false) {
|
|
|
4928
4933
|
if (baseline) {
|
|
4929
4934
|
benchMap[t.id].baseline = {
|
|
4930
4935
|
...baseline,
|
|
4931
|
-
samples: Array(baseline.sampleCount)
|
|
4936
|
+
samples: Array.from({ length: baseline.sampleCount })
|
|
4932
4937
|
};
|
|
4933
4938
|
}
|
|
4934
4939
|
}
|
|
@@ -5217,6 +5222,7 @@ const BenchmarkReportsMap = {
|
|
|
5217
5222
|
verbose: VerboseReporter
|
|
5218
5223
|
};
|
|
5219
5224
|
|
|
5225
|
+
const TestFile = TestModule;
|
|
5220
5226
|
const ReportersMap = {
|
|
5221
5227
|
"default": DefaultReporter,
|
|
5222
5228
|
"basic": BasicReporter,
|
|
@@ -5231,4 +5237,4 @@ const ReportersMap = {
|
|
|
5231
5237
|
"github-actions": GithubActionsReporter
|
|
5232
5238
|
};
|
|
5233
5239
|
|
|
5234
|
-
export { BasicReporter as B, DefaultReporter as D, GithubActionsReporter as G, HangingProcessReporter as H, JsonReporter as J, Logger as L, ReportersMap as R, TapReporter as T, VerboseReporter as V, DotReporter as a, JUnitReporter as b, TapFlatReporter as c,
|
|
5240
|
+
export { BasicReporter as B, DefaultReporter as D, GithubActionsReporter as G, HangingProcessReporter as H, JsonReporter as J, Logger as L, ReportersMap as R, TapReporter as T, VerboseReporter as V, DotReporter as a, JUnitReporter as b, TapFlatReporter as c, TestFile as d, TestCase as e, TestModule as f, TestSuite as g, BenchmarkReportsMap as h, TestProject as i, generateCodeFrame as j, BlobReporter as k, parse as p, readBlobs as r, stringify as s };
|