@jsenv/test 1.0.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.
Files changed (56) hide show
  1. package/dist/controllable_child_process.mjs +129 -0
  2. package/dist/controllable_worker_thread.mjs +91 -0
  3. package/dist/importmap_node_loader.mjs +551 -0
  4. package/dist/js/execute_using_dynamic_import.js +850 -0
  5. package/dist/js/v8_coverage.js +508 -0
  6. package/dist/jsenv_test.js +5993 -0
  7. package/dist/no_experimental_warnings.cjs +10 -0
  8. package/package.json +56 -0
  9. package/src/coverage/babel_plugin_instrument.js +48 -0
  10. package/src/coverage/coverage_reporter_html_directory.js +32 -0
  11. package/src/coverage/coverage_reporter_json_file.js +17 -0
  12. package/src/coverage/coverage_reporter_text_log.js +19 -0
  13. package/src/coverage/empty_coverage_factory.js +52 -0
  14. package/src/coverage/file_by_file_coverage.js +25 -0
  15. package/src/coverage/istanbul_coverage_composition.js +28 -0
  16. package/src/coverage/istanbul_coverage_map_from_coverage.js +16 -0
  17. package/src/coverage/list_files_not_covered.js +15 -0
  18. package/src/coverage/missing_coverage.js +41 -0
  19. package/src/coverage/report_to_coverage.js +198 -0
  20. package/src/coverage/v8_and_istanbul.js +37 -0
  21. package/src/coverage/v8_coverage.js +26 -0
  22. package/src/coverage/v8_coverage_composition.js +24 -0
  23. package/src/coverage/v8_coverage_node_directory.js +85 -0
  24. package/src/coverage/v8_coverage_to_istanbul.js +99 -0
  25. package/src/execution/execute.js +111 -0
  26. package/src/execution/execute_steps.js +423 -0
  27. package/src/execution/execute_test_plan.js +372 -0
  28. package/src/execution/execution_colors.js +10 -0
  29. package/src/execution/execution_steps.js +65 -0
  30. package/src/execution/gc.js +9 -0
  31. package/src/execution/logs_file_execution.js +427 -0
  32. package/src/execution/logs_file_execution.test.mjs +41 -0
  33. package/src/execution/run.js +160 -0
  34. package/src/execution/web_server_param.js +73 -0
  35. package/src/main.js +10 -0
  36. package/src/runtime_browsers/chromium.js +24 -0
  37. package/src/runtime_browsers/firefox.js +23 -0
  38. package/src/runtime_browsers/middleware_istanbul.js +65 -0
  39. package/src/runtime_browsers/middleware_js_supervisor.js +98 -0
  40. package/src/runtime_browsers/using_playwright.js +573 -0
  41. package/src/runtime_browsers/webkit.js +40 -0
  42. package/src/runtime_node/child_exec_options.js +166 -0
  43. package/src/runtime_node/controllable_child_process.mjs +135 -0
  44. package/src/runtime_node/controllable_worker_thread.mjs +103 -0
  45. package/src/runtime_node/exec_options.js +57 -0
  46. package/src/runtime_node/execute_using_dynamic_import.js +53 -0
  47. package/src/runtime_node/exit_codes.js +9 -0
  48. package/src/runtime_node/importmap_node_loader.mjs +51 -0
  49. package/src/runtime_node/importmap_node_loader_file_url.js +4 -0
  50. package/src/runtime_node/kill_process_tree.js +76 -0
  51. package/src/runtime_node/no_experimental_warnings.cjs +13 -0
  52. package/src/runtime_node/no_experimental_warnings_file_url.js +4 -0
  53. package/src/runtime_node/node_child_process.js +374 -0
  54. package/src/runtime_node/node_execution_performance.js +67 -0
  55. package/src/runtime_node/node_worker_thread.js +301 -0
  56. package/src/runtime_node/profiler_v8_coverage.js +56 -0
