@jsenv/test 1.6.9 → 1.7.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.
@@ -19,53 +19,55 @@ export const createExecutionLog = (
19
19
  executionResult,
20
20
  startMs,
21
21
  endMs,
22
+ nowMs,
23
+ timeEllapsed,
24
+ memoryHeap,
25
+ counters,
22
26
  },
23
27
  {
24
28
  logShortForCompletedExecutions,
25
- counters,
26
29
  logRuntime,
27
30
  logEachDuration,
28
- timeEllapsed,
29
- memoryHeap,
31
+ logTimeUsage,
32
+ logMemoryHeapUsage,
30
33
  },
31
34
  ) => {
35
+ const label = formatExecutionLabel(
36
+ {
37
+ executionIndex,
38
+ executionParams,
39
+ executionResult,
40
+ timeEllapsed,
41
+ memoryHeap,
42
+ counters,
43
+ },
44
+ {
45
+ logTimeUsage,
46
+ logMemoryHeapUsage,
47
+ },
48
+ );
49
+
32
50
  const { status } = executionResult;
33
- const descriptionFormatter = descriptionFormatters[status];
34
- const description = descriptionFormatter({
35
- index: executionIndex,
36
- total: counters.total,
37
- executionParams,
38
- });
39
- const summary = createIntermediateSummary({
40
- executionIndex,
41
- counters,
42
- timeEllapsed,
43
- memoryHeap,
44
- });
45
51
  let log;
46
52
  if (logShortForCompletedExecutions && status === "completed") {
47
- log = `${description}${summary}`;
53
+ log = label;
48
54
  } else {
49
- const { consoleCalls = [], errors = [] } = executionResult;
50
- const consoleOutput = formatConsoleCalls(consoleCalls);
51
- const errorsOutput = formatErrors(errors);
52
- log = formatExecution({
53
- label: `${description}${summary}`,
54
- details: {
55
- file: fileRelativeUrl,
56
- ...(logRuntime ? { runtime: `${runtimeName}/${runtimeVersion}` } : {}),
57
- ...(logEachDuration
58
- ? {
59
- duration:
60
- status === "executing"
61
- ? msAsEllapsedTime(Date.now() - startMs)
62
- : msAsDuration(endMs - startMs),
63
- }
64
- : {}),
55
+ log = formatExecution(
56
+ {
57
+ fileRelativeUrl,
58
+ runtimeName,
59
+ runtimeVersion,
60
+ executionResult,
61
+ startMs,
62
+ endMs,
63
+ nowMs,
65
64
  },
66
- consoleOutput,
67
- errorsOutput,
68
- });
65
+ {
66
+ label,
67
+ logRuntime,
68
+ logEachDuration,
69
+ },
70
+ );
69
71
  }
70
72
 
71
73
  const { columns = 80 } = process.stdout;
@@ -86,11 +88,96 @@ export const createExecutionLog = (
86
88
  return log;
87
89
  };
88
90
 
91
+ export const formatExecution = (
92
+ {
93
+ fileRelativeUrl,
94
+ runtimeName,
95
+ runtimeVersion,
96
+ executionResult,
97
+ startMs,
98
+ endMs,
99
+ nowMs,
100
+ },
101
+ { label, logRuntime = true, logEachDuration = true } = {},
102
+ ) => {
103
+ const { status } = executionResult;
104
+ const { consoleCalls = [], errors = [] } = executionResult;
105
+ const consoleOutput = formatConsoleCalls(consoleCalls);
106
+ const errorsOutput = formatErrors(errors);
107
+
108
+ const details = {
109
+ file: fileRelativeUrl,
110
+ ...(logRuntime ? { runtime: `${runtimeName}/${runtimeVersion}` } : {}),
111
+ ...(logEachDuration
112
+ ? {
113
+ duration:
114
+ status === "executing"
115
+ ? msAsEllapsedTime((nowMs || Date.now()) - startMs)
116
+ : msAsDuration(endMs - startMs),
117
+ }
118
+ : {}),
119
+ };
120
+ let message = ``;
121
+ if (label) {
122
+ message += label;
123
+ }
124
+ Object.keys(details).forEach((key) => {
125
+ if (message.length > 0) {
126
+ message += "\n";
127
+ }
128
+ message += `${key}: ${details[key]}`;
129
+ });
130
+ if (consoleOutput) {
131
+ message += `\n${consoleOutput}`;
132
+ }
133
+ if (errorsOutput) {
134
+ message += `\n${errorsOutput}`;
135
+ }
136
+ return message;
137
+ };
138
+
139
+ export const formatExecutionLabel = (
140
+ {
141
+ executionIndex,
142
+ executionParams,
143
+ executionResult,
144
+ timeEllapsed,
145
+ memoryHeap,
146
+ counters,
147
+ },
148
+ { logTimeUsage, logMemoryHeapUsage } = {},
149
+ ) => {
150
+ const { status } = executionResult;
151
+ const descriptionFormatter = descriptionFormatters[status];
152
+ const description = descriptionFormatter({
153
+ index: executionIndex,
154
+ total: counters.total,
155
+ executionParams,
156
+ });
157
+ const intermediateSummaryText = createIntermediateSummary({
158
+ executionIndex,
159
+ counters,
160
+ timeEllapsed,
161
+ memoryHeap,
162
+ logTimeUsage,
163
+ logMemoryHeapUsage,
164
+ });
165
+ return `${description}${intermediateSummaryText}`;
166
+ };
167
+
89
168
  const formatErrors = (errors) => {
90
169
  if (errors.length === 0) {
91
170
  return "";
92
171
  }
93
- const formatError = (error) => error.stack || error.message || error;
172
+ const formatError = (error) => {
173
+ if (error === null || error === undefined) {
174
+ return String(error);
175
+ }
176
+ if (error) {
177
+ return error.stack || error.message || error;
178
+ }
179
+ return error;
180
+ };
94
181
 
95
182
  if (errors.length === 1) {
96
183
  return `${ANSI.color(`-------- error --------`, ANSI.RED)}
@@ -113,13 +200,17 @@ ${output.join(`\n`)}
113
200
  ${ANSI.color(`-------------------------`, ANSI.RED)}`;
114
201
  };
115
202
 
116
- export const createSummaryLog = (
203
+ export const formatSummaryLog = (
117
204
  summary,
118
205
  ) => `-------------- summary -----------------
119
- ${createAllExecutionsSummary(summary)}
120
- total duration: ${msAsDuration(summary.duration)}
206
+ ${formatSummary(summary)}
121
207
  ----------------------------------------`;
122
208
 
209
+ export const formatSummary = (summary) => `${createAllExecutionsSummary(
210
+ summary,
211
+ )}
212
+ total duration: ${msAsDuration(summary.duration)}`;
213
+
123
214
  const createAllExecutionsSummary = ({ counters }) => {
124
215
  if (counters.total === 0) {
125
216
  return `no execution`;
@@ -136,6 +227,8 @@ const createIntermediateSummary = ({
136
227
  counters,
137
228
  memoryHeap,
138
229
  timeEllapsed,
230
+ logTimeUsage,
231
+ logMemoryHeapUsage,
139
232
  }) => {
140
233
  const parts = [];
141
234
  if (executionIndex > 0 || counters.done > 0) {
@@ -148,10 +241,10 @@ const createIntermediateSummary = ({
148
241
  }),
149
242
  );
150
243
  }
151
- if (timeEllapsed) {
244
+ if (logTimeUsage && timeEllapsed) {
152
245
  parts.push(`duration: ${msAsEllapsedTime(timeEllapsed)}`);
153
246
  }
154
- if (memoryHeap) {
247
+ if (logMemoryHeapUsage && memoryHeap) {
155
248
  parts.push(`memory heap: ${byteAsMemoryUsage(memoryHeap)}`);
156
249
  }
157
250
  if (parts.length === 0) {
@@ -404,24 +497,3 @@ const formatConsoleSummary = (repartition) => {
404
497
  }
405
498
  return `console (${parts.join(" ")})`;
406
499
  };
407
-
408
- const formatExecution = ({
409
- label,
410
- details = {},
411
- consoleOutput,
412
- errorsOutput,
413
- }) => {
414
- let message = ``;
415
- message += label;
416
- Object.keys(details).forEach((key) => {
417
- message += `
418
- ${key}: ${details[key]}`;
419
- });
420
- if (consoleOutput) {
421
- message += `\n${consoleOutput}`;
422
- }
423
- if (errorsOutput) {
424
- message += `\n${errorsOutput}`;
425
- }
426
- return message;
427
- };
@@ -402,15 +402,9 @@ export const createRuntimeUsingPlaywright = ({
402
402
  if (executionResult.status === "failed") {
403
403
  result.status = "failed";
404
404
  if (executionResult.exception) {
405
- result.errors.push({
406
- ...executionResult.exception,
407
- stack: executionResult.exception.text,
408
- });
405
+ result.errors.push(executionResult.exception);
409
406
  } else {
410
- result.errors.push({
411
- ...executionResult.error,
412
- stack: executionResult.error.stack,
413
- });
407
+ result.errors.push(executionResult.error);
414
408
  }
415
409
  }
416
410
  });
@@ -15,8 +15,8 @@ import { EXIT_CODES } from "./exit_codes.js";
15
15
  import { IMPORTMAP_NODE_LOADER_FILE_URL } from "./importmap_node_loader_file_url.js";
16
16
  import { NO_EXPERIMENTAL_WARNING_FILE_URL } from "./no_experimental_warnings_file_url.js";
17
17
 
18
- const CONTROLLABLE_CHILD_PROCESS_URL = new URL(
19
- "./controllable_child_process.mjs?entry_point",
18
+ const CONTROLLED_CHILD_PROCESS_URL = new URL(
19
+ "./node_child_process_controlled.mjs?entry_point",
20
20
  import.meta.url,
21
21
  ).href;
22
22
 
@@ -103,10 +103,10 @@ export const nodeChildProcess = ({
103
103
  };
104
104
  logger[logProcessCommand ? "info" : "debug"](
105
105
  `${process.argv[0]} ${execArgv.join(" ")} ${fileURLToPath(
106
- CONTROLLABLE_CHILD_PROCESS_URL,
106
+ CONTROLLED_CHILD_PROCESS_URL,
107
107
  )}`,
108
108
  );
109
- const childProcess = fork(fileURLToPath(CONTROLLABLE_CHILD_PROCESS_URL), {
109
+ const childProcess = fork(fileURLToPath(CONTROLLED_CHILD_PROCESS_URL), {
110
110
  execArgv,
111
111
  // silent: true
112
112
  stdio: ["pipe", "pipe", "pipe", "ipc"],
@@ -356,8 +356,7 @@ const onceChildProcessMessage = (childProcess, type, callback) => {
356
356
  const onmessage = (message) => {
357
357
  if (message && message.jsenv && message.type === type) {
358
358
  childProcess.removeListener("message", onmessage);
359
- // eslint-disable-next-line no-eval
360
- callback(message.data ? eval(`(${message.data})`) : "");
359
+ callback(message.data ? JSON.parse(message.data) : "");
361
360
  }
362
361
  };
363
362
  childProcess.on("message", onmessage);
@@ -1,5 +1,4 @@
1
- import { uneval } from "@jsenv/uneval";
2
-
1
+ import { createException } from "../execution/exception.js";
3
2
  import { executeUsingDynamicImport } from "./execute_using_dynamic_import.js";
4
3
 
5
4
  const ACTIONS_AVAILABLE = {
@@ -27,20 +26,13 @@ const ACTION_RESPONSE_STATUS_FAILED = "action-failed";
27
26
  const ACTION_RESPONSE_STATUS_COMPLETED = "action-completed";
28
27
 
29
28
  const sendActionFailed = (error) => {
30
- if (error.hasOwnProperty("toString")) {
31
- delete error.toString;
32
- }
29
+ const exception = createException(error);
33
30
  sendToParent(
34
31
  ACTION_RESPONSE_EVENT_NAME,
35
- // process.send algorithm does not send non enumerable values
36
- // so use @jsenv/uneval
37
- uneval(
38
- {
39
- status: ACTION_RESPONSE_STATUS_FAILED,
40
- value: error,
41
- },
42
- { ignoreSymbols: true },
43
- ),
32
+ JSON.stringify({
33
+ status: ACTION_RESPONSE_STATUS_FAILED,
34
+ value: exception,
35
+ }),
44
36
  );
45
37
  };
46
38
 
@@ -16,8 +16,8 @@ import { EXIT_CODES } from "./exit_codes.js";
16
16
  import { IMPORTMAP_NODE_LOADER_FILE_URL } from "./importmap_node_loader_file_url.js";
17
17
  import { NO_EXPERIMENTAL_WARNING_FILE_URL } from "./no_experimental_warnings_file_url.js";
18
18
 
19
- const CONTROLLABLE_WORKER_THREAD_URL = new URL(
20
- "./controllable_worker_thread.mjs?entry_point",
19
+ const CONTROLLED_WORKER_THREAD_URL = new URL(
20
+ "./node_worker_thread_controlled.mjs?entry_point",
21
21
  import.meta.url,
22
22
  ).href;
23
23
 
@@ -94,7 +94,7 @@ export const nodeWorkerThread = ({
94
94
  actionOperation.addAbortSignal(signal);
95
95
  // https://nodejs.org/api/worker_threads.html#new-workerfilename-options
96
96
  const workerThread = new Worker(
97
- fileURLToPath(CONTROLLABLE_WORKER_THREAD_URL),
97
+ fileURLToPath(CONTROLLED_WORKER_THREAD_URL),
98
98
  {
99
99
  env: envForWorkerThread,
100
100
  execArgv: execArgvForWorkerThread,
@@ -281,8 +281,7 @@ const onceWorkerThreadMessage = (workerThread, type, callback) => {
281
281
  const onmessage = (message) => {
282
282
  if (message && message.jsenv && message.type === type) {
283
283
  workerThread.removeListener("message", onmessage);
284
- // eslint-disable-next-line no-eval
285
- callback(message.data ? eval(`(${message.data})`) : undefined);
284
+ callback(message.data ? JSON.parse(message.data) : undefined);
286
285
  }
287
286
  };
288
287
  workerThread.on("message", onmessage);
@@ -1,6 +1,6 @@
1
1
  import { parentPort } from "node:worker_threads";
2
- import { uneval } from "@jsenv/uneval";
3
2
 
3
+ import { createException } from "../execution/exception.js";
4
4
  import { executeUsingDynamicImport } from "./execute_using_dynamic_import.js";
5
5
 
6
6
  const ACTIONS_AVAILABLE = {
@@ -12,20 +12,13 @@ const ACTION_RESPONSE_STATUS_FAILED = "action-failed";
12
12
  const ACTION_RESPONSE_STATUS_COMPLETED = "action-completed";
13
13
 
14
14
  const sendActionFailed = (error) => {
15
- if (error.hasOwnProperty("toString")) {
16
- delete error.toString;
17
- }
15
+ const exception = createException(error);
18
16
  sendToParent(
19
17
  ACTION_RESPONSE_EVENT_NAME,
20
- // process.send algorithm does not send non enumerable values
21
- // so use @jsenv/uneval
22
- uneval(
23
- {
24
- status: ACTION_RESPONSE_STATUS_FAILED,
25
- value: error,
26
- },
27
- { ignoreSymbols: true },
28
- ),
18
+ JSON.stringify({
19
+ status: ACTION_RESPONSE_STATUS_FAILED,
20
+ value: exception,
21
+ }),
29
22
  );
30
23
  };
31
24
 
@@ -1,41 +0,0 @@
1
- import { assert } from "@jsenv/assert";
2
-
3
- import { formatConsoleOutput } from "./logs_file_execution.js";
4
-
5
- {
6
- const actual = formatConsoleOutput([
7
- { type: "log", text: "a\n" },
8
- { type: "log", text: "b\n" },
9
- ]);
10
- const expected = ` a
11
- b`;
12
- assert({ actual, expected });
13
- }
14
-
15
- {
16
- const actual = formatConsoleOutput([
17
- { type: "log", text: "a" },
18
- { type: "log", text: "b" },
19
- ]);
20
- const expected = ` ab`;
21
- assert({ actual, expected });
22
- }
23
-
24
- {
25
- const actual = formatConsoleOutput([
26
- {
27
- type: "log",
28
- text: `1
29
- 2`,
30
- },
31
- {
32
- type: "log",
33
- text: `alpha
34
- beta`,
35
- },
36
- ]);
37
- const expected = ` 1
38
- 2alpha
39
- beta`;
40
- assert({ actual, expected });
41
- }