executable-stories-formatters 0.7.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters.d.cts +1 -1
- package/dist/adapters.d.ts +1 -1
- package/dist/cli.js +307 -98
- package/dist/cli.js.map +1 -1
- package/dist/{index-BndkylIV.d.cts → index-C0OOaaiK.d.cts} +19 -2
- package/dist/{index-BndkylIV.d.ts → index-C0OOaaiK.d.ts} +19 -2
- package/dist/index.cjs +242 -72
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +34 -4
- package/dist/index.d.ts +34 -4
- package/dist/index.js +240 -71
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/schemas/raw-run.schema.json +35 -12
- package/skills/formatters-cli/SKILL.md +41 -0
package/dist/index.cjs
CHANGED
|
@@ -47,6 +47,7 @@ __export(src_exports, {
|
|
|
47
47
|
adaptPlaywrightRun: () => adaptPlaywrightRun,
|
|
48
48
|
adaptVitestRun: () => adaptVitestRun,
|
|
49
49
|
assertValidRun: () => assertValidRun,
|
|
50
|
+
bundleAssets: () => bundleAssets,
|
|
50
51
|
calculateFlakiness: () => calculateFlakiness,
|
|
51
52
|
calculateStability: () => calculateStability,
|
|
52
53
|
canonicalizeRun: () => canonicalizeRun,
|
|
@@ -98,8 +99,8 @@ __export(src_exports, {
|
|
|
98
99
|
validateCanonicalRun: () => validateCanonicalRun
|
|
99
100
|
});
|
|
100
101
|
module.exports = __toCommonJS(src_exports);
|
|
101
|
-
var
|
|
102
|
-
var
|
|
102
|
+
var fs6 = require("fs");
|
|
103
|
+
var path6 = __toESM(require("path"), 1);
|
|
103
104
|
var fsPromises = __toESM(require("fs/promises"), 1);
|
|
104
105
|
|
|
105
106
|
// src/converters/acl/status.ts
|
|
@@ -351,6 +352,9 @@ function canonicalizeTestCase(raw, options, projectRoot) {
|
|
|
351
352
|
projectRoot
|
|
352
353
|
});
|
|
353
354
|
const tags = normalizeTags(story);
|
|
355
|
+
if (story.tickets) {
|
|
356
|
+
story.tickets = normalizeTickets(story.tickets);
|
|
357
|
+
}
|
|
354
358
|
const titlePath = buildTitlePath(raw, story);
|
|
355
359
|
return {
|
|
356
360
|
id,
|
|
@@ -374,6 +378,9 @@ function normalizeTags(story) {
|
|
|
374
378
|
const tags = story.tags ?? [];
|
|
375
379
|
return [...new Set(tags)].sort();
|
|
376
380
|
}
|
|
381
|
+
function normalizeTickets(raw) {
|
|
382
|
+
return raw.map((t) => typeof t === "string" ? { id: t } : t);
|
|
383
|
+
}
|
|
377
384
|
function buildTitlePath(raw, story) {
|
|
378
385
|
if (story.suitePath && story.suitePath.length > 0) {
|
|
379
386
|
return story.suitePath;
|
|
@@ -2692,6 +2699,16 @@ body {
|
|
|
2692
2699
|
background: none;
|
|
2693
2700
|
}
|
|
2694
2701
|
|
|
2702
|
+
/* ============================================================================
|
|
2703
|
+
Documentation Entries - Children
|
|
2704
|
+
============================================================================ */
|
|
2705
|
+
.doc-children {
|
|
2706
|
+
margin-left: 1rem;
|
|
2707
|
+
padding-left: 1rem;
|
|
2708
|
+
border-left: 2px solid var(--border);
|
|
2709
|
+
margin-top: 0.25rem;
|
|
2710
|
+
}
|
|
2711
|
+
|
|
2695
2712
|
/* ============================================================================
|
|
2696
2713
|
Trace View - OTel span waterfall
|
|
2697
2714
|
============================================================================ */
|
|
@@ -12406,30 +12423,46 @@ function renderDocCustom(entry, deps) {
|
|
|
12406
12423
|
</div>`;
|
|
12407
12424
|
}
|
|
12408
12425
|
function renderDocEntry(entry, deps) {
|
|
12426
|
+
let html;
|
|
12409
12427
|
switch (entry.kind) {
|
|
12410
12428
|
case "note":
|
|
12411
|
-
|
|
12429
|
+
html = renderDocNote(entry, deps);
|
|
12430
|
+
break;
|
|
12412
12431
|
case "tag":
|
|
12413
|
-
|
|
12432
|
+
html = renderDocTag(entry, deps);
|
|
12433
|
+
break;
|
|
12414
12434
|
case "kv":
|
|
12415
|
-
|
|
12435
|
+
html = renderDocKv(entry, deps);
|
|
12436
|
+
break;
|
|
12416
12437
|
case "code":
|
|
12417
|
-
|
|
12438
|
+
html = renderDocCode(entry, deps);
|
|
12439
|
+
break;
|
|
12418
12440
|
case "table":
|
|
12419
|
-
|
|
12441
|
+
html = renderDocTable(entry, deps);
|
|
12442
|
+
break;
|
|
12420
12443
|
case "link":
|
|
12421
|
-
|
|
12444
|
+
html = renderDocLink(entry, deps);
|
|
12445
|
+
break;
|
|
12422
12446
|
case "section":
|
|
12423
|
-
|
|
12447
|
+
html = renderDocSection(entry, deps);
|
|
12448
|
+
break;
|
|
12424
12449
|
case "mermaid":
|
|
12425
|
-
|
|
12450
|
+
html = renderDocMermaid(entry, deps);
|
|
12451
|
+
break;
|
|
12426
12452
|
case "screenshot":
|
|
12427
|
-
|
|
12453
|
+
html = renderDocScreenshot(entry, deps);
|
|
12454
|
+
break;
|
|
12428
12455
|
case "custom":
|
|
12429
|
-
|
|
12456
|
+
html = renderDocCustom(entry, deps);
|
|
12457
|
+
break;
|
|
12430
12458
|
default:
|
|
12431
|
-
|
|
12459
|
+
html = "";
|
|
12460
|
+
}
|
|
12461
|
+
if (entry.children && entry.children.length > 0) {
|
|
12462
|
+
const childrenHtml = entry.children.map((child) => renderDocEntry(child, deps)).join("");
|
|
12463
|
+
html += `<div class="doc-children">${childrenHtml}</div>`;
|
|
12432
12464
|
}
|
|
12465
|
+
return html;
|
|
12433
12466
|
}
|
|
12434
12467
|
|
|
12435
12468
|
// src/formatters/html/renderers/steps.ts
|
|
@@ -12491,12 +12524,20 @@ function hasSufficientHistory(entries, min) {
|
|
|
12491
12524
|
}
|
|
12492
12525
|
|
|
12493
12526
|
// src/formatters/html/renderers/scenario.ts
|
|
12527
|
+
function renderTicket(ticket, template, escapeHtml3) {
|
|
12528
|
+
const url = ticket.url ?? (template ? template.replace("{ticket}", ticket.id) : void 0);
|
|
12529
|
+
if (url) {
|
|
12530
|
+
return `<a class="tag ticket-tag" href="${escapeHtml3(url)}" target="_blank" rel="noopener noreferrer">${escapeHtml3(ticket.id)}</a>`;
|
|
12531
|
+
}
|
|
12532
|
+
return `<span class="tag ticket-tag">${escapeHtml3(ticket.id)}</span>`;
|
|
12533
|
+
}
|
|
12494
12534
|
function renderScenario(args, deps) {
|
|
12495
12535
|
const { tc } = args;
|
|
12496
12536
|
const statusIcon = deps.getStatusIcon(tc.status);
|
|
12497
12537
|
const statusClass = `status-${tc.status}`;
|
|
12498
12538
|
const duration = tc.durationMs > 0 ? `${(tc.durationMs / 1e3).toFixed(2)}s` : "";
|
|
12499
12539
|
const tags = tc.tags.map((t) => `<span class="tag">${deps.escapeHtml(t)}</span>`).join("");
|
|
12540
|
+
const tickets = (tc.story.tickets ?? []).map((t) => renderTicket(t, deps.ticketUrlTemplate, deps.escapeHtml)).join("");
|
|
12500
12541
|
const otelMeta = tc.story.meta?.otel;
|
|
12501
12542
|
let traceBadge = "";
|
|
12502
12543
|
if (otelMeta?.traceId) {
|
|
@@ -12564,7 +12605,7 @@ function renderScenario(args, deps) {
|
|
|
12564
12605
|
<span class="status-icon ${statusClass}">${statusIcon}</span>
|
|
12565
12606
|
<span class="scenario-name">${deps.escapeHtml(tc.story.scenario)}</span>
|
|
12566
12607
|
</div>
|
|
12567
|
-
<div class="scenario-meta">${tags}${sourceLink}${traceBadge}${metricBadges}</div>
|
|
12608
|
+
<div class="scenario-meta">${tags}${tickets}${sourceLink}${traceBadge}${metricBadges}</div>
|
|
12568
12609
|
</div>
|
|
12569
12610
|
<span class="scenario-duration">${duration}</span>
|
|
12570
12611
|
</div>
|
|
@@ -12909,6 +12950,7 @@ function normalizeOptions(options = {}) {
|
|
|
12909
12950
|
mermaidEnabled: options.mermaidEnabled ?? true,
|
|
12910
12951
|
markdownEnabled: options.markdownEnabled ?? true,
|
|
12911
12952
|
permalinkBaseUrl: options.permalinkBaseUrl,
|
|
12953
|
+
ticketUrlTemplate: options.ticketUrlTemplate,
|
|
12912
12954
|
theme: options.theme ?? "default"
|
|
12913
12955
|
};
|
|
12914
12956
|
}
|
|
@@ -12941,7 +12983,8 @@ function createHtmlFormatter(options = {}) {
|
|
|
12941
12983
|
renderAttachments: (args, d) => renderAttachments(args, d),
|
|
12942
12984
|
renderTraceView: (args, d) => renderTraceView(args, d),
|
|
12943
12985
|
embedScreenshots: opts.embedScreenshots,
|
|
12944
|
-
permalinkBaseUrl: opts.permalinkBaseUrl
|
|
12986
|
+
permalinkBaseUrl: opts.permalinkBaseUrl,
|
|
12987
|
+
ticketUrlTemplate: opts.ticketUrlTemplate
|
|
12945
12988
|
};
|
|
12946
12989
|
const featureDeps = {
|
|
12947
12990
|
escapeHtml,
|
|
@@ -13454,14 +13497,16 @@ var MarkdownFormatter = class {
|
|
|
13454
13497
|
}
|
|
13455
13498
|
if (tc.story.tickets && tc.story.tickets.length > 0) {
|
|
13456
13499
|
const ticketTemplate = this.options.ticketUrlTemplate;
|
|
13457
|
-
|
|
13458
|
-
|
|
13459
|
-
|
|
13460
|
-
|
|
13461
|
-
|
|
13462
|
-
|
|
13463
|
-
|
|
13464
|
-
|
|
13500
|
+
const ticketLinks = tc.story.tickets.map((t) => {
|
|
13501
|
+
if (t.url) {
|
|
13502
|
+
return `[${t.id}](${t.url})`;
|
|
13503
|
+
}
|
|
13504
|
+
if (ticketTemplate) {
|
|
13505
|
+
return `[${t.id}](${ticketTemplate.replace("{ticket}", t.id)})`;
|
|
13506
|
+
}
|
|
13507
|
+
return `\`${t.id}\``;
|
|
13508
|
+
});
|
|
13509
|
+
meta.push(`Tickets: ${ticketLinks.join(", ")}`);
|
|
13465
13510
|
}
|
|
13466
13511
|
const otelMeta = tc.story.meta?.otel;
|
|
13467
13512
|
if (otelMeta?.traceId) {
|
|
@@ -13635,6 +13680,12 @@ var MarkdownFormatter = class {
|
|
|
13635
13680
|
lines.push(`${indent}`);
|
|
13636
13681
|
break;
|
|
13637
13682
|
}
|
|
13683
|
+
if (entry.children && entry.children.length > 0) {
|
|
13684
|
+
const childIndent = indent + " ";
|
|
13685
|
+
for (const child of entry.children) {
|
|
13686
|
+
this.renderDocEntry(lines, child, childIndent);
|
|
13687
|
+
}
|
|
13688
|
+
}
|
|
13638
13689
|
}
|
|
13639
13690
|
/**
|
|
13640
13691
|
* Get status icon for a status.
|
|
@@ -13707,8 +13758,8 @@ function extractFeatureName(testCases, uri) {
|
|
|
13707
13758
|
return tc.titlePath[0];
|
|
13708
13759
|
}
|
|
13709
13760
|
}
|
|
13710
|
-
const
|
|
13711
|
-
return
|
|
13761
|
+
const basename3 = uri.replace(/^.*[\\/]/, "").replace(/\.[^.]+$/, "");
|
|
13762
|
+
return basename3.replace(/[-_]+/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
13712
13763
|
}
|
|
13713
13764
|
function synthesizeFeature(uri, testCases) {
|
|
13714
13765
|
const featureName = extractFeatureName(testCases, uri);
|
|
@@ -14320,8 +14371,8 @@ function extractDocAttachments(step) {
|
|
|
14320
14371
|
}
|
|
14321
14372
|
return attachments;
|
|
14322
14373
|
}
|
|
14323
|
-
function guessMediaType(
|
|
14324
|
-
const lower =
|
|
14374
|
+
function guessMediaType(path7) {
|
|
14375
|
+
const lower = path7.toLowerCase();
|
|
14325
14376
|
if (lower.endsWith(".png")) return "image/png";
|
|
14326
14377
|
if (lower.endsWith(".jpg") || lower.endsWith(".jpeg")) return "image/jpeg";
|
|
14327
14378
|
if (lower.endsWith(".gif")) return "image/gif";
|
|
@@ -14462,11 +14513,11 @@ var CucumberHtmlFormatter = class {
|
|
|
14462
14513
|
for (const envelope of envelopes) {
|
|
14463
14514
|
const accepted = htmlStream.write(envelope);
|
|
14464
14515
|
if (!accepted) {
|
|
14465
|
-
await new Promise((
|
|
14516
|
+
await new Promise((resolve5) => htmlStream.once("drain", resolve5));
|
|
14466
14517
|
}
|
|
14467
14518
|
}
|
|
14468
|
-
await new Promise((
|
|
14469
|
-
collector.on("finish",
|
|
14519
|
+
await new Promise((resolve5, reject) => {
|
|
14520
|
+
collector.on("finish", resolve5);
|
|
14470
14521
|
collector.on("error", reject);
|
|
14471
14522
|
htmlStream.end();
|
|
14472
14523
|
});
|
|
@@ -14584,7 +14635,7 @@ function buildFlags(baseline, current) {
|
|
|
14584
14635
|
steps: stableJson(baseline.story.steps) !== stableJson(current.story.steps),
|
|
14585
14636
|
docs: stableJson(baselineDocs) !== stableJson(currentDocs),
|
|
14586
14637
|
tags: !compareStringArrays(baseline.tags, current.tags),
|
|
14587
|
-
tickets:
|
|
14638
|
+
tickets: stableJson(baseline.story.tickets ?? []) !== stableJson(current.story.tickets ?? []),
|
|
14588
14639
|
source: baseline.sourceFile !== current.sourceFile || baseline.sourceLine !== current.sourceLine,
|
|
14589
14640
|
duration: baseline.durationMs !== current.durationMs,
|
|
14590
14641
|
attachments: stableJson(baseline.attachments) !== stableJson(current.attachments),
|
|
@@ -14807,7 +14858,7 @@ function renderScenarioCard(scenario) {
|
|
|
14807
14858
|
<dd>${escapeHtml2(before.errorMessage ?? "") || " "}</dd>
|
|
14808
14859
|
${scenario.flags.steps ? `<dt>Steps</dt><dd>${formatSteps(before.steps)}</dd>` : ""}
|
|
14809
14860
|
${scenario.flags.docs ? `<dt>Docs</dt><dd>${formatDocs(before.docs)}</dd>` : ""}
|
|
14810
|
-
${scenario.flags.tickets ? `<dt>Tickets</dt><dd>${escapeHtml2(before.tickets.join(", ")) || " "}</dd>` : ""}
|
|
14861
|
+
${scenario.flags.tickets ? `<dt>Tickets</dt><dd>${escapeHtml2(before.tickets.map((t) => t.id).join(", ")) || " "}</dd>` : ""}
|
|
14811
14862
|
</dl>
|
|
14812
14863
|
</section>
|
|
14813
14864
|
<section>
|
|
@@ -14821,7 +14872,7 @@ function renderScenarioCard(scenario) {
|
|
|
14821
14872
|
<dd>${escapeHtml2(after.errorMessage ?? "") || " "}</dd>
|
|
14822
14873
|
${scenario.flags.steps ? `<dt>Steps</dt><dd>${formatSteps(after.steps)}</dd>` : ""}
|
|
14823
14874
|
${scenario.flags.docs ? `<dt>Docs</dt><dd>${formatDocs(after.docs)}</dd>` : ""}
|
|
14824
|
-
${scenario.flags.tickets ? `<dt>Tickets</dt><dd>${escapeHtml2(after.tickets.join(", ")) || " "}</dd>` : ""}
|
|
14875
|
+
${scenario.flags.tickets ? `<dt>Tickets</dt><dd>${escapeHtml2(after.tickets.map((t) => t.id).join(", ")) || " "}</dd>` : ""}
|
|
14825
14876
|
</dl>
|
|
14826
14877
|
</section>
|
|
14827
14878
|
</div>` : (() => {
|
|
@@ -14835,7 +14886,7 @@ function renderScenarioCard(scenario) {
|
|
|
14835
14886
|
return `<div class="snapshot-detail">
|
|
14836
14887
|
<dl>
|
|
14837
14888
|
${hasTags ? `<dt>Tags</dt><dd>${escapeHtml2(snapshot.tags.join(", "))}</dd>` : ""}
|
|
14838
|
-
${hasTickets ? `<dt>Tickets</dt><dd>${escapeHtml2(snapshot.tickets.join(", "))}</dd>` : ""}
|
|
14889
|
+
${hasTickets ? `<dt>Tickets</dt><dd>${escapeHtml2(snapshot.tickets.map((t) => t.id).join(", "))}</dd>` : ""}
|
|
14839
14890
|
${hasSteps ? `<dt>Steps</dt><dd>${formatSteps(snapshot.steps)}</dd>` : ""}
|
|
14840
14891
|
${hasDocs ? `<dt>Docs</dt><dd>${formatDocs(snapshot.docs)}</dd>` : ""}
|
|
14841
14892
|
</dl>
|
|
@@ -15150,7 +15201,7 @@ function renderScenario2(lines, scenario) {
|
|
|
15150
15201
|
lines.push(`| Docs | ${escapeCell(formatDocs2(before.docs))} | ${escapeCell(formatDocs2(after.docs))} |`);
|
|
15151
15202
|
}
|
|
15152
15203
|
if (scenario.flags.tickets) {
|
|
15153
|
-
lines.push(`| Tickets | ${escapeCell(before.tickets.join(", "))} | ${escapeCell(after.tickets.join(", "))} |`);
|
|
15204
|
+
lines.push(`| Tickets | ${escapeCell(before.tickets.map((t) => t.id).join(", "))} | ${escapeCell(after.tickets.map((t) => t.id).join(", "))} |`);
|
|
15154
15205
|
}
|
|
15155
15206
|
lines.push("");
|
|
15156
15207
|
} else {
|
|
@@ -15166,7 +15217,7 @@ function renderSnapshotDetail(lines, snapshot) {
|
|
|
15166
15217
|
lines.push("");
|
|
15167
15218
|
}
|
|
15168
15219
|
if (snapshot.tickets.length > 0) {
|
|
15169
|
-
lines.push(`**Tickets:** ${snapshot.tickets.join(", ")}`);
|
|
15220
|
+
lines.push(`**Tickets:** ${snapshot.tickets.map((t) => t.id).join(", ")}`);
|
|
15170
15221
|
lines.push("");
|
|
15171
15222
|
}
|
|
15172
15223
|
if (snapshot.steps.length > 0) {
|
|
@@ -15364,6 +15415,110 @@ function selectTestCases(args, deps) {
|
|
|
15364
15415
|
return sortTestCases(selected, sortMode);
|
|
15365
15416
|
}
|
|
15366
15417
|
|
|
15418
|
+
// src/bundler/bundle-assets.ts
|
|
15419
|
+
var fs3 = __toESM(require("fs"), 1);
|
|
15420
|
+
var path3 = __toESM(require("path"), 1);
|
|
15421
|
+
|
|
15422
|
+
// src/bundler/scan-html-assets.ts
|
|
15423
|
+
function scanHtmlAssets(html) {
|
|
15424
|
+
const seen = /* @__PURE__ */ new Set();
|
|
15425
|
+
const patterns = [
|
|
15426
|
+
/<(?:img|video)\b[^>]*?\bsrc=["']([^"']+)["']/g,
|
|
15427
|
+
/<a\b[^>]*?\bclass=["']attachment["'][^>]*?\bhref=["']([^"']+)["']/g,
|
|
15428
|
+
/<a\b[^>]*?\bhref=["']([^"']+)["'][^>]*?\bclass=["']attachment["']/g
|
|
15429
|
+
];
|
|
15430
|
+
for (const pattern of patterns) {
|
|
15431
|
+
let match;
|
|
15432
|
+
while ((match = pattern.exec(html)) !== null) {
|
|
15433
|
+
const ref = match[1];
|
|
15434
|
+
if (isLocalAssetRef(ref) && !seen.has(ref)) {
|
|
15435
|
+
seen.add(ref);
|
|
15436
|
+
}
|
|
15437
|
+
}
|
|
15438
|
+
}
|
|
15439
|
+
return [...seen];
|
|
15440
|
+
}
|
|
15441
|
+
function isLocalAssetRef(ref) {
|
|
15442
|
+
if (!ref) return false;
|
|
15443
|
+
if (ref.startsWith("data:")) return false;
|
|
15444
|
+
if (ref.startsWith("http://") || ref.startsWith("https://")) return false;
|
|
15445
|
+
if (ref.startsWith("#")) return false;
|
|
15446
|
+
return true;
|
|
15447
|
+
}
|
|
15448
|
+
|
|
15449
|
+
// src/bundler/copy-asset.ts
|
|
15450
|
+
var fs2 = __toESM(require("fs"), 1);
|
|
15451
|
+
var path2 = __toESM(require("path"), 1);
|
|
15452
|
+
var crypto = __toESM(require("crypto"), 1);
|
|
15453
|
+
function copyAsset(sourcePath, assetsDir) {
|
|
15454
|
+
if (!fs2.existsSync(assetsDir)) {
|
|
15455
|
+
fs2.mkdirSync(assetsDir, { recursive: true });
|
|
15456
|
+
}
|
|
15457
|
+
const content = fs2.readFileSync(sourcePath);
|
|
15458
|
+
const hash = crypto.createHash("sha256").update(content).digest("hex").slice(0, 8);
|
|
15459
|
+
const ext = path2.extname(sourcePath);
|
|
15460
|
+
const baseName = sanitize(path2.basename(sourcePath, ext));
|
|
15461
|
+
const destName = `${baseName}-${hash}${ext}`;
|
|
15462
|
+
const destPath = path2.join(assetsDir, destName);
|
|
15463
|
+
if (!fs2.existsSync(destPath)) {
|
|
15464
|
+
fs2.copyFileSync(sourcePath, destPath);
|
|
15465
|
+
}
|
|
15466
|
+
return `assets/${destName}`;
|
|
15467
|
+
}
|
|
15468
|
+
function sanitize(name) {
|
|
15469
|
+
return name.replace(/[^a-zA-Z0-9._-]/g, "-").replace(/-{2,}/g, "-").replace(/^-|-$/g, "");
|
|
15470
|
+
}
|
|
15471
|
+
|
|
15472
|
+
// src/bundler/bundle-assets.ts
|
|
15473
|
+
function bundleAssets(htmlPath, options = {}) {
|
|
15474
|
+
const htmlDir = path3.dirname(htmlPath);
|
|
15475
|
+
const assetsDir = path3.join(htmlDir, "assets");
|
|
15476
|
+
let html = fs3.readFileSync(htmlPath, "utf8");
|
|
15477
|
+
const refs = scanHtmlAssets(html);
|
|
15478
|
+
let copiedCount = 0;
|
|
15479
|
+
const missing = [];
|
|
15480
|
+
for (const ref of refs) {
|
|
15481
|
+
const absolutePath = path3.resolve(htmlDir, ref);
|
|
15482
|
+
if (!fs3.existsSync(absolutePath)) {
|
|
15483
|
+
missing.push(ref);
|
|
15484
|
+
continue;
|
|
15485
|
+
}
|
|
15486
|
+
const newRelPath = copyAsset(absolutePath, assetsDir);
|
|
15487
|
+
html = replaceAssetRef(html, ref, newRelPath);
|
|
15488
|
+
copiedCount++;
|
|
15489
|
+
}
|
|
15490
|
+
if (missing.length > 0 && !options.allowMissing) {
|
|
15491
|
+
throw new Error(
|
|
15492
|
+
`Missing asset${missing.length > 1 ? "s" : ""}: ${missing.join(", ")}`
|
|
15493
|
+
);
|
|
15494
|
+
}
|
|
15495
|
+
fs3.writeFileSync(htmlPath, html, "utf8");
|
|
15496
|
+
return {
|
|
15497
|
+
copiedCount,
|
|
15498
|
+
missingCount: missing.length,
|
|
15499
|
+
missing
|
|
15500
|
+
};
|
|
15501
|
+
}
|
|
15502
|
+
function replaceAssetRef(html, original, replacement) {
|
|
15503
|
+
const escaped = original.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
15504
|
+
const srcPattern = new RegExp(
|
|
15505
|
+
`(<(?:img|video)\\b[^>]*?\\bsrc=["'])${escaped}(["'])`,
|
|
15506
|
+
"g"
|
|
15507
|
+
);
|
|
15508
|
+
html = html.replace(srcPattern, `$1${replacement}$2`);
|
|
15509
|
+
const hrefClassFirst = new RegExp(
|
|
15510
|
+
`(<a\\b[^>]*?\\bclass=["']attachment["'][^>]*?\\bhref=["'])${escaped}(["'])`,
|
|
15511
|
+
"g"
|
|
15512
|
+
);
|
|
15513
|
+
html = html.replace(hrefClassFirst, `$1${replacement}$2`);
|
|
15514
|
+
const hrefHrefFirst = new RegExp(
|
|
15515
|
+
`(<a\\b[^>]*?\\bhref=["'])${escaped}(["'][^>]*?\\bclass=["']attachment["'])`,
|
|
15516
|
+
"g"
|
|
15517
|
+
);
|
|
15518
|
+
html = html.replace(hrefHrefFirst, `$1${replacement}$2`);
|
|
15519
|
+
return html;
|
|
15520
|
+
}
|
|
15521
|
+
|
|
15367
15522
|
// src/converters/adapters/jest.ts
|
|
15368
15523
|
function mapJestStatus(status) {
|
|
15369
15524
|
switch (status) {
|
|
@@ -16131,27 +16286,27 @@ function pickleStepArgumentToDocs(ps) {
|
|
|
16131
16286
|
}
|
|
16132
16287
|
|
|
16133
16288
|
// src/utils/git-info.ts
|
|
16134
|
-
var
|
|
16135
|
-
var
|
|
16289
|
+
var fs4 = __toESM(require("fs"), 1);
|
|
16290
|
+
var path4 = __toESM(require("path"), 1);
|
|
16136
16291
|
function readGitSha(cwd = process.cwd()) {
|
|
16137
16292
|
const envSha = process.env.GITHUB_SHA || process.env.GIT_COMMIT || process.env.CI_COMMIT_SHA;
|
|
16138
16293
|
if (envSha) return envSha;
|
|
16139
16294
|
const gitDir = findGitDir(cwd);
|
|
16140
16295
|
if (!gitDir) return void 0;
|
|
16141
16296
|
try {
|
|
16142
|
-
const headPath =
|
|
16143
|
-
const head =
|
|
16297
|
+
const headPath = path4.join(gitDir, "HEAD");
|
|
16298
|
+
const head = fs4.readFileSync(headPath, "utf8").trim();
|
|
16144
16299
|
if (!head.startsWith("ref:")) {
|
|
16145
16300
|
return head;
|
|
16146
16301
|
}
|
|
16147
16302
|
const refPath = head.replace("ref:", "").trim();
|
|
16148
|
-
const refFile =
|
|
16149
|
-
if (
|
|
16150
|
-
return
|
|
16303
|
+
const refFile = path4.join(gitDir, refPath);
|
|
16304
|
+
if (fs4.existsSync(refFile)) {
|
|
16305
|
+
return fs4.readFileSync(refFile, "utf8").trim();
|
|
16151
16306
|
}
|
|
16152
|
-
const packedRefs =
|
|
16153
|
-
if (
|
|
16154
|
-
const content =
|
|
16307
|
+
const packedRefs = path4.join(gitDir, "packed-refs");
|
|
16308
|
+
if (fs4.existsSync(packedRefs)) {
|
|
16309
|
+
const content = fs4.readFileSync(packedRefs, "utf8");
|
|
16155
16310
|
for (const line of content.split("\n")) {
|
|
16156
16311
|
if (!line || line.startsWith("#") || line.startsWith("^")) continue;
|
|
16157
16312
|
const [sha, ref] = line.split(" ");
|
|
@@ -16166,19 +16321,19 @@ function readGitSha(cwd = process.cwd()) {
|
|
|
16166
16321
|
function findGitDir(start) {
|
|
16167
16322
|
let current = start;
|
|
16168
16323
|
while (true) {
|
|
16169
|
-
const candidate =
|
|
16170
|
-
if (
|
|
16171
|
-
const stat =
|
|
16324
|
+
const candidate = path4.join(current, ".git");
|
|
16325
|
+
if (fs4.existsSync(candidate)) {
|
|
16326
|
+
const stat = fs4.statSync(candidate);
|
|
16172
16327
|
if (stat.isFile()) {
|
|
16173
|
-
const content =
|
|
16328
|
+
const content = fs4.readFileSync(candidate, "utf8").trim();
|
|
16174
16329
|
const match = content.match(/^gitdir: (.+)$/);
|
|
16175
16330
|
if (match) {
|
|
16176
|
-
return
|
|
16331
|
+
return path4.resolve(current, match[1]);
|
|
16177
16332
|
}
|
|
16178
16333
|
}
|
|
16179
16334
|
return candidate;
|
|
16180
16335
|
}
|
|
16181
|
-
const parent =
|
|
16336
|
+
const parent = path4.dirname(current);
|
|
16182
16337
|
if (parent === current) return void 0;
|
|
16183
16338
|
current = parent;
|
|
16184
16339
|
}
|
|
@@ -16189,8 +16344,8 @@ function readBranchName(cwd = process.cwd()) {
|
|
|
16189
16344
|
const gitDir = findGitDir(cwd);
|
|
16190
16345
|
if (!gitDir) return void 0;
|
|
16191
16346
|
try {
|
|
16192
|
-
const headPath =
|
|
16193
|
-
const head =
|
|
16347
|
+
const headPath = path4.join(gitDir, "HEAD");
|
|
16348
|
+
const head = fs4.readFileSync(headPath, "utf8").trim();
|
|
16194
16349
|
if (head.startsWith("ref:")) {
|
|
16195
16350
|
const refPath = head.replace("ref:", "").trim();
|
|
16196
16351
|
const match = refPath.match(/^refs\/heads\/(.+)$/);
|
|
@@ -16227,8 +16382,8 @@ function nanosecondsToMs(ns) {
|
|
|
16227
16382
|
}
|
|
16228
16383
|
|
|
16229
16384
|
// src/utils/metadata.ts
|
|
16230
|
-
var
|
|
16231
|
-
var
|
|
16385
|
+
var fs5 = __toESM(require("fs"), 1);
|
|
16386
|
+
var path5 = __toESM(require("path"), 1);
|
|
16232
16387
|
var versionCache = /* @__PURE__ */ new Map();
|
|
16233
16388
|
function readPackageVersion(root) {
|
|
16234
16389
|
if (versionCache.has(root)) {
|
|
@@ -16239,18 +16394,18 @@ function readPackageVersion(root) {
|
|
|
16239
16394
|
return version;
|
|
16240
16395
|
}
|
|
16241
16396
|
function findPackageVersion(startDir) {
|
|
16242
|
-
let current =
|
|
16397
|
+
let current = path5.resolve(startDir);
|
|
16243
16398
|
while (true) {
|
|
16244
|
-
const pkgPath =
|
|
16399
|
+
const pkgPath = path5.join(current, "package.json");
|
|
16245
16400
|
try {
|
|
16246
|
-
if (
|
|
16247
|
-
const raw =
|
|
16401
|
+
if (fs5.existsSync(pkgPath)) {
|
|
16402
|
+
const raw = fs5.readFileSync(pkgPath, "utf8");
|
|
16248
16403
|
const parsed = JSON.parse(raw);
|
|
16249
16404
|
return parsed.version;
|
|
16250
16405
|
}
|
|
16251
16406
|
} catch {
|
|
16252
16407
|
}
|
|
16253
|
-
const parent =
|
|
16408
|
+
const parent = path5.dirname(current);
|
|
16254
16409
|
if (parent === current) {
|
|
16255
16410
|
return void 0;
|
|
16256
16411
|
}
|
|
@@ -17208,11 +17363,11 @@ function computeOutputPath(sourceFile, format, mode, colocatedStyle, baseOutputD
|
|
|
17208
17363
|
const ext = FORMAT_EXTENSIONS[format];
|
|
17209
17364
|
const effectiveName = outputName + (outputNameSuffix ?? "");
|
|
17210
17365
|
if (mode === "aggregated") {
|
|
17211
|
-
return toPosix(
|
|
17366
|
+
return toPosix(path6.join(baseOutputDir, `${effectiveName}${ext}`));
|
|
17212
17367
|
}
|
|
17213
17368
|
const normalizedSource = toPosix(sourceFile);
|
|
17214
|
-
const dirOfSource =
|
|
17215
|
-
let baseName =
|
|
17369
|
+
const dirOfSource = path6.posix.dirname(normalizedSource);
|
|
17370
|
+
let baseName = path6.posix.basename(normalizedSource);
|
|
17216
17371
|
for (const testExt of TEST_EXTENSIONS) {
|
|
17217
17372
|
if (baseName.endsWith(testExt)) {
|
|
17218
17373
|
baseName = baseName.slice(0, -testExt.length);
|
|
@@ -17221,9 +17376,9 @@ function computeOutputPath(sourceFile, format, mode, colocatedStyle, baseOutputD
|
|
|
17221
17376
|
}
|
|
17222
17377
|
const fileName = `${baseName}.${effectiveName}${ext}`;
|
|
17223
17378
|
if (colocatedStyle === "adjacent") {
|
|
17224
|
-
return toPosix(
|
|
17379
|
+
return toPosix(path6.posix.join(dirOfSource, fileName));
|
|
17225
17380
|
}
|
|
17226
|
-
return toPosix(
|
|
17381
|
+
return toPosix(path6.posix.join(baseOutputDir, dirOfSource, fileName));
|
|
17227
17382
|
}
|
|
17228
17383
|
function groupTestCasesByOutput(testCases, format, options, logger, outputNameSuffix) {
|
|
17229
17384
|
const groups = /* @__PURE__ */ new Map();
|
|
@@ -17322,6 +17477,7 @@ var ReportGenerator = class {
|
|
|
17322
17477
|
mermaidEnabled: options.html?.mermaidEnabled ?? true,
|
|
17323
17478
|
markdownEnabled: options.html?.markdownEnabled ?? true,
|
|
17324
17479
|
permalinkBaseUrl: options.html?.permalinkBaseUrl,
|
|
17480
|
+
ticketUrlTemplate: options.html?.ticketUrlTemplate,
|
|
17325
17481
|
theme: options.html?.theme ?? "default"
|
|
17326
17482
|
},
|
|
17327
17483
|
junit: {
|
|
@@ -17345,7 +17501,9 @@ var ReportGenerator = class {
|
|
|
17345
17501
|
traceUrlTemplate: options.markdown?.traceUrlTemplate,
|
|
17346
17502
|
includeSourceLinks: options.markdown?.includeSourceLinks ?? true,
|
|
17347
17503
|
customRenderers: options.markdown?.customRenderers
|
|
17348
|
-
}
|
|
17504
|
+
},
|
|
17505
|
+
assetMode: options.assetMode ?? "none",
|
|
17506
|
+
allowMissingAssets: options.allowMissingAssets ?? false
|
|
17349
17507
|
};
|
|
17350
17508
|
}
|
|
17351
17509
|
/**
|
|
@@ -17372,6 +17530,16 @@ var ReportGenerator = class {
|
|
|
17372
17530
|
const paths = await this.generateFormat(filteredRun, format);
|
|
17373
17531
|
results.set(format, paths);
|
|
17374
17532
|
}
|
|
17533
|
+
if (this.options.assetMode === "copy") {
|
|
17534
|
+
const htmlPaths = results.get("html");
|
|
17535
|
+
if (htmlPaths) {
|
|
17536
|
+
for (const htmlPath of htmlPaths) {
|
|
17537
|
+
bundleAssets(htmlPath, {
|
|
17538
|
+
allowMissing: this.options.allowMissingAssets
|
|
17539
|
+
});
|
|
17540
|
+
}
|
|
17541
|
+
}
|
|
17542
|
+
}
|
|
17375
17543
|
return results;
|
|
17376
17544
|
}
|
|
17377
17545
|
/**
|
|
@@ -17389,9 +17557,9 @@ var ReportGenerator = class {
|
|
|
17389
17557
|
if (groups.size === 0 && this.options.output.mode === "aggregated") {
|
|
17390
17558
|
const ext = FORMAT_EXTENSIONS[format];
|
|
17391
17559
|
const effectiveName = this.options.outputName + (outputNameSuffix ?? "");
|
|
17392
|
-
const outputPath = toPosix(
|
|
17560
|
+
const outputPath = toPosix(path6.join(this.options.outputDir, `${effectiveName}${ext}`));
|
|
17393
17561
|
const content = await this.formatContent(run, format);
|
|
17394
|
-
const dir =
|
|
17562
|
+
const dir = path6.dirname(outputPath);
|
|
17395
17563
|
await fsPromises.mkdir(dir, { recursive: true });
|
|
17396
17564
|
await this.deps.writeFile(outputPath, content);
|
|
17397
17565
|
return [outputPath];
|
|
@@ -17403,7 +17571,7 @@ var ReportGenerator = class {
|
|
|
17403
17571
|
testCases
|
|
17404
17572
|
};
|
|
17405
17573
|
const content = await this.formatContent(groupRun, format);
|
|
17406
|
-
const dir =
|
|
17574
|
+
const dir = path6.dirname(outputPath);
|
|
17407
17575
|
await fsPromises.mkdir(dir, { recursive: true });
|
|
17408
17576
|
await this.deps.writeFile(outputPath, content);
|
|
17409
17577
|
writtenPaths.push(outputPath);
|
|
@@ -17432,7 +17600,8 @@ var ReportGenerator = class {
|
|
|
17432
17600
|
syntaxHighlighting: this.options.html.syntaxHighlighting,
|
|
17433
17601
|
mermaidEnabled: this.options.html.mermaidEnabled,
|
|
17434
17602
|
markdownEnabled: this.options.html.markdownEnabled,
|
|
17435
|
-
permalinkBaseUrl: this.options.html.permalinkBaseUrl
|
|
17603
|
+
permalinkBaseUrl: this.options.html.permalinkBaseUrl,
|
|
17604
|
+
ticketUrlTemplate: this.options.html.ticketUrlTemplate
|
|
17436
17605
|
});
|
|
17437
17606
|
return formatter.format(run);
|
|
17438
17607
|
}
|
|
@@ -17500,7 +17669,7 @@ async function generateRunComparison(args) {
|
|
|
17500
17669
|
await fsPromises.mkdir(outputDir, { recursive: true });
|
|
17501
17670
|
for (const format of args.formats) {
|
|
17502
17671
|
const ext = format === "html" ? ".html" : ".md";
|
|
17503
|
-
const outputPath = toPosix(
|
|
17672
|
+
const outputPath = toPosix(path6.join(outputDir, `${outputName}${ext}`));
|
|
17504
17673
|
const content = format === "html" ? new RunDiffHtmlFormatter({ title: args.title }).format(diff) : new RunDiffMarkdownFormatter({ title: args.title }).format(diff);
|
|
17505
17674
|
await fsPromises.writeFile(outputPath, content, "utf8");
|
|
17506
17675
|
files.push(outputPath);
|
|
@@ -17538,6 +17707,7 @@ function normalizePlaywrightResults(testResults, adapterOptions, canonicalizeOpt
|
|
|
17538
17707
|
adaptPlaywrightRun,
|
|
17539
17708
|
adaptVitestRun,
|
|
17540
17709
|
assertValidRun,
|
|
17710
|
+
bundleAssets,
|
|
17541
17711
|
calculateFlakiness,
|
|
17542
17712
|
calculateStability,
|
|
17543
17713
|
canonicalizeRun,
|