executable-stories-formatters 0.1.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/LICENSE +21 -0
- package/README.md +1 -1
- package/dist/cli.js +347 -28
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +377 -28
- 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 +374 -28
- package/dist/index.js.map +1 -1
- package/package.json +12 -12
- 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);
|
|
@@ -763,50 +765,162 @@ function initTheme() {
|
|
|
763
765
|
}
|
|
764
766
|
`;
|
|
765
767
|
var JS_CORE = `
|
|
768
|
+
// Filter state
|
|
769
|
+
var activeTags = new Set();
|
|
770
|
+
var activeStatus = null;
|
|
771
|
+
|
|
766
772
|
// Search functionality
|
|
767
773
|
function initSearch() {
|
|
768
|
-
|
|
774
|
+
var input = document.querySelector('.search-input');
|
|
769
775
|
if (!input) return;
|
|
770
776
|
|
|
771
|
-
|
|
772
|
-
input.addEventListener('input', (
|
|
777
|
+
var debounceTimer;
|
|
778
|
+
input.addEventListener('input', function() {
|
|
773
779
|
clearTimeout(debounceTimer);
|
|
774
|
-
debounceTimer = setTimeout(()
|
|
775
|
-
|
|
780
|
+
debounceTimer = setTimeout(function() {
|
|
781
|
+
applyAllFilters();
|
|
776
782
|
}, 150);
|
|
777
783
|
});
|
|
778
784
|
|
|
779
785
|
// Clear search on Escape
|
|
780
|
-
input.addEventListener('keydown', (e)
|
|
786
|
+
input.addEventListener('keydown', function(e) {
|
|
781
787
|
if (e.key === 'Escape') {
|
|
782
788
|
e.target.value = '';
|
|
783
|
-
|
|
789
|
+
applyAllFilters();
|
|
784
790
|
}
|
|
785
791
|
});
|
|
786
792
|
}
|
|
787
793
|
|
|
788
|
-
|
|
789
|
-
|
|
794
|
+
// Tag filter
|
|
795
|
+
function initTagFilter() {
|
|
796
|
+
document.querySelectorAll('.tag-pill').forEach(function(pill) {
|
|
797
|
+
pill.addEventListener('click', function() {
|
|
798
|
+
var tag = pill.dataset.tag;
|
|
799
|
+
if (activeTags.has(tag)) {
|
|
800
|
+
activeTags.delete(tag);
|
|
801
|
+
pill.classList.remove('active');
|
|
802
|
+
} else {
|
|
803
|
+
activeTags.add(tag);
|
|
804
|
+
pill.classList.add('active');
|
|
805
|
+
}
|
|
806
|
+
updateClearButton();
|
|
807
|
+
applyAllFilters();
|
|
808
|
+
});
|
|
809
|
+
});
|
|
790
810
|
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
811
|
+
var clearBtn = document.querySelector('.tag-bar-clear');
|
|
812
|
+
if (clearBtn) {
|
|
813
|
+
clearBtn.addEventListener('click', function() {
|
|
814
|
+
activeTags.clear();
|
|
815
|
+
document.querySelectorAll('.tag-pill.active').forEach(function(p) { p.classList.remove('active'); });
|
|
816
|
+
updateClearButton();
|
|
817
|
+
applyAllFilters();
|
|
818
|
+
});
|
|
819
|
+
}
|
|
820
|
+
}
|
|
794
821
|
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
822
|
+
function updateClearButton() {
|
|
823
|
+
var clearBtn = document.querySelector('.tag-bar-clear');
|
|
824
|
+
if (clearBtn) {
|
|
825
|
+
clearBtn.style.display = activeTags.size > 0 ? '' : 'none';
|
|
826
|
+
}
|
|
827
|
+
}
|
|
799
828
|
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
829
|
+
// Status filter (clickable summary cards)
|
|
830
|
+
function initStatusFilter() {
|
|
831
|
+
document.querySelectorAll('.summary-card').forEach(function(card) {
|
|
832
|
+
card.style.cursor = 'pointer';
|
|
833
|
+
if (!card.classList.contains('passed') && !card.classList.contains('failed') && !card.classList.contains('skipped')) {
|
|
834
|
+
card.addEventListener('click', function() {
|
|
835
|
+
activeStatus = null;
|
|
836
|
+
document.querySelectorAll('.summary-card').forEach(function(c) { c.classList.remove('status-active'); });
|
|
837
|
+
applyAllFilters();
|
|
838
|
+
});
|
|
839
|
+
return;
|
|
840
|
+
}
|
|
841
|
+
card.addEventListener('click', function() {
|
|
842
|
+
var status = card.classList.contains('passed') ? 'passed' :
|
|
843
|
+
card.classList.contains('failed') ? 'failed' : 'skipped';
|
|
844
|
+
if (activeStatus === status) {
|
|
845
|
+
activeStatus = null;
|
|
846
|
+
card.classList.remove('status-active');
|
|
847
|
+
} else {
|
|
848
|
+
activeStatus = status;
|
|
849
|
+
document.querySelectorAll('.summary-card').forEach(function(c) { c.classList.remove('status-active'); });
|
|
850
|
+
card.classList.add('status-active');
|
|
851
|
+
}
|
|
852
|
+
applyAllFilters();
|
|
853
|
+
});
|
|
854
|
+
});
|
|
855
|
+
}
|
|
804
856
|
|
|
805
|
-
|
|
806
|
-
|
|
857
|
+
// Unified filter: composes search + tags + status
|
|
858
|
+
function applyAllFilters() {
|
|
859
|
+
var searchInput = document.querySelector('.search-input');
|
|
860
|
+
var searchQuery = searchInput ? searchInput.value.toLowerCase().trim() : '';
|
|
861
|
+
var features = document.querySelectorAll('.feature');
|
|
862
|
+
var visibleCount = 0;
|
|
863
|
+
var totalCount = 0;
|
|
864
|
+
|
|
865
|
+
features.forEach(function(feature) {
|
|
866
|
+
var scenarios = feature.querySelectorAll('.scenario');
|
|
867
|
+
var featureVisible = 0;
|
|
868
|
+
|
|
869
|
+
scenarios.forEach(function(scenario) {
|
|
870
|
+
totalCount++;
|
|
871
|
+
var title = (scenario.querySelector('.scenario-title') || {}).textContent || '';
|
|
872
|
+
title = title.toLowerCase();
|
|
873
|
+
var tags = Array.from(scenario.querySelectorAll('.scenario-meta .tag')).map(function(t) { return t.textContent.toLowerCase(); });
|
|
874
|
+
var steps = Array.from(scenario.querySelectorAll('.step-text')).map(function(s) { return s.textContent.toLowerCase(); });
|
|
875
|
+
var statusEl = scenario.querySelector('.status-icon');
|
|
876
|
+
var status = statusEl && statusEl.classList.contains('status-passed') ? 'passed' :
|
|
877
|
+
statusEl && statusEl.classList.contains('status-failed') ? 'failed' :
|
|
878
|
+
statusEl && statusEl.classList.contains('status-skipped') ? 'skipped' : 'pending';
|
|
879
|
+
|
|
880
|
+
var matchesSearch = !searchQuery ||
|
|
881
|
+
title.includes(searchQuery) ||
|
|
882
|
+
tags.some(function(t) { return t.includes(searchQuery); }) ||
|
|
883
|
+
steps.some(function(s) { return s.includes(searchQuery); });
|
|
884
|
+
|
|
885
|
+
var matchesTags = activeTags.size === 0 ||
|
|
886
|
+
tags.some(function(t) { return activeTags.has(t); });
|
|
887
|
+
|
|
888
|
+
var matchesStatus = !activeStatus ||
|
|
889
|
+
status === activeStatus ||
|
|
890
|
+
(activeStatus === 'skipped' && status === 'pending');
|
|
891
|
+
|
|
892
|
+
var visible = matchesSearch && matchesTags && matchesStatus;
|
|
893
|
+
scenario.style.display = visible ? '' : 'none';
|
|
894
|
+
if (visible) { visibleCount++; featureVisible++; }
|
|
807
895
|
});
|
|
808
896
|
|
|
809
|
-
feature.style.display =
|
|
897
|
+
feature.style.display = featureVisible > 0 ? '' : 'none';
|
|
898
|
+
});
|
|
899
|
+
|
|
900
|
+
updateFilterResults(visibleCount, totalCount);
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
function updateFilterResults(visible, total) {
|
|
904
|
+
var el = document.querySelector('.filter-results');
|
|
905
|
+
if (!el) return;
|
|
906
|
+
var searchInput = document.querySelector('.search-input');
|
|
907
|
+
var isFiltering = activeTags.size > 0 || activeStatus ||
|
|
908
|
+
(searchInput && searchInput.value.trim().length > 0);
|
|
909
|
+
el.style.display = isFiltering ? '' : 'none';
|
|
910
|
+
var vc = el.querySelector('.visible-count');
|
|
911
|
+
var tc = el.querySelector('.total-count');
|
|
912
|
+
if (vc) vc.textContent = visible;
|
|
913
|
+
if (tc) tc.textContent = total;
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
// Keyboard shortcuts
|
|
917
|
+
function initKeyboardShortcuts() {
|
|
918
|
+
document.addEventListener('keydown', function(e) {
|
|
919
|
+
if (e.key === '/' && !e.ctrlKey && !e.metaKey && e.target.tagName !== 'INPUT') {
|
|
920
|
+
e.preventDefault();
|
|
921
|
+
var input = document.querySelector('.search-input');
|
|
922
|
+
if (input) input.focus();
|
|
923
|
+
}
|
|
810
924
|
});
|
|
811
925
|
}
|
|
812
926
|
|
|
@@ -841,6 +955,18 @@ function initCollapse() {
|
|
|
841
955
|
}
|
|
842
956
|
});
|
|
843
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
|
+
});
|
|
844
970
|
}
|
|
845
971
|
|
|
846
972
|
function expandAll() {
|
|
@@ -891,6 +1017,9 @@ function generateScript(options) {
|
|
|
891
1017
|
initCalls.push("initTheme();");
|
|
892
1018
|
}
|
|
893
1019
|
initCalls.push("initSearch();");
|
|
1020
|
+
initCalls.push("initTagFilter();");
|
|
1021
|
+
initCalls.push("initStatusFilter();");
|
|
1022
|
+
initCalls.push("initKeyboardShortcuts();");
|
|
894
1023
|
initCalls.push("initCollapse();");
|
|
895
1024
|
const initScript = `
|
|
896
1025
|
// Initialize on load
|
|
@@ -1041,6 +1170,7 @@ var CSS_STYLES = `
|
|
|
1041
1170
|
--tag-bg: hsl(145 55% 95%);
|
|
1042
1171
|
--tag-color: hsl(145 63% 30%);
|
|
1043
1172
|
--tag-border: hsl(145 55% 85%);
|
|
1173
|
+
--step-param-color: hsl(220 70% 50%);
|
|
1044
1174
|
|
|
1045
1175
|
/* Accordion/Collapsible styling */
|
|
1046
1176
|
--accordion-header-hover: hsl(0 0% 98%);
|
|
@@ -1099,6 +1229,7 @@ var CSS_STYLES = `
|
|
|
1099
1229
|
--tag-bg: hsl(145 35% 14%);
|
|
1100
1230
|
--tag-color: hsl(145 63% 60%);
|
|
1101
1231
|
--tag-border: hsl(145 35% 22%);
|
|
1232
|
+
--step-param-color: hsl(220 70% 70%);
|
|
1102
1233
|
|
|
1103
1234
|
/* Accordion/Collapsible styling */
|
|
1104
1235
|
--accordion-header-hover: hsl(0 0% 11%);
|
|
@@ -1147,6 +1278,7 @@ var CSS_STYLES = `
|
|
|
1147
1278
|
--tag-bg: hsl(145 35% 14%);
|
|
1148
1279
|
--tag-color: hsl(145 63% 60%);
|
|
1149
1280
|
--tag-border: hsl(145 35% 22%);
|
|
1281
|
+
--step-param-color: hsl(220 70% 70%);
|
|
1150
1282
|
--accordion-header-hover: hsl(0 0% 11%);
|
|
1151
1283
|
--accordion-content-bg: hsl(0 0% 7%);
|
|
1152
1284
|
}
|
|
@@ -1374,6 +1506,98 @@ body {
|
|
|
1374
1506
|
}
|
|
1375
1507
|
.summary-card.pending .value { color: var(--pending); }
|
|
1376
1508
|
|
|
1509
|
+
/* ============================================================================
|
|
1510
|
+
Tag Filter Bar
|
|
1511
|
+
============================================================================ */
|
|
1512
|
+
.tag-bar {
|
|
1513
|
+
margin-bottom: 1rem;
|
|
1514
|
+
padding: 0.75rem 1rem;
|
|
1515
|
+
background: var(--card);
|
|
1516
|
+
border: 1px solid var(--border);
|
|
1517
|
+
border-radius: var(--radius);
|
|
1518
|
+
position: sticky;
|
|
1519
|
+
top: 0;
|
|
1520
|
+
z-index: 10;
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
.tag-bar-header {
|
|
1524
|
+
display: flex;
|
|
1525
|
+
justify-content: space-between;
|
|
1526
|
+
align-items: center;
|
|
1527
|
+
margin-bottom: 0.5rem;
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1530
|
+
.tag-bar-label {
|
|
1531
|
+
font-size: 0.6875rem;
|
|
1532
|
+
text-transform: uppercase;
|
|
1533
|
+
letter-spacing: 0.05em;
|
|
1534
|
+
color: var(--muted-foreground);
|
|
1535
|
+
font-weight: 500;
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
.tag-bar-clear {
|
|
1539
|
+
font-size: 0.75rem;
|
|
1540
|
+
font-weight: 500;
|
|
1541
|
+
color: var(--primary);
|
|
1542
|
+
background: none;
|
|
1543
|
+
border: none;
|
|
1544
|
+
cursor: pointer;
|
|
1545
|
+
padding: 0.125rem 0.5rem;
|
|
1546
|
+
border-radius: var(--radius);
|
|
1547
|
+
transition: all 0.15s ease;
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1550
|
+
.tag-bar-clear:hover {
|
|
1551
|
+
background: var(--muted);
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1554
|
+
.tag-bar-pills {
|
|
1555
|
+
display: flex;
|
|
1556
|
+
flex-wrap: wrap;
|
|
1557
|
+
gap: 0.375rem;
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1560
|
+
.tag-pill {
|
|
1561
|
+
font-size: 0.75rem;
|
|
1562
|
+
font-weight: 500;
|
|
1563
|
+
padding: 0.25rem 0.625rem;
|
|
1564
|
+
background: var(--tag-bg);
|
|
1565
|
+
color: var(--tag-color);
|
|
1566
|
+
border: 1px solid var(--tag-border);
|
|
1567
|
+
border-radius: 9999px;
|
|
1568
|
+
font-family: var(--font-mono);
|
|
1569
|
+
cursor: pointer;
|
|
1570
|
+
transition: all 0.15s ease;
|
|
1571
|
+
}
|
|
1572
|
+
|
|
1573
|
+
.tag-pill:hover {
|
|
1574
|
+
background: var(--success-border);
|
|
1575
|
+
}
|
|
1576
|
+
|
|
1577
|
+
.tag-pill.active {
|
|
1578
|
+
background: var(--primary);
|
|
1579
|
+
color: var(--primary-foreground);
|
|
1580
|
+
border-color: var(--primary);
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1583
|
+
/* ============================================================================
|
|
1584
|
+
Summary Card Status Filter
|
|
1585
|
+
============================================================================ */
|
|
1586
|
+
.summary-card.status-active {
|
|
1587
|
+
box-shadow: 0 0 0 2px var(--background), 0 0 0 4px var(--ring);
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1590
|
+
/* ============================================================================
|
|
1591
|
+
Filter Results Counter
|
|
1592
|
+
============================================================================ */
|
|
1593
|
+
.filter-results {
|
|
1594
|
+
text-align: center;
|
|
1595
|
+
font-size: 0.8125rem;
|
|
1596
|
+
color: var(--muted-foreground);
|
|
1597
|
+
margin-bottom: 1rem;
|
|
1598
|
+
font-weight: 500;
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1377
1601
|
/* ============================================================================
|
|
1378
1602
|
Feature Sections - shadcn accordion style
|
|
1379
1603
|
============================================================================ */
|
|
@@ -1600,6 +1824,12 @@ body {
|
|
|
1600
1824
|
color: var(--foreground);
|
|
1601
1825
|
}
|
|
1602
1826
|
|
|
1827
|
+
.step-param {
|
|
1828
|
+
font-style: italic;
|
|
1829
|
+
font-weight: 500;
|
|
1830
|
+
color: var(--step-param-color);
|
|
1831
|
+
}
|
|
1832
|
+
|
|
1603
1833
|
.step-duration {
|
|
1604
1834
|
color: var(--muted-foreground);
|
|
1605
1835
|
font-size: 0.6875rem;
|
|
@@ -1761,8 +1991,10 @@ body {
|
|
|
1761
1991
|
padding: 0;
|
|
1762
1992
|
}
|
|
1763
1993
|
|
|
1764
|
-
.header-actions
|
|
1765
|
-
|
|
1994
|
+
.header-actions,
|
|
1995
|
+
.tag-bar,
|
|
1996
|
+
.filter-results {
|
|
1997
|
+
display: none !important;
|
|
1766
1998
|
}
|
|
1767
1999
|
|
|
1768
2000
|
.feature,
|
|
@@ -2274,6 +2506,7 @@ body {
|
|
|
2274
2506
|
font-family: inherit;
|
|
2275
2507
|
background: none;
|
|
2276
2508
|
}
|
|
2509
|
+
|
|
2277
2510
|
`;
|
|
2278
2511
|
|
|
2279
2512
|
// src/formatters/html/renderers/status.ts
|
|
@@ -2336,6 +2569,28 @@ function renderSummary(args, _deps) {
|
|
|
2336
2569
|
</div>`;
|
|
2337
2570
|
}
|
|
2338
2571
|
|
|
2572
|
+
// src/formatters/html/renderers/tag-bar.ts
|
|
2573
|
+
function renderTagBar(args, deps) {
|
|
2574
|
+
const { tags, totalScenarios } = args;
|
|
2575
|
+
if (tags.length === 0) return "";
|
|
2576
|
+
const pills = tags.map(
|
|
2577
|
+
(tag) => `<button type="button" class="tag-pill" data-tag="${deps.escapeHtml(tag)}">${deps.escapeHtml(tag)}</button>`
|
|
2578
|
+
).join("\n ");
|
|
2579
|
+
return `
|
|
2580
|
+
<div class="tag-bar">
|
|
2581
|
+
<div class="tag-bar-header">
|
|
2582
|
+
<span class="tag-bar-label">Filter by tag</span>
|
|
2583
|
+
<button type="button" class="tag-bar-clear" style="display:none">Clear</button>
|
|
2584
|
+
</div>
|
|
2585
|
+
<div class="tag-bar-pills">
|
|
2586
|
+
${pills}
|
|
2587
|
+
</div>
|
|
2588
|
+
</div>
|
|
2589
|
+
<div class="filter-results" style="display:none">
|
|
2590
|
+
Showing <span class="visible-count">0</span> of <span class="total-count">${totalScenarios}</span> scenarios
|
|
2591
|
+
</div>`;
|
|
2592
|
+
}
|
|
2593
|
+
|
|
2339
2594
|
// src/formatters/html/renderers/error-box.ts
|
|
2340
2595
|
function renderErrorBox(args, deps) {
|
|
2341
2596
|
const body = args.stack != null ? `${deps.escapeHtml(args.message)}
|
|
@@ -2496,10 +2751,11 @@ function renderStep(step, stepResult, index, deps) {
|
|
|
2496
2751
|
const isContinuation = CONTINUATION_KEYWORDS.includes(keywordTrimmed);
|
|
2497
2752
|
const stepClass = isContinuation ? "step continuation" : "step";
|
|
2498
2753
|
const stepDocs = deps.renderDocs(step.docs, "step-docs");
|
|
2754
|
+
const textHtml = deps.highlightStepParams ? deps.highlightStepParams(step.text) : deps.escapeHtml(step.text);
|
|
2499
2755
|
return `<div class="${stepClass}">
|
|
2500
2756
|
<span class="step-status ${statusClass}">${statusIcon}</span>
|
|
2501
2757
|
<span class="step-keyword">${deps.escapeHtml(step.keyword)}</span>
|
|
2502
|
-
<span class="step-text">${
|
|
2758
|
+
<span class="step-text">${textHtml}</span>
|
|
2503
2759
|
<span class="step-duration">${duration}</span>
|
|
2504
2760
|
</div>${stepDocs}`;
|
|
2505
2761
|
}
|
|
@@ -2511,6 +2767,30 @@ function renderSteps(args, deps) {
|
|
|
2511
2767
|
return `<div class="steps">${stepsHtml}</div>`;
|
|
2512
2768
|
}
|
|
2513
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
|
+
|
|
2514
2794
|
// src/formatters/html/renderers/scenario.ts
|
|
2515
2795
|
function renderScenario(args, deps) {
|
|
2516
2796
|
const { tc } = args;
|
|
@@ -2518,6 +2798,19 @@ function renderScenario(args, deps) {
|
|
|
2518
2798
|
const statusClass = `status-${tc.status}`;
|
|
2519
2799
|
const duration = tc.durationMs > 0 ? `${(tc.durationMs / 1e3).toFixed(2)}s` : "";
|
|
2520
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
|
+
}
|
|
2521
2814
|
const storyDocs = deps.renderDocs(tc.story.docs, "story-docs");
|
|
2522
2815
|
const steps = deps.renderSteps(
|
|
2523
2816
|
{ steps: tc.story.steps, stepResults: tc.stepResults },
|
|
@@ -2548,7 +2841,7 @@ function renderScenario(args, deps) {
|
|
|
2548
2841
|
<span class="status-icon ${statusClass}">${statusIcon}</span>
|
|
2549
2842
|
<span class="scenario-name">${deps.escapeHtml(tc.story.scenario)}</span>
|
|
2550
2843
|
</div>
|
|
2551
|
-
<div class="scenario-meta">${tags}</div>
|
|
2844
|
+
<div class="scenario-meta">${tags}${traceBadge}</div>
|
|
2552
2845
|
</div>
|
|
2553
2846
|
<span class="scenario-duration">${duration}</span>
|
|
2554
2847
|
</div>
|
|
@@ -2635,6 +2928,15 @@ function buildBody(args, deps) {
|
|
|
2635
2928
|
deps.summaryDeps
|
|
2636
2929
|
)
|
|
2637
2930
|
);
|
|
2931
|
+
const allTags = [
|
|
2932
|
+
...new Set(run.testCases.flatMap((tc) => tc.tags))
|
|
2933
|
+
].sort();
|
|
2934
|
+
parts.push(
|
|
2935
|
+
deps.renderTagBar(
|
|
2936
|
+
{ tags: allTags, totalScenarios: total },
|
|
2937
|
+
deps.tagBarDeps
|
|
2938
|
+
)
|
|
2939
|
+
);
|
|
2638
2940
|
const byFile = groupBy(run.testCases, (tc) => tc.sourceFile);
|
|
2639
2941
|
for (const [file, testCases] of byFile) {
|
|
2640
2942
|
parts.push(
|
|
@@ -2673,7 +2975,8 @@ function createHtmlFormatter(options = {}) {
|
|
|
2673
2975
|
const stepsDeps = {
|
|
2674
2976
|
escapeHtml,
|
|
2675
2977
|
getStatusIcon,
|
|
2676
|
-
renderDocs
|
|
2978
|
+
renderDocs,
|
|
2979
|
+
highlightStepParams: (text) => highlightStepParams(text, { escapeHtml })
|
|
2677
2980
|
};
|
|
2678
2981
|
const scenarioDeps = {
|
|
2679
2982
|
escapeHtml,
|
|
@@ -2691,12 +2994,15 @@ function createHtmlFormatter(options = {}) {
|
|
|
2691
2994
|
renderScenario: (args) => renderScenario(args, scenarioDeps),
|
|
2692
2995
|
scenarioDeps
|
|
2693
2996
|
};
|
|
2997
|
+
const tagBarDeps = { escapeHtml };
|
|
2694
2998
|
const bodyDeps = {
|
|
2695
2999
|
renderMetaInfo,
|
|
2696
3000
|
renderSummary,
|
|
3001
|
+
renderTagBar,
|
|
2697
3002
|
renderFeature,
|
|
2698
3003
|
metaDeps: { escapeHtml },
|
|
2699
3004
|
summaryDeps: {},
|
|
3005
|
+
tagBarDeps,
|
|
2700
3006
|
featureDeps
|
|
2701
3007
|
};
|
|
2702
3008
|
return {
|
|
@@ -2972,6 +3278,7 @@ var MarkdownFormatter = class {
|
|
|
2972
3278
|
includeSummaryTable: options.includeSummaryTable ?? false,
|
|
2973
3279
|
permalinkBaseUrl: options.permalinkBaseUrl,
|
|
2974
3280
|
ticketUrlTemplate: options.ticketUrlTemplate,
|
|
3281
|
+
traceUrlTemplate: options.traceUrlTemplate,
|
|
2975
3282
|
includeSourceLinks: options.includeSourceLinks ?? true,
|
|
2976
3283
|
customRenderers: options.customRenderers
|
|
2977
3284
|
};
|
|
@@ -3194,6 +3501,18 @@ var MarkdownFormatter = class {
|
|
|
3194
3501
|
meta.push(`Tickets: ${tc.story.tickets.map((t) => `\`${t}\``).join(", ")}`);
|
|
3195
3502
|
}
|
|
3196
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
|
+
}
|
|
3197
3516
|
if (meta.length > 0) {
|
|
3198
3517
|
lines.push(meta.join(" | "));
|
|
3199
3518
|
}
|
|
@@ -5136,6 +5455,32 @@ function detectCI4(env = process.env) {
|
|
|
5136
5455
|
return void 0;
|
|
5137
5456
|
}
|
|
5138
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
|
+
|
|
5139
5484
|
// src/index.ts
|
|
5140
5485
|
var FORMAT_EXTENSIONS = {
|
|
5141
5486
|
markdown: ".md",
|
|
@@ -5326,6 +5671,7 @@ var ReportGenerator = class {
|
|
|
5326
5671
|
includeSummaryTable: options.markdown?.includeSummaryTable ?? false,
|
|
5327
5672
|
permalinkBaseUrl: options.markdown?.permalinkBaseUrl,
|
|
5328
5673
|
ticketUrlTemplate: options.markdown?.ticketUrlTemplate,
|
|
5674
|
+
traceUrlTemplate: options.markdown?.traceUrlTemplate,
|
|
5329
5675
|
includeSourceLinks: options.markdown?.includeSourceLinks ?? true,
|
|
5330
5676
|
customRenderers: options.markdown?.customRenderers
|
|
5331
5677
|
}
|
|
@@ -5451,6 +5797,7 @@ var ReportGenerator = class {
|
|
|
5451
5797
|
includeSummaryTable: this.options.markdown.includeSummaryTable,
|
|
5452
5798
|
permalinkBaseUrl: this.options.markdown.permalinkBaseUrl,
|
|
5453
5799
|
ticketUrlTemplate: this.options.markdown.ticketUrlTemplate,
|
|
5800
|
+
traceUrlTemplate: this.options.markdown.traceUrlTemplate,
|
|
5454
5801
|
includeSourceLinks: this.options.markdown.includeSourceLinks,
|
|
5455
5802
|
customRenderers: this.options.markdown.customRenderers
|
|
5456
5803
|
});
|
|
@@ -5513,7 +5860,9 @@ function normalizePlaywrightResults(testResults, adapterOptions, canonicalizeOpt
|
|
|
5513
5860
|
readPackageVersion,
|
|
5514
5861
|
resolveAttachment,
|
|
5515
5862
|
resolveAttachments,
|
|
5863
|
+
resolveTraceUrl,
|
|
5516
5864
|
slugify,
|
|
5865
|
+
tryGetActiveOtelContext,
|
|
5517
5866
|
validateCanonicalRun
|
|
5518
5867
|
});
|
|
5519
5868
|
//# sourceMappingURL=index.cjs.map
|