@@ -0,0 +1,129 @@
1
+ import { uneval, executeUsingDynamicImport } from "./js/execute_using_dynamic_import.js";
2
+ import "node:fs";
3
+ import "node:inspector";
4
+ import "node:perf_hooks";
5
+
6
+ const ACTIONS_AVAILABLE = {
7
+ "execute-using-dynamic-import": executeUsingDynamicImport,
8
+ "execute-using-require": async ({
9
+ fileUrl
10
+ }) => {
11
+ const {
12
+ createRequire
13
+ } = await import("node:module");
14
+ const {
15
+ fileURLToPath
16
+ } = await import("node:url");
17
+ const filePath = fileURLToPath(fileUrl);
18
+ const require = createRequire(fileUrl);
19
+ // eslint-disable-next-line import/no-dynamic-require
20
+ const namespace = require(filePath);
21
+ const namespaceResolved = {};
22
+ await Promise.all(Object.keys(namespace).map(async key => {
23
+ const value = await namespace[key];
24
+ namespaceResolved[key] = value;
25
+ }));
26
+ return namespaceResolved;
27
+ }
28
+ };
29
+ const ACTION_REQUEST_EVENT_NAME = "action";
30
+ const ACTION_RESPONSE_EVENT_NAME = "action-result";
31
+ const ACTION_RESPONSE_STATUS_FAILED = "action-failed";
32
+ const ACTION_RESPONSE_STATUS_COMPLETED = "action-completed";
33
+ const sendActionFailed = error => {
34
+ if (error.hasOwnProperty("toString")) {
35
+ delete error.toString;
36
+ }
37
+ sendToParent(ACTION_RESPONSE_EVENT_NAME,
38
+ // process.send algorithm does not send non enumerable values
39
+ // so use @jsenv/uneval
40
+ uneval({
41
+ status: ACTION_RESPONSE_STATUS_FAILED,
42
+ value: error
43
+ }, {
44
+ ignoreSymbols: true
45
+ }));
46
+ };
47
+ const sendActionCompleted = value => {
48
+ sendToParent(ACTION_RESPONSE_EVENT_NAME,
49
+ // here we use JSON.stringify because we should not
50
+ // have non enumerable value (unlike there is on Error objects)
51
+ // otherwise uneval is quite slow to turn a giant object
52
+ // into a string (and value can be giant when using coverage)
53
+ JSON.stringify({
54
+ status: ACTION_RESPONSE_STATUS_COMPLETED,
55
+ value
56
+ }));
57
+ };
58
+ const sendToParent = (type, data) => {
59
+ // https://nodejs.org/api/process.html#process_process_connected
60
+ // not connected anymore, cannot communicate with parent
61
+ if (!process.connected) {
62
+ return;
63
+ }
64
+ // this can keep process alive longer than expected
65
+ // when source is a long string.
66
+ // It means node process may stay alive longer than expected
67
+ // the time to send the data to the parent.
68
+ process.send({
69
+ jsenv: true,
70
+ type,
71
+ data
72
+ });
73
+ };
74
+ const onceParentMessage = (type, callback) => {
75
+ const listener = message => {
76
+ if (message && message.jsenv && message.type === type) {
77
+ removeListener(); // commenting this line keep this process alive
78
+ callback(message.data);
79
+ }
80
+ };
81
+ const removeListener = () => {
82
+ process.removeListener("message", listener);
83
+ };
84
+ process.on("message", listener);
85
+ return removeListener;
86
+ };
87
+ const removeActionRequestListener = onceParentMessage(ACTION_REQUEST_EVENT_NAME, async ({
88
+ actionType,
89
+ actionParams
90
+ }) => {
91
+ const action = ACTIONS_AVAILABLE[actionType];
92
+ if (!action) {
93
+ sendActionFailed(new Error(`unknown action ${actionType}`));
94
+ return;
95
+ }
96
+ let value;
97
+ let failed = false;
98
+ try {
99
+ value = await action(actionParams);
100
+ } catch (e) {
101
+ failed = true;
102
+ value = e;
103
+ }
104
+
105
+ // setTimeout(() => {}, 100)
106
+
107
+ if (failed) {
108
+ sendActionFailed(value);
109
+ } else {
110
+ sendActionCompleted(value);
111
+ }
112
+
113
+ // removeActionRequestListener()
114
+ if (actionParams.exitAfterAction) {
115
+ removeActionRequestListener();
116
+ // for some reason this fixes v8 coverage directory sometimes empty on Ubuntu
117
+ // process.exit()
118
+ }
119
+ });
120
+
121
+ // remove listener to process.on('message')
122
+ // which is sufficient to let child process die
123
+ // assuming nothing else keeps it alive
124
+ // process.once("SIGTERM", removeActionRequestListener)
125
+ // process.once("SIGINT", removeActionRequestListener)
126
+
127
+ setTimeout(() => {
128
+ sendToParent("ready");
129
+ });
@@ -0,0 +1,91 @@
1
+ import { parentPort } from "node:worker_threads";
2
+ import { uneval, executeUsingDynamicImport } from "./js/execute_using_dynamic_import.js";
3
+ import "node:fs";
4
+ import "node:inspector";
5
+ import "node:perf_hooks";
6
+
7
+ const ACTIONS_AVAILABLE = {
8
+ "execute-using-dynamic-import": executeUsingDynamicImport
9
+ };
10
+ const ACTION_REQUEST_EVENT_NAME = "action";
11
+ const ACTION_RESPONSE_EVENT_NAME = "action-result";
12
+ const ACTION_RESPONSE_STATUS_FAILED = "action-failed";
13
+ const ACTION_RESPONSE_STATUS_COMPLETED = "action-completed";
14
+ const sendActionFailed = error => {
15
+ if (error.hasOwnProperty("toString")) {
16
+ delete error.toString;
17
+ }
18
+ sendToParent(ACTION_RESPONSE_EVENT_NAME,
19
+ // process.send algorithm does not send non enumerable values
20
+ // so use @jsenv/uneval
21
+ uneval({
22
+ status: ACTION_RESPONSE_STATUS_FAILED,
23
+ value: error
24
+ }, {
25
+ ignoreSymbols: true
26
+ }));
27
+ };
28
+ const sendActionCompleted = value => {
29
+ sendToParent(ACTION_RESPONSE_EVENT_NAME,
30
+ // here we use JSON.stringify because we should not
31
+ // have non enumerable value (unlike there is on Error objects)
32
+ // otherwise uneval is quite slow to turn a giant object
33
+ // into a string (and value can be giant when using coverage)
34
+ JSON.stringify({
35
+ status: ACTION_RESPONSE_STATUS_COMPLETED,
36
+ value
37
+ }));
38
+ };
39
+ const sendToParent = (type, data) => {
40
+ // this can keep process alive longer than expected
41
+ // when source is a long string.
42
+ // It means node process may stay alive longer than expected
43
+ // the time to send the data to the parent.
44
+ parentPort.postMessage({
45
+ jsenv: true,
46
+ type,
47
+ data
48
+ });
49
+ };
50
+ const onceParentMessage = (type, callback) => {
51
+ const listener = message => {
52
+ if (message && message.jsenv && message.type === type) {
53
+ removeListener(); // commenting this line keep this worker alive
54
+ callback(message.data);
55
+ }
56
+ };
57
+ const removeListener = () => {
58
+ parentPort.removeListener("message", listener);
59
+ };
60
+ parentPort.on("message", listener);
61
+ return removeListener;
62
+ };
63
+ const removeActionRequestListener = onceParentMessage(ACTION_REQUEST_EVENT_NAME, async ({
64
+ actionType,
65
+ actionParams
66
+ }) => {
67
+ const action = ACTIONS_AVAILABLE[actionType];
68
+ if (!action) {
69
+ sendActionFailed(new Error(`unknown action ${actionType}`));
70
+ return;
71
+ }
72
+ let value;
73
+ let failed = false;
74
+ try {
75
+ value = await action(actionParams);
76
+ } catch (e) {
77
+ failed = true;
78
+ value = e;
79
+ }
80
+ if (failed) {
81
+ sendActionFailed(value);
82
+ } else {
83
+ sendActionCompleted(value);
84
+ }
85
+ if (actionParams.exitAfterAction) {
86
+ removeActionRequestListener();
87
+ }
88
+ });
89
+ setTimeout(() => {
90
+ sendToParent("ready");
91
+ });