@vitest/coverage-v8 4.1.5 → 5.0.0-beta.2

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.d.ts CHANGED
@@ -1,5 +1,8 @@
1
1
  import { CoverageProviderModule } from 'vitest/node';
2
2
 
3
- declare const mod: CoverageProviderModule;
3
+ declare const mod: CoverageProviderModule & {
4
+ extendedContextCoverageDir?: string;
5
+ session?: unknown | null;
6
+ };
4
7
 
5
8
  export { mod as default };
package/dist/index.js CHANGED
@@ -1,17 +1,28 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { existsSync } from 'node:fs';
3
+ import { readdir, readFile, rm } from 'node:fs/promises';
1
4
  import inspector from 'node:inspector/promises';
5
+ import { resolve } from 'node:path';
2
6
  import { fileURLToPath } from 'node:url';
3
7
  import { provider } from 'std-env';
4
8
  import { l as loadProvider } from './load-provider-CdgAx3rL.js';
5
9
  import { n as normalize } from './pathe.M-eThtNZ-BTaAGrLg.js';
6
10
 
7
- const session = new inspector.Session();
8
11
  let enabled = false;
9
12
  const mod = {
10
- async startCoverage({ isolate }) {
13
+ extendedContextCoverageDir: undefined,
14
+ session: null,
15
+ async startCoverage({ isolate, autoAttachSubprocess, reportsDirectory }) {
11
16
  if (isolate === false && enabled) {
12
17
  return;
13
18
  }
14
19
  enabled = true;
20
+ if (autoAttachSubprocess) {
21
+ this.extendedContextCoverageDir = resolve(reportsDirectory, "tmp", randomUUID());
22
+ process.env.NODE_V8_COVERAGE = this.extendedContextCoverageDir;
23
+ }
24
+ this.session ||= new inspector.Session();
25
+ const session = this.session;
15
26
  session.connect();
16
27
  await session.post("Profiler.enable");
17
28
  await session.post("Profiler.startPreciseCoverage", {
@@ -23,15 +34,36 @@ const mod = {
23
34
  if (provider === "stackblitz") {
24
35
  return { result: [] };
25
36
  }
37
+ const session = this.session;
38
+ if (!session) {
39
+ throw new Error("V8 provider missing inspector session.");
40
+ }
26
41
  const coverage = await session.post("Profiler.takePreciseCoverage");
27
42
  const result = [];
28
43
  // Reduce amount of data sent over rpc by doing some early result filtering
29
44
  for (const entry of coverage.result) {
30
45
  if (filterResult(entry)) {
31
- result.push({
32
- ...entry,
33
- startOffset: options?.moduleExecutionInfo?.get(normalize(fileURLToPath(entry.url)))?.startOffset || 0
34
- });
46
+ entry.startOffset = options?.moduleExecutionInfo?.get(normalize(fileURLToPath(entry.url)))?.startOffset || 0;
47
+ result.push(entry);
48
+ }
49
+ }
50
+ if (this.extendedContextCoverageDir && existsSync(this.extendedContextCoverageDir)) {
51
+ const filenames = await readdir(this.extendedContextCoverageDir);
52
+ const contents = await Promise.all(filenames.filter((filename) => filename.endsWith(".json")).map(async (filename) => {
53
+ const path = `${this.extendedContextCoverageDir}/${filename}`;
54
+ const content = await readFile(path, "utf8");
55
+ await rm(path);
56
+ return content;
57
+ }));
58
+ for (const content of contents) {
59
+ const json = JSON.parse(content);
60
+ for (const entry of json.result) {
61
+ if (filterResult(entry)) {
62
+ entry.startOffset = 0;
63
+ entry.isExtendedContext = true;
64
+ result.push(entry);
65
+ }
66
+ }
35
67
  }
36
68
  }
37
69
  return { result };
@@ -40,9 +72,14 @@ const mod = {
40
72
  if (isolate === false) {
41
73
  return;
42
74
  }
75
+ const session = this.session;
76
+ if (!session) {
77
+ throw new Error("V8 provider missing inspector session.");
78
+ }
43
79
  await session.post("Profiler.stopPreciseCoverage");
44
80
  await session.post("Profiler.disable");
45
81
  session.disconnect();
82
+ this.session = null;
46
83
  },
47
84
  async getProvider() {
48
85
  return loadProvider();
@@ -5,6 +5,8 @@ import { BaseCoverageProvider, CoverageProvider, Vitest, ReportContext } from 'v
5
5
 
6
6
  interface ScriptCoverageWithOffset extends Profiler.ScriptCoverage {
7
7
  startOffset: number;
8
+ /** Whether script ran outside Vite, e.g. in sub-processes or worker threads */
9
+ isExtendedContext?: boolean;
8
10
  }
9
11
  declare class V8CoverageProvider extends BaseCoverageProvider implements CoverageProvider {
10
12
  name: "v8";
package/dist/provider.js CHANGED
@@ -12,7 +12,7 @@ import c from 'tinyrainbow';
12
12
  import { BaseCoverageProvider, parseAstAsync } from 'vitest/node';
13
13
  import { n as normalize } from './pathe.M-eThtNZ-BTaAGrLg.js';
14
14
 
15
- var version = "4.1.5";
15
+ var version = "5.0.0-beta.2";
16
16
 
17
17
  const FILE_PROTOCOL = "file://";
18
18
  const debug = createDebug("vitest:coverage");
@@ -21,6 +21,16 @@ class V8CoverageProvider extends BaseCoverageProvider {
21
21
  version = version;
22
22
  initialize(ctx) {
23
23
  this._initialize(ctx);
24
+ if (this.options.autoAttachSubprocess) {
25
+ const isAnyThreadsPools = ctx.projects.some((p) => p.config.pool === "threads" || p.config.pool === "vmThreads");
26
+ if (isAnyThreadsPools) {
27
+ // Work-around for https://github.com/nodejs/node/issues/46378
28
+ // Node never does anything with this directory, it's just required so that
29
+ // the next Workers read **their** env.NODE_V8_COVERAGE.
30
+ // Node never creates this .unused directory at all.
31
+ process.env.NODE_V8_COVERAGE = `${this.coverageFilesDirectory}/.unused`;
32
+ }
33
+ }
24
34
  }
25
35
  createCoverageMap() {
26
36
  return libCoverage.createCoverageMap({});
@@ -29,15 +39,22 @@ class V8CoverageProvider extends BaseCoverageProvider {
29
39
  const start = debug.enabled ? performance.now() : 0;
30
40
  const coverageMap = this.createCoverageMap();
31
41
  let merged = { result: [] };
42
+ const autoAttachSubprocess = this.options.autoAttachSubprocess;
32
43
  await this.readCoverageFiles({
33
44
  onFileRead(coverage) {
34
45
  merged = mergeProcessCovs([merged, coverage]);
46
+ // mergeProcessCovs sometimes loses autoAttachSubprocess
47
+ const fromExtendedContext = autoAttachSubprocess ? coverage.result.filter((r) => r.isExtendedContext) : [];
35
48
  // mergeProcessCovs sometimes loses startOffset, e.g. in vue
36
49
  merged.result.forEach((result) => {
37
50
  if (!result.startOffset) {
38
51
  const original = coverage.result.find((r) => r.url === result.url);
39
52
  result.startOffset = original?.startOffset || 0;
40
53
  }
54
+ if (autoAttachSubprocess && !result.isExtendedContext) {
55
+ const actual = fromExtendedContext.find((r) => r.url === result.url);
56
+ result.isExtendedContext = actual?.isExtendedContext;
57
+ }
41
58
  });
42
59
  },
43
60
  onFinished: async (project, environment) => {
@@ -189,11 +206,11 @@ class V8CoverageProvider extends BaseCoverageProvider {
189
206
  }
190
207
  });
191
208
  }
192
- async getSources(url, onTransform, functions = []) {
209
+ async getSources(url, onTransform, functions = [], isExtendedContext = false) {
193
210
  // TODO: need to standardize file urls before this call somehow, this is messy
194
211
  const filepath = url.match(/^file:\/\/\/\w:\//) ? url.slice(8) : removeStartsWith(url, FILE_PROTOCOL);
195
212
  // TODO: do we still need to "catch" here? why would it fail?
196
- const transformResult = await onTransform(filepath).catch(() => null);
213
+ const transformResult = await onTransform(filepath, isExtendedContext).catch(() => null);
197
214
  const map = transformResult?.map;
198
215
  const code = transformResult?.code;
199
216
  if (code == null) {
@@ -223,8 +240,8 @@ class V8CoverageProvider extends BaseCoverageProvider {
223
240
  if (environment === "__browser__" && !project.browser) {
224
241
  throw new Error(`Cannot access browser module graph because it was torn down.`);
225
242
  }
226
- const onTransform = async (filepath) => {
227
- const result = await this.transformFile(filepath, project, environment);
243
+ const onTransform = async (filepath, isExtendedContext = false) => {
244
+ const result = await this.transformFile(filepath, project, environment, !isExtendedContext);
228
245
  if (result && environment === "__browser__" && project.browser) {
229
246
  return {
230
247
  ...result,
@@ -258,14 +275,14 @@ class V8CoverageProvider extends BaseCoverageProvider {
258
275
  index += chunk.length;
259
276
  debug("Converting %d/%d", index, scriptCoverages.length);
260
277
  }
261
- await Promise.all(chunk.map(async ({ url, functions, startOffset }) => {
278
+ await Promise.all(chunk.map(async ({ url, functions, startOffset, isExtendedContext }) => {
262
279
  let timeout;
263
280
  let start;
264
281
  if (debug.enabled) {
265
282
  start = performance.now();
266
283
  timeout = setTimeout(() => debug(c.bgRed(`File "${fileURLToPath(url)}" is taking longer than 3s`)), 3e3);
267
284
  }
268
- const sources = await this.getSources(url, onTransform, functions);
285
+ const sources = await this.getSources(url, onTransform, functions, isExtendedContext);
269
286
  coverageMap.merge(await this.remapCoverage(url, startOffset, sources, functions));
270
287
  if (debug.enabled) {
271
288
  clearTimeout(timeout);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vitest/coverage-v8",
3
3
  "type": "module",
4
- "version": "4.1.5",
4
+ "version": "5.0.0-beta.2",
5
5
  "description": "V8 coverage provider for Vitest",
6
6
  "author": "Anthony Fu <anthonyfu117@hotmail.com>",
7
7
  "license": "MIT",
@@ -41,8 +41,8 @@
41
41
  "dist"
42
42
  ],
43
43
  "peerDependencies": {
44
- "@vitest/browser": "4.1.5",
45
- "vitest": "4.1.5"
44
+ "@vitest/browser": "5.0.0-beta.2",
45
+ "vitest": "5.0.0-beta.2"
46
46
  },
47
47
  "peerDependenciesMeta": {
48
48
  "@vitest/browser": {
@@ -59,16 +59,16 @@
59
59
  "obug": "^2.1.1",
60
60
  "std-env": "^4.0.0-rc.1",
61
61
  "tinyrainbow": "^3.1.0",
62
- "@vitest/utils": "4.1.5"
62
+ "@vitest/utils": "5.0.0-beta.2"
63
63
  },
64
64
  "devDependencies": {
65
65
  "@types/istanbul-lib-coverage": "^2.0.6",
66
66
  "@types/istanbul-lib-report": "^3.0.3",
67
67
  "@types/istanbul-reports": "^3.0.4",
68
68
  "pathe": "^2.0.3",
69
- "vitest": "4.1.5",
70
- "@vitest/browser": "4.1.5",
71
- "@vitest/browser-playwright": "4.1.5"
69
+ "@vitest/browser-playwright": "5.0.0-beta.2",
70
+ "vitest": "5.0.0-beta.2",
71
+ "@vitest/browser": "5.0.0-beta.2"
72
72
  },
73
73
  "scripts": {
74
74
  "build": "premove dist && rollup -c",