@jsenv/test 1.1.2 → 1.1.3
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/jsenv_test.js +4 -2
- package/package.json +2 -2
- package/src/coverage/babel_plugin_instrument.js +15 -15
- package/src/coverage/coverage_reporter_html_directory.js +10 -10
- package/src/coverage/coverage_reporter_json_file.js +7 -7
- package/src/coverage/coverage_reporter_text_log.js +8 -8
- package/src/coverage/empty_coverage_factory.js +24 -24
- package/src/coverage/file_by_file_coverage.js +10 -10
- package/src/coverage/istanbul_coverage_composition.js +16 -16
- package/src/coverage/istanbul_coverage_map_from_coverage.js +8 -8
- package/src/coverage/list_files_not_covered.js +4 -4
- package/src/coverage/missing_coverage.js +17 -17
- package/src/coverage/report_to_coverage.js +52 -52
- package/src/coverage/v8_and_istanbul.js +17 -16
- package/src/coverage/v8_coverage.js +8 -8
- package/src/coverage/v8_coverage_composition.js +12 -12
- package/src/coverage/v8_coverage_node_directory.js +42 -42
- package/src/coverage/v8_coverage_to_istanbul.js +45 -45
- package/src/execution/execute.js +21 -21
- package/src/execution/execute_steps.js +129 -129
- package/src/execution/execute_test_plan.js +72 -68
- package/src/execution/execution_colors.js +2 -2
- package/src/execution/execution_steps.js +20 -20
- package/src/execution/gc.js +5 -5
- package/src/execution/logs_file_execution.js +126 -126
- package/src/execution/logs_file_execution.test.mjs +11 -11
- package/src/execution/run.js +51 -51
- package/src/execution/web_server_param.js +24 -24
- package/src/main.js +7 -7
- package/src/runtime_browsers/chromium.js +7 -7
- package/src/runtime_browsers/firefox.js +10 -10
- package/src/runtime_browsers/middleware_istanbul.js +23 -23
- package/src/runtime_browsers/middleware_js_supervisor.js +32 -32
- package/src/runtime_browsers/using_playwright.js +186 -186
- package/src/runtime_browsers/webkit.js +11 -11
- package/src/runtime_node/child_exec_options.js +43 -43
- package/src/runtime_node/controllable_child_process.mjs +47 -47
- package/src/runtime_node/controllable_worker_thread.mjs +37 -37
- package/src/runtime_node/exec_options.js +26 -26
- package/src/runtime_node/execute_using_dynamic_import.js +26 -26
- package/src/runtime_node/exit_codes.js +4 -4
- package/src/runtime_node/importmap_node_loader.mjs +24 -24
- package/src/runtime_node/importmap_node_loader_file_url.js +1 -1
- package/src/runtime_node/kill_process_tree.js +30 -30
- package/src/runtime_node/no_experimental_warnings.cjs +4 -4
- package/src/runtime_node/no_experimental_warnings_file_url.js +1 -1
- package/src/runtime_node/node_child_process.js +128 -128
- package/src/runtime_node/node_execution_performance.js +28 -28
- package/src/runtime_node/node_worker_thread.js +108 -108
- package/src/runtime_node/profiler_v8_coverage.js +21 -21
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
import { fork } from "node:child_process"
|
|
2
|
-
import { fileURLToPath } from "node:url"
|
|
1
|
+
import { fork } from "node:child_process";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
3
|
import {
|
|
4
4
|
Abort,
|
|
5
5
|
raceCallbacks,
|
|
6
6
|
createCallbackListNotifiedOnce,
|
|
7
|
-
} from "@jsenv/abort"
|
|
8
|
-
import { createDetailedMessage } from "@jsenv/log"
|
|
9
|
-
import { memoize } from "@jsenv/utils/src/memoize/memoize.js"
|
|
7
|
+
} from "@jsenv/abort";
|
|
8
|
+
import { createDetailedMessage } from "@jsenv/log";
|
|
9
|
+
import { memoize } from "@jsenv/utils/src/memoize/memoize.js";
|
|
10
10
|
|
|
11
|
-
import { createChildExecOptions } from "./child_exec_options.js"
|
|
12
|
-
import { ExecOptions } from "./exec_options.js"
|
|
13
|
-
import { killProcessTree } from "./kill_process_tree.js"
|
|
14
|
-
import { EXIT_CODES } from "./exit_codes.js"
|
|
15
|
-
import { IMPORTMAP_NODE_LOADER_FILE_URL } from "./importmap_node_loader_file_url.js"
|
|
16
|
-
import { NO_EXPERIMENTAL_WARNING_FILE_URL } from "./no_experimental_warnings_file_url.js"
|
|
11
|
+
import { createChildExecOptions } from "./child_exec_options.js";
|
|
12
|
+
import { ExecOptions } from "./exec_options.js";
|
|
13
|
+
import { killProcessTree } from "./kill_process_tree.js";
|
|
14
|
+
import { EXIT_CODES } from "./exit_codes.js";
|
|
15
|
+
import { IMPORTMAP_NODE_LOADER_FILE_URL } from "./importmap_node_loader_file_url.js";
|
|
16
|
+
import { NO_EXPERIMENTAL_WARNING_FILE_URL } from "./no_experimental_warnings_file_url.js";
|
|
17
17
|
|
|
18
18
|
const CONTROLLABLE_CHILD_PROCESS_URL = new URL(
|
|
19
19
|
"./controllable_child_process.mjs?entry_point",
|
|
20
20
|
import.meta.url,
|
|
21
|
-
).href
|
|
21
|
+
).href;
|
|
22
22
|
|
|
23
23
|
export const nodeChildProcess = ({
|
|
24
24
|
logProcessCommand = false,
|
|
@@ -35,12 +35,12 @@ export const nodeChildProcess = ({
|
|
|
35
35
|
stderr = "pipe",
|
|
36
36
|
} = {}) => {
|
|
37
37
|
if (env !== undefined && typeof env !== "object") {
|
|
38
|
-
throw new TypeError(`env must be an object, got ${env}`)
|
|
38
|
+
throw new TypeError(`env must be an object, got ${env}`);
|
|
39
39
|
}
|
|
40
40
|
env = {
|
|
41
41
|
...env,
|
|
42
42
|
JSENV: true,
|
|
43
|
-
}
|
|
43
|
+
};
|
|
44
44
|
|
|
45
45
|
return {
|
|
46
46
|
type: "node",
|
|
@@ -64,54 +64,54 @@ export const nodeChildProcess = ({
|
|
|
64
64
|
collectPerformance,
|
|
65
65
|
}) => {
|
|
66
66
|
if (coverageMethodForNodeJs !== "NODE_V8_COVERAGE") {
|
|
67
|
-
env.NODE_V8_COVERAGE = ""
|
|
67
|
+
env.NODE_V8_COVERAGE = "";
|
|
68
68
|
}
|
|
69
69
|
commandLineOptions = [
|
|
70
70
|
"--experimental-import-meta-resolve",
|
|
71
71
|
...commandLineOptions,
|
|
72
|
-
]
|
|
72
|
+
];
|
|
73
73
|
|
|
74
74
|
if (importMap) {
|
|
75
|
-
env.IMPORT_MAP = JSON.stringify(importMap)
|
|
76
|
-
env.IMPORT_MAP_BASE_URL = rootDirectoryUrl
|
|
75
|
+
env.IMPORT_MAP = JSON.stringify(importMap);
|
|
76
|
+
env.IMPORT_MAP_BASE_URL = rootDirectoryUrl;
|
|
77
77
|
commandLineOptions.push(
|
|
78
78
|
`--experimental-loader=${IMPORTMAP_NODE_LOADER_FILE_URL}`,
|
|
79
|
-
)
|
|
79
|
+
);
|
|
80
80
|
commandLineOptions.push(
|
|
81
81
|
`--require=${fileURLToPath(NO_EXPERIMENTAL_WARNING_FILE_URL)}`,
|
|
82
|
-
)
|
|
82
|
+
);
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
const cleanupCallbackList = createCallbackListNotifiedOnce()
|
|
85
|
+
const cleanupCallbackList = createCallbackListNotifiedOnce();
|
|
86
86
|
const cleanup = async (reason) => {
|
|
87
|
-
await cleanupCallbackList.notify({ reason })
|
|
88
|
-
}
|
|
87
|
+
await cleanupCallbackList.notify({ reason });
|
|
88
|
+
};
|
|
89
89
|
|
|
90
90
|
const childExecOptions = await createChildExecOptions({
|
|
91
91
|
signal,
|
|
92
92
|
debugPort,
|
|
93
93
|
debugMode,
|
|
94
94
|
debugModeInheritBreak,
|
|
95
|
-
})
|
|
95
|
+
});
|
|
96
96
|
const execArgv = ExecOptions.toExecArgv({
|
|
97
97
|
...childExecOptions,
|
|
98
98
|
...ExecOptions.fromExecArgv(commandLineOptions),
|
|
99
|
-
})
|
|
99
|
+
});
|
|
100
100
|
const envForChildProcess = {
|
|
101
101
|
...(inheritProcessEnv ? process.env : {}),
|
|
102
102
|
...env,
|
|
103
|
-
}
|
|
103
|
+
};
|
|
104
104
|
logger[logProcessCommand ? "info" : "debug"](
|
|
105
105
|
`${process.argv[0]} ${execArgv.join(" ")} ${fileURLToPath(
|
|
106
106
|
CONTROLLABLE_CHILD_PROCESS_URL,
|
|
107
107
|
)}`,
|
|
108
|
-
)
|
|
108
|
+
);
|
|
109
109
|
const childProcess = fork(fileURLToPath(CONTROLLABLE_CHILD_PROCESS_URL), {
|
|
110
110
|
execArgv,
|
|
111
111
|
// silent: true
|
|
112
112
|
stdio: ["pipe", "pipe", "pipe", "ipc"],
|
|
113
113
|
env: envForChildProcess,
|
|
114
|
-
})
|
|
114
|
+
});
|
|
115
115
|
logger.debug(
|
|
116
116
|
createDetailedMessage(
|
|
117
117
|
`child process forked (pid ${childProcess.pid})`,
|
|
@@ -119,26 +119,26 @@ export const nodeChildProcess = ({
|
|
|
119
119
|
"custom env": JSON.stringify(env, null, " "),
|
|
120
120
|
},
|
|
121
121
|
),
|
|
122
|
-
)
|
|
122
|
+
);
|
|
123
123
|
// if we pass stream, pipe them https://github.com/sindresorhus/execa/issues/81
|
|
124
124
|
if (typeof stdin === "object") {
|
|
125
|
-
stdin.pipe(childProcess.stdin)
|
|
125
|
+
stdin.pipe(childProcess.stdin);
|
|
126
126
|
}
|
|
127
127
|
if (typeof stdout === "object") {
|
|
128
|
-
childProcess.stdout.pipe(stdout)
|
|
128
|
+
childProcess.stdout.pipe(stdout);
|
|
129
129
|
}
|
|
130
130
|
if (typeof stderr === "object") {
|
|
131
|
-
childProcess.stderr.pipe(stderr)
|
|
131
|
+
childProcess.stderr.pipe(stderr);
|
|
132
132
|
}
|
|
133
133
|
const childProcessReadyPromise = new Promise((resolve) => {
|
|
134
|
-
onceChildProcessMessage(childProcess, "ready", resolve)
|
|
135
|
-
})
|
|
134
|
+
onceChildProcessMessage(childProcess, "ready", resolve);
|
|
135
|
+
});
|
|
136
136
|
const removeOutputListener = installChildProcessOutputListener(
|
|
137
137
|
childProcess,
|
|
138
138
|
({ type, text }) => {
|
|
139
|
-
onConsole({ type, text })
|
|
139
|
+
onConsole({ type, text });
|
|
140
140
|
},
|
|
141
|
-
)
|
|
141
|
+
);
|
|
142
142
|
const stop = memoize(async ({ gracefulStopAllocatedMs } = {}) => {
|
|
143
143
|
// all libraries are facing problem on windows when trying
|
|
144
144
|
// to kill a process spawning other processes.
|
|
@@ -147,40 +147,40 @@ export const nodeChildProcess = ({
|
|
|
147
147
|
// There is no satisfying solution to this problem so we stick to the basic
|
|
148
148
|
// childProcess.kill()
|
|
149
149
|
if (process.platform === "win32") {
|
|
150
|
-
childProcess.kill()
|
|
151
|
-
return
|
|
150
|
+
childProcess.kill();
|
|
151
|
+
return;
|
|
152
152
|
}
|
|
153
153
|
if (gracefulStopAllocatedMs) {
|
|
154
154
|
try {
|
|
155
155
|
await killProcessTree(childProcess.pid, {
|
|
156
156
|
signal: GRACEFUL_STOP_SIGNAL,
|
|
157
157
|
timeout: gracefulStopAllocatedMs,
|
|
158
|
-
})
|
|
159
|
-
return
|
|
158
|
+
});
|
|
159
|
+
return;
|
|
160
160
|
} catch (e) {
|
|
161
161
|
if (e.code === "TIMEOUT") {
|
|
162
162
|
logger.debug(
|
|
163
163
|
`kill with SIGTERM because gracefulStop still pending after ${gracefulStopAllocatedMs}ms`,
|
|
164
|
-
)
|
|
164
|
+
);
|
|
165
165
|
await killProcessTree(childProcess.pid, {
|
|
166
166
|
signal: GRACEFUL_STOP_FAILED_SIGNAL,
|
|
167
|
-
})
|
|
168
|
-
return
|
|
167
|
+
});
|
|
168
|
+
return;
|
|
169
169
|
}
|
|
170
|
-
throw e
|
|
170
|
+
throw e;
|
|
171
171
|
}
|
|
172
172
|
}
|
|
173
|
-
await killProcessTree(childProcess.pid, { signal: STOP_SIGNAL })
|
|
174
|
-
return
|
|
175
|
-
})
|
|
173
|
+
await killProcessTree(childProcess.pid, { signal: STOP_SIGNAL });
|
|
174
|
+
return;
|
|
175
|
+
});
|
|
176
176
|
|
|
177
|
-
const actionOperation = Abort.startOperation()
|
|
178
|
-
actionOperation.addAbortSignal(signal)
|
|
177
|
+
const actionOperation = Abort.startOperation();
|
|
178
|
+
actionOperation.addAbortSignal(signal);
|
|
179
179
|
const winnerPromise = new Promise((resolve) => {
|
|
180
180
|
raceCallbacks(
|
|
181
181
|
{
|
|
182
182
|
aborted: (cb) => {
|
|
183
|
-
return actionOperation.addAbortCallback(cb)
|
|
183
|
+
return actionOperation.addAbortCallback(cb);
|
|
184
184
|
},
|
|
185
185
|
// https://nodejs.org/api/child_process.html#child_process_event_disconnect
|
|
186
186
|
// disconnect: (cb) => {
|
|
@@ -188,34 +188,34 @@ export const nodeChildProcess = ({
|
|
|
188
188
|
// },
|
|
189
189
|
// https://nodejs.org/api/child_process.html#child_process_event_error
|
|
190
190
|
error: (cb) => {
|
|
191
|
-
return onceChildProcessEvent(childProcess, "error", cb)
|
|
191
|
+
return onceChildProcessEvent(childProcess, "error", cb);
|
|
192
192
|
},
|
|
193
193
|
exit: (cb) => {
|
|
194
194
|
return onceChildProcessEvent(
|
|
195
195
|
childProcess,
|
|
196
196
|
"exit",
|
|
197
197
|
(code, signal) => {
|
|
198
|
-
cb({ code, signal })
|
|
198
|
+
cb({ code, signal });
|
|
199
199
|
},
|
|
200
|
-
)
|
|
200
|
+
);
|
|
201
201
|
},
|
|
202
202
|
response: (cb) => {
|
|
203
|
-
return onceChildProcessMessage(childProcess, "action-result", cb)
|
|
203
|
+
return onceChildProcessMessage(childProcess, "action-result", cb);
|
|
204
204
|
},
|
|
205
205
|
},
|
|
206
206
|
resolve,
|
|
207
|
-
)
|
|
208
|
-
})
|
|
207
|
+
);
|
|
208
|
+
});
|
|
209
209
|
const result = {
|
|
210
210
|
status: "executing",
|
|
211
211
|
errors: [],
|
|
212
212
|
namespace: null,
|
|
213
|
-
}
|
|
213
|
+
};
|
|
214
214
|
|
|
215
215
|
const writeResult = async () => {
|
|
216
|
-
actionOperation.throwIfAborted()
|
|
217
|
-
await childProcessReadyPromise
|
|
218
|
-
actionOperation.throwIfAborted()
|
|
216
|
+
actionOperation.throwIfAborted();
|
|
217
|
+
await childProcessReadyPromise;
|
|
218
|
+
actionOperation.throwIfAborted();
|
|
219
219
|
await sendToChildProcess(childProcess, {
|
|
220
220
|
type: "action",
|
|
221
221
|
data: {
|
|
@@ -231,30 +231,30 @@ export const nodeChildProcess = ({
|
|
|
231
231
|
exitAfterAction: true,
|
|
232
232
|
},
|
|
233
233
|
},
|
|
234
|
-
})
|
|
235
|
-
const winner = await winnerPromise
|
|
234
|
+
});
|
|
235
|
+
const winner = await winnerPromise;
|
|
236
236
|
if (winner.name === "aborted") {
|
|
237
|
-
result.status = "aborted"
|
|
238
|
-
return
|
|
237
|
+
result.status = "aborted";
|
|
238
|
+
return;
|
|
239
239
|
}
|
|
240
240
|
if (winner.name === "error") {
|
|
241
|
-
const error = winner.data
|
|
242
|
-
removeOutputListener()
|
|
243
|
-
result.status = "failed"
|
|
244
|
-
result.errors.push(error)
|
|
245
|
-
return
|
|
241
|
+
const error = winner.data;
|
|
242
|
+
removeOutputListener();
|
|
243
|
+
result.status = "failed";
|
|
244
|
+
result.errors.push(error);
|
|
245
|
+
return;
|
|
246
246
|
}
|
|
247
247
|
if (winner.name === "exit") {
|
|
248
|
-
const { code } = winner.data
|
|
249
|
-
await cleanup("process exit")
|
|
248
|
+
const { code } = winner.data;
|
|
249
|
+
await cleanup("process exit");
|
|
250
250
|
if (code === 12) {
|
|
251
|
-
result.status = "failed"
|
|
251
|
+
result.status = "failed";
|
|
252
252
|
result.errors.push(
|
|
253
253
|
new Error(
|
|
254
254
|
`node process exited with 12 (the forked child process wanted to use a non-available port for debug)`,
|
|
255
255
|
),
|
|
256
|
-
)
|
|
257
|
-
return
|
|
256
|
+
);
|
|
257
|
+
return;
|
|
258
258
|
}
|
|
259
259
|
if (
|
|
260
260
|
code === null ||
|
|
@@ -263,59 +263,59 @@ export const nodeChildProcess = ({
|
|
|
263
263
|
code === EXIT_CODES.SIGTERM ||
|
|
264
264
|
code === EXIT_CODES.SIGABORT
|
|
265
265
|
) {
|
|
266
|
-
result.status = "failed"
|
|
266
|
+
result.status = "failed";
|
|
267
267
|
result.errors.push(
|
|
268
268
|
new Error(`node process exited during execution`),
|
|
269
|
-
)
|
|
270
|
-
return
|
|
269
|
+
);
|
|
270
|
+
return;
|
|
271
271
|
}
|
|
272
272
|
// process.exit(1) in child process or process.exitCode = 1 + process.exit()
|
|
273
273
|
// means there was an error even if we don't know exactly what.
|
|
274
|
-
result.status = "failed"
|
|
274
|
+
result.status = "failed";
|
|
275
275
|
result.errors.push(
|
|
276
276
|
new Error(`node process exited with code ${code} during execution`),
|
|
277
|
-
)
|
|
278
|
-
return
|
|
277
|
+
);
|
|
278
|
+
return;
|
|
279
279
|
}
|
|
280
|
-
const { status, value } = winner.data
|
|
280
|
+
const { status, value } = winner.data;
|
|
281
281
|
if (status === "action-failed") {
|
|
282
|
-
result.status = "failed"
|
|
283
|
-
result.errors.push(value)
|
|
284
|
-
return
|
|
282
|
+
result.status = "failed";
|
|
283
|
+
result.errors.push(value);
|
|
284
|
+
return;
|
|
285
285
|
}
|
|
286
|
-
const { namespace, performance, coverage } = value
|
|
287
|
-
result.status = "completed"
|
|
288
|
-
result.namespace = namespace
|
|
289
|
-
result.performance = performance
|
|
290
|
-
result.coverage = coverage
|
|
291
|
-
}
|
|
286
|
+
const { namespace, performance, coverage } = value;
|
|
287
|
+
result.status = "completed";
|
|
288
|
+
result.namespace = namespace;
|
|
289
|
+
result.performance = performance;
|
|
290
|
+
result.coverage = coverage;
|
|
291
|
+
};
|
|
292
292
|
|
|
293
293
|
try {
|
|
294
|
-
await writeResult()
|
|
294
|
+
await writeResult();
|
|
295
295
|
} catch (e) {
|
|
296
|
-
result.status = "failed"
|
|
297
|
-
result.errors.push(e)
|
|
296
|
+
result.status = "failed";
|
|
297
|
+
result.errors.push(e);
|
|
298
298
|
}
|
|
299
299
|
if (keepRunning) {
|
|
300
|
-
stopSignal.notify = stop
|
|
300
|
+
stopSignal.notify = stop;
|
|
301
301
|
} else {
|
|
302
302
|
await stop({
|
|
303
303
|
gracefulStopAllocatedMs,
|
|
304
|
-
})
|
|
304
|
+
});
|
|
305
305
|
}
|
|
306
|
-
await actionOperation.end()
|
|
307
|
-
return result
|
|
306
|
+
await actionOperation.end();
|
|
307
|
+
return result;
|
|
308
308
|
},
|
|
309
|
-
}
|
|
310
|
-
}
|
|
309
|
+
};
|
|
310
|
+
};
|
|
311
311
|
|
|
312
312
|
// http://man7.org/linux/man-pages/man7/signal.7.html
|
|
313
313
|
// https:// github.com/nodejs/node/blob/1d9511127c419ec116b3ddf5fc7a59e8f0f1c1e4/lib/internal/child_process.js#L472
|
|
314
|
-
const GRACEFUL_STOP_SIGNAL = "SIGTERM"
|
|
315
|
-
const STOP_SIGNAL = "SIGKILL"
|
|
314
|
+
const GRACEFUL_STOP_SIGNAL = "SIGTERM";
|
|
315
|
+
const STOP_SIGNAL = "SIGKILL";
|
|
316
316
|
// it would be more correct if GRACEFUL_STOP_FAILED_SIGNAL was SIGHUP instead of SIGKILL.
|
|
317
317
|
// but I'm not sure and it changes nothing so just use SIGKILL
|
|
318
|
-
const GRACEFUL_STOP_FAILED_SIGNAL = "SIGKILL"
|
|
318
|
+
const GRACEFUL_STOP_FAILED_SIGNAL = "SIGKILL";
|
|
319
319
|
|
|
320
320
|
const sendToChildProcess = async (childProcess, { type, data }) => {
|
|
321
321
|
return new Promise((resolve, reject) => {
|
|
@@ -327,48 +327,48 @@ const sendToChildProcess = async (childProcess, { type, data }) => {
|
|
|
327
327
|
},
|
|
328
328
|
(error) => {
|
|
329
329
|
if (error) {
|
|
330
|
-
reject(error)
|
|
330
|
+
reject(error);
|
|
331
331
|
} else {
|
|
332
|
-
resolve()
|
|
332
|
+
resolve();
|
|
333
333
|
}
|
|
334
334
|
},
|
|
335
|
-
)
|
|
336
|
-
})
|
|
337
|
-
}
|
|
335
|
+
);
|
|
336
|
+
});
|
|
337
|
+
};
|
|
338
338
|
|
|
339
339
|
const installChildProcessOutputListener = (childProcess, callback) => {
|
|
340
340
|
// beware that we may receive ansi output here, should not be a problem but keep that in mind
|
|
341
341
|
const stdoutDataCallback = (chunk) => {
|
|
342
|
-
callback({ type: "log", text: String(chunk) })
|
|
343
|
-
}
|
|
344
|
-
childProcess.stdout.on("data", stdoutDataCallback)
|
|
342
|
+
callback({ type: "log", text: String(chunk) });
|
|
343
|
+
};
|
|
344
|
+
childProcess.stdout.on("data", stdoutDataCallback);
|
|
345
345
|
const stdErrorDataCallback = (chunk) => {
|
|
346
|
-
callback({ type: "error", text: String(chunk) })
|
|
347
|
-
}
|
|
348
|
-
childProcess.stderr.on("data", stdErrorDataCallback)
|
|
346
|
+
callback({ type: "error", text: String(chunk) });
|
|
347
|
+
};
|
|
348
|
+
childProcess.stderr.on("data", stdErrorDataCallback);
|
|
349
349
|
return () => {
|
|
350
|
-
childProcess.stdout.removeListener("data", stdoutDataCallback)
|
|
351
|
-
childProcess.stderr.removeListener("data", stdoutDataCallback)
|
|
352
|
-
}
|
|
353
|
-
}
|
|
350
|
+
childProcess.stdout.removeListener("data", stdoutDataCallback);
|
|
351
|
+
childProcess.stderr.removeListener("data", stdoutDataCallback);
|
|
352
|
+
};
|
|
353
|
+
};
|
|
354
354
|
|
|
355
355
|
const onceChildProcessMessage = (childProcess, type, callback) => {
|
|
356
356
|
const onmessage = (message) => {
|
|
357
357
|
if (message && message.jsenv && message.type === type) {
|
|
358
|
-
childProcess.removeListener("message", onmessage)
|
|
358
|
+
childProcess.removeListener("message", onmessage);
|
|
359
359
|
// eslint-disable-next-line no-eval
|
|
360
|
-
callback(message.data ? eval(`(${message.data})`) : "")
|
|
360
|
+
callback(message.data ? eval(`(${message.data})`) : "");
|
|
361
361
|
}
|
|
362
|
-
}
|
|
363
|
-
childProcess.on("message", onmessage)
|
|
362
|
+
};
|
|
363
|
+
childProcess.on("message", onmessage);
|
|
364
364
|
return () => {
|
|
365
|
-
childProcess.removeListener("message", onmessage)
|
|
366
|
-
}
|
|
367
|
-
}
|
|
365
|
+
childProcess.removeListener("message", onmessage);
|
|
366
|
+
};
|
|
367
|
+
};
|
|
368
368
|
|
|
369
369
|
const onceChildProcessEvent = (childProcess, type, callback) => {
|
|
370
|
-
childProcess.once(type, callback)
|
|
370
|
+
childProcess.once(type, callback);
|
|
371
371
|
return () => {
|
|
372
|
-
childProcess.removeListener(type, callback)
|
|
373
|
-
}
|
|
374
|
-
}
|
|
372
|
+
childProcess.removeListener(type, callback);
|
|
373
|
+
};
|
|
374
|
+
};
|
|
@@ -1,67 +1,67 @@
|
|
|
1
|
-
import { PerformanceObserver, performance } from "node:perf_hooks"
|
|
1
|
+
import { PerformanceObserver, performance } from "node:perf_hooks";
|
|
2
2
|
|
|
3
3
|
export const startObservingPerformances = () => {
|
|
4
|
-
const measureEntries = []
|
|
4
|
+
const measureEntries = [];
|
|
5
5
|
// https://nodejs.org/dist/latest-v16.x/docs/api/perf_hooks.html
|
|
6
6
|
const perfObserver = new PerformanceObserver(
|
|
7
7
|
(
|
|
8
8
|
// https://nodejs.org/dist/latest-v16.x/docs/api/perf_hooks.html#perf_hooks_class_performanceobserverentrylist
|
|
9
9
|
list,
|
|
10
10
|
) => {
|
|
11
|
-
const perfMeasureEntries = list.getEntriesByType("measure")
|
|
12
|
-
measureEntries.push(...perfMeasureEntries)
|
|
11
|
+
const perfMeasureEntries = list.getEntriesByType("measure");
|
|
12
|
+
measureEntries.push(...perfMeasureEntries);
|
|
13
13
|
},
|
|
14
|
-
)
|
|
14
|
+
);
|
|
15
15
|
perfObserver.observe({
|
|
16
16
|
entryTypes: ["measure"],
|
|
17
|
-
})
|
|
17
|
+
});
|
|
18
18
|
return async () => {
|
|
19
19
|
// wait for node to call the performance observer
|
|
20
20
|
await new Promise((resolve) => {
|
|
21
|
-
setTimeout(resolve)
|
|
22
|
-
})
|
|
23
|
-
performance.clearMarks()
|
|
24
|
-
perfObserver.disconnect()
|
|
21
|
+
setTimeout(resolve);
|
|
22
|
+
});
|
|
23
|
+
performance.clearMarks();
|
|
24
|
+
perfObserver.disconnect();
|
|
25
25
|
return {
|
|
26
26
|
...readNodePerformance(),
|
|
27
27
|
measures: measuresFromMeasureEntries(measureEntries),
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
31
|
|
|
32
32
|
const readNodePerformance = () => {
|
|
33
33
|
const nodePerformance = {
|
|
34
34
|
nodeTiming: asPlainObject(performance.nodeTiming),
|
|
35
35
|
timeOrigin: performance.timeOrigin,
|
|
36
36
|
eventLoopUtilization: performance.eventLoopUtilization(),
|
|
37
|
-
}
|
|
38
|
-
return nodePerformance
|
|
39
|
-
}
|
|
37
|
+
};
|
|
38
|
+
return nodePerformance;
|
|
39
|
+
};
|
|
40
40
|
|
|
41
41
|
// remove getters that cannot be stringified
|
|
42
42
|
const asPlainObject = (objectWithGetters) => {
|
|
43
|
-
const objectWithoutGetters = {}
|
|
43
|
+
const objectWithoutGetters = {};
|
|
44
44
|
Object.keys(objectWithGetters).forEach((key) => {
|
|
45
|
-
objectWithoutGetters[key] = objectWithGetters[key]
|
|
46
|
-
})
|
|
47
|
-
return objectWithoutGetters
|
|
48
|
-
}
|
|
45
|
+
objectWithoutGetters[key] = objectWithGetters[key];
|
|
46
|
+
});
|
|
47
|
+
return objectWithoutGetters;
|
|
48
|
+
};
|
|
49
49
|
|
|
50
50
|
const measuresFromMeasureEntries = (measureEntries) => {
|
|
51
|
-
const measures = {}
|
|
51
|
+
const measures = {};
|
|
52
52
|
// Sort to ensure measures order is predictable
|
|
53
53
|
// It seems to be already predictable on Node 16+ but
|
|
54
54
|
// it's not the case on Node 14.
|
|
55
55
|
measureEntries.sort((a, b) => {
|
|
56
|
-
return a.startTime - b.startTime
|
|
57
|
-
})
|
|
56
|
+
return a.startTime - b.startTime;
|
|
57
|
+
});
|
|
58
58
|
measureEntries.forEach(
|
|
59
59
|
(
|
|
60
60
|
// https://nodejs.org/dist/latest-v16.x/docs/api/perf_hooks.html#perf_hooks_class_performanceentry
|
|
61
61
|
perfMeasureEntry,
|
|
62
62
|
) => {
|
|
63
|
-
measures[perfMeasureEntry.name] = perfMeasureEntry.duration
|
|
63
|
+
measures[perfMeasureEntry.name] = perfMeasureEntry.duration;
|
|
64
64
|
},
|
|
65
|
-
)
|
|
66
|
-
return measures
|
|
67
|
-
}
|
|
65
|
+
);
|
|
66
|
+
return measures;
|
|
67
|
+
};
|