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/README.md
CHANGED
|
@@ -119,7 +119,7 @@ const generator = new ReportGenerator({
|
|
|
119
119
|
|
|
120
120
|
| Format | Description | File Extension |
|
|
121
121
|
| --- | --- | --- |
|
|
122
|
-
| `html` | Interactive HTML report with search and
|
|
122
|
+
| `html` | Interactive HTML report with search, screenshots, step parameter highlighting (quoted strings and numbers), syntax-highlighted code blocks, Mermaid diagrams, and Markdown in doc sections | `.html` |
|
|
123
123
|
| `markdown` | Markdown user-story documentation | `.md` |
|
|
124
124
|
| `junit` | JUnit XML for CI integration | `.junit.xml` |
|
|
125
125
|
| `cucumber-json` | Cucumber JSON for tooling compatibility | `.cucumber.json` |
|
package/dist/cli.js
CHANGED
|
@@ -1086,6 +1086,18 @@ function initCollapse() {
|
|
|
1086
1086
|
}
|
|
1087
1087
|
});
|
|
1088
1088
|
});
|
|
1089
|
+
|
|
1090
|
+
document.querySelectorAll('.trace-view-header').forEach(header => {
|
|
1091
|
+
header.addEventListener('click', () => {
|
|
1092
|
+
toggleCollapse(header, header.closest('.trace-view'));
|
|
1093
|
+
});
|
|
1094
|
+
header.addEventListener('keydown', (e) => {
|
|
1095
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
1096
|
+
e.preventDefault();
|
|
1097
|
+
toggleCollapse(header, header.closest('.trace-view'));
|
|
1098
|
+
}
|
|
1099
|
+
});
|
|
1100
|
+
});
|
|
1089
1101
|
}
|
|
1090
1102
|
|
|
1091
1103
|
function expandAll() {
|
|
@@ -1289,6 +1301,7 @@ var CSS_STYLES = `
|
|
|
1289
1301
|
--tag-bg: hsl(145 55% 95%);
|
|
1290
1302
|
--tag-color: hsl(145 63% 30%);
|
|
1291
1303
|
--tag-border: hsl(145 55% 85%);
|
|
1304
|
+
--step-param-color: hsl(220 70% 50%);
|
|
1292
1305
|
|
|
1293
1306
|
/* Accordion/Collapsible styling */
|
|
1294
1307
|
--accordion-header-hover: hsl(0 0% 98%);
|
|
@@ -1347,6 +1360,7 @@ var CSS_STYLES = `
|
|
|
1347
1360
|
--tag-bg: hsl(145 35% 14%);
|
|
1348
1361
|
--tag-color: hsl(145 63% 60%);
|
|
1349
1362
|
--tag-border: hsl(145 35% 22%);
|
|
1363
|
+
--step-param-color: hsl(220 70% 70%);
|
|
1350
1364
|
|
|
1351
1365
|
/* Accordion/Collapsible styling */
|
|
1352
1366
|
--accordion-header-hover: hsl(0 0% 11%);
|
|
@@ -1395,6 +1409,7 @@ var CSS_STYLES = `
|
|
|
1395
1409
|
--tag-bg: hsl(145 35% 14%);
|
|
1396
1410
|
--tag-color: hsl(145 63% 60%);
|
|
1397
1411
|
--tag-border: hsl(145 35% 22%);
|
|
1412
|
+
--step-param-color: hsl(220 70% 70%);
|
|
1398
1413
|
--accordion-header-hover: hsl(0 0% 11%);
|
|
1399
1414
|
--accordion-content-bg: hsl(0 0% 7%);
|
|
1400
1415
|
}
|
|
@@ -1940,6 +1955,12 @@ body {
|
|
|
1940
1955
|
color: var(--foreground);
|
|
1941
1956
|
}
|
|
1942
1957
|
|
|
1958
|
+
.step-param {
|
|
1959
|
+
font-style: italic;
|
|
1960
|
+
font-weight: 500;
|
|
1961
|
+
color: var(--step-param-color);
|
|
1962
|
+
}
|
|
1963
|
+
|
|
1943
1964
|
.step-duration {
|
|
1944
1965
|
color: var(--muted-foreground);
|
|
1945
1966
|
font-size: 0.6875rem;
|
|
@@ -2616,6 +2637,7 @@ body {
|
|
|
2616
2637
|
font-family: inherit;
|
|
2617
2638
|
background: none;
|
|
2618
2639
|
}
|
|
2640
|
+
|
|
2619
2641
|
`;
|
|
2620
2642
|
|
|
2621
2643
|
// src/formatters/html/renderers/status.ts
|
|
@@ -2860,10 +2882,11 @@ function renderStep(step, stepResult, index, deps) {
|
|
|
2860
2882
|
const isContinuation = CONTINUATION_KEYWORDS.includes(keywordTrimmed);
|
|
2861
2883
|
const stepClass = isContinuation ? "step continuation" : "step";
|
|
2862
2884
|
const stepDocs = deps.renderDocs(step.docs, "step-docs");
|
|
2885
|
+
const textHtml = deps.highlightStepParams ? deps.highlightStepParams(step.text) : deps.escapeHtml(step.text);
|
|
2863
2886
|
return `<div class="${stepClass}">
|
|
2864
2887
|
<span class="step-status ${statusClass}">${statusIcon}</span>
|
|
2865
2888
|
<span class="step-keyword">${deps.escapeHtml(step.keyword)}</span>
|
|
2866
|
-
<span class="step-text">${
|
|
2889
|
+
<span class="step-text">${textHtml}</span>
|
|
2867
2890
|
<span class="step-duration">${duration}</span>
|
|
2868
2891
|
</div>${stepDocs}`;
|
|
2869
2892
|
}
|
|
@@ -2875,6 +2898,30 @@ function renderSteps(args, deps) {
|
|
|
2875
2898
|
return `<div class="steps">${stepsHtml}</div>`;
|
|
2876
2899
|
}
|
|
2877
2900
|
|
|
2901
|
+
// src/formatters/html/renderers/step-params.ts
|
|
2902
|
+
var STEP_PARAM_PATTERN = /"[^"]*"|(?<![\w.\-])\d+(?:\.\d+)?(?![\w.\-])/g;
|
|
2903
|
+
function highlightStepParams(text, deps) {
|
|
2904
|
+
const matches = Array.from(text.matchAll(STEP_PARAM_PATTERN));
|
|
2905
|
+
if (matches.length === 0) {
|
|
2906
|
+
return deps.escapeHtml(text);
|
|
2907
|
+
}
|
|
2908
|
+
let result = "";
|
|
2909
|
+
let lastIndex = 0;
|
|
2910
|
+
for (const match of matches) {
|
|
2911
|
+
const matchStart = match.index;
|
|
2912
|
+
const matchEnd = matchStart + match[0].length;
|
|
2913
|
+
if (matchStart > lastIndex) {
|
|
2914
|
+
result += deps.escapeHtml(text.slice(lastIndex, matchStart));
|
|
2915
|
+
}
|
|
2916
|
+
result += `<span class="step-param">${deps.escapeHtml(match[0])}</span>`;
|
|
2917
|
+
lastIndex = matchEnd;
|
|
2918
|
+
}
|
|
2919
|
+
if (lastIndex < text.length) {
|
|
2920
|
+
result += deps.escapeHtml(text.slice(lastIndex));
|
|
2921
|
+
}
|
|
2922
|
+
return result;
|
|
2923
|
+
}
|
|
2924
|
+
|
|
2878
2925
|
// src/formatters/html/renderers/scenario.ts
|
|
2879
2926
|
function renderScenario(args, deps) {
|
|
2880
2927
|
const { tc } = args;
|
|
@@ -2882,6 +2929,19 @@ function renderScenario(args, deps) {
|
|
|
2882
2929
|
const statusClass = `status-${tc.status}`;
|
|
2883
2930
|
const duration = tc.durationMs > 0 ? `${(tc.durationMs / 1e3).toFixed(2)}s` : "";
|
|
2884
2931
|
const tags = tc.tags.map((t) => `<span class="tag">${deps.escapeHtml(t)}</span>`).join("");
|
|
2932
|
+
const otelMeta = tc.story.meta?.otel;
|
|
2933
|
+
let traceBadge = "";
|
|
2934
|
+
if (otelMeta?.traceId) {
|
|
2935
|
+
const shortId = otelMeta.traceId.slice(0, 16);
|
|
2936
|
+
const traceLink = tc.story.docs?.find(
|
|
2937
|
+
(d) => d.kind === "link" && d.label === "View Trace"
|
|
2938
|
+
);
|
|
2939
|
+
if (traceLink) {
|
|
2940
|
+
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>`;
|
|
2941
|
+
} else {
|
|
2942
|
+
traceBadge = `<span class="tag trace-tag" title="${deps.escapeHtml(otelMeta.traceId)}">${deps.escapeHtml(shortId)}\u2026</span>`;
|
|
2943
|
+
}
|
|
2944
|
+
}
|
|
2885
2945
|
const storyDocs = deps.renderDocs(tc.story.docs, "story-docs");
|
|
2886
2946
|
const steps = deps.renderSteps(
|
|
2887
2947
|
{ steps: tc.story.steps, stepResults: tc.stepResults },
|
|
@@ -2912,7 +2972,7 @@ function renderScenario(args, deps) {
|
|
|
2912
2972
|
<span class="status-icon ${statusClass}">${statusIcon}</span>
|
|
2913
2973
|
<span class="scenario-name">${deps.escapeHtml(tc.story.scenario)}</span>
|
|
2914
2974
|
</div>
|
|
2915
|
-
<div class="scenario-meta">${tags}</div>
|
|
2975
|
+
<div class="scenario-meta">${tags}${traceBadge}</div>
|
|
2916
2976
|
</div>
|
|
2917
2977
|
<span class="scenario-duration">${duration}</span>
|
|
2918
2978
|
</div>
|
|
@@ -3046,7 +3106,8 @@ function createHtmlFormatter(options = {}) {
|
|
|
3046
3106
|
const stepsDeps = {
|
|
3047
3107
|
escapeHtml,
|
|
3048
3108
|
getStatusIcon,
|
|
3049
|
-
renderDocs
|
|
3109
|
+
renderDocs,
|
|
3110
|
+
highlightStepParams: (text) => highlightStepParams(text, { escapeHtml })
|
|
3050
3111
|
};
|
|
3051
3112
|
const scenarioDeps = {
|
|
3052
3113
|
escapeHtml,
|
|
@@ -3348,6 +3409,7 @@ var MarkdownFormatter = class {
|
|
|
3348
3409
|
includeSummaryTable: options.includeSummaryTable ?? false,
|
|
3349
3410
|
permalinkBaseUrl: options.permalinkBaseUrl,
|
|
3350
3411
|
ticketUrlTemplate: options.ticketUrlTemplate,
|
|
3412
|
+
traceUrlTemplate: options.traceUrlTemplate,
|
|
3351
3413
|
includeSourceLinks: options.includeSourceLinks ?? true,
|
|
3352
3414
|
customRenderers: options.customRenderers
|
|
3353
3415
|
};
|
|
@@ -3570,6 +3632,18 @@ var MarkdownFormatter = class {
|
|
|
3570
3632
|
meta.push(`Tickets: ${tc.story.tickets.map((t) => `\`${t}\``).join(", ")}`);
|
|
3571
3633
|
}
|
|
3572
3634
|
}
|
|
3635
|
+
const otelMeta = tc.story.meta?.otel;
|
|
3636
|
+
if (otelMeta?.traceId) {
|
|
3637
|
+
const traceTemplate = this.options.traceUrlTemplate;
|
|
3638
|
+
if (traceTemplate) {
|
|
3639
|
+
const url = traceTemplate.replace(/\{traceId\}/g, otelMeta.traceId);
|
|
3640
|
+
meta.push(
|
|
3641
|
+
`Trace: [${otelMeta.traceId.slice(0, 16)}\u2026](${url})`
|
|
3642
|
+
);
|
|
3643
|
+
} else {
|
|
3644
|
+
meta.push(`Trace: \`${otelMeta.traceId}\``);
|
|
3645
|
+
}
|
|
3646
|
+
}
|
|
3573
3647
|
if (meta.length > 0) {
|
|
3574
3648
|
lines.push(meta.join(" | "));
|
|
3575
3649
|
}
|
|
@@ -5124,6 +5198,7 @@ var ReportGenerator = class {
|
|
|
5124
5198
|
includeSummaryTable: options.markdown?.includeSummaryTable ?? false,
|
|
5125
5199
|
permalinkBaseUrl: options.markdown?.permalinkBaseUrl,
|
|
5126
5200
|
ticketUrlTemplate: options.markdown?.ticketUrlTemplate,
|
|
5201
|
+
traceUrlTemplate: options.markdown?.traceUrlTemplate,
|
|
5127
5202
|
includeSourceLinks: options.markdown?.includeSourceLinks ?? true,
|
|
5128
5203
|
customRenderers: options.markdown?.customRenderers
|
|
5129
5204
|
}
|
|
@@ -5249,6 +5324,7 @@ var ReportGenerator = class {
|
|
|
5249
5324
|
includeSummaryTable: this.options.markdown.includeSummaryTable,
|
|
5250
5325
|
permalinkBaseUrl: this.options.markdown.permalinkBaseUrl,
|
|
5251
5326
|
ticketUrlTemplate: this.options.markdown.ticketUrlTemplate,
|
|
5327
|
+
traceUrlTemplate: this.options.markdown.traceUrlTemplate,
|
|
5252
5328
|
includeSourceLinks: this.options.markdown.includeSourceLinks,
|
|
5253
5329
|
customRenderers: this.options.markdown.customRenderers
|
|
5254
5330
|
});
|