@jsenv/test 1.6.9 → 1.7.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.
@@ -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,92 @@ 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
+ message += label;
122
+ Object.keys(details).forEach((key) => {
123
+ message += `
124
+ ${key}: ${details[key]}`;
125
+ });
126
+ if (consoleOutput) {
127
+ message += `\n${consoleOutput}`;
128
+ }
129
+ if (errorsOutput) {
130
+ message += `\n${errorsOutput}`;
131
+ }
132
+ return message;
133
+ };
134
+
135
+ export const formatExecutionLabel = (
136
+ {
137
+ executionIndex,
138
+ executionParams,
139
+ executionResult,
140
+ timeEllapsed,
141
+ memoryHeap,
142
+ counters,
143
+ },
144
+ { logTimeUsage, logMemoryHeapUsage } = {},
145
+ ) => {
146
+ const { status } = executionResult;
147
+ const descriptionFormatter = descriptionFormatters[status];
148
+ const description = descriptionFormatter({
149
+ index: executionIndex,
150
+ total: counters.total,
151
+ executionParams,
152
+ });
153
+ const intermediateSummaryText = createIntermediateSummary({
154
+ executionIndex,
155
+ counters,
156
+ timeEllapsed,
157
+ memoryHeap,
158
+ logTimeUsage,
159
+ logMemoryHeapUsage,
160
+ });
161
+ return `${description}${intermediateSummaryText}`;
162
+ };
163
+
89
164
  const formatErrors = (errors) => {
90
165
  if (errors.length === 0) {
91
166
  return "";
92
167
  }
93
- const formatError = (error) => error.stack || error.message || error;
168
+ const formatError = (error) => {
169
+ if (error === null || error === undefined) {
170
+ return String(error);
171
+ }
172
+ if (error) {
173
+ return error.stack || error.message || error;
174
+ }
175
+ return error;
176
+ };
94
177
 
95
178
  if (errors.length === 1) {
96
179
  return `${ANSI.color(`-------- error --------`, ANSI.RED)}
@@ -113,13 +196,17 @@ ${output.join(`\n`)}
113
196
  ${ANSI.color(`-------------------------`, ANSI.RED)}`;
114
197
  };
115
198
 
116
- export const createSummaryLog = (
199
+ export const formatSummaryLog = (
117
200
  summary,
118
201
  ) => `-------------- summary -----------------
119
- ${createAllExecutionsSummary(summary)}
120
- total duration: ${msAsDuration(summary.duration)}
202
+ ${formatSummary(summary)}
121
203
  ----------------------------------------`;
122
204
 
205
+ export const formatSummary = (summary) => `${createAllExecutionsSummary(
206
+ summary,
207
+ )}
208
+ total duration: ${msAsDuration(summary.duration)}`;
209
+
123
210
  const createAllExecutionsSummary = ({ counters }) => {
124
211
  if (counters.total === 0) {
125
212
  return `no execution`;
@@ -136,6 +223,8 @@ const createIntermediateSummary = ({
136
223
  counters,
137
224
  memoryHeap,
138
225
  timeEllapsed,
226
+ logTimeUsage,
227
+ logMemoryHeapUsage,
139
228
  }) => {
140
229
  const parts = [];
141
230
  if (executionIndex > 0 || counters.done > 0) {
@@ -148,10 +237,10 @@ const createIntermediateSummary = ({
148
237
  }),
149
238
  );
150
239
  }
151
- if (timeEllapsed) {
240
+ if (logTimeUsage && timeEllapsed) {
152
241
  parts.push(`duration: ${msAsEllapsedTime(timeEllapsed)}`);
153
242
  }
154
- if (memoryHeap) {
243
+ if (logMemoryHeapUsage && memoryHeap) {
155
244
  parts.push(`memory heap: ${byteAsMemoryUsage(memoryHeap)}`);
156
245
  }
157
246
  if (parts.length === 0) {
@@ -404,24 +493,3 @@ const formatConsoleSummary = (repartition) => {
404
493
  }
405
494
  return `console (${parts.join(" ")})`;
406
495
  };
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
- }