@jsenv/test 1.2.4 → 1.3.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.
- package/dist/controllable_child_process.mjs +73 -66
- package/dist/controllable_worker_thread.mjs +62 -49
- package/dist/importmap_node_loader.mjs +286 -185
- package/dist/js/execute_using_dynamic_import.js +397 -282
- package/dist/js/v8_coverage.js +91 -98
- package/dist/jsenv_test.js +2603 -1902
- package/dist/no_experimental_warnings.cjs +4 -1
- package/package.json +4 -4
|
@@ -5,56 +5,60 @@ import "node:perf_hooks";
|
|
|
5
5
|
|
|
6
6
|
const ACTIONS_AVAILABLE = {
|
|
7
7
|
"execute-using-dynamic-import": executeUsingDynamicImport,
|
|
8
|
-
"execute-using-require": async ({
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const {
|
|
12
|
-
createRequire
|
|
13
|
-
} = await import("node:module");
|
|
14
|
-
const {
|
|
15
|
-
fileURLToPath
|
|
16
|
-
} = await import("node:url");
|
|
8
|
+
"execute-using-require": async ({ fileUrl }) => {
|
|
9
|
+
const { createRequire } = await import("node:module");
|
|
10
|
+
const { fileURLToPath } = await import("node:url");
|
|
17
11
|
const filePath = fileURLToPath(fileUrl);
|
|
18
12
|
const require = createRequire(fileUrl);
|
|
19
13
|
// eslint-disable-next-line import/no-dynamic-require
|
|
20
14
|
const namespace = require(filePath);
|
|
21
15
|
const namespaceResolved = {};
|
|
22
|
-
await Promise.all(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
16
|
+
await Promise.all(
|
|
17
|
+
Object.keys(namespace).map(async (key) => {
|
|
18
|
+
const value = await namespace[key];
|
|
19
|
+
namespaceResolved[key] = value;
|
|
20
|
+
}),
|
|
21
|
+
);
|
|
26
22
|
return namespaceResolved;
|
|
27
|
-
}
|
|
23
|
+
},
|
|
28
24
|
};
|
|
29
25
|
const ACTION_REQUEST_EVENT_NAME = "action";
|
|
30
26
|
const ACTION_RESPONSE_EVENT_NAME = "action-result";
|
|
31
27
|
const ACTION_RESPONSE_STATUS_FAILED = "action-failed";
|
|
32
28
|
const ACTION_RESPONSE_STATUS_COMPLETED = "action-completed";
|
|
33
|
-
|
|
29
|
+
|
|
30
|
+
const sendActionFailed = (error) => {
|
|
34
31
|
if (error.hasOwnProperty("toString")) {
|
|
35
32
|
delete error.toString;
|
|
36
33
|
}
|
|
37
|
-
sendToParent(
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
34
|
+
sendToParent(
|
|
35
|
+
ACTION_RESPONSE_EVENT_NAME,
|
|
36
|
+
// process.send algorithm does not send non enumerable values
|
|
37
|
+
// so use @jsenv/uneval
|
|
38
|
+
uneval(
|
|
39
|
+
{
|
|
40
|
+
status: ACTION_RESPONSE_STATUS_FAILED,
|
|
41
|
+
value: error,
|
|
42
|
+
},
|
|
43
|
+
{ ignoreSymbols: true },
|
|
44
|
+
),
|
|
45
|
+
);
|
|
46
46
|
};
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
47
|
+
|
|
48
|
+
const sendActionCompleted = (value) => {
|
|
49
|
+
sendToParent(
|
|
50
|
+
ACTION_RESPONSE_EVENT_NAME,
|
|
51
|
+
// here we use JSON.stringify because we should not
|
|
52
|
+
// have non enumerable value (unlike there is on Error objects)
|
|
53
|
+
// otherwise uneval is quite slow to turn a giant object
|
|
54
|
+
// into a string (and value can be giant when using coverage)
|
|
55
|
+
JSON.stringify({
|
|
56
|
+
status: ACTION_RESPONSE_STATUS_COMPLETED,
|
|
57
|
+
value,
|
|
58
|
+
}),
|
|
59
|
+
);
|
|
57
60
|
};
|
|
61
|
+
|
|
58
62
|
const sendToParent = (type, data) => {
|
|
59
63
|
// https://nodejs.org/api/process.html#process_process_connected
|
|
60
64
|
// not connected anymore, cannot communicate with parent
|
|
@@ -68,11 +72,12 @@ const sendToParent = (type, data) => {
|
|
|
68
72
|
process.send({
|
|
69
73
|
jsenv: true,
|
|
70
74
|
type,
|
|
71
|
-
data
|
|
75
|
+
data,
|
|
72
76
|
});
|
|
73
77
|
};
|
|
78
|
+
|
|
74
79
|
const onceParentMessage = (type, callback) => {
|
|
75
|
-
const listener = message => {
|
|
80
|
+
const listener = (message) => {
|
|
76
81
|
if (message && message.jsenv && message.type === type) {
|
|
77
82
|
removeListener(); // commenting this line keep this process alive
|
|
78
83
|
callback(message.data);
|
|
@@ -84,39 +89,41 @@ const onceParentMessage = (type, callback) => {
|
|
|
84
89
|
process.on("message", listener);
|
|
85
90
|
return removeListener;
|
|
86
91
|
};
|
|
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
92
|
|
|
105
|
-
|
|
93
|
+
const removeActionRequestListener = onceParentMessage(
|
|
94
|
+
ACTION_REQUEST_EVENT_NAME,
|
|
95
|
+
async ({ actionType, actionParams }) => {
|
|
96
|
+
const action = ACTIONS_AVAILABLE[actionType];
|
|
97
|
+
if (!action) {
|
|
98
|
+
sendActionFailed(new Error(`unknown action ${actionType}`));
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
106
101
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
102
|
+
let value;
|
|
103
|
+
let failed = false;
|
|
104
|
+
try {
|
|
105
|
+
value = await action(actionParams);
|
|
106
|
+
} catch (e) {
|
|
107
|
+
failed = true;
|
|
108
|
+
value = e;
|
|
109
|
+
}
|
|
112
110
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
111
|
+
// setTimeout(() => {}, 100)
|
|
112
|
+
|
|
113
|
+
if (failed) {
|
|
114
|
+
sendActionFailed(value);
|
|
115
|
+
} else {
|
|
116
|
+
sendActionCompleted(value);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// removeActionRequestListener()
|
|
120
|
+
if (actionParams.exitAfterAction) {
|
|
121
|
+
removeActionRequestListener();
|
|
122
|
+
// for some reason this fixes v8 coverage directory sometimes empty on Ubuntu
|
|
123
|
+
// process.exit()
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
);
|
|
120
127
|
|
|
121
128
|
// remove listener to process.on('message')
|
|
122
129
|
// which is sufficient to let child process die
|
|
@@ -5,37 +5,45 @@ import "node:inspector";
|
|
|
5
5
|
import "node:perf_hooks";
|
|
6
6
|
|
|
7
7
|
const ACTIONS_AVAILABLE = {
|
|
8
|
-
"execute-using-dynamic-import": executeUsingDynamicImport
|
|
8
|
+
"execute-using-dynamic-import": executeUsingDynamicImport,
|
|
9
9
|
};
|
|
10
10
|
const ACTION_REQUEST_EVENT_NAME = "action";
|
|
11
11
|
const ACTION_RESPONSE_EVENT_NAME = "action-result";
|
|
12
12
|
const ACTION_RESPONSE_STATUS_FAILED = "action-failed";
|
|
13
13
|
const ACTION_RESPONSE_STATUS_COMPLETED = "action-completed";
|
|
14
|
-
|
|
14
|
+
|
|
15
|
+
const sendActionFailed = (error) => {
|
|
15
16
|
if (error.hasOwnProperty("toString")) {
|
|
16
17
|
delete error.toString;
|
|
17
18
|
}
|
|
18
|
-
sendToParent(
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
19
|
+
sendToParent(
|
|
20
|
+
ACTION_RESPONSE_EVENT_NAME,
|
|
21
|
+
// process.send algorithm does not send non enumerable values
|
|
22
|
+
// so use @jsenv/uneval
|
|
23
|
+
uneval(
|
|
24
|
+
{
|
|
25
|
+
status: ACTION_RESPONSE_STATUS_FAILED,
|
|
26
|
+
value: error,
|
|
27
|
+
},
|
|
28
|
+
{ ignoreSymbols: true },
|
|
29
|
+
),
|
|
30
|
+
);
|
|
27
31
|
};
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
32
|
+
|
|
33
|
+
const sendActionCompleted = (value) => {
|
|
34
|
+
sendToParent(
|
|
35
|
+
ACTION_RESPONSE_EVENT_NAME,
|
|
36
|
+
// here we use JSON.stringify because we should not
|
|
37
|
+
// have non enumerable value (unlike there is on Error objects)
|
|
38
|
+
// otherwise uneval is quite slow to turn a giant object
|
|
39
|
+
// into a string (and value can be giant when using coverage)
|
|
40
|
+
JSON.stringify({
|
|
41
|
+
status: ACTION_RESPONSE_STATUS_COMPLETED,
|
|
42
|
+
value,
|
|
43
|
+
}),
|
|
44
|
+
);
|
|
38
45
|
};
|
|
46
|
+
|
|
39
47
|
const sendToParent = (type, data) => {
|
|
40
48
|
// this can keep process alive longer than expected
|
|
41
49
|
// when source is a long string.
|
|
@@ -44,11 +52,12 @@ const sendToParent = (type, data) => {
|
|
|
44
52
|
parentPort.postMessage({
|
|
45
53
|
jsenv: true,
|
|
46
54
|
type,
|
|
47
|
-
data
|
|
55
|
+
data,
|
|
48
56
|
});
|
|
49
57
|
};
|
|
58
|
+
|
|
50
59
|
const onceParentMessage = (type, callback) => {
|
|
51
|
-
const listener = message => {
|
|
60
|
+
const listener = (message) => {
|
|
52
61
|
if (message && message.jsenv && message.type === type) {
|
|
53
62
|
removeListener(); // commenting this line keep this worker alive
|
|
54
63
|
callback(message.data);
|
|
@@ -60,32 +69,36 @@ const onceParentMessage = (type, callback) => {
|
|
|
60
69
|
parentPort.on("message", listener);
|
|
61
70
|
return removeListener;
|
|
62
71
|
};
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}) => {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
72
|
+
|
|
73
|
+
const removeActionRequestListener = onceParentMessage(
|
|
74
|
+
ACTION_REQUEST_EVENT_NAME,
|
|
75
|
+
async ({ actionType, actionParams }) => {
|
|
76
|
+
const action = ACTIONS_AVAILABLE[actionType];
|
|
77
|
+
if (!action) {
|
|
78
|
+
sendActionFailed(new Error(`unknown action ${actionType}`));
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
let value;
|
|
83
|
+
let failed = false;
|
|
84
|
+
try {
|
|
85
|
+
value = await action(actionParams);
|
|
86
|
+
} catch (e) {
|
|
87
|
+
failed = true;
|
|
88
|
+
value = e;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (failed) {
|
|
92
|
+
sendActionFailed(value);
|
|
93
|
+
} else {
|
|
94
|
+
sendActionCompleted(value);
|
|
95
|
+
}
|
|
96
|
+
if (actionParams.exitAfterAction) {
|
|
97
|
+
removeActionRequestListener();
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
);
|
|
101
|
+
|
|
89
102
|
setTimeout(() => {
|
|
90
103
|
sendToParent("ready");
|
|
91
104
|
});
|