@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,39 +1,29 @@
|
|
|
1
1
|
import { parentPort } from "node:worker_threads";
|
|
2
|
+
import { memoryUsage } from "node:process";
|
|
3
|
+
import { setFlagsFromString } from "node:v8";
|
|
4
|
+
import { runInNewContext } from "node:vm";
|
|
2
5
|
|
|
3
6
|
import { createException } from "../execution/exception.js";
|
|
4
7
|
import { executeUsingDynamicImport } from "./execute_using_dynamic_import.js";
|
|
5
8
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
};
|
|
9
|
-
const ACTION_REQUEST_EVENT_NAME = "action";
|
|
10
|
-
const ACTION_RESPONSE_EVENT_NAME = "action-result";
|
|
11
|
-
const ACTION_RESPONSE_STATUS_FAILED = "action-failed";
|
|
12
|
-
const ACTION_RESPONSE_STATUS_COMPLETED = "action-completed";
|
|
9
|
+
setFlagsFromString("--expose_gc");
|
|
10
|
+
global.gc = runInNewContext("gc");
|
|
13
11
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
status: ACTION_RESPONSE_STATUS_FAILED,
|
|
20
|
-
value: exception,
|
|
21
|
-
}),
|
|
22
|
-
);
|
|
23
|
-
};
|
|
12
|
+
let memoryHeapUsedAtStart;
|
|
13
|
+
if (process.env.MEASURE_MEMORY_AT_START) {
|
|
14
|
+
global.gc();
|
|
15
|
+
memoryHeapUsedAtStart = memoryUsage().heapUsed;
|
|
16
|
+
}
|
|
24
17
|
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
//
|
|
31
|
-
//
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
value,
|
|
35
|
-
}),
|
|
36
|
-
);
|
|
18
|
+
const ACTIONS_AVAILABLE = {
|
|
19
|
+
"execute-using-dynamic-import": (params) => {
|
|
20
|
+
return executeUsingDynamicImport(params);
|
|
21
|
+
},
|
|
22
|
+
"measure-memory-usage": () => {
|
|
23
|
+
// we compare usage - usageAtstart to prevent
|
|
24
|
+
// node or os specificities to have too much influences on the measures
|
|
25
|
+
return memoryUsage().heapUsed - memoryHeapUsedAtStart;
|
|
26
|
+
},
|
|
37
27
|
};
|
|
38
28
|
|
|
39
29
|
const sendToParent = (type, data) => {
|
|
@@ -42,16 +32,14 @@ const sendToParent = (type, data) => {
|
|
|
42
32
|
// It means node process may stay alive longer than expected
|
|
43
33
|
// the time to send the data to the parent.
|
|
44
34
|
parentPort.postMessage({
|
|
45
|
-
|
|
46
|
-
type,
|
|
35
|
+
__jsenv__: type,
|
|
47
36
|
data,
|
|
48
37
|
});
|
|
49
38
|
};
|
|
50
39
|
|
|
51
|
-
const
|
|
40
|
+
const onActionRequestedByParent = (callback) => {
|
|
52
41
|
const listener = (message) => {
|
|
53
|
-
if (message && message.
|
|
54
|
-
removeListener(); // commenting this line keep this worker alive
|
|
42
|
+
if (message && message.__jsenv__ === "action") {
|
|
55
43
|
callback(message.data);
|
|
56
44
|
}
|
|
57
45
|
};
|
|
@@ -62,31 +50,60 @@ const onceParentMessage = (type, callback) => {
|
|
|
62
50
|
return removeListener;
|
|
63
51
|
};
|
|
64
52
|
|
|
65
|
-
const removeActionRequestListener =
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
53
|
+
const removeActionRequestListener = onActionRequestedByParent(
|
|
54
|
+
async ({ id, type, params = {} }) => {
|
|
55
|
+
const sendActionInternalError = (id, error) => {
|
|
56
|
+
const exception = createException(error);
|
|
57
|
+
sendToParent(
|
|
58
|
+
"action-result",
|
|
59
|
+
JSON.stringify({
|
|
60
|
+
id,
|
|
61
|
+
status: "error",
|
|
62
|
+
value: exception,
|
|
63
|
+
}),
|
|
64
|
+
);
|
|
65
|
+
};
|
|
66
|
+
const sendActionCompleted = (id, value) => {
|
|
67
|
+
sendToParent(
|
|
68
|
+
"action-result",
|
|
69
|
+
// here we use JSON.stringify because we should not
|
|
70
|
+
// have non enumerable value (unlike there is on Error objects)
|
|
71
|
+
// otherwise uneval is quite slow to turn a giant object
|
|
72
|
+
// into a string (and value can be giant when using coverage)
|
|
73
|
+
JSON.stringify({
|
|
74
|
+
id,
|
|
75
|
+
status: "completed",
|
|
76
|
+
value,
|
|
77
|
+
}),
|
|
78
|
+
);
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const action = ACTIONS_AVAILABLE[type];
|
|
69
82
|
if (!action) {
|
|
70
|
-
|
|
83
|
+
sendActionInternalError(id, new Error(`unknown action ${type}`));
|
|
71
84
|
return;
|
|
72
85
|
}
|
|
73
86
|
|
|
74
|
-
let
|
|
75
|
-
|
|
87
|
+
let gotInternalError = false;
|
|
88
|
+
const onUncaughtException = (err) => {
|
|
89
|
+
gotInternalError = true;
|
|
90
|
+
sendActionInternalError(id, err);
|
|
91
|
+
process.exit(1);
|
|
92
|
+
};
|
|
93
|
+
process.on("uncaughtException", onUncaughtException);
|
|
94
|
+
|
|
76
95
|
try {
|
|
77
|
-
value = await action(
|
|
96
|
+
const value = await action(params);
|
|
97
|
+
if (!gotInternalError) {
|
|
98
|
+
sendActionCompleted(id, value);
|
|
99
|
+
}
|
|
78
100
|
} catch (e) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
} else {
|
|
86
|
-
sendActionCompleted(value);
|
|
87
|
-
}
|
|
88
|
-
if (actionParams.exitAfterAction) {
|
|
89
|
-
removeActionRequestListener();
|
|
101
|
+
sendActionInternalError(id, e);
|
|
102
|
+
} finally {
|
|
103
|
+
process.removeListener("uncaughtException", onUncaughtException);
|
|
104
|
+
if (params.exitAfterAction) {
|
|
105
|
+
removeActionRequestListener();
|
|
106
|
+
}
|
|
90
107
|
}
|
|
91
108
|
},
|
|
92
109
|
);
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { fileURLToPath } from "node:url";
|
|
2
|
-
import { readFileSync } from "node:fs";
|
|
3
|
-
|
|
4
|
-
import { importWithRequire } from "../helpers/import_with_require.js";
|
|
5
|
-
import { istanbulCoverageMapFromCoverage } from "./istanbul_coverage_map_from_coverage.js";
|
|
6
|
-
|
|
7
|
-
export const generateCoverageHtmlDirectory = async (
|
|
8
|
-
coverage,
|
|
9
|
-
{
|
|
10
|
-
rootDirectoryUrl,
|
|
11
|
-
coverageHtmlDirectoryRelativeUrl,
|
|
12
|
-
coverageReportSkipEmpty,
|
|
13
|
-
coverageReportSkipFull,
|
|
14
|
-
},
|
|
15
|
-
) => {
|
|
16
|
-
const libReport = importWithRequire("istanbul-lib-report");
|
|
17
|
-
const reports = importWithRequire("istanbul-reports");
|
|
18
|
-
|
|
19
|
-
const context = libReport.createContext({
|
|
20
|
-
dir: fileURLToPath(rootDirectoryUrl),
|
|
21
|
-
coverageMap: istanbulCoverageMapFromCoverage(coverage),
|
|
22
|
-
sourceFinder: (path) =>
|
|
23
|
-
readFileSync(new URL(path, rootDirectoryUrl), "utf8"),
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
const report = reports.create("html", {
|
|
27
|
-
skipEmpty: coverageReportSkipEmpty,
|
|
28
|
-
skipFull: coverageReportSkipFull,
|
|
29
|
-
subdir: coverageHtmlDirectoryRelativeUrl,
|
|
30
|
-
});
|
|
31
|
-
report.execute(context);
|
|
32
|
-
};
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { writeFile } from "@jsenv/filesystem";
|
|
2
|
-
import { urlToFileSystemPath } from "@jsenv/urls";
|
|
3
|
-
import { byteAsFileSize } from "@jsenv/log";
|
|
4
|
-
|
|
5
|
-
export const generateCoverageJsonFile = async ({
|
|
6
|
-
coverage,
|
|
7
|
-
coverageJsonFileUrl,
|
|
8
|
-
logger,
|
|
9
|
-
}) => {
|
|
10
|
-
const coverageAsText = JSON.stringify(coverage, null, " ");
|
|
11
|
-
logger.info(
|
|
12
|
-
`-> ${urlToFileSystemPath(coverageJsonFileUrl)} (${byteAsFileSize(
|
|
13
|
-
Buffer.byteLength(coverageAsText),
|
|
14
|
-
)})`,
|
|
15
|
-
);
|
|
16
|
-
await writeFile(coverageJsonFileUrl, coverageAsText);
|
|
17
|
-
};
|
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
|
-
import { Abort } from "@jsenv/abort";
|
|
3
|
-
|
|
4
|
-
import { filterV8Coverage } from "./v8_coverage.js";
|
|
5
|
-
import { readNodeV8CoverageDirectory } from "./v8_coverage_node_directory.js";
|
|
6
|
-
import { composeTwoV8Coverages } from "./v8_coverage_composition.js";
|
|
7
|
-
import { composeTwoFileByFileIstanbulCoverages } from "./istanbul_coverage_composition.js";
|
|
8
|
-
import { v8CoverageToIstanbul } from "./v8_coverage_to_istanbul.js";
|
|
9
|
-
import { composeV8AndIstanbul } from "./v8_and_istanbul.js";
|
|
10
|
-
import { normalizeFileByFileCoveragePaths } from "./file_by_file_coverage.js";
|
|
11
|
-
import { getMissingFileByFileCoverage } from "./missing_coverage.js";
|
|
12
|
-
|
|
13
|
-
export const reportToCoverage = async (
|
|
14
|
-
report,
|
|
15
|
-
{
|
|
16
|
-
signal,
|
|
17
|
-
logger,
|
|
18
|
-
rootDirectoryUrl,
|
|
19
|
-
coverageConfig,
|
|
20
|
-
coverageIncludeMissing,
|
|
21
|
-
coverageMethodForNodeJs,
|
|
22
|
-
coverageV8ConflictWarning,
|
|
23
|
-
},
|
|
24
|
-
) => {
|
|
25
|
-
// collect v8 and istanbul coverage from executions
|
|
26
|
-
let { v8Coverage, fileByFileIstanbulCoverage } = await getCoverageFromReport({
|
|
27
|
-
signal,
|
|
28
|
-
report,
|
|
29
|
-
onMissing: ({ file, executionResult, executionName }) => {
|
|
30
|
-
// several reasons not to have coverage here:
|
|
31
|
-
// 1. the file we executed did not import an instrumented file.
|
|
32
|
-
// - a test file without import
|
|
33
|
-
// - a test file importing only file excluded from coverage
|
|
34
|
-
// - a coverDescription badly configured so that we don't realize
|
|
35
|
-
// a file should be covered
|
|
36
|
-
|
|
37
|
-
// 2. the file we wanted to executed timedout
|
|
38
|
-
// - infinite loop
|
|
39
|
-
// - too extensive operation
|
|
40
|
-
// - a badly configured or too low allocatedMs for that execution.
|
|
41
|
-
|
|
42
|
-
// 3. the file we wanted to execute contains syntax-error
|
|
43
|
-
|
|
44
|
-
// in any scenario we are fine because
|
|
45
|
-
// coverDescription will generate empty coverage for files
|
|
46
|
-
// that were suppose to be coverage but were not.
|
|
47
|
-
if (
|
|
48
|
-
executionResult.status === "completed" &&
|
|
49
|
-
executionResult.type === "node" &&
|
|
50
|
-
coverageMethodForNodeJs !== "NODE_V8_COVERAGE"
|
|
51
|
-
) {
|
|
52
|
-
logger.warn(
|
|
53
|
-
`"${executionName}" execution of ${file} did not properly write coverage into ${executionResult.coverageFileUrl}`,
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
},
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
if (coverageMethodForNodeJs === "NODE_V8_COVERAGE") {
|
|
60
|
-
await readNodeV8CoverageDirectory({
|
|
61
|
-
logger,
|
|
62
|
-
signal,
|
|
63
|
-
onV8Coverage: async (nodeV8Coverage) => {
|
|
64
|
-
const nodeV8CoverageLight = await filterV8Coverage(nodeV8Coverage, {
|
|
65
|
-
rootDirectoryUrl,
|
|
66
|
-
coverageConfig,
|
|
67
|
-
});
|
|
68
|
-
v8Coverage = v8Coverage
|
|
69
|
-
? composeTwoV8Coverages(v8Coverage, nodeV8CoverageLight)
|
|
70
|
-
: nodeV8CoverageLight;
|
|
71
|
-
},
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// try to merge v8 with istanbul, if any
|
|
76
|
-
let fileByFileCoverage;
|
|
77
|
-
if (v8Coverage) {
|
|
78
|
-
let v8FileByFileCoverage = await v8CoverageToIstanbul(v8Coverage, {
|
|
79
|
-
signal,
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
v8FileByFileCoverage = normalizeFileByFileCoveragePaths(
|
|
83
|
-
v8FileByFileCoverage,
|
|
84
|
-
rootDirectoryUrl,
|
|
85
|
-
);
|
|
86
|
-
|
|
87
|
-
if (fileByFileIstanbulCoverage) {
|
|
88
|
-
fileByFileIstanbulCoverage = normalizeFileByFileCoveragePaths(
|
|
89
|
-
fileByFileIstanbulCoverage,
|
|
90
|
-
rootDirectoryUrl,
|
|
91
|
-
);
|
|
92
|
-
fileByFileCoverage = composeV8AndIstanbul(
|
|
93
|
-
v8FileByFileCoverage,
|
|
94
|
-
fileByFileIstanbulCoverage,
|
|
95
|
-
{ coverageV8ConflictWarning },
|
|
96
|
-
);
|
|
97
|
-
} else {
|
|
98
|
-
fileByFileCoverage = v8FileByFileCoverage;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
// get istanbul only
|
|
102
|
-
else if (fileByFileIstanbulCoverage) {
|
|
103
|
-
fileByFileCoverage = normalizeFileByFileCoveragePaths(
|
|
104
|
-
fileByFileIstanbulCoverage,
|
|
105
|
-
rootDirectoryUrl,
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
|
-
// no coverage found in execution (or zero file where executed)
|
|
109
|
-
else {
|
|
110
|
-
fileByFileCoverage = {};
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// now add coverage for file not covered
|
|
114
|
-
if (coverageIncludeMissing) {
|
|
115
|
-
const missingFileByFileCoverage = await getMissingFileByFileCoverage({
|
|
116
|
-
signal,
|
|
117
|
-
rootDirectoryUrl,
|
|
118
|
-
coverageConfig,
|
|
119
|
-
fileByFileCoverage,
|
|
120
|
-
});
|
|
121
|
-
Object.assign(
|
|
122
|
-
fileByFileCoverage,
|
|
123
|
-
normalizeFileByFileCoveragePaths(
|
|
124
|
-
missingFileByFileCoverage,
|
|
125
|
-
rootDirectoryUrl,
|
|
126
|
-
),
|
|
127
|
-
);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
return fileByFileCoverage;
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
const getCoverageFromReport = async ({ signal, report, onMissing }) => {
|
|
134
|
-
const operation = Abort.startOperation();
|
|
135
|
-
operation.addAbortSignal(signal);
|
|
136
|
-
|
|
137
|
-
try {
|
|
138
|
-
let v8Coverage;
|
|
139
|
-
let fileByFileIstanbulCoverage;
|
|
140
|
-
|
|
141
|
-
// collect v8 and istanbul coverage from executions
|
|
142
|
-
await Object.keys(report).reduce(async (previous, file) => {
|
|
143
|
-
operation.throwIfAborted();
|
|
144
|
-
await previous;
|
|
145
|
-
|
|
146
|
-
const executionResultForFile = report[file];
|
|
147
|
-
await Object.keys(executionResultForFile).reduce(
|
|
148
|
-
async (previous, executionName) => {
|
|
149
|
-
operation.throwIfAborted();
|
|
150
|
-
await previous;
|
|
151
|
-
|
|
152
|
-
const executionResultForFileOnRuntime =
|
|
153
|
-
executionResultForFile[executionName];
|
|
154
|
-
const { coverageFileUrl } = executionResultForFileOnRuntime;
|
|
155
|
-
let executionCoverage;
|
|
156
|
-
try {
|
|
157
|
-
executionCoverage = JSON.parse(
|
|
158
|
-
String(readFileSync(new URL(coverageFileUrl))),
|
|
159
|
-
);
|
|
160
|
-
} catch (e) {
|
|
161
|
-
if (e.code === "ENOENT" || e.name === "SyntaxError") {
|
|
162
|
-
onMissing({
|
|
163
|
-
executionName,
|
|
164
|
-
file,
|
|
165
|
-
executionResult: executionResultForFileOnRuntime,
|
|
166
|
-
});
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
throw e;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
if (isV8Coverage(executionCoverage)) {
|
|
173
|
-
v8Coverage = v8Coverage
|
|
174
|
-
? composeTwoV8Coverages(v8Coverage, executionCoverage)
|
|
175
|
-
: executionCoverage;
|
|
176
|
-
} else {
|
|
177
|
-
fileByFileIstanbulCoverage = fileByFileIstanbulCoverage
|
|
178
|
-
? composeTwoFileByFileIstanbulCoverages(
|
|
179
|
-
fileByFileIstanbulCoverage,
|
|
180
|
-
executionCoverage,
|
|
181
|
-
)
|
|
182
|
-
: executionCoverage;
|
|
183
|
-
}
|
|
184
|
-
},
|
|
185
|
-
Promise.resolve(),
|
|
186
|
-
);
|
|
187
|
-
}, Promise.resolve());
|
|
188
|
-
|
|
189
|
-
return {
|
|
190
|
-
v8Coverage,
|
|
191
|
-
fileByFileIstanbulCoverage,
|
|
192
|
-
};
|
|
193
|
-
} finally {
|
|
194
|
-
await operation.end();
|
|
195
|
-
}
|
|
196
|
-
};
|
|
197
|
-
|
|
198
|
-
const isV8Coverage = (coverage) => Boolean(coverage.result);
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import { Abort } from "@jsenv/abort";
|
|
2
|
-
import { collectFiles } from "@jsenv/filesystem";
|
|
3
|
-
import { createDetailedMessage } from "@jsenv/log";
|
|
4
|
-
|
|
5
|
-
export const executionStepsFromTestPlan = async ({
|
|
6
|
-
signal,
|
|
7
|
-
rootDirectoryUrl,
|
|
8
|
-
testPlan,
|
|
9
|
-
}) => {
|
|
10
|
-
try {
|
|
11
|
-
const fileResultArray = await collectFiles({
|
|
12
|
-
signal,
|
|
13
|
-
directoryUrl: rootDirectoryUrl,
|
|
14
|
-
associations: { testPlan },
|
|
15
|
-
predicate: ({ testPlan }) => testPlan,
|
|
16
|
-
});
|
|
17
|
-
const executionSteps = [];
|
|
18
|
-
fileResultArray.forEach(({ relativeUrl, meta }) => {
|
|
19
|
-
const fileExecutionSteps = generateFileExecutionSteps({
|
|
20
|
-
fileRelativeUrl: relativeUrl,
|
|
21
|
-
filePlan: meta.testPlan,
|
|
22
|
-
});
|
|
23
|
-
executionSteps.push(...fileExecutionSteps);
|
|
24
|
-
});
|
|
25
|
-
return executionSteps;
|
|
26
|
-
} catch (e) {
|
|
27
|
-
if (Abort.isAbortError(e)) {
|
|
28
|
-
return {
|
|
29
|
-
aborted: true,
|
|
30
|
-
planSummary: {},
|
|
31
|
-
planReport: {},
|
|
32
|
-
planCoverage: null,
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
throw e;
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
export const generateFileExecutionSteps = ({ fileRelativeUrl, filePlan }) => {
|
|
40
|
-
const fileExecutionSteps = [];
|
|
41
|
-
Object.keys(filePlan).forEach((executionName) => {
|
|
42
|
-
const stepConfig = filePlan[executionName];
|
|
43
|
-
if (stepConfig === null || stepConfig === undefined) {
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
if (typeof stepConfig !== "object") {
|
|
47
|
-
throw new TypeError(
|
|
48
|
-
createDetailedMessage(
|
|
49
|
-
`found unexpected value in plan, they must be object`,
|
|
50
|
-
{
|
|
51
|
-
["file relative path"]: fileRelativeUrl,
|
|
52
|
-
["execution name"]: executionName,
|
|
53
|
-
["value"]: stepConfig,
|
|
54
|
-
},
|
|
55
|
-
),
|
|
56
|
-
);
|
|
57
|
-
}
|
|
58
|
-
fileExecutionSteps.push({
|
|
59
|
-
executionName,
|
|
60
|
-
fileRelativeUrl,
|
|
61
|
-
...stepConfig,
|
|
62
|
-
});
|
|
63
|
-
});
|
|
64
|
-
return fileExecutionSteps;
|
|
65
|
-
};
|