@jsenv/core 30.4.2 → 31.0.1
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/js/supervisor.js +1 -1
- package/dist/js/v8_coverage.js +29 -22
- package/dist/main.js +582 -832
- package/package.json +5 -5
- package/src/build/build.js +26 -3
- package/src/build/start_build_server.js +43 -24
- package/src/dev/file_service.js +2 -1
- package/src/dev/start_dev_server.js +31 -15
- package/src/execute/execute.js +1 -1
- package/src/execute/run.js +2 -2
- package/src/execute/runtimes/browsers/from_playwright.js +5 -5
- package/src/execute/runtimes/node/node_child_process.js +6 -6
- package/src/execute/runtimes/node/node_worker_thread.js +6 -6
- package/src/kitchen/kitchen.js +11 -1
- package/src/plugins/supervisor/client/supervisor.js +1 -1
- package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic_library.js +1 -4
- package/src/test/execute_plan.js +4 -4
- package/src/test/execute_test_plan.js +57 -39
- package/src/test/execution_colors.js +1 -1
- package/src/test/logs_file_execution.js +7 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/core",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "31.0.1",
|
|
4
4
|
"description": "Tool to develop, test and build js projects",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -69,16 +69,16 @@
|
|
|
69
69
|
"@jsenv/abort": "4.2.4",
|
|
70
70
|
"@jsenv/ast": "3.0.3",
|
|
71
71
|
"@jsenv/babel-plugins": "1.1.5",
|
|
72
|
-
"@jsenv/filesystem": "4.
|
|
72
|
+
"@jsenv/filesystem": "4.2.0",
|
|
73
73
|
"@jsenv/importmap": "1.2.1",
|
|
74
74
|
"@jsenv/integrity": "0.0.1",
|
|
75
75
|
"@jsenv/log": "3.3.4",
|
|
76
76
|
"@jsenv/node-esm-resolution": "1.0.1",
|
|
77
|
-
"@jsenv/plugin-bundling": "
|
|
78
|
-
"@jsenv/server": "
|
|
77
|
+
"@jsenv/plugin-bundling": "2.0.0",
|
|
78
|
+
"@jsenv/server": "15.0.0",
|
|
79
79
|
"@jsenv/sourcemap": "1.0.9",
|
|
80
80
|
"@jsenv/uneval": "1.6.0",
|
|
81
|
-
"@jsenv/url-meta": "7.0
|
|
81
|
+
"@jsenv/url-meta": "7.1.0",
|
|
82
82
|
"@jsenv/urls": "1.2.8",
|
|
83
83
|
"@jsenv/utils": "2.0.1",
|
|
84
84
|
"@paralleldrive/cuid2": "2.2.0",
|
package/src/build/build.js
CHANGED
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
urlToRelativeUrl,
|
|
29
29
|
} from "@jsenv/urls"
|
|
30
30
|
import {
|
|
31
|
-
|
|
31
|
+
validateDirectoryUrl,
|
|
32
32
|
ensureEmptyDirectory,
|
|
33
33
|
writeFileSync,
|
|
34
34
|
registerDirectoryLifecycle,
|
|
@@ -155,7 +155,32 @@ export const build = async ({
|
|
|
155
155
|
writeGeneratedFiles = false,
|
|
156
156
|
assetManifest = versioningMethod === "filename",
|
|
157
157
|
assetManifestFileRelativeUrl = "asset-manifest.json",
|
|
158
|
+
...rest
|
|
158
159
|
}) => {
|
|
160
|
+
// param validation
|
|
161
|
+
{
|
|
162
|
+
const unexpectedParamNames = Object.keys(rest)
|
|
163
|
+
if (unexpectedParamNames.length > 0) {
|
|
164
|
+
throw new TypeError(
|
|
165
|
+
`${unexpectedParamNames.join(",")}: there is no such param`,
|
|
166
|
+
)
|
|
167
|
+
}
|
|
168
|
+
const rootDirectoryUrlValidation = validateDirectoryUrl(rootDirectoryUrl)
|
|
169
|
+
if (!rootDirectoryUrlValidation.valid) {
|
|
170
|
+
throw new TypeError(
|
|
171
|
+
`rootDirectoryUrl ${rootDirectoryUrlValidation.message}, got ${rootDirectoryUrl}`,
|
|
172
|
+
)
|
|
173
|
+
}
|
|
174
|
+
rootDirectoryUrl = rootDirectoryUrlValidation.value
|
|
175
|
+
const buildDirectoryUrlValidation = validateDirectoryUrl(buildDirectoryUrl)
|
|
176
|
+
if (!buildDirectoryUrlValidation.valid) {
|
|
177
|
+
throw new TypeError(
|
|
178
|
+
`buildDirectoryUrl ${buildDirectoryUrlValidation.message}, got ${buildDirectoryUrlValidation}`,
|
|
179
|
+
)
|
|
180
|
+
}
|
|
181
|
+
buildDirectoryUrl = buildDirectoryUrlValidation.value
|
|
182
|
+
}
|
|
183
|
+
|
|
159
184
|
const operation = Abort.startOperation()
|
|
160
185
|
operation.addAbortSignal(signal)
|
|
161
186
|
if (handleSIGINT) {
|
|
@@ -169,8 +194,6 @@ export const build = async ({
|
|
|
169
194
|
})
|
|
170
195
|
}
|
|
171
196
|
|
|
172
|
-
rootDirectoryUrl = assertAndNormalizeDirectoryUrl(rootDirectoryUrl)
|
|
173
|
-
buildDirectoryUrl = assertAndNormalizeDirectoryUrl(buildDirectoryUrl)
|
|
174
197
|
assertEntryPoints({ entryPoints })
|
|
175
198
|
if (!["filename", "search_param"].includes(versioningMethod)) {
|
|
176
199
|
throw new Error(
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
jsenvServiceErrorHandler,
|
|
24
24
|
} from "@jsenv/server"
|
|
25
25
|
import {
|
|
26
|
-
|
|
26
|
+
validateDirectoryUrl,
|
|
27
27
|
registerDirectoryLifecycle,
|
|
28
28
|
} from "@jsenv/filesystem"
|
|
29
29
|
import { Abort, raceProcessTeardownEvents } from "@jsenv/abort"
|
|
@@ -44,10 +44,8 @@ export const startBuildServer = async ({
|
|
|
44
44
|
handleSIGINT = true,
|
|
45
45
|
logLevel,
|
|
46
46
|
serverLogLevel = "warn",
|
|
47
|
-
|
|
47
|
+
https,
|
|
48
48
|
http2,
|
|
49
|
-
certificate,
|
|
50
|
-
privateKey,
|
|
51
49
|
acceptAnyIp,
|
|
52
50
|
hostname,
|
|
53
51
|
port = 9779,
|
|
@@ -64,32 +62,55 @@ export const startBuildServer = async ({
|
|
|
64
62
|
buildServerAutoreload = false,
|
|
65
63
|
buildServerMainFile = getCallerPosition().url,
|
|
66
64
|
cooldownBetweenFileEvents,
|
|
65
|
+
...rest
|
|
67
66
|
}) => {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
67
|
+
// params validation
|
|
68
|
+
{
|
|
69
|
+
const unexpectedParamNames = Object.keys(rest)
|
|
70
|
+
if (unexpectedParamNames.length > 0) {
|
|
71
|
+
throw new TypeError(
|
|
72
|
+
`${unexpectedParamNames.join(",")}: there is no such param`,
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
const rootDirectoryUrlValidation = validateDirectoryUrl(rootDirectoryUrl)
|
|
76
|
+
if (!rootDirectoryUrlValidation.valid) {
|
|
77
|
+
throw new TypeError(
|
|
78
|
+
`rootDirectoryUrl ${rootDirectoryUrlValidation.message}, got ${rootDirectoryUrl}`,
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
rootDirectoryUrl = rootDirectoryUrlValidation.value
|
|
82
|
+
const buildDirectoryUrlValidation = validateDirectoryUrl(buildDirectoryUrl)
|
|
83
|
+
if (!buildDirectoryUrlValidation.valid) {
|
|
73
84
|
throw new TypeError(
|
|
74
|
-
`
|
|
85
|
+
`buildDirectoryUrl ${buildDirectoryUrlValidation.message}, got ${buildDirectoryUrlValidation}`,
|
|
75
86
|
)
|
|
76
87
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
`buildIndexPath must be relative, got ${buildIndexPath}`,
|
|
88
|
+
buildDirectoryUrl = buildDirectoryUrlValidation.value
|
|
89
|
+
|
|
90
|
+
if (buildIndexPath) {
|
|
91
|
+
if (typeof buildIndexPath !== "string") {
|
|
92
|
+
throw new TypeError(
|
|
93
|
+
`buildIndexPath must be a string, got ${buildIndexPath}`,
|
|
84
94
|
)
|
|
85
95
|
}
|
|
86
|
-
buildIndexPath
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
96
|
+
if (buildIndexPath[0] === "/") {
|
|
97
|
+
buildIndexPath = buildIndexPath.slice(1)
|
|
98
|
+
} else {
|
|
99
|
+
const buildIndexUrl = new URL(buildIndexPath, buildDirectoryUrl).href
|
|
100
|
+
if (!buildIndexUrl.startsWith(buildDirectoryUrl)) {
|
|
101
|
+
throw new Error(
|
|
102
|
+
`buildIndexPath must be relative, got ${buildIndexPath}`,
|
|
103
|
+
)
|
|
104
|
+
}
|
|
105
|
+
buildIndexPath = buildIndexUrl.slice(buildDirectoryUrl.length)
|
|
106
|
+
}
|
|
107
|
+
if (!existsSync(new URL(buildIndexPath, buildDirectoryUrl))) {
|
|
108
|
+
buildIndexPath = null
|
|
109
|
+
}
|
|
90
110
|
}
|
|
91
111
|
}
|
|
92
112
|
|
|
113
|
+
const logger = createLogger({ logLevel })
|
|
93
114
|
const operation = Abort.startOperation()
|
|
94
115
|
operation.addAbortSignal(signal)
|
|
95
116
|
if (handleSIGINT) {
|
|
@@ -169,10 +190,8 @@ export const startBuildServer = async ({
|
|
|
169
190
|
logLevel: serverLogLevel,
|
|
170
191
|
startLog: false,
|
|
171
192
|
|
|
172
|
-
|
|
193
|
+
https,
|
|
173
194
|
http2,
|
|
174
|
-
certificate,
|
|
175
|
-
privateKey,
|
|
176
195
|
acceptAnyIp,
|
|
177
196
|
hostname,
|
|
178
197
|
port,
|
package/src/dev/file_service.js
CHANGED
|
@@ -20,6 +20,7 @@ export const createFileService = ({
|
|
|
20
20
|
logLevel,
|
|
21
21
|
serverStopCallbacks,
|
|
22
22
|
serverEventsDispatcher,
|
|
23
|
+
contextCache,
|
|
23
24
|
|
|
24
25
|
rootDirectoryUrl,
|
|
25
26
|
runtimeCompat,
|
|
@@ -82,7 +83,6 @@ export const createFileService = ({
|
|
|
82
83
|
})
|
|
83
84
|
serverStopCallbacks.push(stopWatchingClientFiles)
|
|
84
85
|
|
|
85
|
-
const contextCache = new Map()
|
|
86
86
|
const getOrCreateContext = (request) => {
|
|
87
87
|
const { runtimeName, runtimeVersion } = parseUserAgentHeader(
|
|
88
88
|
request.headers["user-agent"],
|
|
@@ -150,6 +150,7 @@ export const createFileService = ({
|
|
|
150
150
|
ribbon,
|
|
151
151
|
}),
|
|
152
152
|
],
|
|
153
|
+
supervisor,
|
|
153
154
|
minification: false,
|
|
154
155
|
sourcemaps,
|
|
155
156
|
sourcemapsSourcesProtocol,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { parentPort } from "node:worker_threads"
|
|
2
2
|
import {
|
|
3
|
-
|
|
3
|
+
validateDirectoryUrl,
|
|
4
4
|
registerDirectoryLifecycle,
|
|
5
5
|
} from "@jsenv/filesystem"
|
|
6
6
|
import { Abort, raceProcessTeardownEvents } from "@jsenv/abort"
|
|
@@ -32,12 +32,10 @@ export const startDevServer = async ({
|
|
|
32
32
|
handleSIGINT = true,
|
|
33
33
|
logLevel = "info",
|
|
34
34
|
serverLogLevel = "warn",
|
|
35
|
-
|
|
35
|
+
https,
|
|
36
36
|
// it's better to use http1 by default because it allows to get statusText in devtools
|
|
37
37
|
// which gives valuable information when there is errors
|
|
38
38
|
http2 = false,
|
|
39
|
-
certificate,
|
|
40
|
-
privateKey,
|
|
41
39
|
hostname,
|
|
42
40
|
port = 3456,
|
|
43
41
|
acceptAnyIp,
|
|
@@ -82,9 +80,26 @@ export const startDevServer = async ({
|
|
|
82
80
|
// no real need to write files during github workflow
|
|
83
81
|
// and mitigates https://github.com/actions/runner-images/issues/3885
|
|
84
82
|
writeGeneratedFiles = !process.env.CI,
|
|
83
|
+
...rest
|
|
85
84
|
}) => {
|
|
85
|
+
// params type checking
|
|
86
|
+
{
|
|
87
|
+
const unexpectedParamNames = Object.keys(rest)
|
|
88
|
+
if (unexpectedParamNames.length > 0) {
|
|
89
|
+
throw new TypeError(
|
|
90
|
+
`${unexpectedParamNames.join(",")}: there is no such param`,
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
const rootDirectoryUrlValidation = validateDirectoryUrl(rootDirectoryUrl)
|
|
94
|
+
if (!rootDirectoryUrlValidation.valid) {
|
|
95
|
+
throw new TypeError(
|
|
96
|
+
`rootDirectoryUrl ${rootDirectoryUrlValidation.message}, got ${rootDirectoryUrl}`,
|
|
97
|
+
)
|
|
98
|
+
}
|
|
99
|
+
rootDirectoryUrl = rootDirectoryUrlValidation.value
|
|
100
|
+
}
|
|
101
|
+
|
|
86
102
|
const logger = createLogger({ logLevel })
|
|
87
|
-
rootDirectoryUrl = assertAndNormalizeDirectoryUrl(rootDirectoryUrl)
|
|
88
103
|
const operation = Abort.startOperation()
|
|
89
104
|
operation.addAbortSignal(signal)
|
|
90
105
|
if (handleSIGINT) {
|
|
@@ -158,6 +173,7 @@ export const startDevServer = async ({
|
|
|
158
173
|
serverStopCallbacks.push(() => {
|
|
159
174
|
serverEventsDispatcher.destroy()
|
|
160
175
|
})
|
|
176
|
+
const contextCache = new Map()
|
|
161
177
|
const server = await startServer({
|
|
162
178
|
signal,
|
|
163
179
|
stopOnExit: false,
|
|
@@ -167,10 +183,8 @@ export const startDevServer = async ({
|
|
|
167
183
|
logLevel: serverLogLevel,
|
|
168
184
|
startLog: false,
|
|
169
185
|
|
|
170
|
-
|
|
186
|
+
https,
|
|
171
187
|
http2,
|
|
172
|
-
certificate,
|
|
173
|
-
privateKey,
|
|
174
188
|
acceptAnyIp,
|
|
175
189
|
hostname,
|
|
176
190
|
port,
|
|
@@ -195,6 +209,7 @@ export const startDevServer = async ({
|
|
|
195
209
|
logLevel,
|
|
196
210
|
serverStopCallbacks,
|
|
197
211
|
serverEventsDispatcher,
|
|
212
|
+
contextCache,
|
|
198
213
|
|
|
199
214
|
rootDirectoryUrl,
|
|
200
215
|
runtimeCompat,
|
|
@@ -265,13 +280,13 @@ export const startDevServer = async ({
|
|
|
265
280
|
sendErrorDetails: true,
|
|
266
281
|
}),
|
|
267
282
|
],
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
283
|
+
})
|
|
284
|
+
server.stoppedPromise.then((reason) => {
|
|
285
|
+
onStop()
|
|
286
|
+
serverStopCallbacks.forEach((serverStopCallback) => {
|
|
287
|
+
serverStopCallback(reason)
|
|
288
|
+
})
|
|
289
|
+
serverStopCallbacks.length = 0
|
|
275
290
|
})
|
|
276
291
|
startDevServerTask.done()
|
|
277
292
|
if (hostname) {
|
|
@@ -291,5 +306,6 @@ export const startDevServer = async ({
|
|
|
291
306
|
stop: () => {
|
|
292
307
|
server.stop()
|
|
293
308
|
},
|
|
309
|
+
contextCache,
|
|
294
310
|
}
|
|
295
311
|
}
|
package/src/execute/execute.js
CHANGED
package/src/execute/run.js
CHANGED
|
@@ -119,7 +119,7 @@ export const run = async ({
|
|
|
119
119
|
cb(runResult)
|
|
120
120
|
} catch (e) {
|
|
121
121
|
cb({
|
|
122
|
-
status: "
|
|
122
|
+
status: "failed",
|
|
123
123
|
errors: [e],
|
|
124
124
|
})
|
|
125
125
|
}
|
|
@@ -147,7 +147,7 @@ export const run = async ({
|
|
|
147
147
|
result.status = "aborted"
|
|
148
148
|
}
|
|
149
149
|
} else {
|
|
150
|
-
result.status = "
|
|
150
|
+
result.status = "failed"
|
|
151
151
|
result.errors.push(e)
|
|
152
152
|
}
|
|
153
153
|
} finally {
|
|
@@ -331,12 +331,12 @@ export const createRuntimeFromPlaywright = ({
|
|
|
331
331
|
}
|
|
332
332
|
if (winner.name === "error") {
|
|
333
333
|
let error = winner.data
|
|
334
|
-
result.status = "
|
|
334
|
+
result.status = "failed"
|
|
335
335
|
result.errors.push(error)
|
|
336
336
|
return
|
|
337
337
|
}
|
|
338
338
|
if (winner.name === "closed") {
|
|
339
|
-
result.status = "
|
|
339
|
+
result.status = "failed"
|
|
340
340
|
result.errors.push(
|
|
341
341
|
isBrowserDedicatedToExecution
|
|
342
342
|
? new Error(`browser disconnected during execution`)
|
|
@@ -350,8 +350,8 @@ export const createRuntimeFromPlaywright = ({
|
|
|
350
350
|
result.namespace = executionResults
|
|
351
351
|
Object.keys(executionResults).forEach((key) => {
|
|
352
352
|
const executionResult = executionResults[key]
|
|
353
|
-
if (executionResult.status === "
|
|
354
|
-
result.status = "
|
|
353
|
+
if (executionResult.status === "failed") {
|
|
354
|
+
result.status = "failed"
|
|
355
355
|
result.errors.push({
|
|
356
356
|
...executionResult.exception,
|
|
357
357
|
stack: executionResult.exception.text,
|
|
@@ -370,7 +370,7 @@ export const createRuntimeFromPlaywright = ({
|
|
|
370
370
|
await callback()
|
|
371
371
|
}, Promise.resolve())
|
|
372
372
|
} catch (e) {
|
|
373
|
-
result.status = "
|
|
373
|
+
result.status = "failed"
|
|
374
374
|
result.errors = [e]
|
|
375
375
|
}
|
|
376
376
|
if (keepRunning) {
|
|
@@ -219,7 +219,7 @@ nodeChildProcess.run = async ({
|
|
|
219
219
|
if (winner.name === "error") {
|
|
220
220
|
const error = winner.data
|
|
221
221
|
removeOutputListener()
|
|
222
|
-
result.status = "
|
|
222
|
+
result.status = "failed"
|
|
223
223
|
result.errors.push(error)
|
|
224
224
|
return
|
|
225
225
|
}
|
|
@@ -227,7 +227,7 @@ nodeChildProcess.run = async ({
|
|
|
227
227
|
const { code } = winner.data
|
|
228
228
|
await cleanup("process exit")
|
|
229
229
|
if (code === 12) {
|
|
230
|
-
result.status = "
|
|
230
|
+
result.status = "failed"
|
|
231
231
|
result.errors.push(
|
|
232
232
|
new Error(
|
|
233
233
|
`node process exited with 12 (the forked child process wanted to use a non-available port for debug)`,
|
|
@@ -242,13 +242,13 @@ nodeChildProcess.run = async ({
|
|
|
242
242
|
code === EXIT_CODES.SIGTERM ||
|
|
243
243
|
code === EXIT_CODES.SIGABORT
|
|
244
244
|
) {
|
|
245
|
-
result.status = "
|
|
245
|
+
result.status = "failed"
|
|
246
246
|
result.errors.push(new Error(`node process exited during execution`))
|
|
247
247
|
return
|
|
248
248
|
}
|
|
249
249
|
// process.exit(1) in child process or process.exitCode = 1 + process.exit()
|
|
250
250
|
// means there was an error even if we don't know exactly what.
|
|
251
|
-
result.status = "
|
|
251
|
+
result.status = "failed"
|
|
252
252
|
result.errors.push(
|
|
253
253
|
new Error(`node process exited with code ${code} during execution`),
|
|
254
254
|
)
|
|
@@ -256,7 +256,7 @@ nodeChildProcess.run = async ({
|
|
|
256
256
|
}
|
|
257
257
|
const { status, value } = winner.data
|
|
258
258
|
if (status === "action-failed") {
|
|
259
|
-
result.status = "
|
|
259
|
+
result.status = "failed"
|
|
260
260
|
result.errors.push(value)
|
|
261
261
|
return
|
|
262
262
|
}
|
|
@@ -270,7 +270,7 @@ nodeChildProcess.run = async ({
|
|
|
270
270
|
try {
|
|
271
271
|
await writeResult()
|
|
272
272
|
} catch (e) {
|
|
273
|
-
result.status = "
|
|
273
|
+
result.status = "failed"
|
|
274
274
|
result.errors.push(e)
|
|
275
275
|
}
|
|
276
276
|
if (keepRunning) {
|
|
@@ -171,7 +171,7 @@ nodeWorkerThread.run = async ({
|
|
|
171
171
|
if (winner.name === "error") {
|
|
172
172
|
const error = winner.data
|
|
173
173
|
removeOutputListener()
|
|
174
|
-
result.status = "
|
|
174
|
+
result.status = "failed"
|
|
175
175
|
result.errors.push(error)
|
|
176
176
|
return
|
|
177
177
|
}
|
|
@@ -179,7 +179,7 @@ nodeWorkerThread.run = async ({
|
|
|
179
179
|
const { code } = winner.data
|
|
180
180
|
await cleanup("process exit")
|
|
181
181
|
if (code === 12) {
|
|
182
|
-
result.status = "
|
|
182
|
+
result.status = "failed"
|
|
183
183
|
result.errors.push(
|
|
184
184
|
new Error(
|
|
185
185
|
`node process exited with 12 (the forked child process wanted to use a non-available port for debug)`,
|
|
@@ -194,7 +194,7 @@ nodeWorkerThread.run = async ({
|
|
|
194
194
|
code === EXIT_CODES.SIGTERM ||
|
|
195
195
|
code === EXIT_CODES.SIGABORT
|
|
196
196
|
) {
|
|
197
|
-
result.status = "
|
|
197
|
+
result.status = "failed"
|
|
198
198
|
result.errors.push(
|
|
199
199
|
new Error(`node worker thread exited during execution`),
|
|
200
200
|
)
|
|
@@ -202,7 +202,7 @@ nodeWorkerThread.run = async ({
|
|
|
202
202
|
}
|
|
203
203
|
// process.exit(1) in child process or process.exitCode = 1 + process.exit()
|
|
204
204
|
// means there was an error even if we don't know exactly what.
|
|
205
|
-
result.status = "
|
|
205
|
+
result.status = "failed"
|
|
206
206
|
result.errors.push(
|
|
207
207
|
new Error(
|
|
208
208
|
`node worker thread exited with code ${code} during execution`,
|
|
@@ -211,7 +211,7 @@ nodeWorkerThread.run = async ({
|
|
|
211
211
|
}
|
|
212
212
|
const { status, value } = winner.data
|
|
213
213
|
if (status === "action-failed") {
|
|
214
|
-
result.status = "
|
|
214
|
+
result.status = "failed"
|
|
215
215
|
result.errors.push(value)
|
|
216
216
|
return
|
|
217
217
|
}
|
|
@@ -225,7 +225,7 @@ nodeWorkerThread.run = async ({
|
|
|
225
225
|
try {
|
|
226
226
|
await writeResult()
|
|
227
227
|
} catch (e) {
|
|
228
|
-
result.status = "
|
|
228
|
+
result.status = "failed"
|
|
229
229
|
result.errors.push(e)
|
|
230
230
|
}
|
|
231
231
|
|
package/src/kitchen/kitchen.js
CHANGED
|
@@ -673,7 +673,17 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
|
|
|
673
673
|
// (error hapenning before urlInfo.content can be set, or 404 for instance)
|
|
674
674
|
// in that case we can't write anything
|
|
675
675
|
} else {
|
|
676
|
-
|
|
676
|
+
let contentIsInlined = urlInfo.isInline
|
|
677
|
+
if (
|
|
678
|
+
contentIsInlined &&
|
|
679
|
+
context.supervisor &&
|
|
680
|
+
urlGraph.getUrlInfo(urlInfo.inlineUrlSite.url).type === "html"
|
|
681
|
+
) {
|
|
682
|
+
contentIsInlined = false
|
|
683
|
+
}
|
|
684
|
+
if (!contentIsInlined) {
|
|
685
|
+
writeFileSync(new URL(generatedUrl), urlInfo.content)
|
|
686
|
+
}
|
|
677
687
|
const { sourcemapGeneratedUrl, sourcemap } = urlInfo
|
|
678
688
|
if (sourcemapGeneratedUrl && sourcemap) {
|
|
679
689
|
writeFileSync(
|
|
@@ -814,7 +814,7 @@ window.__supervisor__ = (() => {
|
|
|
814
814
|
}
|
|
815
815
|
|
|
816
816
|
const onError = (e) => {
|
|
817
|
-
executionResult.status = "
|
|
817
|
+
executionResult.status = "failed"
|
|
818
818
|
const exception = supervisor.createException({ reason: e })
|
|
819
819
|
if (exception.needsReport) {
|
|
820
820
|
supervisor.reportException(exception)
|
|
@@ -51,10 +51,7 @@ export const jsenvPluginAsJsClassicLibrary = ({
|
|
|
51
51
|
...context,
|
|
52
52
|
buildDirectoryUrl: context.outDirectoryUrl,
|
|
53
53
|
},
|
|
54
|
-
|
|
55
|
-
babelHelpersChunk: false,
|
|
56
|
-
preserveDynamicImport: true,
|
|
57
|
-
},
|
|
54
|
+
preserveDynamicImport: true,
|
|
58
55
|
})
|
|
59
56
|
const jsModuleBundledUrlInfo = bundleUrlInfos[jsModuleUrlInfo.url]
|
|
60
57
|
if (context.dev) {
|
package/src/test/execute_plan.js
CHANGED
|
@@ -225,7 +225,7 @@ export const executePlan = async (
|
|
|
225
225
|
total: executionSteps.length,
|
|
226
226
|
aborted: 0,
|
|
227
227
|
timedout: 0,
|
|
228
|
-
|
|
228
|
+
failed: 0,
|
|
229
229
|
completed: 0,
|
|
230
230
|
done: 0,
|
|
231
231
|
}
|
|
@@ -306,7 +306,7 @@ export const executePlan = async (
|
|
|
306
306
|
})
|
|
307
307
|
} else {
|
|
308
308
|
executionResult = {
|
|
309
|
-
status: "
|
|
309
|
+
status: "failed",
|
|
310
310
|
errors: [
|
|
311
311
|
new Error(
|
|
312
312
|
`No file at ${fileRelativeUrl} for execution "${executionName}"`,
|
|
@@ -336,8 +336,8 @@ export const executePlan = async (
|
|
|
336
336
|
counters.aborted++
|
|
337
337
|
} else if (executionResult.status === "timedout") {
|
|
338
338
|
counters.timedout++
|
|
339
|
-
} else if (executionResult.status === "
|
|
340
|
-
counters.
|
|
339
|
+
} else if (executionResult.status === "failed") {
|
|
340
|
+
counters.failed++
|
|
341
341
|
} else if (executionResult.status === "completed") {
|
|
342
342
|
counters.completed++
|
|
343
343
|
}
|
|
@@ -5,10 +5,7 @@ import {
|
|
|
5
5
|
urlIsInsideOf,
|
|
6
6
|
urlToRelativeUrl,
|
|
7
7
|
} from "@jsenv/urls"
|
|
8
|
-
import {
|
|
9
|
-
ensureEmptyDirectory,
|
|
10
|
-
assertAndNormalizeDirectoryUrl,
|
|
11
|
-
} from "@jsenv/filesystem"
|
|
8
|
+
import { ensureEmptyDirectory, validateDirectoryUrl } from "@jsenv/filesystem"
|
|
12
9
|
import { createLogger, createDetailedMessage } from "@jsenv/log"
|
|
13
10
|
|
|
14
11
|
import { generateCoverageJsonFile } from "./coverage/coverage_reporter_json_file.js"
|
|
@@ -82,51 +79,72 @@ export const executeTestPlan = async ({
|
|
|
82
79
|
coverageReportTextLog = true,
|
|
83
80
|
coverageReportJsonFile = process.env.CI ? null : "./.coverage/coverage.json",
|
|
84
81
|
coverageReportHtmlDirectory = process.env.CI ? "./.coverage/" : null,
|
|
82
|
+
...rest
|
|
85
83
|
}) => {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
-
if (coverageEnabled) {
|
|
92
|
-
if (typeof coverageConfig !== "object") {
|
|
84
|
+
// param validation
|
|
85
|
+
{
|
|
86
|
+
const unexpectedParamNames = Object.keys(rest)
|
|
87
|
+
if (unexpectedParamNames.length > 0) {
|
|
93
88
|
throw new TypeError(
|
|
94
|
-
|
|
89
|
+
`${unexpectedParamNames.join(",")}: there is no such param`,
|
|
95
90
|
)
|
|
96
91
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
92
|
+
const rootDirectoryUrlValidation = validateDirectoryUrl(rootDirectoryUrl)
|
|
93
|
+
if (!rootDirectoryUrlValidation.valid) {
|
|
94
|
+
throw new TypeError(
|
|
95
|
+
`rootDirectoryUrl ${rootDirectoryUrlValidation.message}, got ${rootDirectoryUrl}`,
|
|
100
96
|
)
|
|
101
97
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
)
|
|
111
|
-
const patternsMatchingCoverAndExecute = Object.keys(
|
|
112
|
-
associationsForExecute.execute,
|
|
113
|
-
).filter((testPlanPattern) => {
|
|
114
|
-
const { cover } = URL_META.applyAssociations({
|
|
115
|
-
url: testPlanPattern,
|
|
116
|
-
associations: associationsForCover,
|
|
117
|
-
})
|
|
118
|
-
return cover
|
|
119
|
-
})
|
|
120
|
-
if (patternsMatchingCoverAndExecute.length) {
|
|
121
|
-
// It would be strange, for a given file to be both covered and executed
|
|
122
|
-
throw new Error(
|
|
123
|
-
createDetailedMessage(`some file will be both covered and executed`, {
|
|
124
|
-
patterns: patternsMatchingCoverAndExecute,
|
|
125
|
-
}),
|
|
98
|
+
rootDirectoryUrl = rootDirectoryUrlValidation.value
|
|
99
|
+
if (typeof testPlan !== "object") {
|
|
100
|
+
throw new Error(`testPlan must be an object, got ${testPlan}`)
|
|
101
|
+
}
|
|
102
|
+
if (coverageEnabled) {
|
|
103
|
+
if (typeof coverageConfig !== "object") {
|
|
104
|
+
throw new TypeError(
|
|
105
|
+
`coverageConfig must be an object, got ${coverageConfig}`,
|
|
126
106
|
)
|
|
127
107
|
}
|
|
108
|
+
if (!coverageAndExecutionAllowed) {
|
|
109
|
+
const associationsForExecute = URL_META.resolveAssociations(
|
|
110
|
+
{ execute: testPlan },
|
|
111
|
+
"file:///",
|
|
112
|
+
)
|
|
113
|
+
const associationsForCover = URL_META.resolveAssociations(
|
|
114
|
+
{ cover: coverageConfig },
|
|
115
|
+
"file:///",
|
|
116
|
+
)
|
|
117
|
+
const patternsMatchingCoverAndExecute = Object.keys(
|
|
118
|
+
associationsForExecute.execute,
|
|
119
|
+
).filter((testPlanPattern) => {
|
|
120
|
+
const { cover } = URL_META.applyAssociations({
|
|
121
|
+
url: testPlanPattern,
|
|
122
|
+
associations: associationsForCover,
|
|
123
|
+
})
|
|
124
|
+
return cover
|
|
125
|
+
})
|
|
126
|
+
if (patternsMatchingCoverAndExecute.length) {
|
|
127
|
+
// It would be strange, for a given file to be both covered and executed
|
|
128
|
+
throw new Error(
|
|
129
|
+
createDetailedMessage(
|
|
130
|
+
`some file will be both covered and executed`,
|
|
131
|
+
{
|
|
132
|
+
patterns: patternsMatchingCoverAndExecute,
|
|
133
|
+
},
|
|
134
|
+
),
|
|
135
|
+
)
|
|
136
|
+
}
|
|
137
|
+
}
|
|
128
138
|
}
|
|
129
139
|
}
|
|
140
|
+
|
|
141
|
+
const logger = createLogger({ logLevel })
|
|
142
|
+
if (Object.keys(coverageConfig).length === 0) {
|
|
143
|
+
logger.warn(
|
|
144
|
+
`coverageConfig is an empty object. Nothing will be instrumented for coverage so your coverage will be empty`,
|
|
145
|
+
)
|
|
146
|
+
}
|
|
147
|
+
|
|
130
148
|
const result = await executePlan(testPlan, {
|
|
131
149
|
signal,
|
|
132
150
|
handleSIGINT,
|