@jsenv/core 23.4.1 → 23.5.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.
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/core",
3
- "version": "23.4.1",
3
+ "version": "23.5.2",
4
4
  "description": "Tool to develop, test and build js projects",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -11,8 +11,7 @@
11
11
  "node": ">=14.9.0"
12
12
  },
13
13
  "publishConfig": {
14
- "access": "public",
15
- "registry": "https://registry.npmjs.org"
14
+ "access": "public"
16
15
  },
17
16
  "type": "module",
18
17
  "exports": {
@@ -63,12 +62,12 @@
63
62
  "@babel/plugin-syntax-numeric-separator": "7.10.4",
64
63
  "@babel/plugin-transform-modules-systemjs": "7.15.4",
65
64
  "@c88/v8-coverage": "0.1.1",
66
- "@jsenv/abort": "4.0.0",
67
- "@jsenv/filesystem": "2.5.0",
65
+ "@jsenv/abort": "4.1.1",
66
+ "@jsenv/filesystem": "2.5.1",
68
67
  "@jsenv/importmap": "1.1.0",
69
- "@jsenv/log": "1.1.0",
68
+ "@jsenv/log": "1.4.0",
70
69
  "@jsenv/logger": "4.0.1",
71
- "@jsenv/server": "10.0.0",
70
+ "@jsenv/server": "10.0.4",
72
71
  "@jsenv/uneval": "1.6.0",
73
72
  "@jsenv/workers": "1.2.0",
74
73
  "@rollup/plugin-commonjs": "21.0.0",
package/src/execute.js CHANGED
@@ -27,11 +27,8 @@ export const execute = async ({
27
27
  runtimeParams,
28
28
 
29
29
  allocatedMs,
30
- measureDuration,
31
30
  mirrorConsole = true,
32
31
  captureConsole,
33
- collectRuntimeName,
34
- collectRuntimeVersion,
35
32
  inheritCoverage,
36
33
  collectCoverage,
37
34
  measurePerformance,
@@ -139,11 +136,8 @@ export const execute = async ({
139
136
  },
140
137
 
141
138
  allocatedMs,
142
- measureDuration,
143
139
  mirrorConsole,
144
140
  captureConsole,
145
- collectRuntimeName,
146
- collectRuntimeVersion,
147
141
  inheritCoverage,
148
142
  collectCoverage,
149
143
  measurePerformance,
@@ -33,13 +33,13 @@ export const executeTestPlan = async ({
33
33
 
34
34
  testPlan,
35
35
  defaultMsAllocatedPerExecution,
36
+ cooldownBetweenExecutions,
36
37
 
37
38
  maxExecutionsInParallel,
38
39
 
39
40
  completedExecutionLogAbbreviation = false,
40
41
  completedExecutionLogMerging = false,
41
42
  logSummary = true,
42
- measureGlobalDuration = true,
43
43
  updateProcessExitCode = true,
44
44
 
45
45
  coverage = process.argv.includes("--cover") ||
@@ -144,10 +144,10 @@ export const executeTestPlan = async ({
144
144
 
145
145
  defaultMsAllocatedPerExecution,
146
146
  maxExecutionsInParallel,
147
+ cooldownBetweenExecutions,
147
148
  completedExecutionLogMerging,
148
149
  completedExecutionLogAbbreviation,
149
150
  logSummary,
150
- measureGlobalDuration,
151
151
 
152
152
  coverage,
153
153
  coverageConfig,
@@ -225,6 +225,7 @@ export const executeTestPlan = async ({
225
225
  }
226
226
 
227
227
  return {
228
+ testPlanAborted: result.aborted,
228
229
  testPlanSummary: result.planSummary,
229
230
  testPlanReport: result.planReport,
230
231
  testPlanCoverage: planCoverage,
@@ -71,7 +71,10 @@ export const createCompiledFileService = ({
71
71
 
72
72
  return (request) => {
73
73
  const { origin, ressource } = request
74
- const requestUrl = `${origin}${ressource}`
74
+ // we use "ressourceToPathname" to remove eventual query param from the url
75
+ // Without this a pattern like "**/*.js" would not match "file.js?t=1"
76
+ // This would result in file not being compiled when they should
77
+ const requestUrl = `${origin}${ressourceToPathname(ressource)}`
75
78
 
76
79
  const requestCompileInfo = serverUrlToCompileInfo(requestUrl, {
77
80
  outDirectoryRelativeUrl,
@@ -276,3 +279,12 @@ const babelPluginMapFromCompileId = (
276
279
 
277
280
  return babelPluginMapForGroup
278
281
  }
282
+
283
+ const ressourceToPathname = (ressource) => {
284
+ const searchSeparatorIndex = ressource.indexOf("?")
285
+ const pathname =
286
+ searchSeparatorIndex === -1
287
+ ? ressource
288
+ : ressource.slice(0, searchSeparatorIndex)
289
+ return pathname
290
+ }
@@ -1,4 +1,5 @@
1
1
  import { readFile } from "@jsenv/filesystem"
2
+ import { Abort } from "@jsenv/abort"
2
3
 
3
4
  import {
4
5
  visitNodeV8Directory,
@@ -9,13 +10,12 @@ import { composeTwoFileByFileIstanbulCoverages } from "../coverage_utils/istanbu
9
10
  import { v8CoverageToIstanbul } from "../coverage_utils/v8_coverage_to_istanbul.js"
10
11
  import { composeV8AndIstanbul } from "../coverage_utils/v8_and_istanbul.js"
11
12
  import { normalizeFileByFileCoveragePaths } from "../coverage_utils/file_by_file_coverage.js"
12
- import { listRelativeFileUrlToCover } from "../coverage_empty/list_files_not_covered.js"
13
- import { relativeUrlToEmptyCoverage } from "../coverage_empty/relativeUrlToEmptyCoverage.js"
13
+ import { getMissingFileByFileCoverage } from "../coverage_missing/missing_coverage.js"
14
14
 
15
15
  export const reportToCoverage = async (
16
16
  report,
17
17
  {
18
- multipleExecutionsOperation,
18
+ signal,
19
19
  logger,
20
20
  projectDirectoryUrl,
21
21
  babelPluginMap,
@@ -26,70 +26,39 @@ export const reportToCoverage = async (
26
26
  coverageV8ConflictWarning,
27
27
  },
28
28
  ) => {
29
- let v8Coverage
30
- let fileByFileIstanbulCoverage
31
-
32
29
  // collect v8 and istanbul coverage from executions
33
- await Object.keys(report).reduce(async (previous, file) => {
34
- await previous
35
-
36
- const executionResultForFile = report[file]
37
- await Object.keys(executionResultForFile).reduce(
38
- async (previous, executionName) => {
39
- await previous
40
-
41
- const executionResultForFileOnRuntime =
42
- executionResultForFile[executionName]
43
- const { status, coverageFileUrl } = executionResultForFileOnRuntime
44
- if (!coverageFileUrl) {
45
- // several reasons not to have coverage here:
46
- // 1. the file we executed did not import an instrumented file.
47
- // - a test file without import
48
- // - a test file importing only file excluded from coverage
49
- // - a coverDescription badly configured so that we don't realize
50
- // a file should be covered
51
-
52
- // 2. the file we wanted to executed timedout
53
- // - infinite loop
54
- // - too extensive operation
55
- // - a badly configured or too low allocatedMs for that execution.
56
-
57
- // 3. the file we wanted to execute contains syntax-error
58
-
59
- // in any scenario we are fine because
60
- // coverDescription will generate empty coverage for files
61
- // that were suppose to be coverage but were not.
62
- if (status === "completed") {
63
- logger.debug(
64
- `No execution.coverageFileUrl from execution named "${executionName}" of ${file}`,
65
- )
66
- }
67
- return
68
- }
69
-
70
- const executionCoverage = await readFile(coverageFileUrl, {
71
- as: "json",
72
- })
73
- if (isV8Coverage(executionCoverage)) {
74
- v8Coverage = v8Coverage
75
- ? composeTwoV8Coverages(v8Coverage, executionCoverage)
76
- : executionCoverage
77
- } else {
78
- fileByFileIstanbulCoverage = fileByFileIstanbulCoverage
79
- ? composeTwoFileByFileIstanbulCoverages(
80
- fileByFileIstanbulCoverage,
81
- executionCoverage,
82
- )
83
- : executionCoverage
84
- }
85
- },
86
- Promise.resolve(),
87
- )
88
- }, Promise.resolve())
30
+ let { v8Coverage, fileByFileIstanbulCoverage } = await getCoverageFromReport({
31
+ signal,
32
+ report,
33
+ onMissing: ({ file, executionResult, executionName }) => {
34
+ // several reasons not to have coverage here:
35
+ // 1. the file we executed did not import an instrumented file.
36
+ // - a test file without import
37
+ // - a test file importing only file excluded from coverage
38
+ // - a coverDescription badly configured so that we don't realize
39
+ // a file should be covered
40
+
41
+ // 2. the file we wanted to executed timedout
42
+ // - infinite loop
43
+ // - too extensive operation
44
+ // - a badly configured or too low allocatedMs for that execution.
45
+
46
+ // 3. the file we wanted to execute contains syntax-error
47
+
48
+ // in any scenario we are fine because
49
+ // coverDescription will generate empty coverage for files
50
+ // that were suppose to be coverage but were not.
51
+ if (executionResult.status === "completed") {
52
+ logger.debug(
53
+ `No execution.coverageFileUrl from execution named "${executionName}" of ${file}`,
54
+ )
55
+ }
56
+ },
57
+ })
89
58
 
90
59
  if (!coverageForceIstanbul && process.env.NODE_V8_COVERAGE) {
91
60
  await visitNodeV8Directory({
92
- signal: multipleExecutionsOperation.signal,
61
+ signal,
93
62
  NODE_V8_COVERAGE: process.env.NODE_V8_COVERAGE,
94
63
  onV8Coverage: (nodeV8Coverage) => {
95
64
  const nodeV8CoverageLight = filterV8Coverage(nodeV8Coverage, {
@@ -105,7 +74,9 @@ export const reportToCoverage = async (
105
74
  // try to merge v8 with istanbul, if any
106
75
  let fileByFileCoverage
107
76
  if (v8Coverage) {
108
- let v8FileByFileCoverage = await v8CoverageToIstanbul(v8Coverage)
77
+ let v8FileByFileCoverage = await v8CoverageToIstanbul(v8Coverage, {
78
+ signal,
79
+ })
109
80
 
110
81
  v8FileByFileCoverage = normalizeFileByFileCoveragePaths(
111
82
  v8FileByFileCoverage,
@@ -140,34 +111,77 @@ export const reportToCoverage = async (
140
111
 
141
112
  // now add coverage for file not covered
142
113
  if (coverageIncludeMissing) {
143
- const relativeUrlsToCover = await listRelativeFileUrlToCover({
144
- multipleExecutionsOperation,
114
+ const missingFileByFileCoverage = await getMissingFileByFileCoverage({
115
+ signal,
145
116
  projectDirectoryUrl,
146
117
  coverageConfig,
118
+ fileByFileCoverage,
119
+ babelPluginMap,
147
120
  })
121
+ Object.assign(fileByFileCoverage, missingFileByFileCoverage)
122
+ }
148
123
 
149
- const relativeUrlsMissing = relativeUrlsToCover.filter(
150
- (relativeUrlToCover) =>
151
- Object.keys(fileByFileCoverage).every((key) => {
152
- return key !== `./${relativeUrlToCover}`
153
- }),
154
- )
124
+ return fileByFileCoverage
125
+ }
126
+
127
+ const getCoverageFromReport = async ({ signal, report, onMissing }) => {
128
+ const operation = Abort.startOperation()
129
+ operation.addAbortSignal(signal)
130
+
131
+ try {
132
+ let v8Coverage
133
+ let fileByFileIstanbulCoverage
134
+
135
+ // collect v8 and istanbul coverage from executions
136
+ await Object.keys(report).reduce(async (previous, file) => {
137
+ operation.throwIfAborted()
138
+ await previous
139
+
140
+ const executionResultForFile = report[file]
141
+ await Object.keys(executionResultForFile).reduce(
142
+ async (previous, executionName) => {
143
+ operation.throwIfAborted()
144
+ await previous
145
+
146
+ const executionResultForFileOnRuntime =
147
+ executionResultForFile[executionName]
148
+ const { coverageFileUrl } = executionResultForFileOnRuntime
149
+ if (!coverageFileUrl) {
150
+ onMissing({
151
+ executionName,
152
+ file,
153
+ executionResult: executionResultForFileOnRuntime,
154
+ })
155
+ return
156
+ }
155
157
 
156
- await relativeUrlsMissing.reduce(async (previous, relativeUrlMissing) => {
157
- const emptyCoverage = await relativeUrlToEmptyCoverage(
158
- relativeUrlMissing,
159
- {
160
- multipleExecutionsOperation,
161
- projectDirectoryUrl,
162
- babelPluginMap,
158
+ const executionCoverage = await readFile(coverageFileUrl, {
159
+ as: "json",
160
+ })
161
+ if (isV8Coverage(executionCoverage)) {
162
+ v8Coverage = v8Coverage
163
+ ? composeTwoV8Coverages(v8Coverage, executionCoverage)
164
+ : executionCoverage
165
+ } else {
166
+ fileByFileIstanbulCoverage = fileByFileIstanbulCoverage
167
+ ? composeTwoFileByFileIstanbulCoverages(
168
+ fileByFileIstanbulCoverage,
169
+ executionCoverage,
170
+ )
171
+ : executionCoverage
172
+ }
163
173
  },
174
+ Promise.resolve(),
164
175
  )
165
- fileByFileCoverage[`./${relativeUrlMissing}`] = emptyCoverage
166
- return emptyCoverage
167
176
  }, Promise.resolve())
168
- }
169
177
 
170
- return fileByFileCoverage
178
+ return {
179
+ v8Coverage,
180
+ fileByFileIstanbulCoverage,
181
+ }
182
+ } finally {
183
+ await operation.end()
184
+ }
171
185
  }
172
186
 
173
187
  const isV8Coverage = (coverage) => Boolean(coverage.result)
@@ -1,7 +1,7 @@
1
1
  import { collectFiles } from "@jsenv/filesystem"
2
2
 
3
3
  export const listRelativeFileUrlToCover = async ({
4
- multipleExecutionsOperation,
4
+ signal,
5
5
  projectDirectoryUrl,
6
6
  coverageConfig,
7
7
  }) => {
@@ -10,7 +10,7 @@ export const listRelativeFileUrlToCover = async ({
10
10
  }
11
11
 
12
12
  const matchingFileResultArray = await collectFiles({
13
- signal: multipleExecutionsOperation.signal,
13
+ signal,
14
14
  directoryUrl: projectDirectoryUrl,
15
15
  structuredMetaMap: structuredMetaMapForCoverage,
16
16
  predicate: ({ cover }) => cover,
@@ -0,0 +1,46 @@
1
+ import { Abort } from "@jsenv/abort"
2
+
3
+ import { listRelativeFileUrlToCover } from "./list_files_not_covered.js"
4
+ import { relativeUrlToEmptyCoverage } from "./relativeUrlToEmptyCoverage.js"
5
+
6
+ export const getMissingFileByFileCoverage = async ({
7
+ signal,
8
+ projectDirectoryUrl,
9
+ coverageConfig,
10
+ fileByFileCoverage,
11
+ babelPluginMap,
12
+ }) => {
13
+ const relativeUrlsToCover = await listRelativeFileUrlToCover({
14
+ signal,
15
+ projectDirectoryUrl,
16
+ coverageConfig,
17
+ })
18
+
19
+ const relativeUrlsMissing = relativeUrlsToCover.filter((relativeUrlToCover) =>
20
+ Object.keys(fileByFileCoverage).every((key) => {
21
+ return key !== `./${relativeUrlToCover}`
22
+ }),
23
+ )
24
+
25
+ const operation = Abort.startOperation()
26
+ operation.addAbortSignal(signal)
27
+
28
+ const missingFileByFileCoverage = {}
29
+ await relativeUrlsMissing.reduce(async (previous, relativeUrlMissing) => {
30
+ operation.throwIfAborted()
31
+ await previous
32
+ await operation.withSignal(async (signal) => {
33
+ const emptyCoverage = await relativeUrlToEmptyCoverage(
34
+ relativeUrlMissing,
35
+ {
36
+ signal,
37
+ projectDirectoryUrl,
38
+ babelPluginMap,
39
+ },
40
+ )
41
+ missingFileByFileCoverage[`./${relativeUrlMissing}`] = emptyCoverage
42
+ })
43
+ }, Promise.resolve())
44
+
45
+ return missingFileByFileCoverage
46
+ }
@@ -1,4 +1,5 @@
1
1
  import { resolveUrl, urlToFileSystemPath, readFile } from "@jsenv/filesystem"
2
+ import { Abort } from "@jsenv/abort"
2
3
 
3
4
  import {
4
5
  babelPluginsFromBabelPluginMap,
@@ -9,22 +10,23 @@ import { createEmptyCoverage } from "./createEmptyCoverage.js"
9
10
 
10
11
  export const relativeUrlToEmptyCoverage = async (
11
12
  relativeUrl,
12
- { multipleExecutionsOperation, projectDirectoryUrl, babelPluginMap },
13
+ { signal, projectDirectoryUrl, babelPluginMap },
13
14
  ) => {
14
- const { transformAsync } = await import("@babel/core")
15
-
16
- const fileUrl = resolveUrl(relativeUrl, projectDirectoryUrl)
17
- multipleExecutionsOperation.throwIfAborted()
18
- const source = await readFile(fileUrl)
15
+ const operation = Abort.startOperation()
16
+ operation.addAbortSignal(signal)
19
17
 
20
18
  try {
19
+ const { transformAsync } = await import("@babel/core")
20
+ const fileUrl = resolveUrl(relativeUrl, projectDirectoryUrl)
21
+ const source = await readFile(fileUrl)
22
+
21
23
  babelPluginMap = {
22
24
  ...getMinimalBabelPluginMap(),
23
25
  ...babelPluginMap,
24
26
  "transform-instrument": [babelPluginInstrument, { projectDirectoryUrl }],
25
27
  }
26
28
 
27
- multipleExecutionsOperation.throwIfAborted()
29
+ operation.throwIfAborted()
28
30
  const { metadata } = await transformAsync(source, {
29
31
  filename: urlToFileSystemPath(fileUrl),
30
32
  filenameRelative: relativeUrl,
@@ -55,5 +57,7 @@ export const relativeUrlToEmptyCoverage = async (
55
57
  return createEmptyCoverage(relativeUrl)
56
58
  }
57
59
  throw e
60
+ } finally {
61
+ await operation.end()
58
62
  }
59
63
  }
@@ -5,12 +5,16 @@ import {
5
5
  resolveUrl,
6
6
  } from "@jsenv/filesystem"
7
7
  import { createDetailedMessage } from "@jsenv/logger"
8
+ import { Abort } from "@jsenv/abort"
8
9
 
9
10
  export const visitNodeV8Directory = async ({
10
- // signal
11
+ signal,
11
12
  NODE_V8_COVERAGE,
12
13
  onV8Coverage,
13
14
  }) => {
15
+ const operation = Abort.startOperation()
16
+ operation.addAbortSignal(signal)
17
+
14
18
  const tryReadDirectory = async () => {
15
19
  const dirContent = await readDirectory(NODE_V8_COVERAGE)
16
20
  if (dirContent.length > 0) {
@@ -19,38 +23,47 @@ export const visitNodeV8Directory = async ({
19
23
  console.warn(`v8 coverage directory is empty at ${NODE_V8_COVERAGE}`)
20
24
  return dirContent
21
25
  }
22
- const dirContent = await tryReadDirectory()
23
26
 
24
- const coverageDirectoryUrl = assertAndNormalizeDirectoryUrl(NODE_V8_COVERAGE)
25
- await dirContent.reduce(async (previous, dirEntry) => {
26
- await previous
27
+ try {
28
+ operation.throwIfAborted()
29
+ const dirContent = await tryReadDirectory()
27
30
 
28
- const dirEntryUrl = resolveUrl(dirEntry, coverageDirectoryUrl)
29
- const tryReadJsonFile = async () => {
30
- const fileContent = await readFile(dirEntryUrl, { as: "string" })
31
- if (fileContent === "") {
32
- return null
33
- }
31
+ const coverageDirectoryUrl =
32
+ assertAndNormalizeDirectoryUrl(NODE_V8_COVERAGE)
33
+ await dirContent.reduce(async (previous, dirEntry) => {
34
+ operation.throwIfAborted()
35
+ await previous
34
36
 
35
- try {
36
- const fileAsJson = JSON.parse(fileContent)
37
- return fileAsJson
38
- } catch (e) {
39
- console.warn(
40
- createDetailedMessage(`Error while reading coverage file`, {
41
- "error stack": e.stack,
42
- "file": dirEntryUrl,
43
- }),
44
- )
45
- return null
37
+ const dirEntryUrl = resolveUrl(dirEntry, coverageDirectoryUrl)
38
+ const tryReadJsonFile = async () => {
39
+ const fileContent = await readFile(dirEntryUrl, { as: "string" })
40
+ if (fileContent === "") {
41
+ console.warn(`Coverage JSON file is empty at ${dirEntryUrl}`)
42
+ return null
43
+ }
44
+
45
+ try {
46
+ const fileAsJson = JSON.parse(fileContent)
47
+ return fileAsJson
48
+ } catch (e) {
49
+ console.warn(
50
+ createDetailedMessage(`Error while reading coverage file`, {
51
+ "error stack": e.stack,
52
+ "file": dirEntryUrl,
53
+ }),
54
+ )
55
+ return null
56
+ }
46
57
  }
47
- }
48
58
 
49
- const fileContent = await tryReadJsonFile()
50
- if (fileContent) {
51
- onV8Coverage(fileContent)
52
- }
53
- }, Promise.resolve())
59
+ const fileContent = await tryReadJsonFile()
60
+ if (fileContent) {
61
+ onV8Coverage(fileContent)
62
+ }
63
+ }, Promise.resolve())
64
+ } finally {
65
+ await operation.end()
66
+ }
54
67
  }
55
68
 
56
69
  export const filterV8Coverage = (v8Coverage, { coverageIgnorePredicate }) => {
@@ -1,53 +1,63 @@
1
1
  import { urlToFileSystemPath } from "@jsenv/filesystem"
2
+ import { Abort } from "@jsenv/abort"
2
3
 
3
4
  import { require } from "@jsenv/core/src/internal/require.js"
4
5
 
5
6
  import { composeTwoFileByFileIstanbulCoverages } from "./istanbul_coverage_composition.js"
6
7
 
7
- export const v8CoverageToIstanbul = async (v8Coverage) => {
8
- const v8ToIstanbul = require("v8-to-istanbul")
9
- const sourcemapCache = v8Coverage["source-map-cache"]
10
- let istanbulCoverageComposed = null
11
- await v8Coverage.result.reduce(async (previous, fileV8Coverage) => {
12
- await previous
8
+ export const v8CoverageToIstanbul = async (v8Coverage, { signal }) => {
9
+ const operation = Abort.startOperation()
10
+ operation.addAbortSignal(signal)
13
11
 
14
- const { source } = fileV8Coverage
15
- let sources
16
- // when v8 coverage comes from playwright (chromium) v8Coverage.source is set
17
- if (typeof source === "string") {
18
- sources = { source }
19
- }
20
- // when v8 coverage comes from Node.js, the source can be read from sourcemapCache
21
- else if (sourcemapCache) {
22
- sources = sourcesFromSourceMapCache(fileV8Coverage.url, sourcemapCache)
23
- }
24
- const path = urlToFileSystemPath(fileV8Coverage.url)
12
+ try {
13
+ const v8ToIstanbul = require("v8-to-istanbul")
14
+ const sourcemapCache = v8Coverage["source-map-cache"]
15
+ let istanbulCoverageComposed = null
25
16
 
26
- const converter = v8ToIstanbul(
27
- path,
28
- // wrapperLength is undefined we don't need it
29
- // https://github.com/istanbuljs/v8-to-istanbul/blob/2b54bc97c5edf8a37b39a171ec29134ba9bfd532/lib/v8-to-istanbul.js#L27
30
- undefined,
31
- sources,
32
- )
33
- await converter.load()
17
+ await v8Coverage.result.reduce(async (previous, fileV8Coverage) => {
18
+ operation.throwIfAborted()
19
+ await previous
34
20
 
35
- converter.applyCoverage(fileV8Coverage.functions)
36
- const istanbulCoverage = converter.toIstanbul()
21
+ const { source } = fileV8Coverage
22
+ let sources
23
+ // when v8 coverage comes from playwright (chromium) v8Coverage.source is set
24
+ if (typeof source === "string") {
25
+ sources = { source }
26
+ }
27
+ // when v8 coverage comes from Node.js, the source can be read from sourcemapCache
28
+ else if (sourcemapCache) {
29
+ sources = sourcesFromSourceMapCache(fileV8Coverage.url, sourcemapCache)
30
+ }
31
+ const path = urlToFileSystemPath(fileV8Coverage.url)
37
32
 
38
- istanbulCoverageComposed = istanbulCoverageComposed
39
- ? composeTwoFileByFileIstanbulCoverages(
40
- istanbulCoverageComposed,
41
- istanbulCoverage,
42
- )
43
- : istanbulCoverage
44
- }, Promise.resolve())
33
+ const converter = v8ToIstanbul(
34
+ path,
35
+ // wrapperLength is undefined we don't need it
36
+ // https://github.com/istanbuljs/v8-to-istanbul/blob/2b54bc97c5edf8a37b39a171ec29134ba9bfd532/lib/v8-to-istanbul.js#L27
37
+ undefined,
38
+ sources,
39
+ )
40
+ await converter.load()
45
41
 
46
- if (!istanbulCoverageComposed) {
47
- return {}
42
+ converter.applyCoverage(fileV8Coverage.functions)
43
+ const istanbulCoverage = converter.toIstanbul()
44
+
45
+ istanbulCoverageComposed = istanbulCoverageComposed
46
+ ? composeTwoFileByFileIstanbulCoverages(
47
+ istanbulCoverageComposed,
48
+ istanbulCoverage,
49
+ )
50
+ : istanbulCoverage
51
+ }, Promise.resolve())
52
+
53
+ if (!istanbulCoverageComposed) {
54
+ return {}
55
+ }
56
+ istanbulCoverageComposed = markAsConvertedFromV8(istanbulCoverageComposed)
57
+ return istanbulCoverageComposed
58
+ } finally {
59
+ await operation.end()
48
60
  }
49
- istanbulCoverageComposed = markAsConvertedFromV8(istanbulCoverageComposed)
50
- return istanbulCoverageComposed
51
61
  }
52
62
 
53
63
  const markAsConvertedFromV8 = (fileByFileCoverage) => {