@jsenv/test 2.1.3 → 3.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.
Files changed (46) hide show
  1. package/README.md +2 -1
  2. package/dist/js/exception.js +908 -0
  3. package/dist/js/execute_using_dynamic_import.js +76 -167
  4. package/dist/js/v8_coverage.js +4 -482
  5. package/dist/jsenv_test.js +4608 -2917
  6. package/dist/node_child_process_controlled.mjs +95 -76
  7. package/dist/node_worker_thread_controlled.mjs +72 -54
  8. package/package.json +23 -14
  9. package/src/coverage/generate_coverage.js +186 -0
  10. package/src/coverage/list_files_not_covered.js +2 -2
  11. package/src/coverage/missing_coverage.js +2 -2
  12. package/src/coverage/report_coverage_as_html.js +45 -0
  13. package/src/coverage/report_coverage_as_json.js +20 -0
  14. package/src/coverage/{coverage_reporter_text_log.js → report_coverage_in_console.js} +13 -7
  15. package/src/coverage/v8_and_istanbul.js +4 -4
  16. package/src/coverage/v8_coverage.js +2 -2
  17. package/src/execution/exception.js +151 -68
  18. package/src/execution/execute.js +24 -11
  19. package/src/execution/execute_test_plan.js +834 -750
  20. package/src/execution/format_error_for_terminal.js +187 -0
  21. package/src/execution/github_annotation_from_error.js +3 -3
  22. package/src/execution/junit_xml_file/report_as_junit_xml.js +149 -0
  23. package/src/execution/junit_xml_file/xml_generator.js +141 -0
  24. package/src/execution/reporters/reporter_list.js +687 -0
  25. package/src/execution/run.js +92 -30
  26. package/src/execution/web_server/start_using_command.js +2 -2
  27. package/src/execution/web_server_param.js +5 -5
  28. package/src/helpers/cpu_usage.js +142 -0
  29. package/src/helpers/cpu_usage.test_manual.js +7 -0
  30. package/src/main.js +8 -0
  31. package/src/runtime_browsers/chromium.js +1 -3
  32. package/src/runtime_browsers/firefox.js +0 -3
  33. package/src/runtime_browsers/middleware_istanbul.js +2 -2
  34. package/src/runtime_browsers/using_playwright.js +296 -220
  35. package/src/runtime_browsers/webkit.js +0 -3
  36. package/src/runtime_node/execute_using_dynamic_import.js +75 -28
  37. package/src/runtime_node/node_child_process.js +250 -139
  38. package/src/runtime_node/node_child_process_controlled.mjs +94 -75
  39. package/src/runtime_node/node_worker_thread.js +206 -120
  40. package/src/runtime_node/node_worker_thread_controlled.mjs +70 -53
  41. package/src/coverage/coverage_reporter_html_directory.js +0 -32
  42. package/src/coverage/coverage_reporter_json_file.js +0 -17
  43. package/src/coverage/report_to_coverage.js +0 -198
  44. package/src/execution/execution_colors.js +0 -10
  45. package/src/execution/execution_steps.js +0 -65
  46. package/src/execution/logs_file_execution.js +0 -495
@@ -1,53 +1,100 @@
1
1
  import { writeFileSync } from "node:fs";
2
+ import { memoryUsage } from "node:process";
2
3
 
3
4
  import { startJsCoverage } from "./profiler_v8_coverage.js";
4
5
  import { startObservingPerformances } from "./node_execution_performance.js";
6
+ import { createException } from "../execution/exception.js";
5
7
 
