@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.
- package/README.md +2 -1
- package/dist/js/exception.js +908 -0
- package/dist/js/execute_using_dynamic_import.js +76 -167
- package/dist/js/v8_coverage.js +4 -482
- package/dist/jsenv_test.js +4608 -2917
- package/dist/node_child_process_controlled.mjs +95 -76
- package/dist/node_worker_thread_controlled.mjs +72 -54
- package/package.json +23 -14
- package/src/coverage/generate_coverage.js +186 -0
- package/src/coverage/list_files_not_covered.js +2 -2
- package/src/coverage/missing_coverage.js +2 -2
- package/src/coverage/report_coverage_as_html.js +45 -0
- package/src/coverage/report_coverage_as_json.js +20 -0
- package/src/coverage/{coverage_reporter_text_log.js → report_coverage_in_console.js} +13 -7
- package/src/coverage/v8_and_istanbul.js +4 -4
- package/src/coverage/v8_coverage.js +2 -2
- package/src/execution/exception.js +151 -68
- package/src/execution/execute.js +24 -11
- package/src/execution/execute_test_plan.js +834 -750
- package/src/execution/format_error_for_terminal.js +187 -0
- package/src/execution/github_annotation_from_error.js +3 -3
- package/src/execution/junit_xml_file/report_as_junit_xml.js +149 -0
- package/src/execution/junit_xml_file/xml_generator.js +141 -0
- package/src/execution/reporters/reporter_list.js +687 -0
- package/src/execution/run.js +92 -30
- package/src/execution/web_server/start_using_command.js +2 -2
- package/src/execution/web_server_param.js +5 -5
- package/src/helpers/cpu_usage.js +142 -0
- package/src/helpers/cpu_usage.test_manual.js +7 -0
- package/src/main.js +8 -0
- package/src/runtime_browsers/chromium.js +1 -3
- package/src/runtime_browsers/firefox.js +0 -3
- package/src/runtime_browsers/middleware_istanbul.js +2 -2
- package/src/runtime_browsers/using_playwright.js +296 -220
- package/src/runtime_browsers/webkit.js +0 -3
- package/src/runtime_node/execute_using_dynamic_import.js +75 -28
- package/src/runtime_node/node_child_process.js +250 -139
- package/src/runtime_node/node_child_process_controlled.mjs +94 -75
- package/src/runtime_node/node_worker_thread.js +206 -120
- package/src/runtime_node/node_worker_thread_controlled.mjs +70 -53
- package/src/coverage/coverage_reporter_html_directory.js +0 -32
- package/src/coverage/coverage_reporter_json_file.js +0 -17
- package/src/coverage/report_to_coverage.js +0 -198
- package/src/execution/execution_colors.js +0 -10
- package/src/execution/execution_steps.js +0 -65
- package/src/execution/logs_file_execution.js +0 -495
|
@@ -1,144 +1,8 @@
|
|
|
1
1
|
import { writeFileSync } from "node:fs";
|
|
2
|
+
import { memoryUsage } from "node:process";
|
|
2
3
|
import { Session } from "node:inspector";
|
|
3
4
|
import { PerformanceObserver, performance } from "node:perf_hooks";
|
|
4
|
-
|
|
5
|
-
/*
|
|
6
|
-
* Exception are objects used to wrap a value that is thrown
|
|
7
|
-
* Usually they wrap error but the value can be anything as
|
|
8
|
-
* throw "toto" can be used in JS
|
|
9
|
-
*
|
|
10
|
-
* - provide a common API to interact with value that can be thrown
|
|
11
|
-
* - enrich usual errors with a bit more information (line, column)
|
|
12
|
-
* - normalize error properties
|
|
13
|
-
* - exception.stackTrace: only the stack trace as string (no error.name or error.message)
|
|
14
|
-
* - error.stack: error.name + error.message + error.stackTrace
|
|
15
|
-
*
|
|
16
|
-
* It is used mostly internally by jsenv but can also be found
|
|
17
|
-
* value returned by "executeTestPlan" public export (for failed executions)
|
|
18
|
-
* and value returned by "execute" public export (when execution fails)
|
|
19
|
-
*
|
|
20
|
-
* This file is responsible to wrap error hapenning in Node.js runtime
|
|
21
|
-
* The browser part can be found in "supervisor.js"
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
const createException = (reason) => {
|
|
25
|
-
const exception = {
|
|
26
|
-
isException: true,
|
|
27
|
-
isError: false,
|
|
28
|
-
name: "",
|
|
29
|
-
message: "",
|
|
30
|
-
stack: "",
|
|
31
|
-
stackTrace: "",
|
|
32
|
-
site: null,
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
if (reason === undefined) {
|
|
36
|
-
exception.message = "undefined";
|
|
37
|
-
return exception;
|
|
38
|
-
}
|
|
39
|
-
if (reason === undefined) {
|
|
40
|
-
exception.message = "undefined";
|
|
41
|
-
return exception;
|
|
42
|
-
}
|
|
43
|
-
if (typeof reason === "string") {
|
|
44
|
-
exception.message = reason;
|
|
45
|
-
return exception;
|
|
46
|
-
}
|
|
47
|
-
if (reason instanceof Error) {
|
|
48
|
-
exception.isError = true;
|
|
49
|
-
exception.name = reason.name;
|
|
50
|
-
exception.message = reason.message;
|
|
51
|
-
const stackInfo = getStackInfo(reason);
|
|
52
|
-
if (stackInfo) {
|
|
53
|
-
const { stackTrace, stackObject } = stackInfo;
|
|
54
|
-
exception.stackTrace = stackTrace;
|
|
55
|
-
const [firstCallSite] = stackObject;
|
|
56
|
-
writePropertiesFromCallSite(exception, firstCallSite);
|
|
57
|
-
}
|
|
58
|
-
exception.stack = reason.stack;
|
|
59
|
-
return exception;
|
|
60
|
-
}
|
|
61
|
-
if (typeof reason === "object") {
|
|
62
|
-
exception.code = reason.code;
|
|
63
|
-
exception.message = reason.message;
|
|
64
|
-
exception.stack = reason.stack;
|
|
65
|
-
return exception;
|
|
66
|
-
}
|
|
67
|
-
exception.message = JSON.stringify(reason);
|
|
68
|
-
return exception;
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
const getStackInfo = (reason) => {
|
|
72
|
-
if (reason instanceof Error) {
|
|
73
|
-
const { prepareStackTrace } = Error;
|
|
74
|
-
let stackTrace;
|
|
75
|
-
let stackObject;
|
|
76
|
-
Error.prepareStackTrace = (e, secondArg) => {
|
|
77
|
-
Error.prepareStackTrace = prepareStackTrace;
|
|
78
|
-
stackObject = secondArg;
|
|
79
|
-
stackTrace = secondArg.map((callSite) => ` at ${callSite}`).join("\n");
|
|
80
|
-
const name = e.name || "Error";
|
|
81
|
-
const message = e.message || "";
|
|
82
|
-
let stack = `${name}: ${message}`;
|
|
83
|
-
if (stackTrace) {
|
|
84
|
-
stack += `\n${stackTrace}`;
|
|
85
|
-
}
|
|
86
|
-
return stack;
|
|
87
|
-
};
|
|
88
|
-
// eslint-disable-next-line no-unused-expressions
|
|
89
|
-
reason.stack;
|
|
90
|
-
if (stackTrace === undefined) {
|
|
91
|
-
return null;
|
|
92
|
-
}
|
|
93
|
-
return {
|
|
94
|
-
stackTrace,
|
|
95
|
-
stackObject,
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
return null;
|
|
99
|
-
};
|
|
100
|
-
const writePropertiesFromCallSite = (exception, callSite) => {
|
|
101
|
-
const source = callSite.getFileName() || callSite.getScriptNameOrSourceURL();
|
|
102
|
-
if (source) {
|
|
103
|
-
const line = callSite.getLineNumber();
|
|
104
|
-
const column = callSite.getColumnNumber() - 1;
|
|
105
|
-
exception.site = {
|
|
106
|
-
url: source,
|
|
107
|
-
line,
|
|
108
|
-
column,
|
|
109
|
-
};
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
// Code called using eval() needs special handling
|
|
113
|
-
if (callSite.isEval()) {
|
|
114
|
-
const origin = callSite.getEvalOrigin();
|
|
115
|
-
if (origin) {
|
|
116
|
-
writePropertiesFromEvalOrigin(exception, origin);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
const writePropertiesFromEvalOrigin = (exception, origin) => {
|
|
121
|
-
// Most eval() calls are in this format
|
|
122
|
-
const topLevelEvalMatch = /^eval at ([^(]+) \((.+):(\d+):(\d+)\)$/.exec(
|
|
123
|
-
origin,
|
|
124
|
-
);
|
|
125
|
-
if (topLevelEvalMatch) {
|
|
126
|
-
const source = topLevelEvalMatch[2];
|
|
127
|
-
const line = Number(topLevelEvalMatch[3]);
|
|
128
|
-
const column = topLevelEvalMatch[4] - 1;
|
|
129
|
-
exception.site = {
|
|
130
|
-
url: source,
|
|
131
|
-
line,
|
|
132
|
-
column,
|
|
133
|
-
};
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
// Parse nested eval() calls using recursion
|
|
137
|
-
const nestedEvalMatch = /^eval at ([^(]+) \((.+)\)$/.exec(origin);
|
|
138
|
-
if (nestedEvalMatch) {
|
|
139
|
-
writePropertiesFromEvalOrigin(exception, nestedEvalMatch[2]);
|
|
140
|
-
}
|
|
141
|
-
};
|
|
5
|
+
import { createException } from "./exception.js";
|
|
142
6
|
|
|
143
7
|
/*
|
|
144
8
|
* Calling Profiler.startPreciseCoverage DO NOT propagate to
|
|
@@ -265,50 +129,95 @@ const measuresFromMeasureEntries = (measureEntries) => {
|
|
|
265
129
|
const executeUsingDynamicImport = async ({
|
|
266
130
|
rootDirectoryUrl,
|
|
267
131
|
fileUrl,
|
|
132
|
+
measureMemoryUsage,
|
|
268
133
|
collectPerformance,
|
|
269
134
|
coverageEnabled,
|
|
270
|
-
|
|
135
|
+
coverageInclude,
|
|
271
136
|
coverageMethodForNodeJs,
|
|
272
137
|
coverageFileUrl,
|
|
273
138
|
}) => {
|
|
274
|
-
const result = {
|
|
275
|
-
|
|
139
|
+
const result = {
|
|
140
|
+
timings: {
|
|
141
|
+
start: null,
|
|
142
|
+
end: null,
|
|
143
|
+
},
|
|
144
|
+
errors: [],
|
|
145
|
+
namespace: null,
|
|
146
|
+
memoryUsage: null,
|
|
147
|
+
performance: null,
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
let finalizePerformance;
|
|
151
|
+
if (collectPerformance) {
|
|
152
|
+
const getPerformance = startObservingPerformances();
|
|
153
|
+
finalizePerformance = async () => {
|
|
154
|
+
const performance = await getPerformance();
|
|
155
|
+
result.performance = performance;
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
let finalizeCoverage;
|
|
276
160
|
if (coverageEnabled && coverageMethodForNodeJs === "Profiler") {
|
|
277
|
-
const { filterV8Coverage } = await import("./v8_coverage.js").then(n => n.v8_coverage);
|
|
278
161
|
const { stopJsCoverage } = await startJsCoverage();
|
|
279
|
-
|
|
280
|
-
const coverage = await
|
|
162
|
+
finalizeCoverage = async () => {
|
|
163
|
+
const [coverage, { filterV8Coverage }] = await Promise.all([
|
|
164
|
+
stopJsCoverage(),
|
|
165
|
+
import("./v8_coverage.js"),
|
|
166
|
+
]);
|
|
281
167
|
const coverageLight = await filterV8Coverage(coverage, {
|
|
282
168
|
rootDirectoryUrl,
|
|
283
|
-
|
|
169
|
+
coverageInclude,
|
|
284
170
|
});
|
|
285
171
|
writeFileSync(
|
|
286
172
|
new URL(coverageFileUrl),
|
|
287
173
|
JSON.stringify(coverageLight, null, " "),
|
|
288
174
|
);
|
|
289
|
-
}
|
|
175
|
+
};
|
|
290
176
|
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
177
|
+
|
|
178
|
+
let finalizeMemoryUsage;
|
|
179
|
+
if (measureMemoryUsage) {
|
|
180
|
+
global.gc();
|
|
181
|
+
const memoryHeapUsedBeforeExecution = memoryUsage().heapUsed;
|
|
182
|
+
finalizeMemoryUsage = () => {
|
|
183
|
+
global.gc();
|
|
184
|
+
const memoryHeapUsedAfterExecution = memoryUsage().heapUsed;
|
|
185
|
+
result.memoryUsage =
|
|
186
|
+
memoryHeapUsedAfterExecution - memoryHeapUsedBeforeExecution;
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
result.timings.start = Date.now();
|
|
191
|
+
try {
|
|
192
|
+
const namespace = await import(fileUrl);
|
|
193
|
+
const namespaceResolved = {};
|
|
194
|
+
await Promise.all(
|
|
195
|
+
Object.keys(namespace).map(async (key) => {
|
|
196
|
+
const value = await namespace[key];
|
|
197
|
+
namespaceResolved[key] = value;
|
|
198
|
+
}),
|
|
199
|
+
);
|
|
200
|
+
result.status = "completed";
|
|
201
|
+
result.namespace = namespaceResolved;
|
|
202
|
+
} catch (e) {
|
|
203
|
+
result.status = "failed";
|
|
204
|
+
result.errors.push(createException(e, { rootDirectoryUrl }));
|
|
205
|
+
} finally {
|
|
206
|
+
result.timings.end = Date.now();
|
|
207
|
+
if (finalizeCoverage) {
|
|
208
|
+
await finalizeCoverage();
|
|
209
|
+
finalizeCoverage = null;
|
|
210
|
+
}
|
|
211
|
+
if (finalizePerformance) {
|
|
212
|
+
await finalizePerformance();
|
|
213
|
+
finalizePerformance = null;
|
|
214
|
+
}
|
|
215
|
+
if (finalizeMemoryUsage) {
|
|
216
|
+
finalizeMemoryUsage();
|
|
217
|
+
finalizeMemoryUsage = null;
|
|
218
|
+
}
|
|
219
|
+
return result;
|
|
297
220
|
}
|
|
298
|
-
const namespace = await import(fileUrl);
|
|
299
|
-
const namespaceResolved = {};
|
|
300
|
-
await Promise.all(
|
|
301
|
-
Object.keys(namespace).map(async (key) => {
|
|
302
|
-
const value = await namespace[key];
|
|
303
|
-
namespaceResolved[key] = value;
|
|
304
|
-
}),
|
|
305
|
-
);
|
|
306
|
-
result.namespace = namespaceResolved;
|
|
307
|
-
await afterImportCallbacks.reduce(async (previous, afterImportCallback) => {
|
|
308
|
-
await previous;
|
|
309
|
-
await afterImportCallback();
|
|
310
|
-
}, Promise.resolve());
|
|
311
|
-
return result;
|
|
312
221
|
};
|
|
313
222
|
|
|
314
|
-
export {
|
|
223
|
+
export { executeUsingDynamicImport };
|