@rpcbase/test 0.343.0 → 0.345.0
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/clearDatabase.js +10 -12
- package/dist/clearDatabase.js.map +1 -1
- package/dist/cli.js +439 -556
- package/dist/cli.js.map +1 -1
- package/dist/coverage/collect.js +63 -101
- package/dist/coverage/collect.js.map +1 -1
- package/dist/coverage/config-loader.js +180 -230
- package/dist/coverage/config-loader.js.map +1 -1
- package/dist/coverage/config.js +76 -100
- package/dist/coverage/config.js.map +1 -1
- package/dist/coverage/console-text-report.js +175 -220
- package/dist/coverage/console-text-report.js.map +1 -1
- package/dist/coverage/files.js +45 -58
- package/dist/coverage/files.js.map +1 -1
- package/dist/coverage/fixtures.js +27 -38
- package/dist/coverage/fixtures.js.map +1 -1
- package/dist/coverage/global-setup.js +15 -18
- package/dist/coverage/global-setup.js.map +1 -1
- package/dist/coverage/index.js +38 -55
- package/dist/coverage/index.js.map +1 -1
- package/dist/coverage/report.js +341 -466
- package/dist/coverage/report.js.map +1 -1
- package/dist/coverage/reporter.js +47 -61
- package/dist/coverage/reporter.js.map +1 -1
- package/dist/coverage/v8-tracker.js +115 -147
- package/dist/coverage/v8-tracker.js.map +1 -1
- package/dist/index.js +46 -75
- package/dist/index.js.map +1 -1
- package/dist/runners/playwright.js +392 -490
- package/dist/runners/playwright.js.map +1 -1
- package/dist/runners/process.js +107 -142
- package/dist/runners/process.js.map +1 -1
- package/dist/runners/vitest.js +124 -171
- package/dist/runners/vitest.js.map +1 -1
- package/dist/serverCoverage.js +28 -42
- package/dist/serverCoverage.js.map +1 -1
- package/dist/vitest.config.d.ts +1 -1
- package/dist/vitest.config.js +62 -74
- package/dist/vitest.config.js.map +1 -1
- package/package.json +1 -1
package/dist/coverage/report.js
CHANGED
|
@@ -1,522 +1,397 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { findCoverageFiles } from "./files.js";
|
|
2
|
+
import { createCollectCoverageMatcher, toPosix } from "./collect.js";
|
|
3
|
+
import { generateConsoleTextCoverageReport } from "./console-text-report.js";
|
|
4
|
+
import fsPromises from "node:fs/promises";
|
|
2
5
|
import path from "node:path";
|
|
3
6
|
import { fileURLToPath } from "node:url";
|
|
7
|
+
import picomatch from "picomatch";
|
|
4
8
|
import * as libCoverage from "istanbul-lib-coverage";
|
|
5
9
|
import * as libInstrument from "istanbul-lib-instrument";
|
|
6
10
|
import fg from "fast-glob";
|
|
7
|
-
import picomatch from "picomatch";
|
|
8
11
|
import v8ToIstanbul from "v8-to-istanbul";
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
}
|
|
12
|
+
//#region src/coverage/report.ts
|
|
13
|
+
var TEXT_REPORT_FILENAME = "coverage.txt";
|
|
14
|
+
var CoverageThresholdError = class extends Error {
|
|
15
|
+
constructor(message) {
|
|
16
|
+
super(message);
|
|
17
|
+
this.name = "CoverageThresholdError";
|
|
18
|
+
}
|
|
19
|
+
};
|
|
19
20
|
async function generateCoverageReport(config) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
console.log(`[coverage] Full text report saved to ${path.join(config.coverageReportDir, TEXT_REPORT_FILENAME)}`);
|
|
70
|
-
const summary = coverageMap.getCoverageSummary();
|
|
71
|
-
enforceThresholds(summary, config.thresholds, "global");
|
|
72
|
-
const targets = Array.isArray(config.thresholdTargets) ? config.thresholdTargets : [];
|
|
73
|
-
if (targets.length > 0) {
|
|
74
|
-
const fileSummaries = buildFileSummaries(coverageMap, config.rootDir);
|
|
75
|
-
for (const target of targets) {
|
|
76
|
-
const matcher = createGlobMatcher(target.pattern);
|
|
77
|
-
const matchResult = collectTargetSummary(fileSummaries, matcher, coverageLib);
|
|
78
|
-
if (matchResult.matched === 0) {
|
|
79
|
-
console.warn(`[coverage] threshold pattern "${target.pattern}" did not match any files — skipping`);
|
|
80
|
-
continue;
|
|
81
|
-
}
|
|
82
|
-
enforceThresholds(matchResult.summary, target.thresholds, target.pattern);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
21
|
+
const coverageFiles = await findCoverageFiles(config);
|
|
22
|
+
if (coverageFiles.length === 0) {
|
|
23
|
+
console.warn("[coverage] no V8 coverage artifacts were generated");
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const coverageLib = resolveCoverageLib();
|
|
27
|
+
const coverageMap = coverageLib.createCoverageMap({});
|
|
28
|
+
const matchesCollectCoverageFrom = createCollectCoverageMatcher(config.collectCoverageFrom, config.rootDir);
|
|
29
|
+
for (const file of coverageFiles) {
|
|
30
|
+
const payload = await readCoverageFile(file);
|
|
31
|
+
if (!payload) continue;
|
|
32
|
+
for (const script of payload.scripts) await mergeScriptCoverage(coverageMap, script, config, matchesCollectCoverageFrom);
|
|
33
|
+
}
|
|
34
|
+
if (config.includeAllFiles) await includeUntestedFiles(coverageMap, config, matchesCollectCoverageFrom);
|
|
35
|
+
if (coverageMap.files().length === 0) {
|
|
36
|
+
console.warn("[coverage] no library files matched the coverage filters");
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
await fsPromises.rm(config.coverageReportDir, {
|
|
40
|
+
recursive: true,
|
|
41
|
+
force: true
|
|
42
|
+
});
|
|
43
|
+
await fsPromises.mkdir(config.coverageReportDir, { recursive: true });
|
|
44
|
+
const { createContext, reports } = await loadIstanbulModules();
|
|
45
|
+
const context = createContext({
|
|
46
|
+
dir: config.coverageReportDir,
|
|
47
|
+
coverageMap,
|
|
48
|
+
defaultSummarizer: "pkg"
|
|
49
|
+
});
|
|
50
|
+
const { output: reportOutput, summarizer } = generateConsoleTextCoverageReport(reports, context);
|
|
51
|
+
process.stdout.write(reportOutput);
|
|
52
|
+
reports.create("text", {
|
|
53
|
+
file: TEXT_REPORT_FILENAME,
|
|
54
|
+
summarizer
|
|
55
|
+
}).execute(context);
|
|
56
|
+
console.log(`[coverage] Full text report saved to ${path.join(config.coverageReportDir, TEXT_REPORT_FILENAME)}`);
|
|
57
|
+
enforceThresholds(coverageMap.getCoverageSummary(), config.thresholds, "global");
|
|
58
|
+
const targets = Array.isArray(config.thresholdTargets) ? config.thresholdTargets : [];
|
|
59
|
+
if (targets.length > 0) {
|
|
60
|
+
const fileSummaries = buildFileSummaries(coverageMap, config.rootDir);
|
|
61
|
+
for (const target of targets) {
|
|
62
|
+
const matchResult = collectTargetSummary(fileSummaries, createGlobMatcher(target.pattern), coverageLib);
|
|
63
|
+
if (matchResult.matched === 0) {
|
|
64
|
+
console.warn(`[coverage] threshold pattern "${target.pattern}" did not match any files — skipping`);
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
enforceThresholds(matchResult.summary, target.thresholds, target.pattern);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
85
70
|
}
|
|
86
71
|
async function collectCoveredFiles(config) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
continue;
|
|
98
|
-
}
|
|
99
|
-
for (const script of payload.scripts) {
|
|
100
|
-
await mergeScriptCoverage(coverageMap, script, config, matchesCollectCoverageFrom);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
return coverageMap.files().sort();
|
|
72
|
+
const coverageFiles = await findCoverageFiles(config);
|
|
73
|
+
if (coverageFiles.length === 0) return [];
|
|
74
|
+
const coverageMap = resolveCoverageLib().createCoverageMap({});
|
|
75
|
+
const matchesCollectCoverageFrom = createCollectCoverageMatcher(config.collectCoverageFrom, config.rootDir);
|
|
76
|
+
for (const file of coverageFiles) {
|
|
77
|
+
const payload = await readCoverageFile(file);
|
|
78
|
+
if (!payload) continue;
|
|
79
|
+
for (const script of payload.scripts) await mergeScriptCoverage(coverageMap, script, config, matchesCollectCoverageFrom);
|
|
80
|
+
}
|
|
81
|
+
return coverageMap.files().sort();
|
|
104
82
|
}
|
|
105
83
|
async function loadIstanbulModules() {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
reports: reportsMod.default ?? reportsMod
|
|
115
|
-
};
|
|
84
|
+
maybeForceColor();
|
|
85
|
+
const [libReportMod, reportsMod] = await Promise.all([import("istanbul-lib-report"), import("istanbul-reports")]);
|
|
86
|
+
const createContext = typeof libReportMod.createContext === "function" ? libReportMod.createContext : libReportMod.default?.createContext;
|
|
87
|
+
if (typeof createContext !== "function") throw new Error("istanbul-lib-report exports are unavailable");
|
|
88
|
+
return {
|
|
89
|
+
createContext,
|
|
90
|
+
reports: reportsMod.default ?? reportsMod
|
|
91
|
+
};
|
|
116
92
|
}
|
|
117
93
|
function maybeForceColor() {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
}
|
|
124
|
-
if (process.env.NO_COLOR !== void 0 || process.env.NODE_DISABLE_COLORS !== void 0) {
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
if (process.env.CI !== void 0) {
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
process.env.FORCE_COLOR = "1";
|
|
94
|
+
if (process.stdout.isTTY) return;
|
|
95
|
+
if (process.env.FORCE_COLOR !== void 0) return;
|
|
96
|
+
if (process.env.NO_COLOR !== void 0 || process.env.NODE_DISABLE_COLORS !== void 0) return;
|
|
97
|
+
if (process.env.CI !== void 0) return;
|
|
98
|
+
process.env.FORCE_COLOR = "1";
|
|
131
99
|
}
|
|
132
100
|
async function mergeScriptCoverage(coverageMap, script, config, matchesCollectCoverageFrom) {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
throw error;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
const sourceMap = await loadSourceMapForScript(scriptPath, source);
|
|
159
|
-
const converter = v8ToIstanbul(scriptPath, 0, sourceMap ? {
|
|
160
|
-
source,
|
|
161
|
-
sourceMap: {
|
|
162
|
-
sourcemap: sourceMap
|
|
163
|
-
}
|
|
164
|
-
} : {
|
|
165
|
-
source
|
|
166
|
-
});
|
|
167
|
-
await converter.load();
|
|
168
|
-
converter.applyCoverage(script.functions);
|
|
169
|
-
const filtered = filterCoverageMap(converter.toIstanbul(), config, matchesCollectCoverageFrom);
|
|
170
|
-
if (Object.keys(filtered).length > 0) {
|
|
171
|
-
coverageMap.merge(filtered);
|
|
172
|
-
}
|
|
101
|
+
const scriptPath = script.absolutePath;
|
|
102
|
+
if (!scriptPath) return;
|
|
103
|
+
if (isNodeModulesPath(scriptPath)) return;
|
|
104
|
+
if (isViteVirtualModulePath(scriptPath)) return;
|
|
105
|
+
let source = script.source && script.source.length > 0 ? script.source : "";
|
|
106
|
+
if (!source) try {
|
|
107
|
+
source = await fsPromises.readFile(scriptPath, "utf8");
|
|
108
|
+
} catch (error) {
|
|
109
|
+
const base = path.basename(scriptPath);
|
|
110
|
+
if (error?.code === "ENOENT" && base && !base.includes(".")) return;
|
|
111
|
+
if (error?.code === "ENOENT" && !matchesCollectCoverageFrom(scriptPath)) return;
|
|
112
|
+
throw error;
|
|
113
|
+
}
|
|
114
|
+
const sourceMap = await loadSourceMapForScript(scriptPath, source);
|
|
115
|
+
const converter = v8ToIstanbul(scriptPath, 0, sourceMap ? {
|
|
116
|
+
source,
|
|
117
|
+
sourceMap: { sourcemap: sourceMap }
|
|
118
|
+
} : { source });
|
|
119
|
+
await converter.load();
|
|
120
|
+
converter.applyCoverage(script.functions);
|
|
121
|
+
const filtered = filterCoverageMap(converter.toIstanbul(), config, matchesCollectCoverageFrom);
|
|
122
|
+
if (Object.keys(filtered).length > 0) coverageMap.merge(filtered);
|
|
173
123
|
}
|
|
174
124
|
async function readCoverageFile(file) {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
125
|
+
try {
|
|
126
|
+
const raw = await fsPromises.readFile(file, "utf8");
|
|
127
|
+
return JSON.parse(raw);
|
|
128
|
+
} catch (error) {
|
|
129
|
+
console.warn(`[coverage] failed to parse ${file}:`, error);
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
182
132
|
}
|
|
183
133
|
function enforceThresholds(summary, thresholds, label = "global") {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
if (failures.length === 0) {
|
|
197
|
-
return;
|
|
198
|
-
}
|
|
199
|
-
const details = failures.map(({
|
|
200
|
-
metric,
|
|
201
|
-
actual,
|
|
202
|
-
minimum
|
|
203
|
-
}) => `${metric}: ${actual.toFixed(2)}% < ${minimum}%`).join("; ");
|
|
204
|
-
throw new CoverageThresholdError(`[coverage] thresholds not met (target: ${label}) — ${details}`);
|
|
134
|
+
const failures = [];
|
|
135
|
+
for (const metric of Object.keys(thresholds)) {
|
|
136
|
+
const minimum = thresholds[metric];
|
|
137
|
+
const actual = summary[metric]?.pct ?? 0;
|
|
138
|
+
if (actual < minimum) failures.push({
|
|
139
|
+
metric,
|
|
140
|
+
actual,
|
|
141
|
+
minimum
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
if (failures.length === 0) return;
|
|
145
|
+
throw new CoverageThresholdError(`[coverage] thresholds not met (target: ${label}) — ${failures.map(({ metric, actual, minimum }) => `${metric}: ${actual.toFixed(2)}% < ${minimum}%`).join("; ")}`);
|
|
205
146
|
}
|
|
206
147
|
function resolveCoverageLib() {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
if (candidate.default && typeof candidate.default.createCoverageMap === "function") {
|
|
212
|
-
return candidate.default;
|
|
213
|
-
}
|
|
214
|
-
throw new Error("istanbul-lib-coverage exports are unavailable");
|
|
148
|
+
const candidate = libCoverage;
|
|
149
|
+
if (typeof candidate.createCoverageMap === "function") return candidate;
|
|
150
|
+
if (candidate.default && typeof candidate.default.createCoverageMap === "function") return candidate.default;
|
|
151
|
+
throw new Error("istanbul-lib-coverage exports are unavailable");
|
|
215
152
|
}
|
|
216
153
|
function resolveInstrumentLib() {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
if (candidate.default && typeof candidate.default.createInstrumenter === "function") {
|
|
222
|
-
return candidate.default;
|
|
223
|
-
}
|
|
224
|
-
throw new Error("istanbul-lib-instrument exports are unavailable");
|
|
154
|
+
const candidate = libInstrument;
|
|
155
|
+
if (typeof candidate.createInstrumenter === "function") return candidate;
|
|
156
|
+
if (candidate.default && typeof candidate.default.createInstrumenter === "function") return candidate.default;
|
|
157
|
+
throw new Error("istanbul-lib-instrument exports are unavailable");
|
|
225
158
|
}
|
|
226
159
|
async function includeUntestedFiles(coverageMap, config, matchesCollectCoverageFrom) {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
160
|
+
const existing = new Set(coverageMap.files().map((filePath) => path.resolve(String(filePath ?? ""))));
|
|
161
|
+
const candidates = await findCollectCoverageFiles(config, matchesCollectCoverageFrom);
|
|
162
|
+
if (candidates.length === 0) return;
|
|
163
|
+
const instrumenter = resolveInstrumentLib().createInstrumenter({
|
|
164
|
+
esModules: true,
|
|
165
|
+
parserPlugins: [
|
|
166
|
+
"typescript",
|
|
167
|
+
"jsx",
|
|
168
|
+
"classProperties",
|
|
169
|
+
"classPrivateProperties",
|
|
170
|
+
"classPrivateMethods",
|
|
171
|
+
"decorators-legacy",
|
|
172
|
+
"importMeta",
|
|
173
|
+
"topLevelAwait"
|
|
174
|
+
]
|
|
175
|
+
});
|
|
176
|
+
for (const filePath of candidates) {
|
|
177
|
+
const normalized = path.resolve(filePath);
|
|
178
|
+
if (existing.has(normalized)) continue;
|
|
179
|
+
const source = await fsPromises.readFile(normalized, "utf8").catch(() => null);
|
|
180
|
+
if (source === null) continue;
|
|
181
|
+
try {
|
|
182
|
+
instrumenter.instrumentSync(source, normalized);
|
|
183
|
+
const fileCoverage = instrumenter.lastFileCoverage();
|
|
184
|
+
if (!fileCoverage) continue;
|
|
185
|
+
coverageMap.addFileCoverage(fileCoverage);
|
|
186
|
+
existing.add(normalized);
|
|
187
|
+
} catch (error) {
|
|
188
|
+
const relative = path.relative(config.rootDir, normalized);
|
|
189
|
+
console.warn(`[coverage] failed to instrument ${relative && !relative.startsWith("..") ? relative : normalized}:`, error);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
259
192
|
}
|
|
260
|
-
|
|
193
|
+
var DEFAULT_COLLECT_COVERAGE_IGNORES = [
|
|
194
|
+
"**/.git/**",
|
|
195
|
+
"**/.next/**",
|
|
196
|
+
"**/.turbo/**",
|
|
197
|
+
"**/.vite/**",
|
|
198
|
+
"**/.vitest/**",
|
|
199
|
+
"**/build/**",
|
|
200
|
+
"**/coverage/**",
|
|
201
|
+
"**/dist/**",
|
|
202
|
+
"**/node_modules/**",
|
|
203
|
+
"**/playwright-report/**",
|
|
204
|
+
"**/spec/**",
|
|
205
|
+
"**/test/**",
|
|
206
|
+
"**/test-results/**",
|
|
207
|
+
"**/tests/**",
|
|
208
|
+
"**/__tests__/**",
|
|
209
|
+
"**/*.d.ts",
|
|
210
|
+
"**/*.map"
|
|
211
|
+
];
|
|
261
212
|
async function findCollectCoverageFiles(config, matchesCollectCoverageFrom) {
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
if (isNodeModulesPath(normalized)) {
|
|
285
|
-
continue;
|
|
286
|
-
}
|
|
287
|
-
if (isViteVirtualModulePath(normalized)) {
|
|
288
|
-
continue;
|
|
289
|
-
}
|
|
290
|
-
if (!matchesCollectCoverageFrom(normalized)) {
|
|
291
|
-
continue;
|
|
292
|
-
}
|
|
293
|
-
collected.add(normalized);
|
|
294
|
-
}
|
|
295
|
-
return Array.from(collected).sort();
|
|
213
|
+
const patterns = Array.isArray(config.collectCoverageFrom) ? config.collectCoverageFrom : [];
|
|
214
|
+
if (patterns.length === 0) return [];
|
|
215
|
+
const rawFiles = await fg(patterns, {
|
|
216
|
+
cwd: config.rootDir,
|
|
217
|
+
absolute: true,
|
|
218
|
+
dot: true,
|
|
219
|
+
onlyFiles: true,
|
|
220
|
+
unique: true,
|
|
221
|
+
followSymbolicLinks: false,
|
|
222
|
+
ignore: DEFAULT_COLLECT_COVERAGE_IGNORES
|
|
223
|
+
}).catch(() => []);
|
|
224
|
+
const collected = /* @__PURE__ */ new Set();
|
|
225
|
+
for (const file of rawFiles) {
|
|
226
|
+
const normalized = path.resolve(String(file ?? ""));
|
|
227
|
+
if (!normalized) continue;
|
|
228
|
+
if (normalized.endsWith(".d.ts") || normalized.endsWith(".map")) continue;
|
|
229
|
+
if (isNodeModulesPath(normalized)) continue;
|
|
230
|
+
if (isViteVirtualModulePath(normalized)) continue;
|
|
231
|
+
if (!matchesCollectCoverageFrom(normalized)) continue;
|
|
232
|
+
collected.add(normalized);
|
|
233
|
+
}
|
|
234
|
+
return Array.from(collected).sort();
|
|
296
235
|
}
|
|
297
236
|
function buildFileSummaries(coverageMap, rootDir) {
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
};
|
|
315
|
-
});
|
|
237
|
+
const normalizedRoot = path.resolve(rootDir);
|
|
238
|
+
return coverageMap.files().map((filePath) => {
|
|
239
|
+
const normalizedAbsolute = path.resolve(filePath);
|
|
240
|
+
const summary = coverageMap.fileCoverageFor(filePath).toSummary();
|
|
241
|
+
const relativePath = path.relative(normalizedRoot, normalizedAbsolute);
|
|
242
|
+
const candidates = /* @__PURE__ */ new Set();
|
|
243
|
+
if (relativePath) {
|
|
244
|
+
const relativePosix = toPosix(relativePath);
|
|
245
|
+
candidates.add(relativePosix);
|
|
246
|
+
candidates.add(`./${relativePosix}`);
|
|
247
|
+
} else candidates.add(toPosix(path.basename(normalizedAbsolute)));
|
|
248
|
+
return {
|
|
249
|
+
summary,
|
|
250
|
+
candidates: Array.from(candidates)
|
|
251
|
+
};
|
|
252
|
+
});
|
|
316
253
|
}
|
|
317
254
|
function collectTargetSummary(fileSummaries, matcher, coverageLib) {
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
matched
|
|
329
|
-
};
|
|
255
|
+
const summary = coverageLib.createCoverageSummary();
|
|
256
|
+
let matched = 0;
|
|
257
|
+
for (const file of fileSummaries) if (file.candidates.some((candidate) => matcher(candidate))) {
|
|
258
|
+
summary.merge(file.summary);
|
|
259
|
+
matched += 1;
|
|
260
|
+
}
|
|
261
|
+
return {
|
|
262
|
+
summary,
|
|
263
|
+
matched
|
|
264
|
+
};
|
|
330
265
|
}
|
|
331
266
|
function createGlobMatcher(pattern) {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
if (isAbsoluteGlobPattern(normalized)) {
|
|
337
|
-
throw new Error(`[coverage] threshold patterns must be relative (absolute paths are not supported): "${pattern}"`);
|
|
338
|
-
}
|
|
339
|
-
return picomatch(normalized, {
|
|
340
|
-
dot: true
|
|
341
|
-
});
|
|
267
|
+
const normalized = toPosix(String(pattern ?? "")).trim();
|
|
268
|
+
if (!normalized) return () => false;
|
|
269
|
+
if (isAbsoluteGlobPattern(normalized)) throw new Error(`[coverage] threshold patterns must be relative (absolute paths are not supported): "${pattern}"`);
|
|
270
|
+
return picomatch(normalized, { dot: true });
|
|
342
271
|
}
|
|
343
272
|
function isAbsoluteGlobPattern(pattern) {
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
return true;
|
|
350
|
-
}
|
|
351
|
-
if (normalized.startsWith("file://")) {
|
|
352
|
-
return true;
|
|
353
|
-
}
|
|
354
|
-
return /^[A-Za-z]:\//.test(normalized);
|
|
273
|
+
const normalized = String(pattern ?? "").trim();
|
|
274
|
+
if (!normalized) return false;
|
|
275
|
+
if (normalized.startsWith("/")) return true;
|
|
276
|
+
if (normalized.startsWith("file://")) return true;
|
|
277
|
+
return /^[A-Za-z]:\//.test(normalized);
|
|
355
278
|
}
|
|
356
279
|
function stripQuery(url) {
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
}
|
|
363
|
-
return url.slice(0, endIndex);
|
|
280
|
+
const queryIndex = url.indexOf("?");
|
|
281
|
+
const hashIndex = url.indexOf("#");
|
|
282
|
+
const endIndex = Math.min(queryIndex === -1 ? Number.POSITIVE_INFINITY : queryIndex, hashIndex === -1 ? Number.POSITIVE_INFINITY : hashIndex);
|
|
283
|
+
if (!Number.isFinite(endIndex)) return url;
|
|
284
|
+
return url.slice(0, endIndex);
|
|
364
285
|
}
|
|
365
286
|
function extractSourceMappingUrl(source) {
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
}
|
|
372
|
-
return typeof last === "string" && last.length > 0 ? last : null;
|
|
287
|
+
const regex = /\/\/[#@]\s*sourceMappingURL=([^\s]+)/g;
|
|
288
|
+
let last = null;
|
|
289
|
+
let match = null;
|
|
290
|
+
while ((match = regex.exec(source)) !== null) last = match[1];
|
|
291
|
+
return typeof last === "string" && last.length > 0 ? last : null;
|
|
373
292
|
}
|
|
374
293
|
function resolveSourceMapPath(scriptPath, mappingUrl) {
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
if (path.isAbsolute(cleaned)) {
|
|
380
|
-
return cleaned;
|
|
381
|
-
}
|
|
382
|
-
return path.resolve(path.dirname(scriptPath), cleaned);
|
|
294
|
+
const cleaned = stripQuery(mappingUrl);
|
|
295
|
+
if (cleaned.startsWith("file://")) return fileURLToPath(cleaned);
|
|
296
|
+
if (path.isAbsolute(cleaned)) return cleaned;
|
|
297
|
+
return path.resolve(path.dirname(scriptPath), cleaned);
|
|
383
298
|
}
|
|
384
299
|
function filterCoverageMap(map, config, matchesCollectCoverageFrom) {
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
continue;
|
|
402
|
-
}
|
|
403
|
-
if (!matchesCollectCoverageFrom(absolutePath)) {
|
|
404
|
-
continue;
|
|
405
|
-
}
|
|
406
|
-
if (fileCoverage && typeof fileCoverage === "object") {
|
|
407
|
-
filtered[absolutePath] = {
|
|
408
|
-
...fileCoverage,
|
|
409
|
-
path: absolutePath
|
|
410
|
-
};
|
|
411
|
-
} else {
|
|
412
|
-
filtered[absolutePath] = fileCoverage;
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
return filtered;
|
|
300
|
+
if (!map || typeof map !== "object") return {};
|
|
301
|
+
const filtered = {};
|
|
302
|
+
for (const [filePath, fileCoverage] of Object.entries(map)) {
|
|
303
|
+
const absolutePath = resolveCoveragePath(filePath, config.rootDir);
|
|
304
|
+
if (!absolutePath) continue;
|
|
305
|
+
if (absolutePath.endsWith(".d.ts") || absolutePath.endsWith(".map")) continue;
|
|
306
|
+
if (isNodeModulesPath(absolutePath)) continue;
|
|
307
|
+
if (isViteVirtualModulePath(absolutePath)) continue;
|
|
308
|
+
if (!matchesCollectCoverageFrom(absolutePath)) continue;
|
|
309
|
+
if (fileCoverage && typeof fileCoverage === "object") filtered[absolutePath] = {
|
|
310
|
+
...fileCoverage,
|
|
311
|
+
path: absolutePath
|
|
312
|
+
};
|
|
313
|
+
else filtered[absolutePath] = fileCoverage;
|
|
314
|
+
}
|
|
315
|
+
return filtered;
|
|
416
316
|
}
|
|
417
317
|
function resolveCoveragePath(filePath, rootDir) {
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
}
|
|
430
|
-
if (path.isAbsolute(cleaned)) {
|
|
431
|
-
return path.normalize(cleaned);
|
|
432
|
-
}
|
|
433
|
-
if (cleaned.includes("://")) {
|
|
434
|
-
return null;
|
|
435
|
-
}
|
|
436
|
-
return path.normalize(path.resolve(rootDir, cleaned));
|
|
318
|
+
const raw = String(filePath ?? "").trim();
|
|
319
|
+
if (!raw) return null;
|
|
320
|
+
const cleaned = stripQuery(raw);
|
|
321
|
+
if (cleaned.startsWith("file://")) try {
|
|
322
|
+
return path.normalize(fileURLToPath(cleaned));
|
|
323
|
+
} catch {
|
|
324
|
+
return null;
|
|
325
|
+
}
|
|
326
|
+
if (path.isAbsolute(cleaned)) return path.normalize(cleaned);
|
|
327
|
+
if (cleaned.includes("://")) return null;
|
|
328
|
+
return path.normalize(path.resolve(rootDir, cleaned));
|
|
437
329
|
}
|
|
438
330
|
function isNodeModulesPath(filePath) {
|
|
439
|
-
|
|
331
|
+
return path.normalize(String(filePath ?? "")).split(path.sep).includes("node_modules");
|
|
440
332
|
}
|
|
441
333
|
function isViteVirtualModulePath(filePath) {
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
334
|
+
const normalized = path.normalize(String(filePath ?? ""));
|
|
335
|
+
const baseName = path.basename(normalized);
|
|
336
|
+
return baseName === "__vite-browser-external" || baseName.startsWith("__vite-browser-external:") || baseName.startsWith("__vite-");
|
|
445
337
|
}
|
|
446
338
|
function parseSourceMapPayload(raw) {
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
if (!Array.isArray(sources) || sources.length === 0) {
|
|
452
|
-
return null;
|
|
453
|
-
}
|
|
454
|
-
return raw;
|
|
339
|
+
if (!raw || typeof raw !== "object") return null;
|
|
340
|
+
const sources = raw.sources;
|
|
341
|
+
if (!Array.isArray(sources) || sources.length === 0) return null;
|
|
342
|
+
return raw;
|
|
455
343
|
}
|
|
456
344
|
function normalizeSourceMap(sourceMap, scriptPath) {
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
}
|
|
480
|
-
return path.normalize(path.resolve(dir, normalizedCandidate));
|
|
481
|
-
});
|
|
482
|
-
return {
|
|
483
|
-
...sourceMap,
|
|
484
|
-
sources: fixedSources
|
|
485
|
-
};
|
|
345
|
+
const root = typeof sourceMap.sourceRoot === "string" ? sourceMap.sourceRoot.replace("file://", "") : "";
|
|
346
|
+
const dir = path.dirname(scriptPath);
|
|
347
|
+
const fixedSources = sourceMap.sources.map((source) => {
|
|
348
|
+
const cleaned = stripQuery(String(source ?? ""));
|
|
349
|
+
if (cleaned.startsWith("file://")) try {
|
|
350
|
+
return path.normalize(fileURLToPath(cleaned));
|
|
351
|
+
} catch {
|
|
352
|
+
return cleaned;
|
|
353
|
+
}
|
|
354
|
+
const withoutWebpack = cleaned.replace(/^webpack:\/\//, "");
|
|
355
|
+
const candidate = path.join(root, withoutWebpack);
|
|
356
|
+
if (path.isAbsolute(candidate)) return path.normalize(candidate);
|
|
357
|
+
const normalizedCandidate = candidate.split("/").join(path.sep);
|
|
358
|
+
if (dir.endsWith(`${path.sep}dist`) && !normalizedCandidate.startsWith(`..${path.sep}`)) {
|
|
359
|
+
if (normalizedCandidate.startsWith(`src${path.sep}`) || normalizedCandidate.startsWith(`lib${path.sep}`)) return path.normalize(path.resolve(dir, "..", normalizedCandidate));
|
|
360
|
+
}
|
|
361
|
+
return path.normalize(path.resolve(dir, normalizedCandidate));
|
|
362
|
+
});
|
|
363
|
+
return {
|
|
364
|
+
...sourceMap,
|
|
365
|
+
sources: fixedSources
|
|
366
|
+
};
|
|
486
367
|
}
|
|
487
368
|
async function loadSourceMapForScript(scriptPath, source) {
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
return parsed ? normalizeSourceMap(parsed, scriptPath) : null;
|
|
513
|
-
} catch {
|
|
514
|
-
return null;
|
|
515
|
-
}
|
|
369
|
+
const mappingUrl = extractSourceMappingUrl(source);
|
|
370
|
+
if (!mappingUrl) return null;
|
|
371
|
+
const cleaned = stripQuery(mappingUrl);
|
|
372
|
+
if (cleaned.startsWith("data:")) {
|
|
373
|
+
const commaIndex = cleaned.indexOf(",");
|
|
374
|
+
if (commaIndex === -1) return null;
|
|
375
|
+
const meta = cleaned.slice(0, commaIndex);
|
|
376
|
+
const payload = cleaned.slice(commaIndex + 1);
|
|
377
|
+
const raw = meta.includes(";base64") ? Buffer.from(payload, "base64").toString("utf8") : decodeURIComponent(payload);
|
|
378
|
+
try {
|
|
379
|
+
const parsed = parseSourceMapPayload(JSON.parse(raw));
|
|
380
|
+
return parsed ? normalizeSourceMap(parsed, scriptPath) : null;
|
|
381
|
+
} catch {
|
|
382
|
+
return null;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
try {
|
|
386
|
+
const mapPath = resolveSourceMapPath(scriptPath, cleaned);
|
|
387
|
+
const raw = await fsPromises.readFile(mapPath, "utf8");
|
|
388
|
+
const parsed = parseSourceMapPayload(JSON.parse(raw));
|
|
389
|
+
return parsed ? normalizeSourceMap(parsed, scriptPath) : null;
|
|
390
|
+
} catch {
|
|
391
|
+
return null;
|
|
392
|
+
}
|
|
516
393
|
}
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
};
|
|
522
|
-
//# sourceMappingURL=report.js.map
|
|
394
|
+
//#endregion
|
|
395
|
+
export { CoverageThresholdError, collectCoveredFiles, generateCoverageReport };
|
|
396
|
+
|
|
397
|
+
//# sourceMappingURL=report.js.map
|