executable-stories-formatters 0.2.0 → 0.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/README.md +1 -1
- package/dist/cli.js +79 -3
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +109 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +27 -1
- package/dist/index.d.ts +27 -1
- package/dist/index.js +106 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/schemas/README.md +7 -12
package/dist/index.cjs
CHANGED
|
@@ -65,7 +65,9 @@ __export(src_exports, {
|
|
|
65
65
|
readPackageVersion: () => readPackageVersion,
|
|
66
66
|
resolveAttachment: () => resolveAttachment,
|
|
67
67
|
resolveAttachments: () => resolveAttachments,
|
|
68
|
+
resolveTraceUrl: () => resolveTraceUrl,
|
|
68
69
|
slugify: () => slugify,
|
|
70
|
+
tryGetActiveOtelContext: () => tryGetActiveOtelContext,
|
|
69
71
|
validateCanonicalRun: () => validateCanonicalRun
|
|
70
72
|
});
|
|
71
73
|
module.exports = __toCommonJS(src_exports);
|
|
@@ -953,6 +955,18 @@ function initCollapse() {
|
|
|
953
955
|
}
|
|
954
956
|
});
|
|
955
957
|
});
|
|
958
|
+
|
|
959
|
+
document.querySelectorAll('.trace-view-header').forEach(header => {
|
|
960
|
+
header.addEventListener('click', () => {
|
|
961
|
+
toggleCollapse(header, header.closest('.trace-view'));
|
|
962
|
+
});
|
|
963
|
+
header.addEventListener('keydown', (e) => {
|
|
964
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
965
|
+
e.preventDefault();
|
|
966
|
+
toggleCollapse(header, header.closest('.trace-view'));
|
|
967
|
+
}
|
|
968
|
+
});
|
|
969
|
+
});
|
|
956
970
|
}
|
|
957
971
|
|
|
958
972
|
function expandAll() {
|
|
@@ -1156,6 +1170,7 @@ var CSS_STYLES = `
|
|
|
1156
1170
|
--tag-bg: hsl(145 55% 95%);
|
|
1157
1171
|
--tag-color: hsl(145 63% 30%);
|
|
1158
1172
|
--tag-border: hsl(145 55% 85%);
|
|
1173
|
+
--step-param-color: hsl(220 70% 50%);
|
|
1159
1174
|
|
|
1160
1175
|
/* Accordion/Collapsible styling */
|
|
1161
1176
|
--accordion-header-hover: hsl(0 0% 98%);
|
|
@@ -1214,6 +1229,7 @@ var CSS_STYLES = `
|
|
|
1214
1229
|
--tag-bg: hsl(145 35% 14%);
|
|
1215
1230
|
--tag-color: hsl(145 63% 60%);
|
|
1216
1231
|
--tag-border: hsl(145 35% 22%);
|
|
1232
|
+
--step-param-color: hsl(220 70% 70%);
|
|
1217
1233
|
|
|
1218
1234
|
/* Accordion/Collapsible styling */
|
|
1219
1235
|
--accordion-header-hover: hsl(0 0% 11%);
|
|
@@ -1262,6 +1278,7 @@ var CSS_STYLES = `
|
|
|
1262
1278
|
--tag-bg: hsl(145 35% 14%);
|
|
1263
1279
|
--tag-color: hsl(145 63% 60%);
|
|
1264
1280
|
--tag-border: hsl(145 35% 22%);
|
|
1281
|
+
--step-param-color: hsl(220 70% 70%);
|
|
1265
1282
|
--accordion-header-hover: hsl(0 0% 11%);
|
|
1266
1283
|
--accordion-content-bg: hsl(0 0% 7%);
|
|
1267
1284
|
}
|
|
@@ -1807,6 +1824,12 @@ body {
|
|
|
1807
1824
|
color: var(--foreground);
|
|
1808
1825
|
}
|
|
1809
1826
|
|
|
1827
|
+
.step-param {
|
|
1828
|
+
font-style: italic;
|
|
1829
|
+
font-weight: 500;
|
|
1830
|
+
color: var(--step-param-color);
|
|
1831
|
+
}
|
|
1832
|
+
|
|
1810
1833
|
.step-duration {
|
|
1811
1834
|
color: var(--muted-foreground);
|
|
1812
1835
|
font-size: 0.6875rem;
|
|
@@ -2483,6 +2506,7 @@ body {
|
|
|
2483
2506
|
font-family: inherit;
|
|
2484
2507
|
background: none;
|
|
2485
2508
|
}
|
|
2509
|
+
|
|
2486
2510
|
`;
|
|
2487
2511
|
|
|
2488
2512
|
// src/formatters/html/renderers/status.ts
|
|
@@ -2727,10 +2751,11 @@ function renderStep(step, stepResult, index, deps) {
|
|
|
2727
2751
|
const isContinuation = CONTINUATION_KEYWORDS.includes(keywordTrimmed);
|
|
2728
2752
|
const stepClass = isContinuation ? "step continuation" : "step";
|
|
2729
2753
|
const stepDocs = deps.renderDocs(step.docs, "step-docs");
|
|
2754
|
+
const textHtml = deps.highlightStepParams ? deps.highlightStepParams(step.text) : deps.escapeHtml(step.text);
|
|
2730
2755
|
return `<div class="${stepClass}">
|
|
2731
2756
|
<span class="step-status ${statusClass}">${statusIcon}</span>
|
|
2732
2757
|
<span class="step-keyword">${deps.escapeHtml(step.keyword)}</span>
|
|
2733
|
-
<span class="step-text">${
|
|
2758
|
+
<span class="step-text">${textHtml}</span>
|
|
2734
2759
|
<span class="step-duration">${duration}</span>
|
|
2735
2760
|
</div>${stepDocs}`;
|
|
2736
2761
|
}
|
|
@@ -2742,6 +2767,30 @@ function renderSteps(args, deps) {
|
|
|
2742
2767
|
return `<div class="steps">${stepsHtml}</div>`;
|
|
2743
2768
|
}
|
|
2744
2769
|
|
|
2770
|
+
// src/formatters/html/renderers/step-params.ts
|
|
2771
|
+
var STEP_PARAM_PATTERN = /"[^"]*"|(?<![\w.\-])\d+(?:\.\d+)?(?![\w.\-])/g;
|
|
2772
|
+
function highlightStepParams(text, deps) {
|
|
2773
|
+
const matches = Array.from(text.matchAll(STEP_PARAM_PATTERN));
|
|
2774
|
+
if (matches.length === 0) {
|
|
2775
|
+
return deps.escapeHtml(text);
|
|
2776
|
+
}
|
|
2777
|
+
let result = "";
|
|
2778
|
+
let lastIndex = 0;
|
|
2779
|
+
for (const match of matches) {
|
|
2780
|
+
const matchStart = match.index;
|
|
2781
|
+
const matchEnd = matchStart + match[0].length;
|
|
2782
|
+
if (matchStart > lastIndex) {
|
|
2783
|
+
result += deps.escapeHtml(text.slice(lastIndex, matchStart));
|
|
2784
|
+
}
|
|
2785
|
+
result += `<span class="step-param">${deps.escapeHtml(match[0])}</span>`;
|
|
2786
|
+
lastIndex = matchEnd;
|
|
2787
|
+
}
|
|
2788
|
+
if (lastIndex < text.length) {
|
|
2789
|
+
result += deps.escapeHtml(text.slice(lastIndex));
|
|
2790
|
+
}
|
|
2791
|
+
return result;
|
|
2792
|
+
}
|
|
2793
|
+
|
|
2745
2794
|
// src/formatters/html/renderers/scenario.ts
|
|
2746
2795
|
function renderScenario(args, deps) {
|
|
2747
2796
|
const { tc } = args;
|
|
@@ -2749,6 +2798,19 @@ function renderScenario(args, deps) {
|
|
|
2749
2798
|
const statusClass = `status-${tc.status}`;
|
|
2750
2799
|
const duration = tc.durationMs > 0 ? `${(tc.durationMs / 1e3).toFixed(2)}s` : "";
|
|
2751
2800
|
const tags = tc.tags.map((t) => `<span class="tag">${deps.escapeHtml(t)}</span>`).join("");
|
|
2801
|
+
const otelMeta = tc.story.meta?.otel;
|
|
2802
|
+
let traceBadge = "";
|
|
2803
|
+
if (otelMeta?.traceId) {
|
|
2804
|
+
const shortId = otelMeta.traceId.slice(0, 16);
|
|
2805
|
+
const traceLink = tc.story.docs?.find(
|
|
2806
|
+
(d) => d.kind === "link" && d.label === "View Trace"
|
|
2807
|
+
);
|
|
2808
|
+
if (traceLink) {
|
|
2809
|
+
traceBadge = `<a class="tag trace-tag" href="${deps.escapeHtml(traceLink.url)}" title="${deps.escapeHtml(otelMeta.traceId)}" target="_blank" rel="noopener">${deps.escapeHtml(shortId)}\u2026</a>`;
|
|
2810
|
+
} else {
|
|
2811
|
+
traceBadge = `<span class="tag trace-tag" title="${deps.escapeHtml(otelMeta.traceId)}">${deps.escapeHtml(shortId)}\u2026</span>`;
|
|
2812
|
+
}
|
|
2813
|
+
}
|
|
2752
2814
|
const storyDocs = deps.renderDocs(tc.story.docs, "story-docs");
|
|
2753
2815
|
const steps = deps.renderSteps(
|
|
2754
2816
|
{ steps: tc.story.steps, stepResults: tc.stepResults },
|
|
@@ -2779,7 +2841,7 @@ function renderScenario(args, deps) {
|
|
|
2779
2841
|
<span class="status-icon ${statusClass}">${statusIcon}</span>
|
|
2780
2842
|
<span class="scenario-name">${deps.escapeHtml(tc.story.scenario)}</span>
|
|
2781
2843
|
</div>
|
|
2782
|
-
<div class="scenario-meta">${tags}</div>
|
|
2844
|
+
<div class="scenario-meta">${tags}${traceBadge}</div>
|
|
2783
2845
|
</div>
|
|
2784
2846
|
<span class="scenario-duration">${duration}</span>
|
|
2785
2847
|
</div>
|
|
@@ -2913,7 +2975,8 @@ function createHtmlFormatter(options = {}) {
|
|
|
2913
2975
|
const stepsDeps = {
|
|
2914
2976
|
escapeHtml,
|
|
2915
2977
|
getStatusIcon,
|
|
2916
|
-
renderDocs
|
|
2978
|
+
renderDocs,
|
|
2979
|
+
highlightStepParams: (text) => highlightStepParams(text, { escapeHtml })
|
|
2917
2980
|
};
|
|
2918
2981
|
const scenarioDeps = {
|
|
2919
2982
|
escapeHtml,
|
|
@@ -3215,6 +3278,7 @@ var MarkdownFormatter = class {
|
|
|
3215
3278
|
includeSummaryTable: options.includeSummaryTable ?? false,
|
|
3216
3279
|
permalinkBaseUrl: options.permalinkBaseUrl,
|
|
3217
3280
|
ticketUrlTemplate: options.ticketUrlTemplate,
|
|
3281
|
+
traceUrlTemplate: options.traceUrlTemplate,
|
|
3218
3282
|
includeSourceLinks: options.includeSourceLinks ?? true,
|
|
3219
3283
|
customRenderers: options.customRenderers
|
|
3220
3284
|
};
|
|
@@ -3437,6 +3501,18 @@ var MarkdownFormatter = class {
|
|
|
3437
3501
|
meta.push(`Tickets: ${tc.story.tickets.map((t) => `\`${t}\``).join(", ")}`);
|
|
3438
3502
|
}
|
|
3439
3503
|
}
|
|
3504
|
+
const otelMeta = tc.story.meta?.otel;
|
|
3505
|
+
if (otelMeta?.traceId) {
|
|
3506
|
+
const traceTemplate = this.options.traceUrlTemplate;
|
|
3507
|
+
if (traceTemplate) {
|
|
3508
|
+
const url = traceTemplate.replace(/\{traceId\}/g, otelMeta.traceId);
|
|
3509
|
+
meta.push(
|
|
3510
|
+
`Trace: [${otelMeta.traceId.slice(0, 16)}\u2026](${url})`
|
|
3511
|
+
);
|
|
3512
|
+
} else {
|
|
3513
|
+
meta.push(`Trace: \`${otelMeta.traceId}\``);
|
|
3514
|
+
}
|
|
3515
|
+
}
|
|
3440
3516
|
if (meta.length > 0) {
|
|
3441
3517
|
lines.push(meta.join(" | "));
|
|
3442
3518
|
}
|
|
@@ -5379,6 +5455,32 @@ function detectCI4(env = process.env) {
|
|
|
5379
5455
|
return void 0;
|
|
5380
5456
|
}
|
|
5381
5457
|
|
|
5458
|
+
// src/utils/otel-detect.ts
|
|
5459
|
+
var import_node_module = require("module");
|
|
5460
|
+
var import_meta2 = {};
|
|
5461
|
+
function getRequire() {
|
|
5462
|
+
const url = import_meta2.url ?? (typeof __filename !== "undefined" ? `file://${__filename}` : void 0);
|
|
5463
|
+
if (!url) throw new Error("Cannot determine module URL");
|
|
5464
|
+
return (0, import_node_module.createRequire)(url);
|
|
5465
|
+
}
|
|
5466
|
+
function tryGetActiveOtelContext() {
|
|
5467
|
+
try {
|
|
5468
|
+
const api = getRequire()("@opentelemetry/api");
|
|
5469
|
+
const span = api.trace?.getActiveSpan?.();
|
|
5470
|
+
if (!span) return void 0;
|
|
5471
|
+
const ctx = span.spanContext?.();
|
|
5472
|
+
if (!ctx?.traceId || ctx.traceId === "00000000000000000000000000000000")
|
|
5473
|
+
return void 0;
|
|
5474
|
+
return { traceId: ctx.traceId, spanId: ctx.spanId };
|
|
5475
|
+
} catch {
|
|
5476
|
+
return void 0;
|
|
5477
|
+
}
|
|
5478
|
+
}
|
|
5479
|
+
function resolveTraceUrl(template, traceId) {
|
|
5480
|
+
if (!template) return void 0;
|
|
5481
|
+
return template.replace(/\{traceId\}/g, traceId);
|
|
5482
|
+
}
|
|
5483
|
+
|
|
5382
5484
|
// src/index.ts
|
|
5383
5485
|
var FORMAT_EXTENSIONS = {
|
|
5384
5486
|
markdown: ".md",
|
|
@@ -5569,6 +5671,7 @@ var ReportGenerator = class {
|
|
|
5569
5671
|
includeSummaryTable: options.markdown?.includeSummaryTable ?? false,
|
|
5570
5672
|
permalinkBaseUrl: options.markdown?.permalinkBaseUrl,
|
|
5571
5673
|
ticketUrlTemplate: options.markdown?.ticketUrlTemplate,
|
|
5674
|
+
traceUrlTemplate: options.markdown?.traceUrlTemplate,
|
|
5572
5675
|
includeSourceLinks: options.markdown?.includeSourceLinks ?? true,
|
|
5573
5676
|
customRenderers: options.markdown?.customRenderers
|
|
5574
5677
|
}
|
|
@@ -5694,6 +5797,7 @@ var ReportGenerator = class {
|
|
|
5694
5797
|
includeSummaryTable: this.options.markdown.includeSummaryTable,
|
|
5695
5798
|
permalinkBaseUrl: this.options.markdown.permalinkBaseUrl,
|
|
5696
5799
|
ticketUrlTemplate: this.options.markdown.ticketUrlTemplate,
|
|
5800
|
+
traceUrlTemplate: this.options.markdown.traceUrlTemplate,
|
|
5697
5801
|
includeSourceLinks: this.options.markdown.includeSourceLinks,
|
|
5698
5802
|
customRenderers: this.options.markdown.customRenderers
|
|
5699
5803
|
});
|
|
@@ -5756,7 +5860,9 @@ function normalizePlaywrightResults(testResults, adapterOptions, canonicalizeOpt
|
|
|
5756
5860
|
readPackageVersion,
|
|
5757
5861
|
resolveAttachment,
|
|
5758
5862
|
resolveAttachments,
|
|
5863
|
+
resolveTraceUrl,
|
|
5759
5864
|
slugify,
|
|
5865
|
+
tryGetActiveOtelContext,
|
|
5760
5866
|
validateCanonicalRun
|
|
5761
5867
|
});
|
|
5762
5868
|
//# sourceMappingURL=index.cjs.map
|