@jsenv/test 3.2.0 → 3.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/js/exception.js +2 -4
- package/dist/jsenv_test.js +476 -162
- package/package.json +7 -7
- package/src/execution/exception.js +2 -4
- package/src/execution/execute_test_plan.js +156 -64
- package/src/execution/format_error_for_terminal.js +2 -51
- package/src/execution/github_annotation_from_error.js +1 -1
- package/src/execution/is_inside_fragment.js +32 -0
- package/src/execution/junit_xml_file/report_as_junit_xml.js +10 -6
- package/src/execution/replace_urls.js +50 -0
- package/src/execution/report_as_json.js +121 -0
- package/src/execution/reporters/reporter_list.js +91 -24
- package/src/main.js +1 -0
- package/src/runtime_browsers/firefox.js +2 -1
- package/src/runtime_node/node_child_process.js +3 -7
- package/src/runtime_node/node_worker_thread.js +3 -6
package/dist/jsenv_test.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import os, { cpus, release, totalmem, availableParallelism, freemem } from "node:os";
|
|
2
2
|
import process$1, { cpuUsage, memoryUsage } from "node:process";
|
|
3
|
-
import { readdir, chmod, stat, lstat, chmodSync, statSync, lstatSync, promises, readFile as readFile$1, writeFileSync as writeFileSync$1, mkdirSync, unlink, openSync, closeSync, rmdir, unlinkSync, readdirSync, rmdirSync,
|
|
3
|
+
import { readdir, chmod, stat, lstat, chmodSync, statSync, lstatSync, promises, readFile as readFile$1, readFileSync, writeFileSync as writeFileSync$1, mkdirSync, unlink, openSync, closeSync, rmdir, unlinkSync, readdirSync, rmdirSync, existsSync } from "node:fs";
|
|
4
4
|
import { takeCoverage } from "node:v8";
|
|
5
5
|
import stripAnsi from "strip-ansi";
|
|
6
6
|
import { URL_META, createException } from "./js/exception.js";
|
|
@@ -720,10 +720,10 @@ function createSupportsColor(stream, options = {}) {
|
|
|
720
720
|
return translateLevel(level);
|
|
721
721
|
}
|
|
722
722
|
|
|
723
|
-
|
|
723
|
+
({
|
|
724
724
|
stdout: createSupportsColor({isTTY: tty.isatty(1)}),
|
|
725
725
|
stderr: createSupportsColor({isTTY: tty.isatty(2)}),
|
|
726
|
-
};
|
|
726
|
+
});
|
|
727
727
|
|
|
728
728
|
// https://github.com/Marak/colors.js/blob/master/lib/styles.js
|
|
729
729
|
// https://stackoverflow.com/a/75985833/2634179
|
|
@@ -763,6 +763,7 @@ const processSupportsBasicColor = createSupportsColor(process.stdout).hasBasic;
|
|
|
763
763
|
|
|
764
764
|
const ANSI = createAnsi({
|
|
765
765
|
supported:
|
|
766
|
+
process.env.FORCE_COLOR === "1" ||
|
|
766
767
|
processSupportsBasicColor ||
|
|
767
768
|
// GitHub workflow does support ANSI but "supports-color" returns false
|
|
768
769
|
// because stream.isTTY returns false, see https://github.com/actions/runner/issues/241
|
|
@@ -810,6 +811,9 @@ const createUnicode = ({ supported, ANSI }) => {
|
|
|
810
811
|
get CIRCLE_CROSS_RAW() {
|
|
811
812
|
return UNICODE.supported ? `ⓧ` : `(×)`;
|
|
812
813
|
},
|
|
814
|
+
get CIRCLE_DOTTED_RAW() {
|
|
815
|
+
return UNICODE.supported ? `◌` : `*`;
|
|
816
|
+
},
|
|
813
817
|
get COMMAND() {
|
|
814
818
|
return ANSI.color(UNICODE.COMMAND_RAW, ANSI.GREY); // ANSI_MAGENTA)
|
|
815
819
|
},
|
|
@@ -839,7 +843,7 @@ const createUnicode = ({ supported, ANSI }) => {
|
|
|
839
843
|
};
|
|
840
844
|
|
|
841
845
|
const UNICODE = createUnicode({
|
|
842
|
-
supported:
|
|
846
|
+
supported: process.env.FORCE_UNICODE === "1" || isUnicodeSupported(),
|
|
843
847
|
ANSI,
|
|
844
848
|
});
|
|
845
849
|
|
|
@@ -2486,6 +2490,9 @@ const readFile = async (value, { as = "buffer" } = {}) => {
|
|
|
2486
2490
|
const writeFileSync = (destination, content = "") => {
|
|
2487
2491
|
const destinationUrl = assertAndNormalizeFileUrl(destination);
|
|
2488
2492
|
const destinationUrlObject = new URL(destinationUrl);
|
|
2493
|
+
if (content && content instanceof URL) {
|
|
2494
|
+
content = readFileSync(content);
|
|
2495
|
+
}
|
|
2489
2496
|
try {
|
|
2490
2497
|
writeFileSync$1(destinationUrlObject, content);
|
|
2491
2498
|
} catch (error) {
|
|
@@ -4295,7 +4302,7 @@ const stringifyUrlSite = ({ url, line, column }) => {
|
|
|
4295
4302
|
};
|
|
4296
4303
|
|
|
4297
4304
|
const replaceUrls$1 = (source, replace) => {
|
|
4298
|
-
return source.replace(/(?:https?|ftp|file):\/\/\S+/
|
|
4305
|
+
return source.replace(/(?:https?|ftp|file):\/\/\S+/g, (match) => {
|
|
4299
4306
|
let replacement = "";
|
|
4300
4307
|
const lastChar = match[match.length - 1];
|
|
4301
4308
|
|
|
@@ -4562,6 +4569,57 @@ const normalizeRuntimeError = (runtimeError) => {
|
|
|
4562
4569
|
return errorProxy;
|
|
4563
4570
|
};
|
|
4564
4571
|
|
|
4572
|
+
// `Error: yo
|
|
4573
|
+
// at Object.execute (http://127.0.0.1:57300/build/src/__test__/file-throw.js:9:13)
|
|
4574
|
+
// at doExec (http://127.0.0.1:3000/src/__test__/file-throw.js:452:38)
|
|
4575
|
+
// at postOrderExec (http://127.0.0.1:3000/src/__test__/file-throw.js:448:16)
|
|
4576
|
+
// at http://127.0.0.1:3000/src/__test__/file-throw.js:399:18`.replace(/(?:https?|ftp|file):\/\/(.*+)$/gm, (...args) => {
|
|
4577
|
+
// debugger
|
|
4578
|
+
// })
|
|
4579
|
+
const replaceUrls = (source, replace) => {
|
|
4580
|
+
return source.replace(/(?:https?|ftp|file):\/\/\S+/g, (match) => {
|
|
4581
|
+
let replacement = "";
|
|
4582
|
+
const lastChar = match[match.length - 1];
|
|
4583
|
+
|
|
4584
|
+
// hotfix because our url regex sucks a bit
|
|
4585
|
+
const endsWithSeparationChar = lastChar === ")" || lastChar === ":";
|
|
4586
|
+
if (endsWithSeparationChar) {
|
|
4587
|
+
match = match.slice(0, -1);
|
|
4588
|
+
}
|
|
4589
|
+
|
|
4590
|
+
const lineAndColumnPattern = /:([0-9]+):([0-9]+)$/;
|
|
4591
|
+
const lineAndColumMatch = match.match(lineAndColumnPattern);
|
|
4592
|
+
if (lineAndColumMatch) {
|
|
4593
|
+
const lineAndColumnString = lineAndColumMatch[0];
|
|
4594
|
+
const lineString = lineAndColumMatch[1];
|
|
4595
|
+
const columnString = lineAndColumMatch[2];
|
|
4596
|
+
replacement = replace({
|
|
4597
|
+
url: match.slice(0, -lineAndColumnString.length),
|
|
4598
|
+
line: lineString ? parseInt(lineString) : null,
|
|
4599
|
+
column: columnString ? parseInt(columnString) : null,
|
|
4600
|
+
});
|
|
4601
|
+
} else {
|
|
4602
|
+
const linePattern = /:([0-9]+)$/;
|
|
4603
|
+
const lineMatch = match.match(linePattern);
|
|
4604
|
+
if (lineMatch) {
|
|
4605
|
+
const lineString = lineMatch[0];
|
|
4606
|
+
replacement = replace({
|
|
4607
|
+
url: match.slice(0, -lineString.length),
|
|
4608
|
+
line: lineString ? parseInt(lineString) : null,
|
|
4609
|
+
});
|
|
4610
|
+
} else {
|
|
4611
|
+
replacement = replace({
|
|
4612
|
+
url: match,
|
|
4613
|
+
});
|
|
4614
|
+
}
|
|
4615
|
+
}
|
|
4616
|
+
if (endsWithSeparationChar) {
|
|
4617
|
+
return `${replacement}${lastChar}`;
|
|
4618
|
+
}
|
|
4619
|
+
return replacement;
|
|
4620
|
+
});
|
|
4621
|
+
};
|
|
4622
|
+
|
|
4565
4623
|
const formatErrorForTerminal = (
|
|
4566
4624
|
error,
|
|
4567
4625
|
{ rootDirectoryUrl, mainFileRelativeUrl, mockFluctuatingValues, tryColors },
|
|
@@ -4694,57 +4752,6 @@ const formatErrorForTerminal = (
|
|
|
4694
4752
|
return text;
|
|
4695
4753
|
};
|
|
4696
4754
|
|
|
4697
|
-
// `Error: yo
|
|
4698
|
-
// at Object.execute (http://127.0.0.1:57300/build/src/__test__/file-throw.js:9:13)
|
|
4699
|
-
// at doExec (http://127.0.0.1:3000/src/__test__/file-throw.js:452:38)
|
|
4700
|
-
// at postOrderExec (http://127.0.0.1:3000/src/__test__/file-throw.js:448:16)
|
|
4701
|
-
// at http://127.0.0.1:3000/src/__test__/file-throw.js:399:18`.replace(/(?:https?|ftp|file):\/\/(.*+)$/gm, (...args) => {
|
|
4702
|
-
// debugger
|
|
4703
|
-
// })
|
|
4704
|
-
const replaceUrls = (source, replace) => {
|
|
4705
|
-
return source.replace(/(?:https?|ftp|file):\/\/\S+/gm, (match) => {
|
|
4706
|
-
let replacement = "";
|
|
4707
|
-
const lastChar = match[match.length - 1];
|
|
4708
|
-
|
|
4709
|
-
// hotfix because our url regex sucks a bit
|
|
4710
|
-
const endsWithSeparationChar = lastChar === ")" || lastChar === ":";
|
|
4711
|
-
if (endsWithSeparationChar) {
|
|
4712
|
-
match = match.slice(0, -1);
|
|
4713
|
-
}
|
|
4714
|
-
|
|
4715
|
-
const lineAndColumnPattern = /:([0-9]+):([0-9]+)$/;
|
|
4716
|
-
const lineAndColumMatch = match.match(lineAndColumnPattern);
|
|
4717
|
-
if (lineAndColumMatch) {
|
|
4718
|
-
const lineAndColumnString = lineAndColumMatch[0];
|
|
4719
|
-
const lineString = lineAndColumMatch[1];
|
|
4720
|
-
const columnString = lineAndColumMatch[2];
|
|
4721
|
-
replacement = replace({
|
|
4722
|
-
url: match.slice(0, -lineAndColumnString.length),
|
|
4723
|
-
line: lineString ? parseInt(lineString) : null,
|
|
4724
|
-
column: columnString ? parseInt(columnString) : null,
|
|
4725
|
-
});
|
|
4726
|
-
} else {
|
|
4727
|
-
const linePattern = /:([0-9]+)$/;
|
|
4728
|
-
const lineMatch = match.match(linePattern);
|
|
4729
|
-
if (lineMatch) {
|
|
4730
|
-
const lineString = lineMatch[0];
|
|
4731
|
-
replacement = replace({
|
|
4732
|
-
url: match.slice(0, -lineString.length),
|
|
4733
|
-
line: lineString ? parseInt(lineString) : null,
|
|
4734
|
-
});
|
|
4735
|
-
} else {
|
|
4736
|
-
replacement = replace({
|
|
4737
|
-
url: match,
|
|
4738
|
-
});
|
|
4739
|
-
}
|
|
4740
|
-
}
|
|
4741
|
-
if (endsWithSeparationChar) {
|
|
4742
|
-
return `${replacement}${lastChar}`;
|
|
4743
|
-
}
|
|
4744
|
-
return replacement;
|
|
4745
|
-
});
|
|
4746
|
-
};
|
|
4747
|
-
|
|
4748
4755
|
/*
|
|
4749
4756
|
* label
|
|
4750
4757
|
* ┌───────────────────────┴────────────────────────────────┐
|
|
@@ -4819,9 +4826,15 @@ const reporterList = ({
|
|
|
4819
4826
|
Object.keys(testPlanResult.results).length === 0
|
|
4820
4827
|
) {
|
|
4821
4828
|
return {
|
|
4822
|
-
afterEachInOrder: (execution) => {
|
|
4823
|
-
const log = renderExecutionLog(
|
|
4824
|
-
|
|
4829
|
+
afterEachInOrder: (execution, testPlanResult, testPlanHelpers) => {
|
|
4830
|
+
const log = renderExecutionLog(
|
|
4831
|
+
execution,
|
|
4832
|
+
logOptions,
|
|
4833
|
+
testPlanHelpers,
|
|
4834
|
+
);
|
|
4835
|
+
if (log) {
|
|
4836
|
+
write(log);
|
|
4837
|
+
}
|
|
4825
4838
|
},
|
|
4826
4839
|
afterAll: async () => {
|
|
4827
4840
|
await write(renderOutro(testPlanResult, logOptions));
|
|
@@ -4889,12 +4902,18 @@ const reporterList = ({
|
|
|
4889
4902
|
console.warn(warning.message);
|
|
4890
4903
|
});
|
|
4891
4904
|
},
|
|
4892
|
-
afterEachInOrder: (execution) => {
|
|
4905
|
+
afterEachInOrder: (execution, testPlanResult, testPlanHelpers) => {
|
|
4893
4906
|
oneExecutionWritten = true;
|
|
4894
4907
|
dynamicLog.clearDuringFunctionCall(
|
|
4895
4908
|
() => {
|
|
4896
|
-
const log = renderExecutionLog(
|
|
4897
|
-
|
|
4909
|
+
const log = renderExecutionLog(
|
|
4910
|
+
execution,
|
|
4911
|
+
logOptions,
|
|
4912
|
+
testPlanHelpers,
|
|
4913
|
+
);
|
|
4914
|
+
if (log) {
|
|
4915
|
+
write(log);
|
|
4916
|
+
}
|
|
4898
4917
|
},
|
|
4899
4918
|
// regenerate the dynamic log to put the leading "\n"
|
|
4900
4919
|
// because of oneExecutionWritten becoming true
|
|
@@ -4951,11 +4970,11 @@ const renderIntro = (testPlanResult, logOptions) => {
|
|
|
4951
4970
|
|
|
4952
4971
|
let title;
|
|
4953
4972
|
if (planified === 0) {
|
|
4954
|
-
title = `
|
|
4973
|
+
title = `nothing to execute`;
|
|
4955
4974
|
} else if (planified === 1) {
|
|
4956
|
-
title = `1 execution
|
|
4975
|
+
title = `1 execution ready`;
|
|
4957
4976
|
} else {
|
|
4958
|
-
title = `${planified} executions
|
|
4977
|
+
title = `${planified} executions ready`;
|
|
4959
4978
|
}
|
|
4960
4979
|
const lines = [];
|
|
4961
4980
|
lines.push(`directory: ${directory}`);
|
|
@@ -4977,6 +4996,11 @@ const renderIntro = (testPlanResult, logOptions) => {
|
|
|
4977
4996
|
testPlanLog += "}";
|
|
4978
4997
|
lines.push(`testPlan: ${testPlanLog}`);
|
|
4979
4998
|
}
|
|
4999
|
+
if (testPlanResult.fragment) {
|
|
5000
|
+
lines.push(
|
|
5001
|
+
`fragment: ${testPlanResult.fragment}, executing only ${testPlanResult.fragmentStart}:${testPlanResult.fragmentEnd}`,
|
|
5002
|
+
);
|
|
5003
|
+
}
|
|
4980
5004
|
if (logOptions.platformInfo) {
|
|
4981
5005
|
{
|
|
4982
5006
|
let osLine = `os: `;
|
|
@@ -5013,7 +5037,36 @@ const renderIntro = (testPlanResult, logOptions) => {
|
|
|
5013
5037
|
})}\n`;
|
|
5014
5038
|
};
|
|
5015
5039
|
|
|
5016
|
-
const renderExecutionLog = (
|
|
5040
|
+
const renderExecutionLog = (
|
|
5041
|
+
execution,
|
|
5042
|
+
logOptions,
|
|
5043
|
+
{ getPreviousExecution, getNextExecution },
|
|
5044
|
+
) => {
|
|
5045
|
+
if (execution.skipped) {
|
|
5046
|
+
const skipReason = execution.skipReason;
|
|
5047
|
+
const prev = getPreviousExecution(execution);
|
|
5048
|
+
if (prev && prev.skipped && prev.skipReason === skipReason) {
|
|
5049
|
+
return "";
|
|
5050
|
+
}
|
|
5051
|
+
let nextExecutionSkippedWithSameReason = 0;
|
|
5052
|
+
let next = getNextExecution(execution);
|
|
5053
|
+
while (next) {
|
|
5054
|
+
if (!next.skipped || next.skipReason !== skipReason) {
|
|
5055
|
+
break;
|
|
5056
|
+
}
|
|
5057
|
+
nextExecutionSkippedWithSameReason++;
|
|
5058
|
+
next = getNextExecution(next);
|
|
5059
|
+
}
|
|
5060
|
+
if (nextExecutionSkippedWithSameReason) {
|
|
5061
|
+
const skippedGroupLog = descriptionFormatters.skippedGroup({
|
|
5062
|
+
from: execution.index,
|
|
5063
|
+
to: execution.index + nextExecutionSkippedWithSameReason,
|
|
5064
|
+
skipReason,
|
|
5065
|
+
});
|
|
5066
|
+
return `${skippedGroupLog}\n`;
|
|
5067
|
+
}
|
|
5068
|
+
}
|
|
5069
|
+
|
|
5017
5070
|
let log = "";
|
|
5018
5071
|
// label
|
|
5019
5072
|
{
|
|
@@ -5094,15 +5147,38 @@ const descriptionFormatters = {
|
|
|
5094
5147
|
executing: ({ fileRelativeUrl }) => {
|
|
5095
5148
|
return ANSI.color(`${fileRelativeUrl}`, COLOR_EXECUTING);
|
|
5096
5149
|
},
|
|
5150
|
+
skippedGroup: ({ from, to, skipReason }) => {
|
|
5151
|
+
let description = `${UNICODE.CIRCLE_DOTTED_RAW} ${from + 1}:${to + 1} skipped`;
|
|
5152
|
+
if (skipReason) {
|
|
5153
|
+
description += ` (${skipReason})`;
|
|
5154
|
+
}
|
|
5155
|
+
return ANSI.color(description, COLOR_SKIPPED);
|
|
5156
|
+
},
|
|
5157
|
+
skipped: ({ index, countersInOrder, fileRelativeUrl, skipReason }) => {
|
|
5158
|
+
const total = countersInOrder.planified;
|
|
5159
|
+
const number = fillLeft(index + 1, total, "0");
|
|
5160
|
+
let description = `${UNICODE.CIRCLE_DOTTED_RAW} ${number}/${total} skipped ${fileRelativeUrl}`;
|
|
5161
|
+
if (skipReason) {
|
|
5162
|
+
description += ` (${skipReason})`;
|
|
5163
|
+
}
|
|
5164
|
+
return ANSI.color(description, COLOR_SKIPPED);
|
|
5165
|
+
},
|
|
5097
5166
|
aborted: ({ index, countersInOrder, fileRelativeUrl }) => {
|
|
5098
5167
|
const total = countersInOrder.planified;
|
|
5099
5168
|
const number = fillLeft(index + 1, total, "0");
|
|
5100
|
-
|
|
5101
5169
|
return ANSI.color(
|
|
5102
5170
|
`${UNICODE.FAILURE_RAW} ${number}/${total} ${fileRelativeUrl}`,
|
|
5103
5171
|
COLOR_ABORTED,
|
|
5104
5172
|
);
|
|
5105
5173
|
},
|
|
5174
|
+
cancelled: ({ index, countersInOrder, fileRelativeUrl }) => {
|
|
5175
|
+
const total = countersInOrder.planified;
|
|
5176
|
+
const number = fillLeft(index + 1, total, "0");
|
|
5177
|
+
return ANSI.color(
|
|
5178
|
+
`${UNICODE.FAILURE_RAW} ${number}/${total} ${fileRelativeUrl}`,
|
|
5179
|
+
COLOR_CANCELLED,
|
|
5180
|
+
);
|
|
5181
|
+
},
|
|
5106
5182
|
timedout: ({ index, countersInOrder, fileRelativeUrl, params }) => {
|
|
5107
5183
|
const total = countersInOrder.planified;
|
|
5108
5184
|
const number = fillLeft(index + 1, total, "0");
|
|
@@ -5130,23 +5206,15 @@ const descriptionFormatters = {
|
|
|
5130
5206
|
COLOR_COMPLETED,
|
|
5131
5207
|
);
|
|
5132
5208
|
},
|
|
5133
|
-
cancelled: ({ index, countersInOrder, fileRelativeUrl }) => {
|
|
5134
|
-
const total = countersInOrder.planified;
|
|
5135
|
-
const number = fillLeft(index + 1, total, "0");
|
|
5136
|
-
|
|
5137
|
-
return ANSI.color(
|
|
5138
|
-
`${UNICODE.FAILURE_RAW} ${number}/${total} ${fileRelativeUrl}`,
|
|
5139
|
-
COLOR_CANCELLED,
|
|
5140
|
-
);
|
|
5141
|
-
},
|
|
5142
5209
|
};
|
|
5143
5210
|
|
|
5144
5211
|
const COLOR_EXECUTING = ANSI.BLUE;
|
|
5212
|
+
const COLOR_SKIPPED = ANSI.GREY;
|
|
5145
5213
|
const COLOR_ABORTED = ANSI.MAGENTA;
|
|
5214
|
+
const COLOR_CANCELLED = ANSI.GREY;
|
|
5146
5215
|
const COLOR_TIMEOUT = ANSI.MAGENTA;
|
|
5147
5216
|
const COLOR_FAILED = ANSI.RED;
|
|
5148
5217
|
const COLOR_COMPLETED = ANSI.GREEN;
|
|
5149
|
-
const COLOR_CANCELLED = ANSI.GREY;
|
|
5150
5218
|
const fillLeft = (value, biggestValue, char = " ") => {
|
|
5151
5219
|
const width = String(value).length;
|
|
5152
5220
|
const biggestWidth = String(biggestValue).length;
|
|
@@ -5424,9 +5492,15 @@ const renderStatusRepartition = (counters, { showProgression } = {}) => {
|
|
|
5424
5492
|
if (counters.planified === 0) {
|
|
5425
5493
|
return ``;
|
|
5426
5494
|
}
|
|
5495
|
+
if (counters.skipped === counters.planified) {
|
|
5496
|
+
return `all ${ANSI.color(`skipped`, COLOR_SKIPPED)}`;
|
|
5497
|
+
}
|
|
5427
5498
|
if (counters.aborted === counters.planified) {
|
|
5428
5499
|
return `all ${ANSI.color(`aborted`, COLOR_ABORTED)}`;
|
|
5429
5500
|
}
|
|
5501
|
+
if (counters.cancelled === counters.planified) {
|
|
5502
|
+
return `all ${ANSI.color(`cancelled`, COLOR_CANCELLED)}`;
|
|
5503
|
+
}
|
|
5430
5504
|
if (counters.timedout === counters.planified) {
|
|
5431
5505
|
return `all ${ANSI.color(`timed out`, COLOR_TIMEOUT)}`;
|
|
5432
5506
|
}
|
|
@@ -5436,9 +5510,6 @@ const renderStatusRepartition = (counters, { showProgression } = {}) => {
|
|
|
5436
5510
|
if (counters.completed === counters.planified) {
|
|
5437
5511
|
return `all ${ANSI.color(`completed`, COLOR_COMPLETED)}`;
|
|
5438
5512
|
}
|
|
5439
|
-
if (counters.cancelled === counters.planified) {
|
|
5440
|
-
return `all ${ANSI.color(`cancelled`, COLOR_CANCELLED)}`;
|
|
5441
|
-
}
|
|
5442
5513
|
const parts = [];
|
|
5443
5514
|
if (counters.timedout) {
|
|
5444
5515
|
parts.push(
|
|
@@ -5461,6 +5532,9 @@ const renderStatusRepartition = (counters, { showProgression } = {}) => {
|
|
|
5461
5532
|
`${counters.cancelled} ${ANSI.color(`cancelled`, COLOR_CANCELLED)}`,
|
|
5462
5533
|
);
|
|
5463
5534
|
}
|
|
5535
|
+
if (counters.skipped) {
|
|
5536
|
+
parts.push(`${counters.skipped} ${ANSI.color(`skipped`, COLOR_SKIPPED)}`);
|
|
5537
|
+
}
|
|
5464
5538
|
if (showProgression) {
|
|
5465
5539
|
if (counters.executing) {
|
|
5466
5540
|
parts.push(`${counters.executing} executing`);
|
|
@@ -5543,6 +5617,39 @@ const renderDetails = (data) => {
|
|
|
5543
5617
|
return string;
|
|
5544
5618
|
};
|
|
5545
5619
|
|
|
5620
|
+
const createIsInsideFragment = (fragment, total) => {
|
|
5621
|
+
let [dividend, divisor] = fragment.split("/");
|
|
5622
|
+
dividend = parseInt(dividend);
|
|
5623
|
+
divisor = parseInt(divisor);
|
|
5624
|
+
const groupSize = Math.ceil(total / divisor);
|
|
5625
|
+
let from;
|
|
5626
|
+
let to;
|
|
5627
|
+
if (groupSize === 0) {
|
|
5628
|
+
if (dividend === 1) {
|
|
5629
|
+
from = 0;
|
|
5630
|
+
to = 0;
|
|
5631
|
+
} else {
|
|
5632
|
+
from = Infinity;
|
|
5633
|
+
to = -1;
|
|
5634
|
+
}
|
|
5635
|
+
} else if (dividend === 1) {
|
|
5636
|
+
from = 0;
|
|
5637
|
+
to = groupSize;
|
|
5638
|
+
} else {
|
|
5639
|
+
from = (dividend - 1) * groupSize;
|
|
5640
|
+
if (dividend === divisor) {
|
|
5641
|
+
to = total;
|
|
5642
|
+
} else {
|
|
5643
|
+
to = from + groupSize;
|
|
5644
|
+
}
|
|
5645
|
+
}
|
|
5646
|
+
return (index) => {
|
|
5647
|
+
if (index < from) return false;
|
|
5648
|
+
if (index >= to) return false;
|
|
5649
|
+
return true;
|
|
5650
|
+
};
|
|
5651
|
+
};
|
|
5652
|
+
|
|
5546
5653
|
/*
|
|
5547
5654
|
*
|
|
5548
5655
|
*/
|
|
@@ -5628,6 +5735,11 @@ const executeTestPlan = async ({
|
|
|
5628
5735
|
handleSIGTERM = true,
|
|
5629
5736
|
updateProcessExitCode = true,
|
|
5630
5737
|
parallel = parallelDefault,
|
|
5738
|
+
// https://github.com/avajs/ava/blob/main/docs/recipes/splitting-tests-ci.md
|
|
5739
|
+
// https://playwright.dev/docs/test-sharding
|
|
5740
|
+
fragment,
|
|
5741
|
+
fragmentByRuntime,
|
|
5742
|
+
fragmentBy,
|
|
5631
5743
|
defaultMsAllocatedPerExecution = 30_000,
|
|
5632
5744
|
failFast = false,
|
|
5633
5745
|
// keepRunning: false to ensure runtime is stopped once executed
|
|
@@ -5721,6 +5833,9 @@ const executeTestPlan = async ({
|
|
|
5721
5833
|
rootDirectoryUrl: String(rootDirectoryUrl),
|
|
5722
5834
|
patterns: Object.keys(testPlan),
|
|
5723
5835
|
groups: {},
|
|
5836
|
+
fragment,
|
|
5837
|
+
fragmentStart: undefined,
|
|
5838
|
+
fragmentEnd: undefined,
|
|
5724
5839
|
counters: {
|
|
5725
5840
|
planified: 0,
|
|
5726
5841
|
remaining: 0,
|
|
@@ -5728,6 +5843,7 @@ const executeTestPlan = async ({
|
|
|
5728
5843
|
executing: 0,
|
|
5729
5844
|
executed: 0,
|
|
5730
5845
|
|
|
5846
|
+
skipped: 0,
|
|
5731
5847
|
aborted: 0,
|
|
5732
5848
|
cancelled: 0,
|
|
5733
5849
|
timedout: 0,
|
|
@@ -5757,6 +5873,36 @@ const executeTestPlan = async ({
|
|
|
5757
5873
|
};
|
|
5758
5874
|
const beforeEachCallbackSet = new Set();
|
|
5759
5875
|
const beforeEachInOrderCallbackSet = new Set();
|
|
5876
|
+
const triggerBeforeEach = (execution, testPlanResult, testPlanHelpers) => {
|
|
5877
|
+
for (const beforeEachCallback of beforeEachCallbackSet) {
|
|
5878
|
+
const returnValue = beforeEachCallback(
|
|
5879
|
+
execution,
|
|
5880
|
+
testPlanResult,
|
|
5881
|
+
testPlanHelpers,
|
|
5882
|
+
);
|
|
5883
|
+
if (typeof returnValue === "function") {
|
|
5884
|
+
const callback = (...args) => {
|
|
5885
|
+
afterEachCallbackSet.delete(callback);
|
|
5886
|
+
return returnValue(...args);
|
|
5887
|
+
};
|
|
5888
|
+
afterEachCallbackSet.add(callback);
|
|
5889
|
+
}
|
|
5890
|
+
}
|
|
5891
|
+
for (const beforeEachInOrderCallback of beforeEachInOrderCallbackSet) {
|
|
5892
|
+
const returnValue = beforeEachInOrderCallback(
|
|
5893
|
+
execution,
|
|
5894
|
+
testPlanResult,
|
|
5895
|
+
testPlanHelpers,
|
|
5896
|
+
);
|
|
5897
|
+
if (typeof returnValue === "function") {
|
|
5898
|
+
const callback = (...args) => {
|
|
5899
|
+
afterEachInOrderCallbackSet.delete(callback);
|
|
5900
|
+
return returnValue(...args);
|
|
5901
|
+
};
|
|
5902
|
+
afterEachInOrderCallbackSet.add(callback);
|
|
5903
|
+
}
|
|
5904
|
+
}
|
|
5905
|
+
};
|
|
5760
5906
|
const afterEachCallbackSet = new Set();
|
|
5761
5907
|
const afterEachInOrderCallbackSet = new Set();
|
|
5762
5908
|
const afterAllCallbackSet = new Set();
|
|
@@ -5889,6 +6035,16 @@ const executeTestPlan = async ({
|
|
|
5889
6035
|
);
|
|
5890
6036
|
}
|
|
5891
6037
|
}
|
|
6038
|
+
// fragment/fragmentByRuntime
|
|
6039
|
+
{
|
|
6040
|
+
if (fragment) {
|
|
6041
|
+
if (!/[0-9]+\/[0-9]+/.test(fragment)) {
|
|
6042
|
+
throw new TypeError(
|
|
6043
|
+
`fragment must look like number/number, received ${fragment}`,
|
|
6044
|
+
);
|
|
6045
|
+
}
|
|
6046
|
+
}
|
|
6047
|
+
}
|
|
5892
6048
|
// testPlan
|
|
5893
6049
|
{
|
|
5894
6050
|
if (typeof testPlan !== "object") {
|
|
@@ -6093,9 +6249,21 @@ To fix this warning:
|
|
|
6093
6249
|
}
|
|
6094
6250
|
}
|
|
6095
6251
|
|
|
6096
|
-
const
|
|
6252
|
+
const executionPlanifiedArray = [];
|
|
6253
|
+
const getPreviousExecution = (execution) => {
|
|
6254
|
+
const index = execution.index;
|
|
6255
|
+
return executionPlanifiedArray[index - 1] || null;
|
|
6256
|
+
};
|
|
6257
|
+
const getNextExecution = (execution) => {
|
|
6258
|
+
const index = execution.index;
|
|
6259
|
+
return executionPlanifiedArray[index + 1] || null;
|
|
6260
|
+
};
|
|
6261
|
+
const testPlanHelpers = {
|
|
6262
|
+
getPreviousExecution,
|
|
6263
|
+
getNextExecution,
|
|
6264
|
+
};
|
|
6097
6265
|
|
|
6098
|
-
// collect files to execute + fill
|
|
6266
|
+
// collect files to execute + fill executionPlanifiedArray
|
|
6099
6267
|
{
|
|
6100
6268
|
const fileResultArray = await collectFiles({
|
|
6101
6269
|
signal,
|
|
@@ -6103,6 +6271,11 @@ To fix this warning:
|
|
|
6103
6271
|
associations: { testPlan },
|
|
6104
6272
|
predicate: ({ testPlan }) => testPlan,
|
|
6105
6273
|
});
|
|
6274
|
+
|
|
6275
|
+
// idéalement dans les logs on aurait un truc comme ceci:
|
|
6276
|
+
// --- 100 execution found ---
|
|
6277
|
+
// Executing only from 33 to 66 according to fragment: "2/3"
|
|
6278
|
+
|
|
6106
6279
|
let index = 0;
|
|
6107
6280
|
let lastExecution;
|
|
6108
6281
|
const fileExecutionCountMap = new Map();
|
|
@@ -6125,10 +6298,6 @@ To fix this warning:
|
|
|
6125
6298
|
),
|
|
6126
6299
|
);
|
|
6127
6300
|
}
|
|
6128
|
-
if (stepConfig.runtime?.disabled) {
|
|
6129
|
-
continue;
|
|
6130
|
-
}
|
|
6131
|
-
|
|
6132
6301
|
const {
|
|
6133
6302
|
runtime,
|
|
6134
6303
|
runtimeParams,
|
|
@@ -6185,6 +6354,8 @@ To fix this warning:
|
|
|
6185
6354
|
runtimeName,
|
|
6186
6355
|
runtimeVersion,
|
|
6187
6356
|
params,
|
|
6357
|
+
skipped: false,
|
|
6358
|
+
skipReason: "",
|
|
6188
6359
|
|
|
6189
6360
|
// will be set by run()
|
|
6190
6361
|
status: "planified",
|
|
@@ -6195,7 +6366,7 @@ To fix this warning:
|
|
|
6195
6366
|
}
|
|
6196
6367
|
|
|
6197
6368
|
lastExecution = execution;
|
|
6198
|
-
|
|
6369
|
+
executionPlanifiedArray.push(execution);
|
|
6199
6370
|
const existingResults = results[relativeUrl];
|
|
6200
6371
|
if (existingResults) {
|
|
6201
6372
|
existingResults[groupName] = execution.result;
|
|
@@ -6215,9 +6386,48 @@ To fix this warning:
|
|
|
6215
6386
|
runtimeVersion,
|
|
6216
6387
|
};
|
|
6217
6388
|
}
|
|
6389
|
+
|
|
6390
|
+
if (runtime?.disabled) {
|
|
6391
|
+
execution.skipped = true;
|
|
6392
|
+
execution.skipReason =
|
|
6393
|
+
runtime.disabledReason || "reason not specified";
|
|
6394
|
+
} else if (fragmentByRuntime && runtime.name !== fragmentByRuntime) {
|
|
6395
|
+
execution.skipped = true;
|
|
6396
|
+
execution.skipReason = "runtime disabled";
|
|
6397
|
+
} else if (fragmentBy) {
|
|
6398
|
+
const fragmentByResult = fragmentBy(execution);
|
|
6399
|
+
if (fragmentByResult) {
|
|
6400
|
+
execution.skipped = true;
|
|
6401
|
+
execution.skipReason =
|
|
6402
|
+
typeof fragmentByResult === "string"
|
|
6403
|
+
? fragmentByResult
|
|
6404
|
+
: `reason not specified`;
|
|
6405
|
+
}
|
|
6406
|
+
}
|
|
6218
6407
|
index++;
|
|
6219
6408
|
}
|
|
6220
6409
|
}
|
|
6410
|
+
|
|
6411
|
+
if (fragment) {
|
|
6412
|
+
const total = executionPlanifiedArray.length;
|
|
6413
|
+
const isInsideFragment = createIsInsideFragment(fragment, total);
|
|
6414
|
+
for (const execution of executionPlanifiedArray) {
|
|
6415
|
+
if (isInsideFragment(execution.index)) {
|
|
6416
|
+
const executionNumber = execution.index + 1;
|
|
6417
|
+
if (testPlanResult.fragmentStart === undefined) {
|
|
6418
|
+
testPlanResult.fragmentStart = executionNumber;
|
|
6419
|
+
}
|
|
6420
|
+
if (
|
|
6421
|
+
testPlanResult.fragmentEnd === undefined ||
|
|
6422
|
+
executionNumber > testPlanResult.fragmentEnd
|
|
6423
|
+
) {
|
|
6424
|
+
testPlanResult.fragmentEnd = executionNumber;
|
|
6425
|
+
}
|
|
6426
|
+
} else {
|
|
6427
|
+
execution.skipped = true;
|
|
6428
|
+
}
|
|
6429
|
+
}
|
|
6430
|
+
}
|
|
6221
6431
|
fileResultArray.length = 0;
|
|
6222
6432
|
fileExecutionCountMap.clear();
|
|
6223
6433
|
if (lastExecution) {
|
|
@@ -6228,11 +6438,11 @@ To fix this warning:
|
|
|
6228
6438
|
counters.planified =
|
|
6229
6439
|
counters.remaining =
|
|
6230
6440
|
counters.waiting =
|
|
6231
|
-
|
|
6441
|
+
executionPlanifiedArray.length;
|
|
6232
6442
|
countersInOrder.planified =
|
|
6233
6443
|
countersInOrder.remaining =
|
|
6234
6444
|
countersInOrder.waiting =
|
|
6235
|
-
|
|
6445
|
+
executionPlanifiedArray.length;
|
|
6236
6446
|
if (githubCheck) {
|
|
6237
6447
|
const githubCheckRun = await startGithubCheckRun({
|
|
6238
6448
|
logLevel: githubCheck.logLevel,
|
|
@@ -6242,7 +6452,7 @@ To fix this warning:
|
|
|
6242
6452
|
commitSha: githubCheck.commitSha,
|
|
6243
6453
|
checkName: githubCheck.name,
|
|
6244
6454
|
checkTitle: githubCheck.title,
|
|
6245
|
-
checkSummary: `${
|
|
6455
|
+
checkSummary: `${executionPlanifiedArray.length} files will be executed`,
|
|
6246
6456
|
});
|
|
6247
6457
|
const annotations = [];
|
|
6248
6458
|
reporters.push({
|
|
@@ -6322,80 +6532,66 @@ To fix this warning:
|
|
|
6322
6532
|
|
|
6323
6533
|
const callWhenPreviousExecutionAreDone = createCallOrderer();
|
|
6324
6534
|
|
|
6325
|
-
const executionRemainingSet = new Set(
|
|
6535
|
+
const executionRemainingSet = new Set(executionPlanifiedArray);
|
|
6326
6536
|
const executionExecutingSet = new Set();
|
|
6327
6537
|
const usedTagSet = new Set();
|
|
6328
6538
|
const start = async (execution) => {
|
|
6329
|
-
if (execution.params.uses) {
|
|
6330
|
-
for (const tagThatWillBeUsed of execution.params.uses) {
|
|
6331
|
-
usedTagSet.add(tagThatWillBeUsed);
|
|
6332
|
-
}
|
|
6333
|
-
}
|
|
6334
6539
|
execution.fileExecutionCount = Object.keys(
|
|
6335
6540
|
testPlanResult.results[execution.fileRelativeUrl],
|
|
6336
6541
|
).length;
|
|
6337
6542
|
mutateCountersBeforeExecutionStarts(counters, execution);
|
|
6338
6543
|
mutateCountersBeforeExecutionStarts(countersInOrder, execution);
|
|
6339
|
-
|
|
6340
|
-
execution.status = "executing";
|
|
6341
6544
|
executionRemainingSet.delete(execution);
|
|
6342
6545
|
executionExecutingSet.add(execution);
|
|
6343
|
-
|
|
6344
|
-
|
|
6345
|
-
|
|
6346
|
-
|
|
6347
|
-
|
|
6348
|
-
|
|
6349
|
-
|
|
6350
|
-
|
|
6546
|
+
triggerBeforeEach(execution, testPlanResult, testPlanHelpers);
|
|
6547
|
+
if (execution.skipped) {
|
|
6548
|
+
execution.result.status = "skipped";
|
|
6549
|
+
execution.result.value = execution.skipReason;
|
|
6550
|
+
} else {
|
|
6551
|
+
if (execution.params.uses) {
|
|
6552
|
+
for (const tagThatWillBeUsed of execution.params.uses) {
|
|
6553
|
+
usedTagSet.add(tagThatWillBeUsed);
|
|
6554
|
+
}
|
|
6351
6555
|
}
|
|
6352
|
-
|
|
6353
|
-
|
|
6354
|
-
|
|
6355
|
-
|
|
6356
|
-
|
|
6357
|
-
|
|
6358
|
-
|
|
6359
|
-
|
|
6360
|
-
|
|
6361
|
-
|
|
6362
|
-
|
|
6363
|
-
|
|
6556
|
+
execution.status = "executing";
|
|
6557
|
+
const executionResult = await run({
|
|
6558
|
+
...execution.params,
|
|
6559
|
+
signal: operation.signal,
|
|
6560
|
+
logger,
|
|
6561
|
+
keepRunning,
|
|
6562
|
+
mirrorConsole: false, // might be executed in parallel: log would be a mess to read
|
|
6563
|
+
coverageEnabled: Boolean(coverage),
|
|
6564
|
+
coverageTempDirectoryUrl: coverage?.tempDirectoryUrl,
|
|
6565
|
+
});
|
|
6566
|
+
Object.assign(execution.result, executionResult);
|
|
6567
|
+
execution.status = "executed";
|
|
6568
|
+
if (execution.params.uses) {
|
|
6569
|
+
for (const tagNoLongerInUse of execution.params.uses) {
|
|
6570
|
+
usedTagSet.delete(tagNoLongerInUse);
|
|
6571
|
+
}
|
|
6364
6572
|
}
|
|
6365
|
-
|
|
6366
|
-
|
|
6367
|
-
|
|
6368
|
-
|
|
6369
|
-
|
|
6370
|
-
keepRunning,
|
|
6371
|
-
mirrorConsole: false, // might be executed in parallel: log would be a mess to read
|
|
6372
|
-
coverageEnabled: Boolean(coverage),
|
|
6373
|
-
coverageTempDirectoryUrl: coverage?.tempDirectoryUrl,
|
|
6374
|
-
});
|
|
6375
|
-
Object.assign(execution.result, executionResult);
|
|
6376
|
-
execution.status = "executed";
|
|
6377
|
-
executionExecutingSet.delete(execution);
|
|
6378
|
-
mutateCountersAfterExecutionEnds(counters, execution);
|
|
6379
|
-
if (execution.result.status !== "completed") {
|
|
6380
|
-
testPlanResult.failed = true;
|
|
6381
|
-
if (updateProcessExitCode) {
|
|
6382
|
-
process.exitCode = 1;
|
|
6573
|
+
if (execution.result.status !== "completed") {
|
|
6574
|
+
testPlanResult.failed = true;
|
|
6575
|
+
if (updateProcessExitCode) {
|
|
6576
|
+
process.exitCode = 1;
|
|
6577
|
+
}
|
|
6383
6578
|
}
|
|
6384
6579
|
}
|
|
6580
|
+
mutateCountersAfterExecutionEnds(counters, execution);
|
|
6581
|
+
executionExecutingSet.delete(execution);
|
|
6385
6582
|
for (const afterEachCallback of afterEachCallbackSet) {
|
|
6386
|
-
afterEachCallback(execution, testPlanResult);
|
|
6583
|
+
afterEachCallback(execution, testPlanResult, testPlanHelpers);
|
|
6387
6584
|
}
|
|
6388
6585
|
callWhenPreviousExecutionAreDone(execution.index, () => {
|
|
6389
6586
|
mutateCountersAfterExecutionEnds(countersInOrder, execution);
|
|
6390
6587
|
for (const afterEachInOrderCallback of afterEachInOrderCallbackSet) {
|
|
6391
|
-
afterEachInOrderCallback(
|
|
6588
|
+
afterEachInOrderCallback(
|
|
6589
|
+
execution,
|
|
6590
|
+
testPlanResult,
|
|
6591
|
+
testPlanHelpers,
|
|
6592
|
+
);
|
|
6392
6593
|
}
|
|
6393
6594
|
});
|
|
6394
|
-
if (execution.params.uses) {
|
|
6395
|
-
for (const tagNoLongerInUse of execution.params.uses) {
|
|
6396
|
-
usedTagSet.delete(tagNoLongerInUse);
|
|
6397
|
-
}
|
|
6398
|
-
}
|
|
6399
6595
|
if (testPlanResult.failed && failFast && counters.remaining) {
|
|
6400
6596
|
logger.info(`"failFast" enabled -> cancel remaining executions`);
|
|
6401
6597
|
failFastAbortController.abort();
|
|
@@ -6609,7 +6805,9 @@ const mutateCountersAfterExecutionEnds = (counters, execution) => {
|
|
|
6609
6805
|
counters.executing--;
|
|
6610
6806
|
counters.executed++;
|
|
6611
6807
|
counters.remaining--;
|
|
6612
|
-
if (execution.result.status === "
|
|
6808
|
+
if (execution.result.status === "skipped") {
|
|
6809
|
+
counters.skipped++;
|
|
6810
|
+
} else if (execution.result.status === "aborted") {
|
|
6613
6811
|
counters.aborted++;
|
|
6614
6812
|
} else if (execution.result.status === "timedout") {
|
|
6615
6813
|
counters.timedout++;
|
|
@@ -7479,7 +7677,7 @@ const createFirefoxRuntime = ({
|
|
|
7479
7677
|
if (disableOnWindowsBecauseFlaky === undefined) {
|
|
7480
7678
|
// https://github.com/microsoft/playwright/issues/1396
|
|
7481
7679
|
console.warn(
|
|
7482
|
-
`Windows + firefox detected: executions on firefox will be ignored
|
|
7680
|
+
`Windows + firefox detected: executions on firefox will be ignored (firefox is flaky on windows).
|
|
7483
7681
|
To disable this warning, use disableOnWindowsBecauseFlaky: true
|
|
7484
7682
|
To ignore potential flakyness, use disableOnWindowsBecauseFlaky: false`,
|
|
7485
7683
|
);
|
|
@@ -7488,6 +7686,7 @@ To ignore potential flakyness, use disableOnWindowsBecauseFlaky: false`,
|
|
|
7488
7686
|
if (disableOnWindowsBecauseFlaky) {
|
|
7489
7687
|
return {
|
|
7490
7688
|
disabled: true,
|
|
7689
|
+
disabledReason: "flaky on windows",
|
|
7491
7690
|
};
|
|
7492
7691
|
}
|
|
7493
7692
|
}
|
|
@@ -7874,11 +8073,8 @@ const nodeChildProcess = ({
|
|
|
7874
8073
|
env = {
|
|
7875
8074
|
...env,
|
|
7876
8075
|
JSENV: true,
|
|
7877
|
-
FORCE_COLOR:
|
|
7878
|
-
|
|
7879
|
-
// GitHub workflow does support ANSI but "supports-color" returns false
|
|
7880
|
-
// because stream.isTTY returns false, see https://github.com/actions/runner/issues/241
|
|
7881
|
-
process.env.GITHUB_WORKFLOW,
|
|
8076
|
+
...(ANSI.supported ? { FORCE_COLOR: "1" } : {}),
|
|
8077
|
+
...(UNICODE.supported ? { FORCE_UNICODE: "1" } : {}),
|
|
7882
8078
|
};
|
|
7883
8079
|
|
|
7884
8080
|
return {
|
|
@@ -8353,11 +8549,8 @@ const nodeWorkerThread = ({
|
|
|
8353
8549
|
env = {
|
|
8354
8550
|
...env,
|
|
8355
8551
|
JSENV: true,
|
|
8356
|
-
FORCE_COLOR:
|
|
8357
|
-
|
|
8358
|
-
// GitHub workflow does support ANSI but "supports-color" returns false
|
|
8359
|
-
// because stream.isTTY returns false, see https://github.com/actions/runner/issues/241
|
|
8360
|
-
process.env.GITHUB_WORKFLOW,
|
|
8552
|
+
...(ANSI.supported ? { FORCE_COLOR: "1" } : {}),
|
|
8553
|
+
...(UNICODE.supported ? { FORCE_UNICODE: "1" } : {}),
|
|
8361
8554
|
};
|
|
8362
8555
|
|
|
8363
8556
|
return {
|
|
@@ -8966,22 +9159,26 @@ const reportAsJunitXml = async (
|
|
|
8966
9159
|
});
|
|
8967
9160
|
testSuite.appendChild(testCase);
|
|
8968
9161
|
|
|
8969
|
-
if (executionResult.status === "
|
|
9162
|
+
if (executionResult.status === "skipped") {
|
|
9163
|
+
testCase.attributes.skipped = 1;
|
|
9164
|
+
const skipped = testCase.createNode("skipped", {
|
|
9165
|
+
message: "Execution was skipped",
|
|
9166
|
+
});
|
|
9167
|
+
testSuite.appendChild(skipped);
|
|
9168
|
+
} else if (executionResult.status === "aborted") {
|
|
8970
9169
|
testCase.attributes.skipped = 1;
|
|
8971
9170
|
const skipped = testCase.createNode("skipped", {
|
|
8972
9171
|
message: "Execution was aborted",
|
|
8973
9172
|
});
|
|
8974
9173
|
testSuite.appendChild(skipped);
|
|
8975
|
-
}
|
|
8976
|
-
if (executionResult.status === "timedout") {
|
|
9174
|
+
} else if (executionResult.status === "timedout") {
|
|
8977
9175
|
testCase.attributes.failures = 1;
|
|
8978
9176
|
const failure = testCase.createNode("failure", {
|
|
8979
9177
|
message: `Execution timeout after ${executionResult.params.allocatedMs}ms"`,
|
|
8980
9178
|
type: "timeout",
|
|
8981
9179
|
});
|
|
8982
9180
|
testSuite.appendChild(failure);
|
|
8983
|
-
}
|
|
8984
|
-
if (executionResult.status === "failed") {
|
|
9181
|
+
} else if (executionResult.status === "failed") {
|
|
8985
9182
|
const [error] = executionResult.errors;
|
|
8986
9183
|
if (
|
|
8987
9184
|
error &&
|
|
@@ -9035,7 +9232,7 @@ const reportAsJunitXml = async (
|
|
|
9035
9232
|
propertiesNode.appendChild(propertyNode);
|
|
9036
9233
|
}
|
|
9037
9234
|
|
|
9038
|
-
const { consoleCalls } = executionResult;
|
|
9235
|
+
const { consoleCalls = [] } = executionResult;
|
|
9039
9236
|
let stdout = "";
|
|
9040
9237
|
let stderr = "";
|
|
9041
9238
|
for (const consoleCall of consoleCalls) {
|
|
@@ -9068,6 +9265,123 @@ ${testSuite.renderAsString()}`;
|
|
|
9068
9265
|
writeFileSync(new URL(fileUrl), junitXmlFileContent);
|
|
9069
9266
|
};
|
|
9070
9267
|
|
|
9268
|
+
const reportAsJson = (
|
|
9269
|
+
testPlanResult,
|
|
9270
|
+
fileUrl,
|
|
9271
|
+
{ mockFluctuatingValues } = {},
|
|
9272
|
+
) => {
|
|
9273
|
+
fileUrl = assertAndNormalizeFileUrl(fileUrl);
|
|
9274
|
+
|
|
9275
|
+
if (!mockFluctuatingValues) {
|
|
9276
|
+
writeFileSync(fileUrl, JSON.stringify(testPlanResult, null, " "));
|
|
9277
|
+
return;
|
|
9278
|
+
}
|
|
9279
|
+
const testPlanResultCopy = deepCopy(testPlanResult, {});
|
|
9280
|
+
testPlanResultCopy.os.name = "<mock>";
|
|
9281
|
+
testPlanResultCopy.os.version = "<mock>";
|
|
9282
|
+
testPlanResultCopy.os.availableCpu = "<mock>";
|
|
9283
|
+
testPlanResultCopy.os.availableMemory = "<mock>";
|
|
9284
|
+
testPlanResultCopy.process.version = "<mock>";
|
|
9285
|
+
testPlanResultCopy.memoryUsage = "<mock>";
|
|
9286
|
+
testPlanResultCopy.cpuUsage = "<mock>";
|
|
9287
|
+
testPlanResultCopy.rootDirectoryUrl = "/mock/";
|
|
9288
|
+
testPlanResultCopy.timings = "<mock>";
|
|
9289
|
+
for (const group of Object.keys(testPlanResultCopy.groups)) {
|
|
9290
|
+
testPlanResultCopy.groups[group].runtimeVersion = "<mock>";
|
|
9291
|
+
}
|
|
9292
|
+
|
|
9293
|
+
for (const relativeUrl of Object.keys(testPlanResultCopy.results)) {
|
|
9294
|
+
const fileResults = testPlanResultCopy.results[relativeUrl];
|
|
9295
|
+
for (const groupName of Object.keys(fileResults)) {
|
|
9296
|
+
const executionResult = fileResults[groupName];
|
|
9297
|
+
const { consoleCalls } = executionResult;
|
|
9298
|
+
if (consoleCalls) {
|
|
9299
|
+
for (const consoleCall of consoleCalls) {
|
|
9300
|
+
consoleCall.text = mockFluctuatingValuesInMessage(consoleCall.text, {
|
|
9301
|
+
rootDirectoryUrl: testPlanResult.rootDirectoryUrl,
|
|
9302
|
+
});
|
|
9303
|
+
consoleCall.text = consoleCall.text.replace(/\r\n/g, "\n");
|
|
9304
|
+
}
|
|
9305
|
+
}
|
|
9306
|
+
const { errors } = executionResult;
|
|
9307
|
+
if (errors) {
|
|
9308
|
+
for (const error of errors) {
|
|
9309
|
+
if (error.message) {
|
|
9310
|
+
error.message = mockFluctuatingValuesInMessage(error.message, {
|
|
9311
|
+
rootDirectoryUrl: testPlanResult.rootDirectoryUrl,
|
|
9312
|
+
});
|
|
9313
|
+
}
|
|
9314
|
+
if (error.stack) {
|
|
9315
|
+
error.stack = mockFluctuatingValuesInMessage(error.stack, {
|
|
9316
|
+
rootDirectoryUrl: testPlanResult.rootDirectoryUrl,
|
|
9317
|
+
});
|
|
9318
|
+
}
|
|
9319
|
+
}
|
|
9320
|
+
}
|
|
9321
|
+
if (executionResult.timings) {
|
|
9322
|
+
executionResult.timings = "<mock>";
|
|
9323
|
+
}
|
|
9324
|
+
if (Object.hasOwn(executionResult, "memoryUsage")) {
|
|
9325
|
+
executionResult.memoryUsage = "<mock>";
|
|
9326
|
+
}
|
|
9327
|
+
if (executionResult.performance) {
|
|
9328
|
+
executionResult.performance = "<mock>";
|
|
9329
|
+
}
|
|
9330
|
+
if (executionResult.coverageFileUrl) {
|
|
9331
|
+
executionResult.coverageFileUrl = "<mock>";
|
|
9332
|
+
}
|
|
9333
|
+
}
|
|
9334
|
+
}
|
|
9335
|
+
writeFileSync(fileUrl, JSON.stringify(testPlanResultCopy, null, " "));
|
|
9336
|
+
};
|
|
9337
|
+
|
|
9338
|
+
const mockFluctuatingValuesInMessage = (message, { rootDirectoryUrl }) => {
|
|
9339
|
+
return replaceUrls(message, ({ url, line, column }) => {
|
|
9340
|
+
let urlAsPath = String(url).startsWith("file:")
|
|
9341
|
+
? urlToFileSystemPath(url)
|
|
9342
|
+
: url;
|
|
9343
|
+
const rootDirectoryPath = urlToFileSystemPath(rootDirectoryUrl);
|
|
9344
|
+
urlAsPath = urlAsPath.replace(rootDirectoryPath, "/mock/");
|
|
9345
|
+
if (process.platform === "win32") {
|
|
9346
|
+
urlAsPath = urlAsPath.replace(/\\/g, "/");
|
|
9347
|
+
}
|
|
9348
|
+
if (typeof line === "number" && typeof column === "number") {
|
|
9349
|
+
return `${urlAsPath}:${line}:${column}`;
|
|
9350
|
+
}
|
|
9351
|
+
if (typeof line === "number") {
|
|
9352
|
+
return `${urlAsPath}:${line}`;
|
|
9353
|
+
}
|
|
9354
|
+
return urlAsPath;
|
|
9355
|
+
});
|
|
9356
|
+
};
|
|
9357
|
+
|
|
9358
|
+
const deepCopy = (from, into) => {
|
|
9359
|
+
const copyValue = (value) => {
|
|
9360
|
+
if (value === null) {
|
|
9361
|
+
return null;
|
|
9362
|
+
}
|
|
9363
|
+
if (typeof value === "object") {
|
|
9364
|
+
if (Array.isArray(value)) {
|
|
9365
|
+
return deepCopy(value, []);
|
|
9366
|
+
}
|
|
9367
|
+
return deepCopy(value, {});
|
|
9368
|
+
}
|
|
9369
|
+
return value;
|
|
9370
|
+
};
|
|
9371
|
+
|
|
9372
|
+
if (Array.isArray(from)) {
|
|
9373
|
+
let i = 0;
|
|
9374
|
+
while (i < from.length) {
|
|
9375
|
+
into[i] = copyValue(from[i]);
|
|
9376
|
+
i++;
|
|
9377
|
+
}
|
|
9378
|
+
}
|
|
9379
|
+
for (const key of Object.keys(from)) {
|
|
9380
|
+
into[key] = copyValue(from[key]);
|
|
9381
|
+
}
|
|
9382
|
+
return into;
|
|
9383
|
+
};
|
|
9384
|
+
|
|
9071
9385
|
/*
|
|
9072
9386
|
* Export a function capable to execute a file on a runtime (browser or node) and return how it goes.
|
|
9073
9387
|
*
|
|
@@ -9262,4 +9576,4 @@ const inlineRuntime = (fn) => {
|
|
|
9262
9576
|
};
|
|
9263
9577
|
};
|
|
9264
9578
|
|
|
9265
|
-
export { chromium, chromiumIsolatedTab, execute, executeTestPlan, firefox, firefoxIsolatedTab, inlineRuntime, nodeChildProcess, nodeWorkerThread, reportAsJunitXml, reportCoverageAsHtml, reportCoverageAsJson, reportCoverageInConsole, reporterList, webkit, webkitIsolatedTab };
|
|
9579
|
+
export { chromium, chromiumIsolatedTab, execute, executeTestPlan, firefox, firefoxIsolatedTab, inlineRuntime, nodeChildProcess, nodeWorkerThread, reportAsJson, reportAsJunitXml, reportCoverageAsHtml, reportCoverageAsJson, reportCoverageInConsole, reporterList, webkit, webkitIsolatedTab };
|