@vitest/coverage-v8 2.1.0-beta.4 → 2.1.0-beta.6

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.
@@ -0,0 +1,16 @@
1
+ import { V8CoverageProvider } from './provider.js';
2
+ import 'istanbul-lib-coverage';
3
+ import 'vitest/coverage';
4
+ import 'vitest/node';
5
+ import 'vitest';
6
+
7
+ declare const _default: {
8
+ startCoverage(): Promise<void>;
9
+ takeCoverage(): Promise<{
10
+ result: any[];
11
+ }>;
12
+ stopCoverage(): Promise<void>;
13
+ getProvider(): Promise<V8CoverageProvider>;
14
+ };
15
+
16
+ export { _default as default };
@@ -0,0 +1,50 @@
1
+ import { cdp } from '@vitest/browser/context';
2
+ import { l as loadProvider } from './load-provider-Bl5rgjsL.js';
3
+
4
+ const session = cdp();
5
+ var browser = {
6
+ async startCoverage() {
7
+ await session.send("Profiler.enable");
8
+ await session.send("Profiler.startPreciseCoverage", {
9
+ callCount: true,
10
+ detailed: true
11
+ });
12
+ },
13
+ async takeCoverage() {
14
+ const coverage = await session.send("Profiler.takePreciseCoverage");
15
+ const result = [];
16
+ for (const entry of coverage.result) {
17
+ if (filterResult(entry)) {
18
+ result.push({
19
+ ...entry,
20
+ url: decodeURIComponent(entry.url.replace(window.location.origin, ""))
21
+ });
22
+ }
23
+ }
24
+ return { result };
25
+ },
26
+ async stopCoverage() {
27
+ await session.send("Profiler.stopPreciseCoverage");
28
+ await session.send("Profiler.disable");
29
+ },
30
+ async getProvider() {
31
+ return loadProvider();
32
+ }
33
+ };
34
+ function filterResult(coverage) {
35
+ if (!coverage.url.startsWith(window.location.origin)) {
36
+ return false;
37
+ }
38
+ if (coverage.url.includes("/node_modules/")) {
39
+ return false;
40
+ }
41
+ if (coverage.url.includes("__vitest_browser__")) {
42
+ return false;
43
+ }
44
+ if (coverage.url.includes("__vitest__/assets")) {
45
+ return false;
46
+ }
47
+ return true;
48
+ }
49
+
50
+ export { browser as default };
package/dist/index.d.ts CHANGED
@@ -2,8 +2,8 @@ import { Profiler } from 'node:inspector';
2
2
  import { V8CoverageProvider } from './provider.js';
3
3
  import 'istanbul-lib-coverage';
4
4
  import 'vitest/coverage';
5
- import 'vitest';
6
5
  import 'vitest/node';
6
+ import 'vitest';
7
7
 
