@midscene/test 1.15.2 → 1.15.3-beta-20261012131523.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/es/cli/index.mjs +109 -0
- package/dist/es/cli/index.mjs.map +1 -1
- package/dist/es/index.mjs +100 -2
- package/dist/es/index.mjs.map +1 -1
- package/dist/es/test-cli.mjs +111 -3
- package/dist/es/test-cli.mjs.map +1 -1
- package/dist/lib/cli/index.js +109 -0
- package/dist/lib/cli/index.js.map +1 -1
- package/dist/lib/index.js +105 -1
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/test-cli.js +111 -3
- package/dist/lib/test-cli.js.map +1 -1
- package/dist/types/cli/index.d.ts +2 -0
- package/dist/types/index.d.ts +88 -0
- package/package.json +13 -13
package/dist/es/cli/index.mjs
CHANGED
|
@@ -634,6 +634,9 @@ const writeTestProjectRunResult = (options)=>{
|
|
|
634
634
|
...result.reportPath ? {
|
|
635
635
|
report: relativeToSummary(result.summaryPath, result.reportPath)
|
|
636
636
|
} : {},
|
|
637
|
+
...result.markdownPath ? {
|
|
638
|
+
markdown: relativeToSummary(result.summaryPath, result.markdownPath)
|
|
639
|
+
} : {},
|
|
637
640
|
summary: result.summary,
|
|
638
641
|
projects: result.projects.map((project)=>({
|
|
639
642
|
projectId: project.projectId,
|
|
@@ -1022,6 +1025,103 @@ async function prepareTestRun(options) {
|
|
|
1022
1025
|
onProgress: options.onProgress ?? (()=>{})
|
|
1023
1026
|
};
|
|
1024
1027
|
}
|
|
1028
|
+
const result_markdown_text = (value)=>value.replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>').replaceAll('"', '"').replaceAll('|', '|').replaceAll('[', '[').replaceAll(']', ']').replaceAll('*', '*').replaceAll('_', '_').replaceAll('`', '`').replaceAll('\\', '\').replace(/[\r\n]+/g, ' ');
|
|
1029
|
+
const duration = (ms)=>{
|
|
1030
|
+
const seconds = Math.round(ms / 1000);
|
|
1031
|
+
return seconds < 60 ? `${seconds}s` : `${Math.floor(seconds / 60)}m ${seconds % 60}s`;
|
|
1032
|
+
};
|
|
1033
|
+
const href = (from, target)=>relative(dirname(from), target).split(sep).map(encodeURIComponent).join('/');
|
|
1034
|
+
function renderTestResultMarkdown(dump, options = {}) {
|
|
1035
|
+
const { summary } = dump;
|
|
1036
|
+
const outcome = 'success' === dump.status ? `✅ **${summary.passed}/${summary.total} passed**` : `❌ **${summary.failed} failed** · ${summary.passed} passed · ${summary.notRun} not run`;
|
|
1037
|
+
const lines = [
|
|
1038
|
+
'## Midscene Test',
|
|
1039
|
+
'',
|
|
1040
|
+
`${outcome} · ${duration(dump.durationMs)}`,
|
|
1041
|
+
''
|
|
1042
|
+
];
|
|
1043
|
+
if (summary.filtered) lines.push(`**Filtered:** ${summary.filtered}`, '');
|
|
1044
|
+
const infrastructure = [
|
|
1045
|
+
summary.collectionErrors ? `${summary.collectionErrors} collection errors` : '',
|
|
1046
|
+
summary.documentFailures ? `${summary.documentFailures} document failures` : '',
|
|
1047
|
+
summary.projectFailures ? `${summary.projectFailures} project failures` : ''
|
|
1048
|
+
].filter(Boolean);
|
|
1049
|
+
if (infrastructure.length) lines.push(`**Infrastructure:** ${infrastructure.join(' · ')}`, '');
|
|
1050
|
+
const groups = [];
|
|
1051
|
+
const errors = [];
|
|
1052
|
+
const recordSteps = (label, steps)=>{
|
|
1053
|
+
for (const step of steps)if ('failed' === step.status) errors.push(`${label} / ${step.node}: ${step.error?.message ?? 'Step failed'}`);
|
|
1054
|
+
};
|
|
1055
|
+
for (const project of dump.projects){
|
|
1056
|
+
if (project.lifecycle?.setupError) errors.push(`${project.name}: ${project.lifecycle.setupError.message}`);
|
|
1057
|
+
for (const error of project.lifecycle?.teardownErrors ?? [])errors.push(`${project.name}: ${error.message}`);
|
|
1058
|
+
for (const error of project.collectionErrors)errors.push(`${project.name} / ${error.sourcePath}: ${error.error.message}`);
|
|
1059
|
+
for (const document of project.documents){
|
|
1060
|
+
const name = document.sourcePath.replace(/\\/g, '/').replace(/\.(?:yaml|yml)$/, '');
|
|
1061
|
+
const group = {
|
|
1062
|
+
name: dump.projects.length > 1 ? `${project.name} / ${name}` : name,
|
|
1063
|
+
rows: []
|
|
1064
|
+
};
|
|
1065
|
+
groups.push(group);
|
|
1066
|
+
recordSteps(`${project.name} / ${document.sourcePath}`, [
|
|
1067
|
+
...document.beforeAll,
|
|
1068
|
+
...document.afterAll
|
|
1069
|
+
]);
|
|
1070
|
+
for (const error of document.teardownErrors ?? [])errors.push(`${document.sourcePath}: ${error.message}`);
|
|
1071
|
+
for (const failure of document.hostErrors ?? [])errors.push(`${document.sourcePath} / ${failure.phase}: ${failure.error.message}`);
|
|
1072
|
+
for (const testCase of document.cases){
|
|
1073
|
+
const attempt = testCase.attempts.at(-1);
|
|
1074
|
+
const steps = attempt ? [
|
|
1075
|
+
...attempt.beforeEach,
|
|
1076
|
+
...attempt.steps,
|
|
1077
|
+
...attempt.afterEach
|
|
1078
|
+
] : [];
|
|
1079
|
+
const failedSteps = steps.filter((step)=>'failed' === step.status);
|
|
1080
|
+
const step = failedSteps.at(-1) ?? [
|
|
1081
|
+
...steps
|
|
1082
|
+
].reverse().find((item)=>item.agentDetails?.length) ?? steps.at(-1);
|
|
1083
|
+
const route = new URLSearchParams({
|
|
1084
|
+
'runner-page': 'case',
|
|
1085
|
+
'runner-project': project.projectId,
|
|
1086
|
+
'runner-case': testCase.caseId,
|
|
1087
|
+
...step ? {
|
|
1088
|
+
'runner-step': step.id
|
|
1089
|
+
} : {}
|
|
1090
|
+
});
|
|
1091
|
+
const target = options.reportHref ? `${options.reportHref}#${route}` : void 0;
|
|
1092
|
+
const name = target ? `[${result_markdown_text(testCase.name)}](<${target}>)` : result_markdown_text(testCase.name);
|
|
1093
|
+
group.rows.push(` - ${'success' === testCase.status ? '✅' : 'not-run' === testCase.status ? '⏭️' : '❌'} ${name}`);
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
for (const diagnostic of dump.diagnostics ?? [])if ('error' === diagnostic.level) errors.push(diagnostic.message);
|
|
1098
|
+
if (errors.length) lines.push('### Execution errors', '', ...errors.map((error)=>`- ${result_markdown_text(error)}`), '');
|
|
1099
|
+
for (const group of groups)if (group.rows.length) lines.push(`- ${result_markdown_text(group.name)}`, ...group.rows);
|
|
1100
|
+
if (!groups.some((group)=>group.rows.length)) lines.push('No cases were reported.');
|
|
1101
|
+
if (options.reportHref) lines.push('', `[Open the Midscene Test report ↗](<${options.reportHref}>)`);
|
|
1102
|
+
return `${lines.join('\n')}\n`;
|
|
1103
|
+
}
|
|
1104
|
+
const emptyIndex = ()=>({
|
|
1105
|
+
sources: [],
|
|
1106
|
+
metrics: {
|
|
1107
|
+
modelCallCount: 0,
|
|
1108
|
+
modelTimeMs: 0,
|
|
1109
|
+
promptTokens: 0,
|
|
1110
|
+
cachedInputTokens: 0,
|
|
1111
|
+
completionTokens: 0,
|
|
1112
|
+
totalTokens: 0
|
|
1113
|
+
}
|
|
1114
|
+
});
|
|
1115
|
+
async function writeTestResultMarkdown(result, index = emptyIndex()) {
|
|
1116
|
+
const output = join(dirname(result.summaryPath), 'result.md');
|
|
1117
|
+
const dump = buildTestRunReportDump(result, index);
|
|
1118
|
+
await writeFile(output, renderTestResultMarkdown(dump, {
|
|
1119
|
+
...result.reportPath ? {
|
|
1120
|
+
reportHref: href(output, result.reportPath)
|
|
1121
|
+
} : {}
|
|
1122
|
+
}));
|
|
1123
|
+
return output;
|
|
1124
|
+
}
|
|
1025
1125
|
const stepPosition = (info)=>'case' === info.scope ? info.case : info.document;
|
|
1026
1126
|
const formatStep = (info)=>{
|
|
1027
1127
|
const position = stepPosition(info);
|
|
@@ -1480,6 +1580,7 @@ async function runPreparedTestProject(plan) {
|
|
|
1480
1580
|
} : {}
|
|
1481
1581
|
};
|
|
1482
1582
|
let completedResult = result;
|
|
1583
|
+
let reportIndex;
|
|
1483
1584
|
const publish = async (operation, path, callback)=>{
|
|
1484
1585
|
try {
|
|
1485
1586
|
await callback();
|
|
@@ -1510,6 +1611,7 @@ async function runPreparedTestProject(plan) {
|
|
|
1510
1611
|
overwrite: false,
|
|
1511
1612
|
sources: collectTestRunReportSources(completedResult),
|
|
1512
1613
|
buildRunnerDump: (index)=>{
|
|
1614
|
+
reportIndex = index;
|
|
1513
1615
|
const dump = buildTestRunReportDump(completedResult, index);
|
|
1514
1616
|
const warn = getDebug('test-runner:report-assembler', {
|
|
1515
1617
|
console: true
|
|
@@ -1527,6 +1629,13 @@ async function runPreparedTestProject(plan) {
|
|
|
1527
1629
|
for (const publication of plan.publications)await publish(publication.operation, publication.path, async ()=>{
|
|
1528
1630
|
await publication.publish(completedResult);
|
|
1529
1631
|
});
|
|
1632
|
+
await publish('write-result', join(dirname(summaryPath), 'result.md'), async ()=>{
|
|
1633
|
+
const markdownPath = await writeTestResultMarkdown(completedResult, reportIndex);
|
|
1634
|
+
completedResult = {
|
|
1635
|
+
...completedResult,
|
|
1636
|
+
markdownPath
|
|
1637
|
+
};
|
|
1638
|
+
});
|
|
1530
1639
|
await writeSummary();
|
|
1531
1640
|
if (hasInfrastructureError) throw new WorkflowExecutionFailure(completedResult, infrastructureErrors);
|
|
1532
1641
|
return completedResult;
|