@jsenv/core 23.3.0 → 23.5.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/package.json +5 -5
- package/readme.md +4 -4
- package/src/execute.js +0 -6
- package/src/executeTestPlan.js +12 -10
- package/src/internal/browser-launcher/executeHtmlFile.js +20 -16
- package/src/internal/compiling/createCompiledFileService.js +13 -1
- package/src/internal/executing/coverage/babel_plugin_instrument.js +1 -0
- package/src/internal/executing/coverage/reportToCoverage.js +160 -119
- package/src/internal/executing/{coverage → coverage_missing}/createEmptyCoverage.js +0 -0
- package/src/internal/executing/coverage_missing/list_files_not_covered.js +20 -0
- package/src/internal/executing/coverage_missing/missing_coverage.js +46 -0
- package/src/internal/executing/{coverage → coverage_missing}/relativeUrlToEmptyCoverage.js +12 -8
- package/src/internal/executing/{coverage/generateCoverageHtmlDirectory.js → coverage_reporter/coverage_reporter_html_directory.js} +11 -4
- package/src/internal/executing/{coverage/generateCoverageJsonFile.js → coverage_reporter/coverage_reporter_json_file.js} +0 -0
- package/src/internal/executing/{coverage/generateCoverageTextLog.js → coverage_reporter/coverage_reporter_text_log.js} +4 -2
- package/src/internal/executing/{coverage → coverage_reporter}/istanbulCoverageMapFromCoverage.js +0 -0
- package/src/internal/executing/{coverage/normalizeIstanbulCoverage.js → coverage_utils/file_by_file_coverage.js} +9 -7
- package/src/internal/executing/coverage_utils/istanbul_coverage_composition.js +28 -0
- package/src/internal/executing/coverage_utils/v8_and_istanbul.js +38 -0
- package/src/internal/executing/coverage_utils/v8_coverage_composition.js +23 -0
- package/src/internal/executing/coverage_utils/v8_coverage_from_directory.js +77 -0
- package/src/internal/executing/{coverage/istanbulCoverageFromV8Coverage.js → coverage_utils/v8_coverage_to_istanbul.js} +38 -17
- package/src/internal/executing/createSummaryLog.js +5 -9
- package/src/internal/executing/executeConcurrently.js +199 -115
- package/src/internal/executing/executePlan.js +8 -5
- package/src/internal/executing/executionLogs.js +66 -37
- package/src/internal/executing/execution_colors.js +2 -1
- package/src/internal/executing/launchAndExecute.js +63 -58
- package/src/internal/logs/msAsDuration.js +4 -3
- package/src/launchBrowser.js +8 -8
- package/src/launchNode.js +5 -93
- package/src/internal/executing/coverage/composeIstanbulCoverages.js +0 -108
- package/src/internal/executing/coverage/composeV8Coverages.js +0 -20
- package/src/internal/executing/coverage/istanbulCoverageFromCoverages.js +0 -43
- package/src/internal/executing/coverage/v8CoverageFromAllV8Coverages.js +0 -40
- package/src/internal/executing/coverage/v8CoverageFromNodeV8Directory.js +0 -67
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import cuid from "cuid"
|
|
1
2
|
import { createLogger, createDetailedMessage } from "@jsenv/logger"
|
|
2
3
|
import { Abort, raceCallbacks } from "@jsenv/abort"
|
|
4
|
+
import { resolveUrl, writeFile } from "@jsenv/filesystem"
|
|
3
5
|
|
|
4
|
-
import {
|
|
6
|
+
import { composeTwoFileByFileIstanbulCoverages } from "./coverage_utils/istanbul_coverage_composition.js"
|
|
5
7
|
|
|
6
8
|
export const launchAndExecute = async ({
|
|
7
9
|
signal = new AbortController().signal,
|
|
@@ -12,13 +14,11 @@ export const launchAndExecute = async ({
|
|
|
12
14
|
executeParams,
|
|
13
15
|
|
|
14
16
|
allocatedMs,
|
|
15
|
-
measureDuration = false,
|
|
16
17
|
mirrorConsole = false,
|
|
17
18
|
captureConsole = false, // rename collectConsole ?
|
|
18
|
-
collectRuntimeName = false,
|
|
19
|
-
collectRuntimeVersion = false,
|
|
20
19
|
inheritCoverage = false,
|
|
21
20
|
collectCoverage = false,
|
|
21
|
+
coverageTempDirectoryUrl,
|
|
22
22
|
measurePerformance,
|
|
23
23
|
collectPerformance = false,
|
|
24
24
|
|
|
@@ -39,8 +39,6 @@ export const launchAndExecute = async ({
|
|
|
39
39
|
// by default throw on error after execution
|
|
40
40
|
throw error
|
|
41
41
|
},
|
|
42
|
-
|
|
43
|
-
coverageV8MergeConflictIsExpected,
|
|
44
42
|
} = {}) => {
|
|
45
43
|
const logger = createLogger({ logLevel: launchAndExecuteLogLevel })
|
|
46
44
|
|
|
@@ -101,25 +99,14 @@ export const launchAndExecute = async ({
|
|
|
101
99
|
)
|
|
102
100
|
}
|
|
103
101
|
|
|
104
|
-
|
|
105
|
-
executionResultTransformer
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (collectRuntimeVersion) {
|
|
115
|
-
executionResultTransformer = composeTransformer(
|
|
116
|
-
executionResultTransformer,
|
|
117
|
-
(executionResult) => {
|
|
118
|
-
executionResult.runtimeVersion = runtime.version
|
|
119
|
-
return executionResult
|
|
120
|
-
},
|
|
121
|
-
)
|
|
122
|
-
}
|
|
102
|
+
executionResultTransformer = composeTransformer(
|
|
103
|
+
executionResultTransformer,
|
|
104
|
+
(executionResult) => {
|
|
105
|
+
executionResult.runtimeName = runtime.name
|
|
106
|
+
executionResult.runtimeVersion = runtime.version
|
|
107
|
+
return executionResult
|
|
108
|
+
},
|
|
109
|
+
)
|
|
123
110
|
|
|
124
111
|
if (
|
|
125
112
|
inheritCoverage &&
|
|
@@ -131,40 +118,61 @@ export const launchAndExecute = async ({
|
|
|
131
118
|
executionResultTransformer = composeTransformer(
|
|
132
119
|
executionResultTransformer,
|
|
133
120
|
(executionResult) => {
|
|
134
|
-
const { coverage
|
|
135
|
-
//
|
|
136
|
-
global.__coverage__ =
|
|
121
|
+
const { coverage } = executionResult
|
|
122
|
+
// propagate coverage from execution to this process
|
|
123
|
+
global.__coverage__ = composeTwoFileByFileIstanbulCoverages(
|
|
137
124
|
global.__coverage__ || {},
|
|
138
125
|
coverage || {},
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
if (!collectCoverageSaved) {
|
|
129
|
+
delete executionResult.coverage
|
|
142
130
|
}
|
|
143
|
-
|
|
131
|
+
|
|
132
|
+
return executionResult
|
|
144
133
|
},
|
|
145
134
|
)
|
|
146
135
|
}
|
|
147
136
|
|
|
148
|
-
// indirectCoverage is a feature making possible to collect
|
|
149
|
-
// coverage generated by executing a node process which executes
|
|
150
|
-
// a browser. The coverage coming the browser executionwould be lost
|
|
151
|
-
// if not propagated somehow.
|
|
152
|
-
// This is possible if the node process collect the browser coverage
|
|
153
|
-
// and write it into global.__indirectCoverage__
|
|
154
|
-
// This is used by jsenv during tests execution
|
|
155
137
|
if (collectCoverage) {
|
|
156
138
|
executionResultTransformer = composeTransformer(
|
|
157
139
|
executionResultTransformer,
|
|
158
|
-
(executionResult) => {
|
|
159
|
-
|
|
140
|
+
async (executionResult) => {
|
|
141
|
+
// we do not keep coverage in memory, it can grow very big
|
|
142
|
+
// instead we store it on the filesystem, they will be read and merged together later on
|
|
143
|
+
// in "executeConcurrently"
|
|
144
|
+
const { coverage } = executionResult
|
|
145
|
+
if (coverage) {
|
|
146
|
+
const coverageFileUrl = resolveUrl(
|
|
147
|
+
`./${runtime.name}/${cuid()}`,
|
|
148
|
+
coverageTempDirectoryUrl,
|
|
149
|
+
)
|
|
150
|
+
await writeFile(coverageFileUrl, JSON.stringify(coverage, null, " "))
|
|
151
|
+
executionResult.coverageFileUrl = coverageFileUrl
|
|
152
|
+
delete executionResult.coverage
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// indirectCoverage is a feature making possible to collect
|
|
156
|
+
// coverage generated by executing a node process which executes
|
|
157
|
+
// a browser. The coverage coming the browser execution would be lost
|
|
158
|
+
// if not propagated somehow.
|
|
159
|
+
// This is possible if the node process collect the browser coverage
|
|
160
|
+
// and write it into global.__indirectCoverage__
|
|
161
|
+
// This is used by jsenv during tests execution
|
|
162
|
+
const { indirectCoverage } = executionResult
|
|
160
163
|
if (indirectCoverage) {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
164
|
+
const indirectCoverageFileUrl = resolveUrl(
|
|
165
|
+
`./${runtime.name}/${cuid()}`,
|
|
166
|
+
coverageTempDirectoryUrl,
|
|
167
|
+
)
|
|
168
|
+
await writeFile(
|
|
169
|
+
indirectCoverageFileUrl,
|
|
170
|
+
JSON.stringify(indirectCoverage, null, " "),
|
|
166
171
|
)
|
|
172
|
+
executionResult.indirectCoverageFileUrl = indirectCoverageFileUrl
|
|
173
|
+
delete executionResult.indirectCoverage
|
|
167
174
|
}
|
|
175
|
+
|
|
168
176
|
return executionResult
|
|
169
177
|
},
|
|
170
178
|
)
|
|
@@ -176,23 +184,20 @@ export const launchAndExecute = async ({
|
|
|
176
184
|
// executionResult.coverage is undefined or {}
|
|
177
185
|
// we delete it just to have a cleaner object
|
|
178
186
|
delete executionResult.coverage
|
|
187
|
+
delete executionResult.indirectCoverage
|
|
179
188
|
return executionResult
|
|
180
189
|
},
|
|
181
190
|
)
|
|
182
191
|
}
|
|
183
192
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
executionResultTransformer
|
|
187
|
-
|
|
188
|
-
(
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
return executionResult
|
|
193
|
-
},
|
|
194
|
-
)
|
|
195
|
-
}
|
|
193
|
+
const startMs = Date.now()
|
|
194
|
+
executionResultTransformer = composeTransformer(
|
|
195
|
+
executionResultTransformer,
|
|
196
|
+
(executionResult) => {
|
|
197
|
+
executionResult.duration = Date.now() - startMs
|
|
198
|
+
return executionResult
|
|
199
|
+
},
|
|
200
|
+
)
|
|
196
201
|
|
|
197
202
|
try {
|
|
198
203
|
const runtimeLabel = `${runtime.name}/${runtime.version}`
|
|
@@ -2,10 +2,11 @@ import { require } from "../require.js"
|
|
|
2
2
|
|
|
3
3
|
const humanizeDuration = require("humanize-duration")
|
|
4
4
|
|
|
5
|
-
export const msAsDuration = (
|
|
6
|
-
return humanizeDuration(
|
|
5
|
+
export const msAsDuration = (ms) => {
|
|
6
|
+
return humanizeDuration(ms, {
|
|
7
7
|
largest: 2,
|
|
8
|
-
maxDecimalPoints:
|
|
8
|
+
maxDecimalPoints: ms < 0.1 ? 3 : ms < 1000 ? 2 : ms < 60000 ? 1 : 0,
|
|
9
|
+
delimiter: " and ",
|
|
9
10
|
// units: ["s"]
|
|
10
11
|
})
|
|
11
12
|
}
|
package/src/launchBrowser.js
CHANGED
|
@@ -37,7 +37,7 @@ chromiumRuntime.launch = async ({
|
|
|
37
37
|
collectPerformance,
|
|
38
38
|
measurePerformance,
|
|
39
39
|
collectCoverage,
|
|
40
|
-
|
|
40
|
+
coverageIgnorePredicate,
|
|
41
41
|
coverageForceIstanbul,
|
|
42
42
|
|
|
43
43
|
headless = true,
|
|
@@ -115,7 +115,7 @@ chromiumRuntime.launch = async ({
|
|
|
115
115
|
collectPerformance,
|
|
116
116
|
measurePerformance,
|
|
117
117
|
collectCoverage,
|
|
118
|
-
|
|
118
|
+
coverageIgnorePredicate,
|
|
119
119
|
coverageForceIstanbul,
|
|
120
120
|
coveragePlaywrightAPIAvailable: true,
|
|
121
121
|
})
|
|
@@ -151,7 +151,7 @@ firefoxRuntime.launch = async ({
|
|
|
151
151
|
collectPerformance,
|
|
152
152
|
measurePerformance,
|
|
153
153
|
collectCoverage,
|
|
154
|
-
|
|
154
|
+
coverageIgnorePredicate,
|
|
155
155
|
coverageForceIstanbul,
|
|
156
156
|
|
|
157
157
|
headless = true,
|
|
@@ -194,7 +194,7 @@ firefoxRuntime.launch = async ({
|
|
|
194
194
|
collectPerformance,
|
|
195
195
|
measurePerformance,
|
|
196
196
|
collectCoverage,
|
|
197
|
-
|
|
197
|
+
coverageIgnorePredicate,
|
|
198
198
|
coverageForceIstanbul,
|
|
199
199
|
})
|
|
200
200
|
|
|
@@ -229,7 +229,7 @@ webkitRuntime.launch = async ({
|
|
|
229
229
|
collectPerformance,
|
|
230
230
|
measurePerformance,
|
|
231
231
|
collectCoverage,
|
|
232
|
-
|
|
232
|
+
coverageIgnorePredicate,
|
|
233
233
|
coverageForceIstanbul,
|
|
234
234
|
|
|
235
235
|
headless = true,
|
|
@@ -272,7 +272,7 @@ webkitRuntime.launch = async ({
|
|
|
272
272
|
collectPerformance,
|
|
273
273
|
measurePerformance,
|
|
274
274
|
collectCoverage,
|
|
275
|
-
|
|
275
|
+
coverageIgnorePredicate,
|
|
276
276
|
coverageForceIstanbul,
|
|
277
277
|
ignoreErrorHook: (error) => {
|
|
278
278
|
// we catch error during execution but safari throw unhandled rejection
|
|
@@ -378,7 +378,7 @@ const browserToRuntimeHooks = (
|
|
|
378
378
|
collectPerformance,
|
|
379
379
|
measurePerformance,
|
|
380
380
|
collectCoverage,
|
|
381
|
-
|
|
381
|
+
coverageIgnorePredicate,
|
|
382
382
|
coverageForceIstanbul,
|
|
383
383
|
coveragePlaywrightAPIAvailable = false,
|
|
384
384
|
ignoreErrorHook = () => false,
|
|
@@ -451,9 +451,9 @@ const browserToRuntimeHooks = (
|
|
|
451
451
|
measurePerformance,
|
|
452
452
|
collectPerformance,
|
|
453
453
|
collectCoverage,
|
|
454
|
-
coverageConfig,
|
|
455
454
|
coverageForceIstanbul,
|
|
456
455
|
coveragePlaywrightAPIAvailable,
|
|
456
|
+
coverageIgnorePredicate,
|
|
457
457
|
transformErrorHook,
|
|
458
458
|
})
|
|
459
459
|
return result
|
package/src/launchNode.js
CHANGED
|
@@ -1,18 +1,9 @@
|
|
|
1
1
|
import { Script } from "node:vm"
|
|
2
|
-
import cuid from "cuid"
|
|
3
2
|
import { loggerToLogLevel } from "@jsenv/logger"
|
|
4
|
-
import {
|
|
5
|
-
writeDirectory,
|
|
6
|
-
resolveUrl,
|
|
7
|
-
urlToFileSystemPath,
|
|
8
|
-
removeFileSystemNode,
|
|
9
|
-
moveDirectoryContent,
|
|
10
|
-
} from "@jsenv/filesystem"
|
|
11
3
|
|
|
12
4
|
import { jsenvCoreDirectoryUrl } from "@jsenv/core/src/internal/jsenvCoreDirectoryUrl.js"
|
|
13
5
|
import { escapeRegexpSpecialCharacters } from "./internal/escapeRegexpSpecialCharacters.js"
|
|
14
6
|
import { createControllableNodeProcess } from "./internal/node-launcher/createControllableNodeProcess.js"
|
|
15
|
-
import { v8CoverageFromNodeV8Directory } from "./internal/executing/coverage/v8CoverageFromNodeV8Directory.js"
|
|
16
7
|
|
|
17
8
|
export const nodeRuntime = {
|
|
18
9
|
name: "node",
|
|
@@ -30,8 +21,8 @@ nodeRuntime.launch = async ({
|
|
|
30
21
|
measurePerformance,
|
|
31
22
|
collectPerformance,
|
|
32
23
|
collectCoverage = false,
|
|
33
|
-
coverageConfig,
|
|
34
24
|
coverageForceIstanbul,
|
|
25
|
+
coverageConfig,
|
|
35
26
|
|
|
36
27
|
debugPort,
|
|
37
28
|
debugMode,
|
|
@@ -69,59 +60,10 @@ nodeRuntime.launch = async ({
|
|
|
69
60
|
JSENV: true,
|
|
70
61
|
}
|
|
71
62
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
// through process.env.NODE_V8_COVERAGE.
|
|
77
|
-
|
|
78
|
-
if (coverageForceIstanbul) {
|
|
79
|
-
// if we want to force istanbul, we will set process.env.NODE_V8_COVERAGE = ''
|
|
80
|
-
// into the child_process
|
|
81
|
-
env.NODE_V8_COVERAGE = ""
|
|
82
|
-
}
|
|
83
|
-
// } else if (process.env.NODE_V8_COVERAGE) {
|
|
84
|
-
// // The V8_COVERAGE was already set by a parent process or command line.
|
|
85
|
-
// // It's the caller that is interested into coverage, it's not anymore this script
|
|
86
|
-
// // responsability to set process.env.NODE_V8_COVERAGE nor to read
|
|
87
|
-
// // coverage files in the v8 directory.
|
|
88
|
-
// }
|
|
89
|
-
// In fact it is so that it's possible to go coverageception:
|
|
90
|
-
// jsenv collect coverage for tests
|
|
91
|
-
// which are testing that coverage can be collected for tests
|
|
92
|
-
// this is possible because we overriding the child process NODE_V8_COVERAGE
|
|
93
|
-
else {
|
|
94
|
-
const NODE_V8_COVERAGE = await getNodeV8CoverageDir({
|
|
95
|
-
projectDirectoryUrl,
|
|
96
|
-
})
|
|
97
|
-
env.NODE_V8_COVERAGE = NODE_V8_COVERAGE
|
|
98
|
-
|
|
99
|
-
// the v8 coverage directory is available once the child process is disconnected
|
|
100
|
-
finalizeExecutionResult = async (executionResult) => {
|
|
101
|
-
if (
|
|
102
|
-
executionResult.status === "timedout" ||
|
|
103
|
-
executionResult.status === "aborted"
|
|
104
|
-
) {
|
|
105
|
-
return executionResult
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const coverage = await ensureV8CoverageDirClean(async () => {
|
|
109
|
-
// prefer istanbul if available
|
|
110
|
-
if (executionResult.coverage) {
|
|
111
|
-
return executionResult.coverage
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const v8Coverage = await v8CoverageFromNodeV8Directory({
|
|
115
|
-
projectDirectoryUrl,
|
|
116
|
-
NODE_V8_COVERAGE,
|
|
117
|
-
coverageConfig,
|
|
118
|
-
})
|
|
119
|
-
return v8Coverage
|
|
120
|
-
}, NODE_V8_COVERAGE)
|
|
121
|
-
executionResult.coverage = coverage
|
|
122
|
-
return executionResult
|
|
123
|
-
}
|
|
124
|
-
}
|
|
63
|
+
if (coverageForceIstanbul) {
|
|
64
|
+
// if we want to force istanbul, we will set process.env.NODE_V8_COVERAGE = ''
|
|
65
|
+
// into the child_process
|
|
66
|
+
env.NODE_V8_COVERAGE = ""
|
|
125
67
|
}
|
|
126
68
|
|
|
127
69
|
commandLineOptions = [
|
|
@@ -198,39 +140,9 @@ nodeRuntime.launch = async ({
|
|
|
198
140
|
outputCallbackList,
|
|
199
141
|
stop,
|
|
200
142
|
execute,
|
|
201
|
-
finalizeExecutionResult,
|
|
202
143
|
}
|
|
203
144
|
}
|
|
204
145
|
|
|
205
|
-
const ensureV8CoverageDirClean = async (fn, NODE_V8_COVERAGE) => {
|
|
206
|
-
try {
|
|
207
|
-
return await fn()
|
|
208
|
-
} finally {
|
|
209
|
-
if (process.env.NODE_V8_COVERAGE === NODE_V8_COVERAGE) {
|
|
210
|
-
// do not try to remove or copy coverage
|
|
211
|
-
} else if (process.env.NODE_V8_COVERAGE) {
|
|
212
|
-
await moveDirectoryContent({
|
|
213
|
-
from: NODE_V8_COVERAGE,
|
|
214
|
-
to: process.env.NODE_V8_COVERAGE,
|
|
215
|
-
})
|
|
216
|
-
await removeFileSystemNode(NODE_V8_COVERAGE, {})
|
|
217
|
-
} else {
|
|
218
|
-
await removeFileSystemNode(NODE_V8_COVERAGE, {
|
|
219
|
-
recursive: true,
|
|
220
|
-
})
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
const getNodeV8CoverageDir = async ({ projectDirectoryUrl }) => {
|
|
226
|
-
const v8CoverageDirectory = resolveUrl(
|
|
227
|
-
`./coverage-v8/${cuid()}`,
|
|
228
|
-
projectDirectoryUrl,
|
|
229
|
-
)
|
|
230
|
-
await writeDirectory(v8CoverageDirectory, { allowUseless: true })
|
|
231
|
-
return urlToFileSystemPath(v8CoverageDirectory)
|
|
232
|
-
}
|
|
233
|
-
|
|
234
146
|
const transformExecutionResult = (
|
|
235
147
|
executionResult,
|
|
236
148
|
{ compileServerOrigin, projectDirectoryUrl },
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import { require } from "../../require.js"
|
|
2
|
-
|
|
3
|
-
// https://github.com/istanbuljs/istanbuljs/blob/5405550c3868712b14fd8bfe0cbd6f2e7ac42279/packages/istanbul-lib-coverage/lib/coverage-map.js#L43
|
|
4
|
-
export const composeIstanbulCoverages = (
|
|
5
|
-
istanbulCoverages,
|
|
6
|
-
{ coverageV8MergeConflictIsExpected = false } = {},
|
|
7
|
-
) => {
|
|
8
|
-
const coverageComposed = {}
|
|
9
|
-
|
|
10
|
-
// we can't merge coverage coming from code instrumented by istanbul
|
|
11
|
-
// with coverage coming from v8 and converted to istanbul, so we want to:
|
|
12
|
-
// 1. Have istanbul and v8 as long as they don't cover the same file
|
|
13
|
-
// 2. Choose istanbul or v8 depending which one cover the most
|
|
14
|
-
// To do that we first merge all v8 together and istanbul together
|
|
15
|
-
// To be able to know which one covers the most in case of merge conflict
|
|
16
|
-
const coverageFromV8Conversion = {}
|
|
17
|
-
const coverageFromIstanbul = {}
|
|
18
|
-
istanbulCoverages.forEach((istanbulCoverage) => {
|
|
19
|
-
Object.keys(istanbulCoverage).forEach((key) => {
|
|
20
|
-
const istanbulFileCoverage = istanbulCoverage[key]
|
|
21
|
-
if (istanbulFileCoverage.fromV8) {
|
|
22
|
-
const existingCoverageForFile = coverageFromV8Conversion[key]
|
|
23
|
-
if (existingCoverageForFile) {
|
|
24
|
-
coverageFromV8Conversion[key] = merge(existingCoverageForFile, istanbulFileCoverage)
|
|
25
|
-
} else {
|
|
26
|
-
coverageFromV8Conversion[key] = istanbulFileCoverage
|
|
27
|
-
}
|
|
28
|
-
} else {
|
|
29
|
-
const existingCoverageForFile = coverageFromIstanbul[key]
|
|
30
|
-
if (existingCoverageForFile) {
|
|
31
|
-
coverageFromIstanbul[key] = merge(existingCoverageForFile, istanbulFileCoverage)
|
|
32
|
-
} else {
|
|
33
|
-
coverageFromIstanbul[key] = istanbulFileCoverage
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
})
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
Object.keys(coverageFromV8Conversion).forEach((key) => {
|
|
40
|
-
const fileCoverageFromV8 = coverageFromV8Conversion[key]
|
|
41
|
-
const fileCoverageFromIstanbul = coverageFromIstanbul[key]
|
|
42
|
-
if (fileCoverageFromIstanbul) {
|
|
43
|
-
const v8HitCount = hitCountFromFileCoverage(fileCoverageFromV8)
|
|
44
|
-
const istanbulHitCount = hitCountFromFileCoverage(fileCoverageFromIstanbul)
|
|
45
|
-
const coverageWithMostHit =
|
|
46
|
-
v8HitCount >= istanbulHitCount ? fileCoverageFromV8 : fileCoverageFromIstanbul
|
|
47
|
-
|
|
48
|
-
if (!coverageV8MergeConflictIsExpected) {
|
|
49
|
-
// ideally when coverageV8MergeConflictIsExpected it would be a console.debug
|
|
50
|
-
console.warn(
|
|
51
|
-
formatMergeConflictBetweenV8AndIstanbulWarning({
|
|
52
|
-
fileRelativeUrl: key,
|
|
53
|
-
coverageKept: coverageWithMostHit,
|
|
54
|
-
}),
|
|
55
|
-
)
|
|
56
|
-
}
|
|
57
|
-
coverageComposed[key] = coverageWithMostHit
|
|
58
|
-
} else {
|
|
59
|
-
coverageComposed[key] = fileCoverageFromV8
|
|
60
|
-
}
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
Object.keys(coverageFromIstanbul).forEach((key) => {
|
|
64
|
-
const fileCoverageFromIstanbul = coverageFromIstanbul[key]
|
|
65
|
-
const fileCoverageFromV8 = coverageFromV8Conversion[key]
|
|
66
|
-
if (fileCoverageFromV8) {
|
|
67
|
-
// already handled
|
|
68
|
-
} else {
|
|
69
|
-
coverageComposed[key] = fileCoverageFromIstanbul
|
|
70
|
-
}
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
return coverageComposed
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const hitCountFromFileCoverage = ({ b, s }) => {
|
|
77
|
-
const statementHitCount = Object.keys(s).reduce((previous, key) => {
|
|
78
|
-
return previous + s[key]
|
|
79
|
-
}, 0)
|
|
80
|
-
|
|
81
|
-
const branchHitCount = Object.keys(b).reduce((previous, key) => {
|
|
82
|
-
const branchCount = b[key].reduce((previous, count) => {
|
|
83
|
-
return previous + count
|
|
84
|
-
}, 0)
|
|
85
|
-
return previous + branchCount
|
|
86
|
-
}, 0)
|
|
87
|
-
|
|
88
|
-
return statementHitCount + branchHitCount
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const merge = (istanbulFileCoverageA, istanbulFileCoverageB) => {
|
|
92
|
-
const { createFileCoverage } = require("istanbul-lib-coverage")
|
|
93
|
-
const istanbulFileCoverageObject = createFileCoverage(istanbulFileCoverageA)
|
|
94
|
-
istanbulFileCoverageObject.merge(istanbulFileCoverageB)
|
|
95
|
-
return istanbulFileCoverageObject.toJSON()
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
const formatMergeConflictBetweenV8AndIstanbulWarning = ({ fileRelativeUrl, coverageKept }) => {
|
|
99
|
-
return `Cannot merge file coverage coming from v8 and istanbul.
|
|
100
|
-
The one with most branch coverage will be kept and the other ignored.
|
|
101
|
-
--- coverage kept ---
|
|
102
|
-
${coverageKept.fromV8 ? "v8" : "istanbul"}
|
|
103
|
-
--- file ---
|
|
104
|
-
${fileRelativeUrl}
|
|
105
|
-
--- suggestion ---
|
|
106
|
-
If this is expected use coverageV8MergeConflictIsExpected to disable this warning
|
|
107
|
-
`
|
|
108
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { require } from "@jsenv/core/src/internal/require.js"
|
|
2
|
-
|
|
3
|
-
export const composeV8Coverages = (v8Coverages) => {
|
|
4
|
-
const { mergeProcessCovs } = require("@c88/v8-coverage")
|
|
5
|
-
|
|
6
|
-
// mergeCoverageReports do not preserves source-map-cache during the merge
|
|
7
|
-
// so we store sourcemap cache now
|
|
8
|
-
const sourceMapCache = {}
|
|
9
|
-
v8Coverages.forEach((coverageReport) => {
|
|
10
|
-
coverageReport.result.forEach((fileReport) => {
|
|
11
|
-
if (fileReport["source-map-cache"]) {
|
|
12
|
-
Object.assign(sourceMapCache, fileReport["source-map-cache"])
|
|
13
|
-
}
|
|
14
|
-
})
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
const v8Coverage = mergeProcessCovs(v8Coverages)
|
|
18
|
-
v8Coverage["source-map-cache"] = sourceMapCache
|
|
19
|
-
return v8Coverage
|
|
20
|
-
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
*
|
|
3
|
-
* The goal is to get an istanbul coverage from a list of coverage that are either
|
|
4
|
-
* v8Coverage or istanbul coverage
|
|
5
|
-
*
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { composeV8Coverages } from "./composeV8Coverages.js"
|
|
9
|
-
import { composeIstanbulCoverages } from "./composeIstanbulCoverages.js"
|
|
10
|
-
import { istanbulCoverageFromV8Coverage } from "./istanbulCoverageFromV8Coverage.js"
|
|
11
|
-
import { normalizeIstanbulCoverage } from "./normalizeIstanbulCoverage.js"
|
|
12
|
-
|
|
13
|
-
export const istanbulCoverageFromCoverages = async (
|
|
14
|
-
coverages,
|
|
15
|
-
{ projectDirectoryUrl, coverageV8MergeConflictIsExpected },
|
|
16
|
-
) => {
|
|
17
|
-
const v8Coverages = []
|
|
18
|
-
const istanbulCoverages = []
|
|
19
|
-
|
|
20
|
-
coverages.forEach((coverage) => {
|
|
21
|
-
if (coverage.result) {
|
|
22
|
-
v8Coverages.push(coverage)
|
|
23
|
-
} else {
|
|
24
|
-
istanbulCoverages.push(normalizeIstanbulCoverage(coverage, projectDirectoryUrl))
|
|
25
|
-
}
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
const v8CoverageComposed = composeV8Coverages(v8Coverages)
|
|
29
|
-
const istanbulCoverageComposed = composeIstanbulCoverages(istanbulCoverages)
|
|
30
|
-
const istanbulCoverageFromV8CoverageComposed = await istanbulCoverageFromV8Coverage(
|
|
31
|
-
v8CoverageComposed,
|
|
32
|
-
)
|
|
33
|
-
const istanbulCoverage = composeIstanbulCoverages(
|
|
34
|
-
[
|
|
35
|
-
istanbulCoverageComposed,
|
|
36
|
-
normalizeIstanbulCoverage(istanbulCoverageFromV8CoverageComposed, projectDirectoryUrl),
|
|
37
|
-
],
|
|
38
|
-
{
|
|
39
|
-
coverageV8MergeConflictIsExpected,
|
|
40
|
-
},
|
|
41
|
-
)
|
|
42
|
-
return istanbulCoverage
|
|
43
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { resolveUrl, normalizeStructuredMetaMap, urlToMeta } from "@jsenv/filesystem"
|
|
2
|
-
|
|
3
|
-
import { composeV8Coverages } from "./composeV8Coverages.js"
|
|
4
|
-
|
|
5
|
-
export const v8CoverageFromAllV8Coverages = (
|
|
6
|
-
allV8Coverages,
|
|
7
|
-
{ coverageRootUrl, coverageConfig },
|
|
8
|
-
) => {
|
|
9
|
-
const v8Coverages = filterCoverageReports(allV8Coverages, {
|
|
10
|
-
coverageRootUrl,
|
|
11
|
-
coverageConfig,
|
|
12
|
-
})
|
|
13
|
-
|
|
14
|
-
const v8Coverage = composeV8Coverages(v8Coverages)
|
|
15
|
-
return v8Coverage
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const filterCoverageReports = (coverageReports, { coverageRootUrl, coverageConfig }) => {
|
|
19
|
-
const structuredMetaMapForCover = normalizeStructuredMetaMap(
|
|
20
|
-
{
|
|
21
|
-
cover: coverageConfig,
|
|
22
|
-
},
|
|
23
|
-
coverageRootUrl,
|
|
24
|
-
)
|
|
25
|
-
const shouldIgnoreCoverage = (url) => {
|
|
26
|
-
return !urlToMeta({
|
|
27
|
-
url: resolveUrl(url, coverageRootUrl),
|
|
28
|
-
structuredMetaMap: structuredMetaMapForCover,
|
|
29
|
-
}).cover
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return coverageReports.map((coverageReport) => {
|
|
33
|
-
return {
|
|
34
|
-
...coverageReport,
|
|
35
|
-
result: coverageReport.result.filter((fileReport) => {
|
|
36
|
-
return !shouldIgnoreCoverage(fileReport.url)
|
|
37
|
-
}),
|
|
38
|
-
}
|
|
39
|
-
})
|
|
40
|
-
}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
assertAndNormalizeDirectoryUrl,
|
|
3
|
-
readDirectory,
|
|
4
|
-
readFile,
|
|
5
|
-
resolveUrl,
|
|
6
|
-
} from "@jsenv/filesystem"
|
|
7
|
-
import { createDetailedMessage } from "@jsenv/logger"
|
|
8
|
-
|
|
9
|
-
import { v8CoverageFromAllV8Coverages } from "./v8CoverageFromAllV8Coverages.js"
|
|
10
|
-
|
|
11
|
-
export const v8CoverageFromNodeV8Directory = async ({
|
|
12
|
-
projectDirectoryUrl,
|
|
13
|
-
NODE_V8_COVERAGE,
|
|
14
|
-
coverageConfig,
|
|
15
|
-
}) => {
|
|
16
|
-
const allV8Coverages = await readV8CoverageReportsFromDirectory(
|
|
17
|
-
NODE_V8_COVERAGE,
|
|
18
|
-
)
|
|
19
|
-
|
|
20
|
-
const v8Coverage = v8CoverageFromAllV8Coverages(allV8Coverages, {
|
|
21
|
-
coverageRootUrl: projectDirectoryUrl,
|
|
22
|
-
coverageConfig,
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
return v8Coverage
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const readV8CoverageReportsFromDirectory = async (coverageDirectory) => {
|
|
29
|
-
const tryReadDirectory = async () => {
|
|
30
|
-
const dirContent = await readDirectory(coverageDirectory)
|
|
31
|
-
if (dirContent.length > 0) {
|
|
32
|
-
return dirContent
|
|
33
|
-
}
|
|
34
|
-
console.warn(`v8 coverage directory is empty at ${coverageDirectory}`)
|
|
35
|
-
return dirContent
|
|
36
|
-
}
|
|
37
|
-
const dirContent = await tryReadDirectory()
|
|
38
|
-
|
|
39
|
-
const coverageReports = []
|
|
40
|
-
const coverageDirectoryUrl = assertAndNormalizeDirectoryUrl(coverageDirectory)
|
|
41
|
-
await Promise.all(
|
|
42
|
-
dirContent.map(async (dirEntry) => {
|
|
43
|
-
const dirEntryUrl = resolveUrl(dirEntry, coverageDirectoryUrl)
|
|
44
|
-
const tryReadJsonFile = async () => {
|
|
45
|
-
try {
|
|
46
|
-
const fileContent = await readFile(dirEntryUrl, { as: "json" })
|
|
47
|
-
return fileContent
|
|
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
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const fileContent = await tryReadJsonFile()
|
|
60
|
-
if (fileContent) {
|
|
61
|
-
coverageReports.push(fileContent)
|
|
62
|
-
}
|
|
63
|
-
}),
|
|
64
|
-
)
|
|
65
|
-
|
|
66
|
-
return coverageReports
|
|
67
|
-
}
|