6
8
  export const executeUsingDynamicImport = async ({
7
9
  rootDirectoryUrl,
8
10
  fileUrl,
11
+ measureMemoryUsage,
9
12
  collectPerformance,
10
13
  coverageEnabled,
11
- coverageConfig,
14
+ coverageInclude,
12
15
  coverageMethodForNodeJs,
13
16
  coverageFileUrl,
14
17
  }) => {
15
- const result = {};
16
- const afterImportCallbacks = [];
18
+ const result = {
19
+ timings: {
20
+ start: null,
21
+ end: null,
22
+ },
23
+ errors: [],
24
+ namespace: null,
25
+ memoryUsage: null,
26
+ performance: null,
27
+ };
28
+
29
+ let finalizePerformance;
30
+ if (collectPerformance) {
31
+ const getPerformance = startObservingPerformances();
32
+ finalizePerformance = async () => {
33
+ const performance = await getPerformance();
34
+ result.performance = performance;
35
+ };
36
+ }
37
+
38
+ let finalizeCoverage;
17
39
  if (coverageEnabled && coverageMethodForNodeJs === "Profiler") {
18
- const { filterV8Coverage } = await import("../coverage/v8_coverage.js");
19
40
  const { stopJsCoverage } = await startJsCoverage();
20
- afterImportCallbacks.push(async () => {
21
- const coverage = await stopJsCoverage();
41
+ finalizeCoverage = async () => {
42
+ const [coverage, { filterV8Coverage }] = await Promise.all([
43
+ stopJsCoverage(),
44
+ import("../coverage/v8_coverage.js"),
45
+ ]);
22
46
  const coverageLight = await filterV8Coverage(coverage, {
23
47
  rootDirectoryUrl,
24
- coverageConfig,
48
+ coverageInclude,
25
49
  });
26
50
  writeFileSync(
27
51
  new URL(coverageFileUrl),
28
52
  JSON.stringify(coverageLight, null, " "),
29
53
  );
30
- });
54
+ };
31
55
  }
32
- if (collectPerformance) {
33
- const getPerformance = startObservingPerformances();
34
- afterImportCallbacks.push(async () => {
35
- const performance = await getPerformance();
36
- result.performance = performance;
37
- });
56
+
57
+ let finalizeMemoryUsage;
58
+ if (measureMemoryUsage) {
59
+ global.gc();
60
+ const memoryHeapUsedBeforeExecution = memoryUsage().heapUsed;
61
+ finalizeMemoryUsage = () => {
62
+ global.gc();
63
+ const memoryHeapUsedAfterExecution = memoryUsage().heapUsed;
64
+ result.memoryUsage =
65
+ memoryHeapUsedAfterExecution - memoryHeapUsedBeforeExecution;
66
+ };
67
+ }
68
+
69
+ result.timings.start = Date.now();
70
+ try {
71
+ const namespace = await import(fileUrl);
72
+ const namespaceResolved = {};
73
+ await Promise.all(
74
+ Object.keys(namespace).map(async (key) => {
75
+ const value = await namespace[key];
76
+ namespaceResolved[key] = value;
77
+ }),
78
+ );
79
+ result.status = "completed";
80
+ result.namespace = namespaceResolved;
81
+ } catch (e) {
82
+ result.status = "failed";
83
+ result.errors.push(createException(e, { rootDirectoryUrl }));
84
+ } finally {
85
+ result.timings.end = Date.now();
86
+ if (finalizeCoverage) {
87
+ await finalizeCoverage();
88
+ finalizeCoverage = null;
89
+ }
90
+ if (finalizePerformance) {
91
+ await finalizePerformance();
92
+ finalizePerformance = null;
93
+ }
94
+ if (finalizeMemoryUsage) {
95
+ finalizeMemoryUsage();
96
+ finalizeMemoryUsage = null;
97
+ }
98
+ return result;
38
99
  }
39
- const namespace = await import(fileUrl);
40
- const namespaceResolved = {};
41
- await Promise.all(
42
- Object.keys(namespace).map(async (key) => {
43
- const value = await namespace[key];
44
- namespaceResolved[key] = value;
45
- }),
46
- );
47
- result.namespace = namespaceResolved;
48
- await afterImportCallbacks.reduce(async (previous, afterImportCallback) => {
49
- await previous;
50
- await afterImportCallback();
51
- }, Promise.resolve());
52
- return result;
53
100
  };
@@ -1,10 +1,6 @@
1
1
  import { fork } from "node:child_process";
2
2
  import { fileURLToPath } from "node:url";
3
- import {
4
- Abort,
5
- raceCallbacks,
6
- createCallbackListNotifiedOnce,
7
- } from "@jsenv/abort";
3
+ import { Abort, raceCallbacks } from "@jsenv/abort";
8
4
  import { createDetailedMessage } from "@jsenv/log";
9
5
  import { memoize } from "@jsenv/utils/src/memoize/memoize.js";
10
6
 
@@ -56,12 +52,17 @@ export const nodeChildProcess = ({
56
52
  keepRunning,
57
53
  stopSignal,
58
54
  onConsole,
55
+ onRuntimeStarted,
56
+ onRuntimeStopped,
59
57
 
58
+ measureMemoryUsage,
59
+ onMeasureMemoryAvailable,
60
+ collectConsole = false,
61
+ collectPerformance,
60
62
  coverageEnabled = false,
61
- coverageConfig,
63
+ coverageInclude,
62
64
  coverageMethodForNodeJs,
63
65
  coverageFileUrl,
64
- collectPerformance,
65
66
  }) => {
66
67
  if (coverageMethodForNodeJs !== "NODE_V8_COVERAGE") {
67
68
  env.NODE_V8_COVERAGE = "";
@@ -70,7 +71,14 @@ export const nodeChildProcess = ({
70
71
  "--experimental-import-meta-resolve",
71
72
  ...commandLineOptions,
72
73
  ];
73
-
74
+ if (onMeasureMemoryAvailable) {
75
+ env.MEASURE_MEMORY_AT_START = "1";
76
+ }
77
+ if (measureMemoryUsage || onMeasureMemoryAvailable) {
78
+ if (!commandLineOptions.includes("--expose-gc")) {
79
+ commandLineOptions.push("--expose-gc");
80
+ }
81
+ }
74
82
  if (importMap) {
75
83
  env.IMPORT_MAP = JSON.stringify(importMap);
76
84
  env.IMPORT_MAP_BASE_URL = rootDirectoryUrl;
@@ -82,9 +90,14 @@ export const nodeChildProcess = ({
82
90
  );
83
91
  }
84
92
 
85
- const cleanupCallbackList = createCallbackListNotifiedOnce();
93
+ const cleanupCallbackSet = new Set();
86
94
  const cleanup = async (reason) => {
87
- await cleanupCallbackList.notify({ reason });
95
+ const promises = [];
96
+ for (const cleanupCallback of cleanupCallbackSet) {
97
+ promises.push(cleanupCallback({ reason }));
98
+ }
99
+ cleanupCallbackSet.clear();
100
+ await Promise.all(promises);
88
101
  };
89
102
 
90
103
  const childExecOptions = await createChildExecOptions({
@@ -106,9 +119,11 @@ export const nodeChildProcess = ({
106
119
  CONTROLLED_CHILD_PROCESS_URL,
107
120
  )}`,
108
121
  );
122
+ const actionOperation = Abort.startOperation();
123
+ actionOperation.addAbortSignal(signal);
109
124
  const childProcess = fork(fileURLToPath(CONTROLLED_CHILD_PROCESS_URL), {
110
125
  execArgv,
111
- // silent: true
126
+ // silent: true,
112
127
  stdio: ["pipe", "pipe", "pipe", "ipc"],
113
128
  env: envForChildProcess,
114
129
  });
@@ -131,15 +146,48 @@ export const nodeChildProcess = ({
131
146
  childProcess.stderr.pipe(stderr);
132
147
  }
133
148
  const childProcessReadyPromise = new Promise((resolve) => {
134
- onceChildProcessMessage(childProcess, "ready", resolve);
149
+ const removeReadyListener = onChildProcessMessage(
150
+ childProcess,
151
+ "ready",
152
+ () => {
153
+ removeReadyListener();
154
+ onRuntimeStarted();
155
+ resolve();
156
+ },
157
+ );
135
158
  });
159
+ cleanupCallbackSet.add(
160
+ onceChildProcessEvent(childProcess, "exit", () => {
161
+ onRuntimeStopped();
162
+ }),
163
+ );
164
+
136
165
  const removeOutputListener = installChildProcessOutputListener(
137
166
  childProcess,
138
167
  ({ type, text }) => {
168
+ if (type === "error" && text.startsWith("Debugger attached.")) {
169
+ return;
170
+ }
171
+ if (
172
+ type === "error" &&
173
+ text.startsWith("Waiting for the debugger to disconnect...")
174
+ ) {
175
+ return;
176
+ }
177
+
139
178
  onConsole({ type, text });
140
179
  },
141
180
  );
142
181
  const stop = memoize(async ({ gracefulStopAllocatedMs } = {}) => {
182
+ // read all stdout before terminating
183
+ // (no need for stderr because it's sync)
184
+ if (collectConsole || onConsole) {
185
+ while (childProcess.stdout.read() !== null) {}
186
+ await new Promise((resolve) => {
187
+ setTimeout(resolve, 50);
188
+ });
189
+ }
190
+
143
191
  // all libraries are facing problem on windows when trying
144
192
  // to kill a process spawning other processes.
145
193
  // "killProcessTree" is theorically correct but sometimes keep process handing forever.
@@ -174,159 +222,214 @@ export const nodeChildProcess = ({
174
222
  return;
175
223
  });
176
224
 
177
- const actionOperation = Abort.startOperation();
178
- actionOperation.addAbortSignal(signal);
179
- const winnerPromise = new Promise((resolve) => {
180
- raceCallbacks(
181
- {
182
- aborted: (cb) => {
183
- return actionOperation.addAbortCallback(cb);
184
- },
185
- // https://nodejs.org/api/child_process.html#child_process_event_disconnect
186
- // disconnect: (cb) => {
187
- // return onceProcessEvent(childProcess, "disconnect", cb)
188
- // },
189
- // https://nodejs.org/api/child_process.html#child_process_event_error
190
- error: (cb) => {
191
- return onceChildProcessEvent(childProcess, "error", cb);
192
- },
193
- exit: (cb) => {
194
- return onceChildProcessEvent(
195
- childProcess,
196
- "exit",
197
- (code, signal) => {
198
- cb({ code, signal });
199
- },
200
- );
201
- },
202
- response: (cb) => {
203
- return onceChildProcessMessage(childProcess, "action-result", cb);
204
- },
205
- },
206
- resolve,
207
- );
208
- });
209
225
  const result = {
210
226
  status: "executing",
211
227
  errors: [],
212
228
  namespace: null,
229
+ timings: {},
230
+ memoryUsage: null,
231
+ performance: null,
213
232
  };
214
233
 
215
- const writeResult = async () => {
234
+ try {
235
+ let executionInternalErrorCallback;
236
+ let executionCompletedCallback;
237
+ const winnerPromise = new Promise((resolve) => {
238
+ raceCallbacks(
239
+ {
240
+ aborted: (cb) => {
241
+ return actionOperation.addAbortCallback(cb);
242
+ },
243
+ // https://nodejs.org/api/child_process.html#child_process_event_disconnect
244
+ // disconnect: (cb) => {
245
+ // return onceProcessEvent(childProcess, "disconnect", cb)
246
+ // },
247
+ // https://nodejs.org/api/child_process.html#child_process_event_error
248
+ error: (cb) => {
249
+ return onceChildProcessEvent(childProcess, "error", cb);
250
+ },
251
+ exit: (cb) => {
252
+ return onceChildProcessEvent(
253
+ childProcess,
254
+ "exit",
255
+ (code, signal) => {
256
+ cb({ code, signal });
257
+ },
258
+ );
259
+ },
260
+ execution_internal_error: (cb) => {
261
+ executionInternalErrorCallback = cb;
262
+ },
263
+ execution_completed: (cb) => {
264
+ executionCompletedCallback = cb;
265
+ },
266
+ },
267
+ resolve,
268
+ );
269
+ });
270
+ const raceHandlers = {
271
+ aborted: () => {
272
+ result.status = "aborted";
273
+ },
274
+ error: (error) => {
275
+ removeOutputListener();
276
+ result.status = "failed";
277
+ result.errors.push(error);
278
+ },
279
+ exit: ({ code }) => {
280
+ onRuntimeStopped();
281
+ if (code === 12) {
282
+ result.status = "failed";
283
+ result.errors.push(
284
+ new Error(
285
+ `node process exited with 12 (the forked child process wanted to use a non-available port for debug)`,
286
+ ),
287
+ );
288
+ return;
289
+ }
290
+ if (code === null || code === 0) {
291
+ result.status = "completed";
292
+ result.namespace = {};
293
+ return;
294
+ }
295
+ if (
296
+ code === EXIT_CODES.SIGINT ||
297
+ code === EXIT_CODES.SIGTERM ||
298
+ code === EXIT_CODES.SIGABORT
299
+ ) {
300
+ result.status = "failed";
301
+ result.errors.push(
302
+ new Error(`node process exited during execution`),
303
+ );
304
+ return;
305
+ }
306
+ // process.exit(1) in child process or process.exitCode = 1 + process.exit()
307
+ // means there was an error even if we don't know exactly what.
308
+ result.status = "failed";
309
+ result.errors.push(
310
+ new Error(
311
+ `node process exited with code ${code} during execution`,
312
+ ),
313
+ );
314
+ },
315
+ execution_internal_error: (error) => {
316
+ result.status = "failed";
317
+ result.errors.push(error);
318
+ },
319
+ execution_completed: ({
320
+ status,
321
+ errors,
322
+ namespace,
323
+ timings,
324
+ memoryUsage,
325
+ performance,
326
+ coverage,
327
+ }) => {
328
+ result.status = status;
329
+ result.errors = errors;
330
+ result.namespace = namespace;
331
+ result.timings = timings;
332
+ result.memoryUsage = memoryUsage;
333
+ result.performance = performance;
334
+ result.coverage = coverage;
335
+ },
336
+ };
216
337
  actionOperation.throwIfAborted();
217
338
  await childProcessReadyPromise;
218
339
  actionOperation.throwIfAborted();
219
- await sendToChildProcess(childProcess, {
220
- type: "action",
221
- data: {
222
- actionType: "execute-using-dynamic-import",
223
- actionParams: {
340
+ if (onMeasureMemoryAvailable) {
341
+ onMeasureMemoryAvailable(async () => {
342
+ let _resolve;
343
+ const memoryUsagePromise = new Promise((resolve) => {
344
+ _resolve = resolve;
345
+ });
346
+ await requestActionOnChildProcess(
347
+ childProcess,
348
+ {
349
+ type: "measure-memory-usage",
350
+ },
351
+ ({ value }) => {
352
+ _resolve(value);
353
+ },
354
+ );
355
+ return memoryUsagePromise;
356
+ });
357
+ }
358
+ await requestActionOnChildProcess(
359
+ childProcess,
360
+ {
361
+ type: "execute-using-dynamic-import",
362
+ params: {
224
363
  rootDirectoryUrl,
225
364
  fileUrl: new URL(fileRelativeUrl, rootDirectoryUrl).href,
365
+ measureMemoryUsage,
226
366
  collectPerformance,
227
367
  coverageEnabled,
228
- coverageConfig,
368
+ coverageInclude,
229
369
  coverageMethodForNodeJs,
230
370
  coverageFileUrl,
231
371
  exitAfterAction: true,
232
372
  },
233
373
  },
234
- });
374
+ ({ status, value }) => {
375
+ if (status === "error") {
376
+ executionInternalErrorCallback(value);
377
+ } else {
378
+ executionCompletedCallback(value);
379
+ }
380
+ },
381
+ );
235
382
  const winner = await winnerPromise;
236
- if (winner.name === "aborted") {
237
- result.status = "aborted";
238
- return;
239
- }
240
- if (winner.name === "error") {
241
- const error = winner.data;
242
- removeOutputListener();
243
- result.status = "failed";
244
- result.errors.push(error);
245
- return;
246
- }
247
- if (winner.name === "exit") {
248
- const { code } = winner.data;
249
- await cleanup("process exit");
250
- if (code === 12) {
251
- result.status = "failed";
252
- result.errors.push(
253
- new Error(
254
- `node process exited with 12 (the forked child process wanted to use a non-available port for debug)`,
255
- ),
256
- );
257
- return;
258
- }
259
- if (code === null || code === 0) {
260
- result.status = "completed";
261
- result.namespace = {};
262
- return;
263
- }
264
- if (
265
- code === EXIT_CODES.SIGINT ||
266
- code === EXIT_CODES.SIGTERM ||
267
- code === EXIT_CODES.SIGABORT
268
- ) {
269
- result.status = "failed";
270
- result.errors.push(
271
- new Error(`node process exited during execution`),
272
- );
273
- return;
274
- }
275
- // process.exit(1) in child process or process.exitCode = 1 + process.exit()
276
- // means there was an error even if we don't know exactly what.
277
- result.status = "failed";
278
- result.errors.push(
279
- new Error(`node process exited with code ${code} during execution`),
280
- );
281
- return;
282
- }
283
- const { status, value } = winner.data;
284
- if (status === "action-failed") {
285
- result.status = "failed";
286
- result.errors.push(value);
287
- return;
288
- }
289
- const { namespace, performance, coverage } = value;
290
- result.status = "completed";
291
- result.namespace = namespace;
292
- result.performance = performance;
293
- result.coverage = coverage;
294
- };
295
-
296
- try {
297
- await writeResult();
383
+ raceHandlers[winner.name](winner.data);
298
384
  } catch (e) {
299
385
  result.status = "failed";
300
386
  result.errors.push(e);
387
+ } finally {
388
+ if (keepRunning) {
389
+ stopSignal.notify = stop;
390
+ } else {
391
+ await stop({
392
+ gracefulStopAllocatedMs,
393
+ });
394
+ onRuntimeStopped();
395
+ }
396
+ await actionOperation.end();
397
+ await cleanup();
398
+ return result;
301
399
  }
302
- if (keepRunning) {
303
- stopSignal.notify = stop;
304
- } else {
305
- await stop({
306
- gracefulStopAllocatedMs,
307
- });
308
- }
309
- await actionOperation.end();
310
- return result;
311
400
  },
312
401
  };
313
402
  };
314
403
 
315
- // http://man7.org/linux/man-pages/man7/signal.7.html
316
- // https:// github.com/nodejs/node/blob/1d9511127c419ec116b3ddf5fc7a59e8f0f1c1e4/lib/internal/child_process.js#L472
317
- const GRACEFUL_STOP_SIGNAL = "SIGTERM";
318
- const STOP_SIGNAL = "SIGKILL";
319
- // it would be more correct if GRACEFUL_STOP_FAILED_SIGNAL was SIGHUP instead of SIGKILL.
320
- // but I'm not sure and it changes nothing so just use SIGKILL
321
- const GRACEFUL_STOP_FAILED_SIGNAL = "SIGKILL";
404
+ let previousId = 0;
405
+ const requestActionOnChildProcess = async (
406
+ childProcess,
407
+ { type, params },
408
+ onResponse,
409
+ ) => {
410
+ const actionId = previousId + 1;
411
+ previousId = actionId;
322
412
 
323
- const sendToChildProcess = async (childProcess, { type, data }) => {
324
- return new Promise((resolve, reject) => {
413
+ const removeMessageListener = onChildProcessMessage(
414
+ childProcess,
415
+ "action-result",
416
+ ({ id, ...payload }) => {
417
+ if (id === actionId) {
418
+ removeMessageListener();
419
+ onResponse(payload);
420
+ }
421
+ },
422
+ );
423
+
424
+ const sendPromise = new Promise((resolve, reject) => {
325
425
  childProcess.send(
326
426
  {
327
- jsenv: true,
328
- type,
329
- data,
427
+ __jsenv__: "action",
428
+ data: {
429
+ id: actionId,
430
+ type,
431
+ params,
432
+ },
330
433
  },
331
434
  (error) => {
332
435
  if (error) {
@@ -337,8 +440,17 @@ const sendToChildProcess = async (childProcess, { type, data }) => {
337
440
  },
338
441
  );
339
442
  });
443
+ await sendPromise;
340
444
  };
341
445
 
446
+ // http://man7.org/linux/man-pages/man7/signal.7.html
447
+ // https:// github.com/nodejs/node/blob/1d9511127c419ec116b3ddf5fc7a59e8f0f1c1e4/lib/internal/child_process.js#L472
448
+ const GRACEFUL_STOP_SIGNAL = "SIGTERM";
449
+ const STOP_SIGNAL = "SIGKILL";
450
+ // it would be more correct if GRACEFUL_STOP_FAILED_SIGNAL was SIGHUP instead of SIGKILL.
451
+ // but I'm not sure and it changes nothing so just use SIGKILL
452
+ const GRACEFUL_STOP_FAILED_SIGNAL = "SIGKILL";
453
+
342
454
  const installChildProcessOutputListener = (childProcess, callback) => {
343
455
  // beware that we may receive ansi output here, should not be a problem but keep that in mind
344
456
  const stdoutDataCallback = (chunk) => {
@@ -351,14 +463,13 @@ const installChildProcessOutputListener = (childProcess, callback) => {
351
463
  childProcess.stderr.on("data", stdErrorDataCallback);
352
464
  return () => {
353
465
  childProcess.stdout.removeListener("data", stdoutDataCallback);
354
- childProcess.stderr.removeListener("data", stdoutDataCallback);
466
+ childProcess.stderr.removeListener("data", stdErrorDataCallback);
355
467
  };
356
468
  };
357
469
 
358
- const onceChildProcessMessage = (childProcess, type, callback) => {
470
+ const onChildProcessMessage = (childProcess, type, callback) => {
359
471
  const onmessage = (message) => {
360
- if (message && message.jsenv && message.type === type) {
361
- childProcess.removeListener("message", onmessage);
472
+ if (message && message.__jsenv__ === type) {
362
473
  callback(message.data ? JSON.parse(message.data) : "");
363
474
  }
364
475
  };