@jsenv/test 3.2.1 → 3.3.2
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/jsenv_test.js +478 -167
- package/package.json +7 -7
- package/src/execution/execute_test_plan.js +156 -64
- package/src/execution/format_error_for_terminal.js +2 -51
- 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 +98 -31
- 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
|
@@ -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
|
|
|
@@ -4565,6 +4569,57 @@ const normalizeRuntimeError = (runtimeError) => {
|
|
|
4565
4569
|
return errorProxy;
|
|
4566
4570
|
};
|
|
4567
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
|
+
|
|
4568
4623
|
const formatErrorForTerminal = (
|
|
4569
4624
|
error,
|
|
4570
4625
|
{ rootDirectoryUrl, mainFileRelativeUrl, mockFluctuatingValues, tryColors },
|
|
@@ -4697,57 +4752,6 @@ const formatErrorForTerminal = (
|
|
|
4697
4752
|
return text;
|
|
4698
4753
|
};
|
|
4699
4754
|
|
|
4700
|
-
// `Error: yo
|
|
4701
|
-
// at Object.execute (http://127.0.0.1:57300/build/src/__test__/file-throw.js:9:13)
|
|
4702
|
-
// at doExec (http://127.0.0.1:3000/src/__test__/file-throw.js:452:38)
|
|
4703
|
-
// at postOrderExec (http://127.0.0.1:3000/src/__test__/file-throw.js:448:16)
|
|
4704
|
-
// at http://127.0.0.1:3000/src/__test__/file-throw.js:399:18`.replace(/(?:https?|ftp|file):\/\/(.*+)$/gm, (...args) => {
|
|
4705
|
-
// debugger
|
|
4706
|
-
// })
|
|
4707
|
-
const replaceUrls = (source, replace) => {
|
|
4708
|
-
return source.replace(/(?:https?|ftp|file):\/\/\S+/g, (match) => {
|
|
4709
|
-
let replacement = "";
|
|
4710
|
-
const lastChar = match[match.length - 1];
|
|
4711
|
-
|
|
4712
|
-
// hotfix because our url regex sucks a bit
|
|
4713
|
-
const endsWithSeparationChar = lastChar === ")" || lastChar === ":";
|
|
4714
|
-
if (endsWithSeparationChar) {
|
|
4715
|
-
match = match.slice(0, -1);
|
|
4716
|
-
}
|
|
4717
|
-
|
|
4718
|
-
const lineAndColumnPattern = /:([0-9]+):([0-9]+)$/;
|
|
4719
|
-
const lineAndColumMatch = match.match(lineAndColumnPattern);
|
|
4720
|
-
if (lineAndColumMatch) {
|
|
4721
|
-
const lineAndColumnString = lineAndColumMatch[0];
|
|
4722
|
-
const lineString = lineAndColumMatch[1];
|
|
4723
|
-
const columnString = lineAndColumMatch[2];
|
|
4724
|
-
replacement = replace({
|
|
4725
|
-
url: match.slice(0, -lineAndColumnString.length),
|
|
4726
|
-
line: lineString ? parseInt(lineString) : null,
|
|
4727
|
-
column: columnString ? parseInt(columnString) : null,
|
|
4728
|
-
});
|
|
4729
|
-
} else {
|
|
4730
|
-
const linePattern = /:([0-9]+)$/;
|
|
4731
|
-
const lineMatch = match.match(linePattern);
|
|
4732
|
-
if (lineMatch) {
|
|
4733
|
-
const lineString = lineMatch[0];
|
|
4734
|
-
replacement = replace({
|
|
4735
|
-
url: match.slice(0, -lineString.length),
|
|
4736
|
-
line: lineString ? parseInt(lineString) : null,
|
|
4737
|
-
});
|
|
4738
|
-
} else {
|
|
4739
|
-
replacement = replace({
|
|
4740
|
-
url: match,
|
|
4741
|
-
});
|
|
4742
|
-
}
|
|
4743
|
-
}
|
|
4744
|
-
if (endsWithSeparationChar) {
|
|
4745
|
-
return `${replacement}${lastChar}`;
|
|
4746
|
-
}
|
|
4747
|
-
return replacement;
|
|
4748
|
-
});
|
|
4749
|
-
};
|
|
4750
|
-
|
|
4751
4755
|
/*
|
|
4752
4756
|
* label
|
|
4753
4757
|
* ┌───────────────────────┴────────────────────────────────┐
|
|
@@ -4822,9 +4826,15 @@ const reporterList = ({
|
|
|
4822
4826
|
Object.keys(testPlanResult.results).length === 0
|
|
4823
4827
|
) {
|
|
4824
4828
|
return {
|
|
4825
|
-
afterEachInOrder: (execution) => {
|
|
4826
|
-
const log = renderExecutionLog(
|
|
4827
|
-
|
|
4829
|
+
afterEachInOrder: (execution, testPlanResult, testPlanHelpers) => {
|
|
4830
|
+
const log = renderExecutionLog(
|
|
4831
|
+
execution,
|
|
4832
|
+
logOptions,
|
|
4833
|
+
testPlanHelpers,
|
|
4834
|
+
);
|
|
4835
|
+
if (log) {
|
|
4836
|
+
write(log);
|
|
4837
|
+
}
|
|
4828
4838
|
},
|
|
4829
4839
|
afterAll: async () => {
|
|
4830
4840
|
await write(renderOutro(testPlanResult, logOptions));
|
|
@@ -4892,12 +4902,18 @@ const reporterList = ({
|
|
|
4892
4902
|
console.warn(warning.message);
|
|
4893
4903
|
});
|
|
4894
4904
|
},
|
|
4895
|
-
afterEachInOrder: (execution) => {
|
|
4905
|
+
afterEachInOrder: (execution, testPlanResult, testPlanHelpers) => {
|
|
4896
4906
|
oneExecutionWritten = true;
|
|
4897
4907
|
dynamicLog.clearDuringFunctionCall(
|
|
4898
4908
|
() => {
|
|
4899
|
-
const log = renderExecutionLog(
|
|
4900
|
-
|
|
4909
|
+
const log = renderExecutionLog(
|
|
4910
|
+
execution,
|
|
4911
|
+
logOptions,
|
|
4912
|
+
testPlanHelpers,
|
|
4913
|
+
);
|
|
4914
|
+
if (log) {
|
|
4915
|
+
write(log);
|
|
4916
|
+
}
|
|
4901
4917
|
},
|
|
4902
4918
|
// regenerate the dynamic log to put the leading "\n"
|
|
4903
4919
|
// because of oneExecutionWritten becoming true
|
|
@@ -4954,11 +4970,11 @@ const renderIntro = (testPlanResult, logOptions) => {
|
|
|
4954
4970
|
|
|
4955
4971
|
let title;
|
|
4956
4972
|
if (planified === 0) {
|
|
4957
|
-
title = `
|
|
4973
|
+
title = `nothing to execute`;
|
|
4958
4974
|
} else if (planified === 1) {
|
|
4959
|
-
title = `1 execution
|
|
4975
|
+
title = `1 execution ready`;
|
|
4960
4976
|
} else {
|
|
4961
|
-
title = `${planified} executions
|
|
4977
|
+
title = `${planified} executions ready`;
|
|
4962
4978
|
}
|
|
4963
4979
|
const lines = [];
|
|
4964
4980
|
lines.push(`directory: ${directory}`);
|
|
@@ -4980,6 +4996,11 @@ const renderIntro = (testPlanResult, logOptions) => {
|
|
|
4980
4996
|
testPlanLog += "}";
|
|
4981
4997
|
lines.push(`testPlan: ${testPlanLog}`);
|
|
4982
4998
|
}
|
|
4999
|
+
if (testPlanResult.fragment) {
|
|
5000
|
+
lines.push(
|
|
5001
|
+
`fragment: ${testPlanResult.fragment}, executing only ${testPlanResult.fragmentStart}:${testPlanResult.fragmentEnd}`,
|
|
5002
|
+
);
|
|
5003
|
+
}
|
|
4983
5004
|
if (logOptions.platformInfo) {
|
|
4984
5005
|
{
|
|
4985
5006
|
let osLine = `os: `;
|
|
@@ -5016,7 +5037,36 @@ const renderIntro = (testPlanResult, logOptions) => {
|
|
|
5016
5037
|
})}\n`;
|
|
5017
5038
|
};
|
|
5018
5039
|
|
|
5019
|
-
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
|
+
|
|
5020
5070
|
let log = "";
|
|
5021
5071
|
// label
|
|
5022
5072
|
{
|
|
@@ -5097,15 +5147,38 @@ const descriptionFormatters = {
|
|
|
5097
5147
|
executing: ({ fileRelativeUrl }) => {
|
|
5098
5148
|
return ANSI.color(`${fileRelativeUrl}`, COLOR_EXECUTING);
|
|
5099
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
|
+
},
|
|
5100
5166
|
aborted: ({ index, countersInOrder, fileRelativeUrl }) => {
|
|
5101
5167
|
const total = countersInOrder.planified;
|
|
5102
5168
|
const number = fillLeft(index + 1, total, "0");
|
|
5103
|
-
|
|
5104
5169
|
return ANSI.color(
|
|
5105
5170
|
`${UNICODE.FAILURE_RAW} ${number}/${total} ${fileRelativeUrl}`,
|
|
5106
5171
|
COLOR_ABORTED,
|
|
5107
5172
|
);
|
|
5108
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
|
+
},
|
|
5109
5182
|
timedout: ({ index, countersInOrder, fileRelativeUrl, params }) => {
|
|
5110
5183
|
const total = countersInOrder.planified;
|
|
5111
5184
|
const number = fillLeft(index + 1, total, "0");
|
|
@@ -5133,23 +5206,15 @@ const descriptionFormatters = {
|
|
|
5133
5206
|
COLOR_COMPLETED,
|
|
5134
5207
|
);
|
|
5135
5208
|
},
|
|
5136
|
-
cancelled: ({ index, countersInOrder, fileRelativeUrl }) => {
|
|
5137
|
-
const total = countersInOrder.planified;
|
|
5138
|
-
const number = fillLeft(index + 1, total, "0");
|
|
5139
|
-
|
|
5140
|
-
return ANSI.color(
|
|
5141
|
-
`${UNICODE.FAILURE_RAW} ${number}/${total} ${fileRelativeUrl}`,
|
|
5142
|
-
COLOR_CANCELLED,
|
|
5143
|
-
);
|
|
5144
|
-
},
|
|
5145
5209
|
};
|
|
5146
5210
|
|
|
5147
5211
|
const COLOR_EXECUTING = ANSI.BLUE;
|
|
5212
|
+
const COLOR_SKIPPED = ANSI.GREY;
|
|
5148
5213
|
const COLOR_ABORTED = ANSI.MAGENTA;
|
|
5214
|
+
const COLOR_CANCELLED = ANSI.GREY;
|
|
5149
5215
|
const COLOR_TIMEOUT = ANSI.MAGENTA;
|
|
5150
5216
|
const COLOR_FAILED = ANSI.RED;
|
|
5151
5217
|
const COLOR_COMPLETED = ANSI.GREEN;
|
|
5152
|
-
const COLOR_CANCELLED = ANSI.GREY;
|
|
5153
5218
|
const fillLeft = (value, biggestValue, char = " ") => {
|
|
5154
5219
|
const width = String(value).length;
|
|
5155
5220
|
const biggestWidth = String(biggestValue).length;
|
|
@@ -5427,9 +5492,15 @@ const renderStatusRepartition = (counters, { showProgression } = {}) => {
|
|
|
5427
5492
|
if (counters.planified === 0) {
|
|
5428
5493
|
return ``;
|
|
5429
5494
|
}
|
|
5495
|
+
if (counters.skipped === counters.planified) {
|
|
5496
|
+
return `all ${ANSI.color(`skipped`, COLOR_SKIPPED)}`;
|
|
5497
|
+
}
|
|
5430
5498
|
if (counters.aborted === counters.planified) {
|
|
5431
5499
|
return `all ${ANSI.color(`aborted`, COLOR_ABORTED)}`;
|
|
5432
5500
|
}
|
|
5501
|
+
if (counters.cancelled === counters.planified) {
|
|
5502
|
+
return `all ${ANSI.color(`cancelled`, COLOR_CANCELLED)}`;
|
|
5503
|
+
}
|
|
5433
5504
|
if (counters.timedout === counters.planified) {
|
|
5434
5505
|
return `all ${ANSI.color(`timed out`, COLOR_TIMEOUT)}`;
|
|
5435
5506
|
}
|
|
@@ -5439,10 +5510,15 @@ const renderStatusRepartition = (counters, { showProgression } = {}) => {
|
|
|
5439
5510
|
if (counters.completed === counters.planified) {
|
|
5440
5511
|
return `all ${ANSI.color(`completed`, COLOR_COMPLETED)}`;
|
|
5441
5512
|
}
|
|
5442
|
-
if (counters.cancelled === counters.planified) {
|
|
5443
|
-
return `all ${ANSI.color(`cancelled`, COLOR_CANCELLED)}`;
|
|
5444
|
-
}
|
|
5445
5513
|
const parts = [];
|
|
5514
|
+
if (showProgression) {
|
|
5515
|
+
if (counters.executing) {
|
|
5516
|
+
parts.push(`${counters.executing} executing`);
|
|
5517
|
+
}
|
|
5518
|
+
if (counters.waiting) {
|
|
5519
|
+
parts.push(`${counters.waiting} waiting`);
|
|
5520
|
+
}
|
|
5521
|
+
}
|
|
5446
5522
|
if (counters.timedout) {
|
|
5447
5523
|
parts.push(
|
|
5448
5524
|
`${counters.timedout} ${ANSI.color(`timed out`, COLOR_TIMEOUT)}`,
|
|
@@ -5464,13 +5540,8 @@ const renderStatusRepartition = (counters, { showProgression } = {}) => {
|
|
|
5464
5540
|
`${counters.cancelled} ${ANSI.color(`cancelled`, COLOR_CANCELLED)}`,
|
|
5465
5541
|
);
|
|
5466
5542
|
}
|
|
5467
|
-
if (
|
|
5468
|
-
|
|
5469
|
-
parts.push(`${counters.executing} executing`);
|
|
5470
|
-
}
|
|
5471
|
-
if (counters.waiting) {
|
|
5472
|
-
parts.push(`${counters.waiting} waiting`);
|
|
5473
|
-
}
|
|
5543
|
+
if (counters.skipped) {
|
|
5544
|
+
parts.push(`${counters.skipped} ${ANSI.color(`skipped`, COLOR_SKIPPED)}`);
|
|
5474
5545
|
}
|
|
5475
5546
|
return `${parts.join(", ")}`;
|
|
5476
5547
|
};
|
|
@@ -5546,6 +5617,39 @@ const renderDetails = (data) => {
|
|
|
5546
5617
|
return string;
|
|
5547
5618
|
};
|
|
5548
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
|
+
|
|
5549
5653
|
/*
|
|
5550
5654
|
*
|
|
5551
5655
|
*/
|
|
@@ -5631,6 +5735,11 @@ const executeTestPlan = async ({
|
|
|
5631
5735
|
handleSIGTERM = true,
|
|
5632
5736
|
updateProcessExitCode = true,
|
|
5633
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,
|
|
5634
5743
|
defaultMsAllocatedPerExecution = 30_000,
|
|
5635
5744
|
failFast = false,
|
|
5636
5745
|
// keepRunning: false to ensure runtime is stopped once executed
|
|
@@ -5724,6 +5833,9 @@ const executeTestPlan = async ({
|
|
|
5724
5833
|
rootDirectoryUrl: String(rootDirectoryUrl),
|
|
5725
5834
|
patterns: Object.keys(testPlan),
|
|
5726
5835
|
groups: {},
|
|
5836
|
+
fragment,
|
|
5837
|
+
fragmentStart: undefined,
|
|
5838
|
+
fragmentEnd: undefined,
|
|
5727
5839
|
counters: {
|
|
5728
5840
|
planified: 0,
|
|
5729
5841
|
remaining: 0,
|
|
@@ -5731,6 +5843,7 @@ const executeTestPlan = async ({
|
|
|
5731
5843
|
executing: 0,
|
|
5732
5844
|
executed: 0,
|
|
5733
5845
|
|
|
5846
|
+
skipped: 0,
|
|
5734
5847
|
aborted: 0,
|
|
5735
5848
|
cancelled: 0,
|
|
5736
5849
|
timedout: 0,
|
|
@@ -5760,6 +5873,36 @@ const executeTestPlan = async ({
|
|
|
5760
5873
|
};
|
|
5761
5874
|
const beforeEachCallbackSet = new Set();
|
|
5762
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
|
+
};
|
|
5763
5906
|
const afterEachCallbackSet = new Set();
|
|
5764
5907
|
const afterEachInOrderCallbackSet = new Set();
|
|
5765
5908
|
const afterAllCallbackSet = new Set();
|
|
@@ -5892,6 +6035,16 @@ const executeTestPlan = async ({
|
|
|
5892
6035
|
);
|
|
5893
6036
|
}
|
|
5894
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
|
+
}
|
|
5895
6048
|
// testPlan
|
|
5896
6049
|
{
|
|
5897
6050
|
if (typeof testPlan !== "object") {
|
|
@@ -6096,9 +6249,21 @@ To fix this warning:
|
|
|
6096
6249
|
}
|
|
6097
6250
|
}
|
|
6098
6251
|
|
|
6099
|
-
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
|
+
};
|
|
6100
6265
|
|
|
6101
|
-
// collect files to execute + fill
|
|
6266
|
+
// collect files to execute + fill executionPlanifiedArray
|
|
6102
6267
|
{
|
|
6103
6268
|
const fileResultArray = await collectFiles({
|
|
6104
6269
|
signal,
|
|
@@ -6106,6 +6271,11 @@ To fix this warning:
|
|
|
6106
6271
|
associations: { testPlan },
|
|
6107
6272
|
predicate: ({ testPlan }) => testPlan,
|
|
6108
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
|
+
|
|
6109
6279
|
let index = 0;
|
|
6110
6280
|
let lastExecution;
|
|
6111
6281
|
const fileExecutionCountMap = new Map();
|
|
@@ -6128,10 +6298,6 @@ To fix this warning:
|
|
|
6128
6298
|
),
|
|
6129
6299
|
);
|
|
6130
6300
|
}
|
|
6131
|
-
if (stepConfig.runtime?.disabled) {
|
|
6132
|
-
continue;
|
|
6133
|
-
}
|
|
6134
|
-
|
|
6135
6301
|
const {
|
|
6136
6302
|
runtime,
|
|
6137
6303
|
runtimeParams,
|
|
@@ -6188,6 +6354,8 @@ To fix this warning:
|
|
|
6188
6354
|
runtimeName,
|
|
6189
6355
|
runtimeVersion,
|
|
6190
6356
|
params,
|
|
6357
|
+
skipped: false,
|
|
6358
|
+
skipReason: "",
|
|
6191
6359
|
|
|
6192
6360
|
// will be set by run()
|
|
6193
6361
|
status: "planified",
|
|
@@ -6198,7 +6366,7 @@ To fix this warning:
|
|
|
6198
6366
|
}
|
|
6199
6367
|
|
|
6200
6368
|
lastExecution = execution;
|
|
6201
|
-
|
|
6369
|
+
executionPlanifiedArray.push(execution);
|
|
6202
6370
|
const existingResults = results[relativeUrl];
|
|
6203
6371
|
if (existingResults) {
|
|
6204
6372
|
existingResults[groupName] = execution.result;
|
|
@@ -6218,9 +6386,48 @@ To fix this warning:
|
|
|
6218
6386
|
runtimeVersion,
|
|
6219
6387
|
};
|
|
6220
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
|
+
}
|
|
6221
6407
|
index++;
|
|
6222
6408
|
}
|
|
6223
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
|
+
}
|
|
6224
6431
|
fileResultArray.length = 0;
|
|
6225
6432
|
fileExecutionCountMap.clear();
|
|
6226
6433
|
if (lastExecution) {
|
|
@@ -6231,11 +6438,11 @@ To fix this warning:
|
|
|
6231
6438
|
counters.planified =
|
|
6232
6439
|
counters.remaining =
|
|
6233
6440
|
counters.waiting =
|
|
6234
|
-
|
|
6441
|
+
executionPlanifiedArray.length;
|
|
6235
6442
|
countersInOrder.planified =
|
|
6236
6443
|
countersInOrder.remaining =
|
|
6237
6444
|
countersInOrder.waiting =
|
|
6238
|
-
|
|
6445
|
+
executionPlanifiedArray.length;
|
|
6239
6446
|
if (githubCheck) {
|
|
6240
6447
|
const githubCheckRun = await startGithubCheckRun({
|
|
6241
6448
|
logLevel: githubCheck.logLevel,
|
|
@@ -6245,7 +6452,7 @@ To fix this warning:
|
|
|
6245
6452
|
commitSha: githubCheck.commitSha,
|
|
6246
6453
|
checkName: githubCheck.name,
|
|
6247
6454
|
checkTitle: githubCheck.title,
|
|
6248
|
-
checkSummary: `${
|
|
6455
|
+
checkSummary: `${executionPlanifiedArray.length} files will be executed`,
|
|
6249
6456
|
});
|
|
6250
6457
|
const annotations = [];
|
|
6251
6458
|
reporters.push({
|
|
@@ -6325,80 +6532,66 @@ To fix this warning:
|
|
|
6325
6532
|
|
|
6326
6533
|
const callWhenPreviousExecutionAreDone = createCallOrderer();
|
|
6327
6534
|
|
|
6328
|
-
const executionRemainingSet = new Set(
|
|
6535
|
+
const executionRemainingSet = new Set(executionPlanifiedArray);
|
|
6329
6536
|
const executionExecutingSet = new Set();
|
|
6330
6537
|
const usedTagSet = new Set();
|
|
6331
6538
|
const start = async (execution) => {
|
|
6332
|
-
if (execution.params.uses) {
|
|
6333
|
-
for (const tagThatWillBeUsed of execution.params.uses) {
|
|
6334
|
-
usedTagSet.add(tagThatWillBeUsed);
|
|
6335
|
-
}
|
|
6336
|
-
}
|
|
6337
6539
|
execution.fileExecutionCount = Object.keys(
|
|
6338
6540
|
testPlanResult.results[execution.fileRelativeUrl],
|
|
6339
6541
|
).length;
|
|
6340
6542
|
mutateCountersBeforeExecutionStarts(counters, execution);
|
|
6341
6543
|
mutateCountersBeforeExecutionStarts(countersInOrder, execution);
|
|
6342
|
-
|
|
6343
|
-
execution.status = "executing";
|
|
6344
6544
|
executionRemainingSet.delete(execution);
|
|
6345
6545
|
executionExecutingSet.add(execution);
|
|
6346
|
-
|
|
6347
|
-
|
|
6348
|
-
|
|
6349
|
-
|
|
6350
|
-
|
|
6351
|
-
|
|
6352
|
-
|
|
6353
|
-
|
|
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
|
+
}
|
|
6354
6555
|
}
|
|
6355
|
-
|
|
6356
|
-
|
|
6357
|
-
|
|
6358
|
-
|
|
6359
|
-
|
|
6360
|
-
|
|
6361
|
-
|
|
6362
|
-
|
|
6363
|
-
|
|
6364
|
-
|
|
6365
|
-
|
|
6366
|
-
|
|
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
|
+
}
|
|
6367
6572
|
}
|
|
6368
|
-
|
|
6369
|
-
|
|
6370
|
-
|
|
6371
|
-
|
|
6372
|
-
|
|
6373
|
-
keepRunning,
|
|
6374
|
-
mirrorConsole: false, // might be executed in parallel: log would be a mess to read
|
|
6375
|
-
coverageEnabled: Boolean(coverage),
|
|
6376
|
-
coverageTempDirectoryUrl: coverage?.tempDirectoryUrl,
|
|
6377
|
-
});
|
|
6378
|
-
Object.assign(execution.result, executionResult);
|
|
6379
|
-
execution.status = "executed";
|
|
6380
|
-
executionExecutingSet.delete(execution);
|
|
6381
|
-
mutateCountersAfterExecutionEnds(counters, execution);
|
|
6382
|
-
if (execution.result.status !== "completed") {
|
|
6383
|
-
testPlanResult.failed = true;
|
|
6384
|
-
if (updateProcessExitCode) {
|
|
6385
|
-
process.exitCode = 1;
|
|
6573
|
+
if (execution.result.status !== "completed") {
|
|
6574
|
+
testPlanResult.failed = true;
|
|
6575
|
+
if (updateProcessExitCode) {
|
|
6576
|
+
process.exitCode = 1;
|
|
6577
|
+
}
|
|
6386
6578
|
}
|
|
6387
6579
|
}
|
|
6580
|
+
mutateCountersAfterExecutionEnds(counters, execution);
|
|
6581
|
+
executionExecutingSet.delete(execution);
|
|
6388
6582
|
for (const afterEachCallback of afterEachCallbackSet) {
|
|
6389
|
-
afterEachCallback(execution, testPlanResult);
|
|
6583
|
+
afterEachCallback(execution, testPlanResult, testPlanHelpers);
|
|
6390
6584
|
}
|
|
6391
6585
|
callWhenPreviousExecutionAreDone(execution.index, () => {
|
|
6392
6586
|
mutateCountersAfterExecutionEnds(countersInOrder, execution);
|
|
6393
6587
|
for (const afterEachInOrderCallback of afterEachInOrderCallbackSet) {
|
|
6394
|
-
afterEachInOrderCallback(
|
|
6588
|
+
afterEachInOrderCallback(
|
|
6589
|
+
execution,
|
|
6590
|
+
testPlanResult,
|
|
6591
|
+
testPlanHelpers,
|
|
6592
|
+
);
|
|
6395
6593
|
}
|
|
6396
6594
|
});
|
|
6397
|
-
if (execution.params.uses) {
|
|
6398
|
-
for (const tagNoLongerInUse of execution.params.uses) {
|
|
6399
|
-
usedTagSet.delete(tagNoLongerInUse);
|
|
6400
|
-
}
|
|
6401
|
-
}
|
|
6402
6595
|
if (testPlanResult.failed && failFast && counters.remaining) {
|
|
6403
6596
|
logger.info(`"failFast" enabled -> cancel remaining executions`);
|
|
6404
6597
|
failFastAbortController.abort();
|
|
@@ -6612,7 +6805,9 @@ const mutateCountersAfterExecutionEnds = (counters, execution) => {
|
|
|
6612
6805
|
counters.executing--;
|
|
6613
6806
|
counters.executed++;
|
|
6614
6807
|
counters.remaining--;
|
|
6615
|
-
if (execution.result.status === "
|
|
6808
|
+
if (execution.result.status === "skipped") {
|
|
6809
|
+
counters.skipped++;
|
|
6810
|
+
} else if (execution.result.status === "aborted") {
|
|
6616
6811
|
counters.aborted++;
|
|
6617
6812
|
} else if (execution.result.status === "timedout") {
|
|
6618
6813
|
counters.timedout++;
|
|
@@ -7482,7 +7677,7 @@ const createFirefoxRuntime = ({
|
|
|
7482
7677
|
if (disableOnWindowsBecauseFlaky === undefined) {
|
|
7483
7678
|
// https://github.com/microsoft/playwright/issues/1396
|
|
7484
7679
|
console.warn(
|
|
7485
|
-
`Windows + firefox detected: executions on firefox will be ignored
|
|
7680
|
+
`Windows + firefox detected: executions on firefox will be ignored (firefox is flaky on windows).
|
|
7486
7681
|
To disable this warning, use disableOnWindowsBecauseFlaky: true
|
|
7487
7682
|
To ignore potential flakyness, use disableOnWindowsBecauseFlaky: false`,
|
|
7488
7683
|
);
|
|
@@ -7491,6 +7686,7 @@ To ignore potential flakyness, use disableOnWindowsBecauseFlaky: false`,
|
|
|
7491
7686
|
if (disableOnWindowsBecauseFlaky) {
|
|
7492
7687
|
return {
|
|
7493
7688
|
disabled: true,
|
|
7689
|
+
disabledReason: "flaky on windows",
|
|
7494
7690
|
};
|
|
7495
7691
|
}
|
|
7496
7692
|
}
|
|
@@ -7877,11 +8073,8 @@ const nodeChildProcess = ({
|
|
|
7877
8073
|
env = {
|
|
7878
8074
|
...env,
|
|
7879
8075
|
JSENV: true,
|
|
7880
|
-
FORCE_COLOR:
|
|
7881
|
-
|
|
7882
|
-
// GitHub workflow does support ANSI but "supports-color" returns false
|
|
7883
|
-
// because stream.isTTY returns false, see https://github.com/actions/runner/issues/241
|
|
7884
|
-
process.env.GITHUB_WORKFLOW,
|
|
8076
|
+
...(ANSI.supported ? { FORCE_COLOR: "1" } : {}),
|
|
8077
|
+
...(UNICODE.supported ? { FORCE_UNICODE: "1" } : {}),
|
|
7885
8078
|
};
|
|
7886
8079
|
|
|
7887
8080
|
return {
|
|
@@ -8356,11 +8549,8 @@ const nodeWorkerThread = ({
|
|
|
8356
8549
|
env = {
|
|
8357
8550
|
...env,
|
|
8358
8551
|
JSENV: true,
|
|
8359
|
-
FORCE_COLOR:
|
|
8360
|
-
|
|
8361
|
-
// GitHub workflow does support ANSI but "supports-color" returns false
|
|
8362
|
-
// because stream.isTTY returns false, see https://github.com/actions/runner/issues/241
|
|
8363
|
-
process.env.GITHUB_WORKFLOW,
|
|
8552
|
+
...(ANSI.supported ? { FORCE_COLOR: "1" } : {}),
|
|
8553
|
+
...(UNICODE.supported ? { FORCE_UNICODE: "1" } : {}),
|
|
8364
8554
|
};
|
|
8365
8555
|
|
|
8366
8556
|
return {
|
|
@@ -8969,22 +9159,26 @@ const reportAsJunitXml = async (
|
|
|
8969
9159
|
});
|
|
8970
9160
|
testSuite.appendChild(testCase);
|
|
8971
9161
|
|
|
8972
|
-
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") {
|
|
8973
9169
|
testCase.attributes.skipped = 1;
|
|
8974
9170
|
const skipped = testCase.createNode("skipped", {
|
|
8975
9171
|
message: "Execution was aborted",
|
|
8976
9172
|
});
|
|
8977
9173
|
testSuite.appendChild(skipped);
|
|
8978
|
-
}
|
|
8979
|
-
if (executionResult.status === "timedout") {
|
|
9174
|
+
} else if (executionResult.status === "timedout") {
|
|
8980
9175
|
testCase.attributes.failures = 1;
|
|
8981
9176
|
const failure = testCase.createNode("failure", {
|
|
8982
9177
|
message: `Execution timeout after ${executionResult.params.allocatedMs}ms"`,
|
|
8983
9178
|
type: "timeout",
|
|
8984
9179
|
});
|
|
8985
9180
|
testSuite.appendChild(failure);
|
|
8986
|
-
}
|
|
8987
|
-
if (executionResult.status === "failed") {
|
|
9181
|
+
} else if (executionResult.status === "failed") {
|
|
8988
9182
|
const [error] = executionResult.errors;
|
|
8989
9183
|
if (
|
|
8990
9184
|
error &&
|
|
@@ -9038,7 +9232,7 @@ const reportAsJunitXml = async (
|
|
|
9038
9232
|
propertiesNode.appendChild(propertyNode);
|
|
9039
9233
|
}
|
|
9040
9234
|
|
|
9041
|
-
const { consoleCalls } = executionResult;
|
|
9235
|
+
const { consoleCalls = [] } = executionResult;
|
|
9042
9236
|
let stdout = "";
|
|
9043
9237
|
let stderr = "";
|
|
9044
9238
|
for (const consoleCall of consoleCalls) {
|
|
@@ -9071,6 +9265,123 @@ ${testSuite.renderAsString()}`;
|
|
|
9071
9265
|
writeFileSync(new URL(fileUrl), junitXmlFileContent);
|
|
9072
9266
|
};
|
|
9073
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
|
+
|
|
9074
9385
|
/*
|
|
9075
9386
|
* Export a function capable to execute a file on a runtime (browser or node) and return how it goes.
|
|
9076
9387
|
*
|
|
@@ -9265,4 +9576,4 @@ const inlineRuntime = (fn) => {
|
|
|
9265
9576
|
};
|
|
9266
9577
|
};
|
|
9267
9578
|
|
|
9268
|
-
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 };
|