@vitest/coverage-v8 2.0.0-beta.10 → 2.0.0-beta.11
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/index.js +8 -4
- package/dist/provider.js +171 -70
- package/package.json +4 -4
package/dist/index.js
CHANGED
@@ -13,13 +13,15 @@ function startCoverage() {
|
|
13
13
|
async function takeCoverage() {
|
14
14
|
return new Promise((resolve, reject) => {
|
15
15
|
session.post("Profiler.takePreciseCoverage", async (error, coverage) => {
|
16
|
-
if (error)
|
16
|
+
if (error) {
|
17
17
|
return reject(error);
|
18
|
+
}
|
18
19
|
const result = coverage.result.filter(filterResult);
|
19
20
|
resolve({ result });
|
20
21
|
});
|
21
|
-
if (provider === "stackblitz")
|
22
|
+
if (provider === "stackblitz") {
|
22
23
|
resolve({ result: [] });
|
24
|
+
}
|
23
25
|
});
|
24
26
|
}
|
25
27
|
function stopCoverage() {
|
@@ -28,10 +30,12 @@ function stopCoverage() {
|
|
28
30
|
session.disconnect();
|
29
31
|
}
|
30
32
|
function filterResult(coverage) {
|
31
|
-
if (!coverage.url.startsWith("file://"))
|
33
|
+
if (!coverage.url.startsWith("file://")) {
|
32
34
|
return false;
|
33
|
-
|
35
|
+
}
|
36
|
+
if (coverage.url.includes("/node_modules/")) {
|
34
37
|
return false;
|
38
|
+
}
|
35
39
|
return true;
|
36
40
|
}
|
37
41
|
|
package/dist/provider.js
CHANGED
@@ -2230,8 +2230,13 @@ class V8CoverageProvider extends BaseCoverageProvider {
|
|
2230
2230
|
...config,
|
2231
2231
|
// Resolved fields
|
2232
2232
|
provider: "v8",
|
2233
|
-
reporter: this.resolveReporters(
|
2234
|
-
|
2233
|
+
reporter: this.resolveReporters(
|
2234
|
+
config.reporter || coverageConfigDefaults.reporter
|
2235
|
+
),
|
2236
|
+
reportsDirectory: resolve(
|
2237
|
+
ctx.config.root,
|
2238
|
+
config.reportsDirectory || coverageConfigDefaults.reportsDirectory
|
2239
|
+
),
|
2235
2240
|
thresholds: config.thresholds && {
|
2236
2241
|
...config.thresholds,
|
2237
2242
|
lines: config.thresholds["100"] ? 100 : config.thresholds.lines,
|
@@ -2250,16 +2255,29 @@ class V8CoverageProvider extends BaseCoverageProvider {
|
|
2250
2255
|
});
|
2251
2256
|
const shard = this.ctx.config.shard;
|
2252
2257
|
const tempDirectory = `.tmp${shard ? `-${shard.index}-${shard.count}` : ""}`;
|
2253
|
-
this.coverageFilesDirectory = resolve(
|
2258
|
+
this.coverageFilesDirectory = resolve(
|
2259
|
+
this.options.reportsDirectory,
|
2260
|
+
tempDirectory
|
2261
|
+
);
|
2254
2262
|
}
|
2255
2263
|
resolveOptions() {
|
2256
2264
|
return this.options;
|
2257
2265
|
}
|
2258
2266
|
async clean(clean = true) {
|
2259
|
-
if (clean && existsSync(this.options.reportsDirectory))
|
2260
|
-
await promises$1.rm(this.options.reportsDirectory, {
|
2261
|
-
|
2262
|
-
|
2267
|
+
if (clean && existsSync(this.options.reportsDirectory)) {
|
2268
|
+
await promises$1.rm(this.options.reportsDirectory, {
|
2269
|
+
recursive: true,
|
2270
|
+
force: true,
|
2271
|
+
maxRetries: 10
|
2272
|
+
});
|
2273
|
+
}
|
2274
|
+
if (existsSync(this.coverageFilesDirectory)) {
|
2275
|
+
await promises$1.rm(this.coverageFilesDirectory, {
|
2276
|
+
recursive: true,
|
2277
|
+
force: true,
|
2278
|
+
maxRetries: 10
|
2279
|
+
});
|
2280
|
+
}
|
2263
2281
|
await promises$1.mkdir(this.coverageFilesDirectory, { recursive: true });
|
2264
2282
|
this.coverageFiles = /* @__PURE__ */ new Map();
|
2265
2283
|
this.pendingPromises = [];
|
@@ -2270,14 +2288,18 @@ class V8CoverageProvider extends BaseCoverageProvider {
|
|
2270
2288
|
* backwards compatibility is a breaking change.
|
2271
2289
|
*/
|
2272
2290
|
onAfterSuiteRun({ coverage, transformMode, projectName }) {
|
2273
|
-
if (transformMode !== "web" && transformMode !== "ssr")
|
2291
|
+
if (transformMode !== "web" && transformMode !== "ssr") {
|
2274
2292
|
throw new Error(`Invalid transform mode: ${transformMode}`);
|
2293
|
+
}
|
2275
2294
|
let entry = this.coverageFiles.get(projectName || DEFAULT_PROJECT);
|
2276
2295
|
if (!entry) {
|
2277
2296
|
entry = { web: [], ssr: [] };
|
2278
2297
|
this.coverageFiles.set(projectName || DEFAULT_PROJECT, entry);
|
2279
2298
|
}
|
2280
|
-
const filename = resolve(
|
2299
|
+
const filename = resolve(
|
2300
|
+
this.coverageFilesDirectory,
|
2301
|
+
`coverage-${uniqueId++}.json`
|
2302
|
+
);
|
2281
2303
|
entry[transformMode].push(filename);
|
2282
2304
|
const promise = promises$1.writeFile(filename, JSON.stringify(coverage), "utf-8");
|
2283
2305
|
this.pendingPromises.push(promise);
|
@@ -2288,21 +2310,35 @@ class V8CoverageProvider extends BaseCoverageProvider {
|
|
2288
2310
|
const total = this.pendingPromises.length;
|
2289
2311
|
await Promise.all(this.pendingPromises);
|
2290
2312
|
this.pendingPromises = [];
|
2291
|
-
for (const [
|
2292
|
-
|
2313
|
+
for (const [
|
2314
|
+
projectName,
|
2315
|
+
coveragePerProject
|
2316
|
+
] of this.coverageFiles.entries()) {
|
2317
|
+
for (const [transformMode, filenames] of Object.entries(
|
2318
|
+
coveragePerProject
|
2319
|
+
)) {
|
2293
2320
|
let merged = { result: [] };
|
2294
|
-
for (const chunk of this.toSlices(
|
2321
|
+
for (const chunk of this.toSlices(
|
2322
|
+
filenames,
|
2323
|
+
this.options.processingConcurrency
|
2324
|
+
)) {
|
2295
2325
|
if (debug.enabled) {
|
2296
2326
|
index += chunk.length;
|
2297
2327
|
debug("Covered files %d/%d", index, total);
|
2298
2328
|
}
|
2299
|
-
await Promise.all(
|
2300
|
-
|
2301
|
-
|
2302
|
-
|
2303
|
-
|
2329
|
+
await Promise.all(
|
2330
|
+
chunk.map(async (filename) => {
|
2331
|
+
const contents = await promises$1.readFile(filename, "utf-8");
|
2332
|
+
const coverage = JSON.parse(contents);
|
2333
|
+
merged = mergeProcessCovs([merged, coverage]);
|
2334
|
+
})
|
2335
|
+
);
|
2304
2336
|
}
|
2305
|
-
const converted = await this.convertCoverage(
|
2337
|
+
const converted = await this.convertCoverage(
|
2338
|
+
merged,
|
2339
|
+
projectName,
|
2340
|
+
transformMode
|
2341
|
+
);
|
2306
2342
|
const transformedCoverage = await transformCoverage(converted);
|
2307
2343
|
coverageMap.merge(transformedCoverage);
|
2308
2344
|
}
|
@@ -2316,8 +2352,13 @@ class V8CoverageProvider extends BaseCoverageProvider {
|
|
2316
2352
|
return coverageMap;
|
2317
2353
|
}
|
2318
2354
|
async reportCoverage(coverageMap, { allTestsRun }) {
|
2319
|
-
if (provider === "stackblitz")
|
2320
|
-
this.ctx.logger.log(
|
2355
|
+
if (provider === "stackblitz") {
|
2356
|
+
this.ctx.logger.log(
|
2357
|
+
c.blue(" % ") + c.yellow(
|
2358
|
+
"@vitest/coverage-v8 does not work on Stackblitz. Report will be empty."
|
2359
|
+
)
|
2360
|
+
);
|
2361
|
+
}
|
2321
2362
|
await this.generateReports(
|
2322
2363
|
coverageMap || libCoverage.createCoverageMap({}),
|
2323
2364
|
allTestsRun
|
@@ -2326,8 +2367,9 @@ class V8CoverageProvider extends BaseCoverageProvider {
|
|
2326
2367
|
if (!keepResults) {
|
2327
2368
|
this.coverageFiles = /* @__PURE__ */ new Map();
|
2328
2369
|
await promises$1.rm(this.coverageFilesDirectory, { recursive: true });
|
2329
|
-
if (readdirSync(this.options.reportsDirectory).length === 0)
|
2370
|
+
if (readdirSync(this.options.reportsDirectory).length === 0) {
|
2330
2371
|
await promises$1.rm(this.options.reportsDirectory, { recursive: true });
|
2372
|
+
}
|
2331
2373
|
}
|
2332
2374
|
}
|
2333
2375
|
async generateReports(coverageMap, allTestsRun) {
|
@@ -2336,8 +2378,11 @@ class V8CoverageProvider extends BaseCoverageProvider {
|
|
2336
2378
|
coverageMap,
|
2337
2379
|
watermarks: this.options.watermarks
|
2338
2380
|
});
|
2339
|
-
if (this.hasTerminalReporter(this.options.reporter))
|
2340
|
-
this.ctx.logger.log(
|
2381
|
+
if (this.hasTerminalReporter(this.options.reporter)) {
|
2382
|
+
this.ctx.logger.log(
|
2383
|
+
c.blue(" % ") + c.dim("Coverage report from ") + c.yellow(this.name)
|
2384
|
+
);
|
2385
|
+
}
|
2341
2386
|
for (const reporter of this.options.reporter) {
|
2342
2387
|
reports.create(reporter[0], {
|
2343
2388
|
skipFull: this.options.skipFull,
|
@@ -2357,63 +2402,95 @@ class V8CoverageProvider extends BaseCoverageProvider {
|
|
2357
2402
|
perFile: this.options.thresholds.perFile
|
2358
2403
|
});
|
2359
2404
|
if (this.options.thresholds.autoUpdate && allTestsRun) {
|
2360
|
-
if (!this.ctx.server.config.configFile)
|
2361
|
-
throw new Error(
|
2405
|
+
if (!this.ctx.server.config.configFile) {
|
2406
|
+
throw new Error(
|
2407
|
+
'Missing configurationFile. The "coverage.thresholds.autoUpdate" can only be enabled when configuration file is used.'
|
2408
|
+
);
|
2409
|
+
}
|
2362
2410
|
const configFilePath = this.ctx.server.config.configFile;
|
2363
|
-
const configModule = parseModule(
|
2411
|
+
const configModule = parseModule(
|
2412
|
+
await promises$1.readFile(configFilePath, "utf8")
|
2413
|
+
);
|
2364
2414
|
this.updateThresholds({
|
2365
2415
|
thresholds: resolvedThresholds,
|
2366
2416
|
perFile: this.options.thresholds.perFile,
|
2367
2417
|
configurationFile: configModule,
|
2368
|
-
onUpdate: () => writeFileSync(
|
2418
|
+
onUpdate: () => writeFileSync(
|
2419
|
+
configFilePath,
|
2420
|
+
configModule.generate().code,
|
2421
|
+
"utf-8"
|
2422
|
+
)
|
2369
2423
|
});
|
2370
2424
|
}
|
2371
2425
|
}
|
2372
2426
|
}
|
2373
2427
|
async mergeReports(coverageMaps) {
|
2374
2428
|
const coverageMap = libCoverage.createCoverageMap({});
|
2375
|
-
for (const coverage of coverageMaps)
|
2429
|
+
for (const coverage of coverageMaps) {
|
2376
2430
|
coverageMap.merge(coverage);
|
2431
|
+
}
|
2377
2432
|
await this.generateReports(coverageMap, true);
|
2378
2433
|
}
|
2379
2434
|
async getUntestedFiles(testedFiles) {
|
2380
|
-
const transformResults = normalizeTransformResults(
|
2435
|
+
const transformResults = normalizeTransformResults(
|
2436
|
+
this.ctx.vitenode.fetchCache
|
2437
|
+
);
|
2381
2438
|
const allFiles = await this.testExclude.glob(this.ctx.config.root);
|
2382
|
-
let includedFiles = allFiles.map(
|
2383
|
-
|
2384
|
-
|
2439
|
+
let includedFiles = allFiles.map(
|
2440
|
+
(file) => resolve(this.ctx.config.root, file)
|
2441
|
+
);
|
2442
|
+
if (this.ctx.config.changed) {
|
2443
|
+
includedFiles = (this.ctx.config.related || []).filter(
|
2444
|
+
(file) => includedFiles.includes(file)
|
2445
|
+
);
|
2446
|
+
}
|
2385
2447
|
const uncoveredFiles = includedFiles.map((file) => pathToFileURL(file)).filter((file) => !testedFiles.includes(file.pathname));
|
2386
2448
|
let merged = { result: [] };
|
2387
2449
|
let index = 0;
|
2388
|
-
for (const chunk of this.toSlices(
|
2450
|
+
for (const chunk of this.toSlices(
|
2451
|
+
uncoveredFiles,
|
2452
|
+
this.options.processingConcurrency
|
2453
|
+
)) {
|
2389
2454
|
if (debug.enabled) {
|
2390
2455
|
index += chunk.length;
|
2391
2456
|
debug("Uncovered files %d/%d", index, uncoveredFiles.length);
|
2392
2457
|
}
|
2393
|
-
const coverages = await Promise.all(
|
2394
|
-
|
2395
|
-
|
2396
|
-
|
2397
|
-
|
2398
|
-
|
2399
|
-
|
2400
|
-
|
2401
|
-
|
2402
|
-
|
2403
|
-
|
2404
|
-
|
2405
|
-
|
2406
|
-
|
2407
|
-
|
2408
|
-
|
2409
|
-
|
2410
|
-
|
2411
|
-
|
2412
|
-
|
2413
|
-
|
2458
|
+
const coverages = await Promise.all(
|
2459
|
+
chunk.map(async (filename) => {
|
2460
|
+
const { originalSource, source } = await this.getSources(
|
2461
|
+
filename.href,
|
2462
|
+
transformResults
|
2463
|
+
);
|
2464
|
+
if (source && stripLiteral(source).trim() === "") {
|
2465
|
+
return null;
|
2466
|
+
}
|
2467
|
+
const coverage = {
|
2468
|
+
url: filename.href,
|
2469
|
+
scriptId: "0",
|
2470
|
+
// Create a made up function to mark whole file as uncovered. Note that this does not exist in source maps.
|
2471
|
+
functions: [
|
2472
|
+
{
|
2473
|
+
ranges: [
|
2474
|
+
{
|
2475
|
+
startOffset: 0,
|
2476
|
+
endOffset: originalSource.length,
|
2477
|
+
count: 0
|
2478
|
+
}
|
2479
|
+
],
|
2480
|
+
isBlockCoverage: true,
|
2481
|
+
// This is magical value that indicates an empty report: https://github.com/istanbuljs/v8-to-istanbul/blob/fca5e6a9e6ef38a9cdc3a178d5a6cf9ef82e6cab/lib/v8-to-istanbul.js#LL131C40-L131C40
|
2482
|
+
functionName: "(empty-report)"
|
2483
|
+
}
|
2484
|
+
]
|
2485
|
+
};
|
2486
|
+
return { result: [coverage] };
|
2487
|
+
})
|
2488
|
+
);
|
2414
2489
|
merged = mergeProcessCovs([
|
2415
2490
|
merged,
|
2416
|
-
...coverages.filter(
|
2491
|
+
...coverages.filter(
|
2492
|
+
(cov) => cov != null
|
2493
|
+
)
|
2417
2494
|
]);
|
2418
2495
|
}
|
2419
2496
|
return merged;
|
@@ -2440,8 +2517,9 @@ class V8CoverageProvider extends BaseCoverageProvider {
|
|
2440
2517
|
};
|
2441
2518
|
}
|
2442
2519
|
const sources = [url];
|
2443
|
-
if (map.sources && map.sources[0] && !url.endsWith(map.sources[0]))
|
2520
|
+
if (map.sources && map.sources[0] && !url.endsWith(map.sources[0])) {
|
2444
2521
|
sources[0] = new URL(map.sources[0], url).href;
|
2522
|
+
}
|
2445
2523
|
return {
|
2446
2524
|
isExecuted,
|
2447
2525
|
originalSource: sourcesContent,
|
@@ -2460,22 +2538,39 @@ class V8CoverageProvider extends BaseCoverageProvider {
|
|
2460
2538
|
const viteNode = this.ctx.projects.find((project) => project.getName() === projectName)?.vitenode || this.ctx.vitenode;
|
2461
2539
|
const fetchCache = transformMode ? viteNode.fetchCaches[transformMode] : viteNode.fetchCache;
|
2462
2540
|
const transformResults = normalizeTransformResults(fetchCache);
|
2463
|
-
const scriptCoverages = coverage.result.filter(
|
2541
|
+
const scriptCoverages = coverage.result.filter(
|
2542
|
+
(result) => this.testExclude.shouldInstrument(fileURLToPath$1(result.url))
|
2543
|
+
);
|
2464
2544
|
const coverageMap = libCoverage.createCoverageMap({});
|
2465
2545
|
let index = 0;
|
2466
|
-
for (const chunk of this.toSlices(
|
2546
|
+
for (const chunk of this.toSlices(
|
2547
|
+
scriptCoverages,
|
2548
|
+
this.options.processingConcurrency
|
2549
|
+
)) {
|
2467
2550
|
if (debug.enabled) {
|
2468
2551
|
index += chunk.length;
|
2469
2552
|
debug("Converting %d/%d", index, scriptCoverages.length);
|
2470
2553
|
}
|
2471
|
-
await Promise.all(
|
2472
|
-
|
2473
|
-
|
2474
|
-
|
2475
|
-
|
2476
|
-
|
2477
|
-
|
2478
|
-
|
2554
|
+
await Promise.all(
|
2555
|
+
chunk.map(async ({ url, functions }) => {
|
2556
|
+
const sources = await this.getSources(
|
2557
|
+
url,
|
2558
|
+
transformResults,
|
2559
|
+
functions
|
2560
|
+
);
|
2561
|
+
const wrapperLength = sources.isExecuted ? WRAPPER_LENGTH : 0;
|
2562
|
+
const converter = v8ToIstanbul$1(
|
2563
|
+
url,
|
2564
|
+
wrapperLength,
|
2565
|
+
sources,
|
2566
|
+
void 0,
|
2567
|
+
this.options.ignoreEmptyLines
|
2568
|
+
);
|
2569
|
+
await converter.load();
|
2570
|
+
converter.applyCoverage(functions);
|
2571
|
+
coverageMap.merge(converter.toIstanbul());
|
2572
|
+
})
|
2573
|
+
);
|
2479
2574
|
}
|
2480
2575
|
return coverageMap;
|
2481
2576
|
}
|
@@ -2485,10 +2580,12 @@ async function transformCoverage(coverageMap) {
|
|
2485
2580
|
return await sourceMapStore.transformCoverage(coverageMap);
|
2486
2581
|
}
|
2487
2582
|
function excludeGeneratedCode(source, map) {
|
2488
|
-
if (!source)
|
2583
|
+
if (!source) {
|
2489
2584
|
return map;
|
2490
|
-
|
2585
|
+
}
|
2586
|
+
if (!source.match(VITE_EXPORTS_LINE_PATTERN) && !source.match(DECORATOR_METADATA_PATTERN)) {
|
2491
2587
|
return map;
|
2588
|
+
}
|
2492
2589
|
const trimmed = new MagicString(source);
|
2493
2590
|
trimmed.replaceAll(VITE_EXPORTS_LINE_PATTERN, "\n");
|
2494
2591
|
trimmed.replaceAll(DECORATOR_METADATA_PATTERN, (match) => "\n".repeat(match.split("\n").length - 1));
|
@@ -2501,7 +2598,10 @@ function excludeGeneratedCode(source, map) {
|
|
2501
2598
|
}
|
2502
2599
|
function findLongestFunctionLength(functions) {
|
2503
2600
|
return functions.reduce((previous, current) => {
|
2504
|
-
const maxEndOffset = current.ranges.reduce(
|
2601
|
+
const maxEndOffset = current.ranges.reduce(
|
2602
|
+
(endOffset, range) => Math.max(endOffset, range.endOffset),
|
2603
|
+
0
|
2604
|
+
);
|
2505
2605
|
return Math.max(previous, maxEndOffset);
|
2506
2606
|
}, 0);
|
2507
2607
|
}
|
@@ -2509,8 +2609,9 @@ function normalizeTransformResults(fetchCache) {
|
|
2509
2609
|
const normalized = /* @__PURE__ */ new Map();
|
2510
2610
|
for (const [key, value] of fetchCache.entries()) {
|
2511
2611
|
const cleanEntry = cleanUrl(key);
|
2512
|
-
if (!normalized.has(cleanEntry))
|
2612
|
+
if (!normalized.has(cleanEntry)) {
|
2513
2613
|
normalized.set(cleanEntry, value.result);
|
2614
|
+
}
|
2514
2615
|
}
|
2515
2616
|
return normalized;
|
2516
2617
|
}
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "@vitest/coverage-v8",
|
3
3
|
"type": "module",
|
4
|
-
"version": "2.0.0-beta.
|
4
|
+
"version": "2.0.0-beta.11",
|
5
5
|
"description": "V8 coverage provider for Vitest",
|
6
6
|
"author": "Anthony Fu <anthonyfu117@hotmail.com>",
|
7
7
|
"license": "MIT",
|
@@ -37,7 +37,7 @@
|
|
37
37
|
"dist"
|
38
38
|
],
|
39
39
|
"peerDependencies": {
|
40
|
-
"vitest": "2.0.0-beta.
|
40
|
+
"vitest": "2.0.0-beta.11"
|
41
41
|
},
|
42
42
|
"dependencies": {
|
43
43
|
"@ampproject/remapping": "^2.3.0",
|
@@ -62,8 +62,8 @@
|
|
62
62
|
"@types/istanbul-reports": "^3.0.4",
|
63
63
|
"pathe": "^1.1.2",
|
64
64
|
"v8-to-istanbul": "^9.2.0",
|
65
|
-
"vite-node": "2.0.0-beta.
|
66
|
-
"vitest": "2.0.0-beta.
|
65
|
+
"vite-node": "2.0.0-beta.11",
|
66
|
+
"vitest": "2.0.0-beta.11"
|
67
67
|
},
|
68
68
|
"scripts": {
|
69
69
|
"build": "rimraf dist && rollup -c",
|