8
8
  declare const _default: {
9
9
  startCoverage(): void;
package/dist/index.js CHANGED
@@ -1,34 +1,40 @@
1
1
  import inspector from 'node:inspector';
2
2
  import { provider } from 'std-env';
3
+ import { l as loadProvider } from './load-provider-Bl5rgjsL.js';
3
4
 
4
5
  const session = new inspector.Session();
5
- function startCoverage() {
6
- session.connect();
7
- session.post("Profiler.enable");
8
- session.post("Profiler.startPreciseCoverage", {
9
- callCount: true,
10
- detailed: true
11
- });
12
- }
13
- async function takeCoverage() {
14
- return new Promise((resolve, reject) => {
15
- session.post("Profiler.takePreciseCoverage", async (error, coverage) => {
16
- if (error) {
17
- return reject(error);
6
+ var index = {
7
+ startCoverage() {
8
+ session.connect();
9
+ session.post("Profiler.enable");
10
+ session.post("Profiler.startPreciseCoverage", {
11
+ callCount: true,
12
+ detailed: true
13
+ });
14
+ },
15
+ takeCoverage() {
16
+ return new Promise((resolve, reject) => {
17
+ session.post("Profiler.takePreciseCoverage", async (error, coverage) => {
18
+ if (error) {
19
+ return reject(error);
20
+ }
21
+ const result = coverage.result.filter(filterResult);
22
+ resolve({ result });
23
+ });
24
+ if (provider === "stackblitz") {
25
+ resolve({ result: [] });
18
26
  }
19
- const result = coverage.result.filter(filterResult);
20
- resolve({ result });
21
27
  });
22
- if (provider === "stackblitz") {
23
- resolve({ result: [] });
24
- }
25
- });
26
- }
27
- function stopCoverage() {
28
- session.post("Profiler.stopPreciseCoverage");
29
- session.post("Profiler.disable");
30
- session.disconnect();
31
- }
28
+ },
29
+ stopCoverage() {
30
+ session.post("Profiler.stopPreciseCoverage");
31
+ session.post("Profiler.disable");
32
+ session.disconnect();
33
+ },
34
+ async getProvider() {
35
+ return loadProvider();
36
+ }
37
+ };
32
38
  function filterResult(coverage) {
33
39
  if (!coverage.url.startsWith("file://")) {
34
40
  return false;
@@ -39,21 +45,4 @@ function filterResult(coverage) {
39
45
  return true;
40
46
  }
41
47
 
42
- var index = {
43
- startCoverage() {
44
- return startCoverage();
45
- },
46
- takeCoverage() {
47
- return takeCoverage();
48
- },
49
- stopCoverage() {
50
- return stopCoverage();
51
- },
52
- async getProvider() {
53
- const name = "./provider.js";
54
- const { V8CoverageProvider } = await import(name);
55
- return new V8CoverageProvider();
56
- }
57
- };
58
-
59
48
  export { index as default };
@@ -0,0 +1,10 @@
1
+ const name = "./provider.js";
2
+ async function loadProvider() {
3
+ const { V8CoverageProvider } = await import(
4
+ /* @vite-ignore */
5
+ name
6
+ );
7
+ return new V8CoverageProvider();
8
+ }
9
+
10
+ export { loadProvider as l };
@@ -1,7 +1,7 @@
1
1
  import { CoverageMap } from 'istanbul-lib-coverage';
2
2
  import { BaseCoverageProvider } from 'vitest/coverage';
3
- import { CoverageProvider, AfterSuiteRunMeta, ReportContext, ResolvedCoverageOptions } from 'vitest';
4
3
  import { Vitest } from 'vitest/node';
4
+ import { CoverageProvider, AfterSuiteRunMeta, ReportContext, ResolvedCoverageOptions } from 'vitest';
5
5
 
6
6
  interface TestExclude {
7
7
  new (opts: {
package/dist/provider.js CHANGED
@@ -2248,10 +2248,13 @@ function cleanUrl(url) {
2248
2248
  "wasi"
2249
2249
  ]);
2250
2250
 
2251
+ var version = "2.1.0-beta.6";
2252
+
2251
2253
  const WRAPPER_LENGTH = 185;
2252
2254
  const VITE_EXPORTS_LINE_PATTERN = /Object\.defineProperty\(__vite_ssr_exports__.*\n/g;
2253
2255
  const DECORATOR_METADATA_PATTERN = /_ts_metadata\("design:paramtypes", \[[^\]]*\]\),*/g;
2254
2256
  const DEFAULT_PROJECT = Symbol.for("default-project");
2257
+ const FILE_PROTOCOL = "file://";
2255
2258
  const debug = createDebug("vitest:coverage");
2256
2259
  let uniqueId = 0;
2257
2260
  class V8CoverageProvider extends BaseCoverageProvider {
@@ -2264,6 +2267,15 @@ class V8CoverageProvider extends BaseCoverageProvider {
2264
2267
  pendingPromises = [];
2265
2268
  initialize(ctx) {
2266
2269
  const config = ctx.config.coverage;
2270
+ if (ctx.version !== version) {
2271
+ ctx.logger.warn(
2272
+ c.yellow(
2273
+ `Loaded ${c.inverse(c.yellow(` vitest@${ctx.version} `))} and ${c.inverse(c.yellow(` @vitest/coverage-v8@${version} `))}.
2274
+ Running mixed versions is not supported and may lead into bugs
2275
+ Update your dependencies and make sure the versions match.`
2276
+ )
2277
+ );
2278
+ }
2267
2279
  this.ctx = ctx;
2268
2280
  this.options = {
2269
2281
  ...coverageConfigDefaults,
@@ -2329,12 +2341,12 @@ class V8CoverageProvider extends BaseCoverageProvider {
2329
2341
  * backwards compatibility is a breaking change.
2330
2342
  */
2331
2343
  onAfterSuiteRun({ coverage, transformMode, projectName }) {
2332
- if (transformMode !== "web" && transformMode !== "ssr") {
2344
+ if (transformMode !== "web" && transformMode !== "ssr" && transformMode !== "browser") {
2333
2345
  throw new Error(`Invalid transform mode: ${transformMode}`);
2334
2346
  }
2335
2347
  let entry = this.coverageFiles.get(projectName || DEFAULT_PROJECT);
2336
2348
  if (!entry) {
2337
- entry = { web: [], ssr: [] };
2349
+ entry = { web: [], ssr: [], browser: [] };
2338
2350
  this.coverageFiles.set(projectName || DEFAULT_PROJECT, entry);
2339
2351
  }
2340
2352
  const filename = resolve(
@@ -2351,18 +2363,11 @@ class V8CoverageProvider extends BaseCoverageProvider {
2351
2363
  const total = this.pendingPromises.length;
2352
2364
  await Promise.all(this.pendingPromises);
2353
2365
  this.pendingPromises = [];
2354
- for (const [
2355
- projectName,
2356
- coveragePerProject
2357
- ] of this.coverageFiles.entries()) {
2358
- for (const [transformMode, filenames] of Object.entries(
2359
- coveragePerProject
2360
- )) {
2366
+ for (const [projectName, coveragePerProject] of this.coverageFiles.entries()) {
2367
+ for (const [transformMode, filenames] of Object.entries(coveragePerProject)) {
2361
2368
  let merged = { result: [] };
2362
- for (const chunk of this.toSlices(
2363
- filenames,
2364
- this.options.processingConcurrency
2365
- )) {
2369
+ const project = this.ctx.projects.find((p) => p.getName() === projectName) || this.ctx.getCoreWorkspaceProject();
2370
+ for (const chunk of this.toSlices(filenames, this.options.processingConcurrency)) {
2366
2371
  if (debug.enabled) {
2367
2372
  index += chunk.length;
2368
2373
  debug("Covered files %d/%d", index, total);
@@ -2377,7 +2382,7 @@ class V8CoverageProvider extends BaseCoverageProvider {
2377
2382
  }
2378
2383
  const converted = await this.convertCoverage(
2379
2384
  merged,
2380
- projectName,
2385
+ project,
2381
2386
  transformMode
2382
2387
  );
2383
2388
  const transformedCoverage = await transformCoverage(converted);
@@ -2390,6 +2395,9 @@ class V8CoverageProvider extends BaseCoverageProvider {
2390
2395
  const converted = await this.convertCoverage(untestedCoverage);
2391
2396
  coverageMap.merge(await transformCoverage(converted));
2392
2397
  }
2398
+ if (this.options.excludeAfterRemap) {
2399
+ coverageMap.filter((filename) => this.testExclude.shouldInstrument(filename));
2400
+ }
2393
2401
  return coverageMap;
2394
2402
  }
2395
2403
  async reportCoverage(coverageMap, { allTestsRun }) {
@@ -2477,6 +2485,7 @@ class V8CoverageProvider extends BaseCoverageProvider {
2477
2485
  const transformResults = normalizeTransformResults(
2478
2486
  this.ctx.vitenode.fetchCache
2479
2487
  );
2488
+ const transform = this.createUncoveredFileTransformer(this.ctx);
2480
2489
  const allFiles = await this.testExclude.glob(this.ctx.config.root);
2481
2490
  let includedFiles = allFiles.map(
2482
2491
  (file) => resolve(this.ctx.config.root, file)
@@ -2501,7 +2510,8 @@ class V8CoverageProvider extends BaseCoverageProvider {
2501
2510
  chunk.map(async (filename) => {
2502
2511
  const { originalSource } = await this.getSources(
2503
2512
  filename.href,
2504
- transformResults
2513
+ transformResults,
2514
+ transform
2505
2515
  );
2506
2516
  const coverage = {
2507
2517
  url: filename.href,
@@ -2534,58 +2544,79 @@ class V8CoverageProvider extends BaseCoverageProvider {
2534
2544
  }
2535
2545
  return merged;
2536
2546
  }
2537
- async getSources(url, transformResults, functions = []) {
2547
+ async getSources(url, transformResults, onTransform, functions = []) {
2538
2548
  const filePath = normalize(fileURLToPath$1(url));
2539
2549
  let isExecuted = true;
2540
2550
  let transformResult = transformResults.get(filePath);
2541
2551
  if (!transformResult) {
2542
2552
  isExecuted = false;
2543
- transformResult = await this.ctx.vitenode.transformRequest(filePath).catch(() => null);
2553
+ transformResult = await onTransform(removeStartsWith(url, FILE_PROTOCOL)).catch(() => void 0);
2544
2554
  }
2545
2555
  const map = transformResult?.map;
2546
2556
  const code = transformResult?.code;
2547
- const sourcesContent = map?.sourcesContent?.[0] || await promises$1.readFile(filePath, "utf-8").catch(() => {
2548
- const length = findLongestFunctionLength(functions);
2549
- return ".".repeat(length);
2550
- });
2557
+ const sourcesContent = map?.sourcesContent || [];
2558
+ if (!sourcesContent[0]) {
2559
+ sourcesContent[0] = await promises$1.readFile(filePath, "utf-8").catch(() => {
2560
+ const length = findLongestFunctionLength(functions);
2561
+ return ".".repeat(length);
2562
+ });
2563
+ }
2551
2564
  if (!map) {
2552
2565
  return {
2553
2566
  isExecuted,
2554
- source: code || sourcesContent,
2555
- originalSource: sourcesContent
2567
+ source: code || sourcesContent[0],
2568
+ originalSource: sourcesContent[0]
2556
2569
  };
2557
2570
  }
2558
- const sources = [url];
2559
- if (map.sources && map.sources[0] && !url.endsWith(map.sources[0])) {
2560
- sources[0] = new URL(map.sources[0], url).href;
2571
+ const sources = (map.sources || []).filter((source) => source != null).map((source) => new URL(source, url).href);
2572
+ if (sources.length === 0) {
2573
+ sources.push(url);
2561
2574
  }
2562
2575
  return {
2563
2576
  isExecuted,
2564
- originalSource: sourcesContent,
2565
- source: code || sourcesContent,
2577
+ originalSource: sourcesContent[0],
2578
+ source: code || sourcesContent[0],
2566
2579
  sourceMap: {
2567
2580
  sourcemap: excludeGeneratedCode(code, {
2568
2581
  ...map,
2569
2582
  version: 3,
2570
2583
  sources,
2571
- sourcesContent: [sourcesContent]
2584
+ sourcesContent
2572
2585
  })
2573
2586
  }
2574
2587
  };
2575
2588
  }
2576
- async convertCoverage(coverage, projectName, transformMode) {
2577
- const viteNode = this.ctx.projects.find((project) => project.getName() === projectName)?.vitenode || this.ctx.vitenode;
2578
- const fetchCache = transformMode ? viteNode.fetchCaches[transformMode] : viteNode.fetchCache;
2589
+ async convertCoverage(coverage, project = this.ctx.getCoreWorkspaceProject(), transformMode) {
2590
+ let fetchCache = project.vitenode.fetchCache;
2591
+ if (transformMode) {
2592
+ fetchCache = transformMode === "browser" ? /* @__PURE__ */ new Map() : project.vitenode.fetchCaches[transformMode];
2593
+ }
2579
2594
  const transformResults = normalizeTransformResults(fetchCache);
2580
- const scriptCoverages = coverage.result.filter(
2581
- (result) => this.testExclude.shouldInstrument(fileURLToPath$1(result.url))
2582
- );
2595
+ async function onTransform(filepath) {
2596
+ if (transformMode === "browser" && project.browser) {
2597
+ const result = await project.browser.vite.transformRequest(removeStartsWith(filepath, project.config.root));
2598
+ if (result) {
2599
+ return { ...result, code: `${result.code}// <inline-source-map>` };
2600
+ }
2601
+ }
2602
+ return project.vitenode.transformRequest(filepath);
2603
+ }
2604
+ const scriptCoverages = [];
2605
+ for (const result of coverage.result) {
2606
+ if (transformMode === "browser") {
2607
+ if (result.url.startsWith("/@fs")) {
2608
+ result.url = `${FILE_PROTOCOL}${removeStartsWith(result.url, "/@fs")}`;
2609
+ } else {
2610
+ result.url = `${FILE_PROTOCOL}${project.config.root}${result.url}`;
2611
+ }
2612
+ }
2613
+ if (this.testExclude.shouldInstrument(fileURLToPath$1(result.url))) {
2614
+ scriptCoverages.push(result);
2615
+ }
2616
+ }
2583
2617
  const coverageMap = libCoverage.createCoverageMap({});
2584
2618
  let index = 0;
2585
- for (const chunk of this.toSlices(
2586
- scriptCoverages,
2587
- this.options.processingConcurrency
2588
- )) {
2619
+ for (const chunk of this.toSlices(scriptCoverages, this.options.processingConcurrency)) {
2589
2620
  if (debug.enabled) {
2590
2621
  index += chunk.length;
2591
2622
  debug("Converting %d/%d", index, scriptCoverages.length);
@@ -2595,6 +2626,7 @@ class V8CoverageProvider extends BaseCoverageProvider {
2595
2626
  const sources = await this.getSources(
2596
2627
  url,
2597
2628
  transformResults,
2629
+ onTransform,
2598
2630
  functions
2599
2631
  );
2600
2632
  const wrapperLength = sources.isExecuted ? WRAPPER_LENGTH : 0;
@@ -2606,7 +2638,12 @@ class V8CoverageProvider extends BaseCoverageProvider {
2606
2638
  this.options.ignoreEmptyLines
2607
2639
  );
2608
2640
  await converter.load();
2609
- converter.applyCoverage(functions);
2641
+ try {
2642
+ converter.applyCoverage(functions);
2643
+ } catch (error) {
2644
+ this.ctx.logger.error(`Failed to convert coverage for ${url}.
2645
+ `, error);
2646
+ }
2610
2647
  coverageMap.merge(converter.toIstanbul());
2611
2648
  })
2612
2649
  );
@@ -2654,5 +2691,11 @@ function normalizeTransformResults(fetchCache) {
2654
2691
  }
2655
2692
  return normalized;
2656
2693
  }
2694
+ function removeStartsWith(filepath, start) {
2695
+ if (filepath.startsWith(start)) {
2696
+ return filepath.slice(start.length);
2697
+ }
2698
+ return filepath;
2699
+ }
2657
2700
 
2658
2701
  export { V8CoverageProvider };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vitest/coverage-v8",
3
3
  "type": "module",
4
- "version": "2.1.0-beta.4",
4
+ "version": "2.1.0-beta.6",
5
5
  "description": "V8 coverage provider for Vitest",
6
6
  "author": "Anthony Fu <anthonyfu117@hotmail.com>",
7
7
  "license": "MIT",
@@ -28,6 +28,10 @@
28
28
  "types": "./dist/index.d.ts",
29
29
  "default": "./dist/index.js"
30
30
  },
31
+ "./browser": {
32
+ "types": "./dist/browser.d.ts",
33
+ "default": "./dist/browser.js"
34
+ },
31
35
  "./*": "./*"
32
36
  },
33
37
  "main": "./dist/index.js",
@@ -37,7 +41,13 @@
37
41
  "dist"
38
42
  ],
39
43
  "peerDependencies": {
40
- "vitest": "2.1.0-beta.4"
44
+ "@vitest/browser": "2.1.0-beta.6",
45
+ "vitest": "2.1.0-beta.6"
46
+ },
47
+ "peerDependenciesMeta": {
48
+ "@vitest/browser": {
49
+ "optional": true
50
+ }
41
51
  },
42
52
  "dependencies": {
43
53
  "@ampproject/remapping": "^2.3.0",
@@ -61,8 +71,9 @@
61
71
  "@types/istanbul-reports": "^3.0.4",
62
72
  "pathe": "^1.1.2",
63
73
  "v8-to-istanbul": "^9.3.0",
64
- "vite-node": "2.1.0-beta.4",
65
- "vitest": "2.1.0-beta.4"
74
+ "@vitest/browser": "2.1.0-beta.6",
75
+ "vite-node": "2.1.0-beta.6",
76
+ "vitest": "2.1.0-beta.6"
66
77
  },
67
78
  "scripts": {
68
79
  "build": "rimraf dist && rollup -c",