executable-stories-formatters 0.1.0 → 0.2.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/dist/cli.js +268 -25
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +268 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +268 -25
- package/dist/index.js.map +1 -1
- package/package.json +12 -12
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Jag Reehal
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/cli.js
CHANGED
|
@@ -896,50 +896,162 @@ function initTheme() {
|
|
|
896
896
|
}
|
|
897
897
|
`;
|
|
898
898
|
var JS_CORE = `
|
|
899
|
+
// Filter state
|
|
900
|
+
var activeTags = new Set();
|
|
901
|
+
var activeStatus = null;
|
|
902
|
+
|
|
899
903
|
// Search functionality
|
|
900
904
|
function initSearch() {
|
|
901
|
-
|
|
905
|
+
var input = document.querySelector('.search-input');
|
|
902
906
|
if (!input) return;
|
|
903
907
|
|
|
904
|
-
|
|
905
|
-
input.addEventListener('input', (
|
|
908
|
+
var debounceTimer;
|
|
909
|
+
input.addEventListener('input', function() {
|
|
906
910
|
clearTimeout(debounceTimer);
|
|
907
|
-
debounceTimer = setTimeout(()
|
|
908
|
-
|
|
911
|
+
debounceTimer = setTimeout(function() {
|
|
912
|
+
applyAllFilters();
|
|
909
913
|
}, 150);
|
|
910
914
|
});
|
|
911
915
|
|
|
912
916
|
// Clear search on Escape
|
|
913
|
-
input.addEventListener('keydown', (e)
|
|
917
|
+
input.addEventListener('keydown', function(e) {
|
|
914
918
|
if (e.key === 'Escape') {
|
|
915
919
|
e.target.value = '';
|
|
916
|
-
|
|
920
|
+
applyAllFilters();
|
|
917
921
|
}
|
|
918
922
|
});
|
|
919
923
|
}
|
|
920
924
|
|
|
921
|
-
|
|
922
|
-
|
|
925
|
+
// Tag filter
|
|
926
|
+
function initTagFilter() {
|
|
927
|
+
document.querySelectorAll('.tag-pill').forEach(function(pill) {
|
|
928
|
+
pill.addEventListener('click', function() {
|
|
929
|
+
var tag = pill.dataset.tag;
|
|
930
|
+
if (activeTags.has(tag)) {
|
|
931
|
+
activeTags.delete(tag);
|
|
932
|
+
pill.classList.remove('active');
|
|
933
|
+
} else {
|
|
934
|
+
activeTags.add(tag);
|
|
935
|
+
pill.classList.add('active');
|
|
936
|
+
}
|
|
937
|
+
updateClearButton();
|
|
938
|
+
applyAllFilters();
|
|
939
|
+
});
|
|
940
|
+
});
|
|
923
941
|
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
942
|
+
var clearBtn = document.querySelector('.tag-bar-clear');
|
|
943
|
+
if (clearBtn) {
|
|
944
|
+
clearBtn.addEventListener('click', function() {
|
|
945
|
+
activeTags.clear();
|
|
946
|
+
document.querySelectorAll('.tag-pill.active').forEach(function(p) { p.classList.remove('active'); });
|
|
947
|
+
updateClearButton();
|
|
948
|
+
applyAllFilters();
|
|
949
|
+
});
|
|
950
|
+
}
|
|
951
|
+
}
|
|
927
952
|
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
953
|
+
function updateClearButton() {
|
|
954
|
+
var clearBtn = document.querySelector('.tag-bar-clear');
|
|
955
|
+
if (clearBtn) {
|
|
956
|
+
clearBtn.style.display = activeTags.size > 0 ? '' : 'none';
|
|
957
|
+
}
|
|
958
|
+
}
|
|
932
959
|
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
960
|
+
// Status filter (clickable summary cards)
|
|
961
|
+
function initStatusFilter() {
|
|
962
|
+
document.querySelectorAll('.summary-card').forEach(function(card) {
|
|
963
|
+
card.style.cursor = 'pointer';
|
|
964
|
+
if (!card.classList.contains('passed') && !card.classList.contains('failed') && !card.classList.contains('skipped')) {
|
|
965
|
+
card.addEventListener('click', function() {
|
|
966
|
+
activeStatus = null;
|
|
967
|
+
document.querySelectorAll('.summary-card').forEach(function(c) { c.classList.remove('status-active'); });
|
|
968
|
+
applyAllFilters();
|
|
969
|
+
});
|
|
970
|
+
return;
|
|
971
|
+
}
|
|
972
|
+
card.addEventListener('click', function() {
|
|
973
|
+
var status = card.classList.contains('passed') ? 'passed' :
|
|
974
|
+
card.classList.contains('failed') ? 'failed' : 'skipped';
|
|
975
|
+
if (activeStatus === status) {
|
|
976
|
+
activeStatus = null;
|
|
977
|
+
card.classList.remove('status-active');
|
|
978
|
+
} else {
|
|
979
|
+
activeStatus = status;
|
|
980
|
+
document.querySelectorAll('.summary-card').forEach(function(c) { c.classList.remove('status-active'); });
|
|
981
|
+
card.classList.add('status-active');
|
|
982
|
+
}
|
|
983
|
+
applyAllFilters();
|
|
984
|
+
});
|
|
985
|
+
});
|
|
986
|
+
}
|
|
937
987
|
|
|
938
|
-
|
|
939
|
-
|
|
988
|
+
// Unified filter: composes search + tags + status
|
|
989
|
+
function applyAllFilters() {
|
|
990
|
+
var searchInput = document.querySelector('.search-input');
|
|
991
|
+
var searchQuery = searchInput ? searchInput.value.toLowerCase().trim() : '';
|
|
992
|
+
var features = document.querySelectorAll('.feature');
|
|
993
|
+
var visibleCount = 0;
|
|
994
|
+
var totalCount = 0;
|
|
995
|
+
|
|
996
|
+
features.forEach(function(feature) {
|
|
997
|
+
var scenarios = feature.querySelectorAll('.scenario');
|
|
998
|
+
var featureVisible = 0;
|
|
999
|
+
|
|
1000
|
+
scenarios.forEach(function(scenario) {
|
|
1001
|
+
totalCount++;
|
|
1002
|
+
var title = (scenario.querySelector('.scenario-title') || {}).textContent || '';
|
|
1003
|
+
title = title.toLowerCase();
|
|
1004
|
+
var tags = Array.from(scenario.querySelectorAll('.scenario-meta .tag')).map(function(t) { return t.textContent.toLowerCase(); });
|
|
1005
|
+
var steps = Array.from(scenario.querySelectorAll('.step-text')).map(function(s) { return s.textContent.toLowerCase(); });
|
|
1006
|
+
var statusEl = scenario.querySelector('.status-icon');
|
|
1007
|
+
var status = statusEl && statusEl.classList.contains('status-passed') ? 'passed' :
|
|
1008
|
+
statusEl && statusEl.classList.contains('status-failed') ? 'failed' :
|
|
1009
|
+
statusEl && statusEl.classList.contains('status-skipped') ? 'skipped' : 'pending';
|
|
1010
|
+
|
|
1011
|
+
var matchesSearch = !searchQuery ||
|
|
1012
|
+
title.includes(searchQuery) ||
|
|
1013
|
+
tags.some(function(t) { return t.includes(searchQuery); }) ||
|
|
1014
|
+
steps.some(function(s) { return s.includes(searchQuery); });
|
|
1015
|
+
|
|
1016
|
+
var matchesTags = activeTags.size === 0 ||
|
|
1017
|
+
tags.some(function(t) { return activeTags.has(t); });
|
|
1018
|
+
|
|
1019
|
+
var matchesStatus = !activeStatus ||
|
|
1020
|
+
status === activeStatus ||
|
|
1021
|
+
(activeStatus === 'skipped' && status === 'pending');
|
|
1022
|
+
|
|
1023
|
+
var visible = matchesSearch && matchesTags && matchesStatus;
|
|
1024
|
+
scenario.style.display = visible ? '' : 'none';
|
|
1025
|
+
if (visible) { visibleCount++; featureVisible++; }
|
|
940
1026
|
});
|
|
941
1027
|
|
|
942
|
-
feature.style.display =
|
|
1028
|
+
feature.style.display = featureVisible > 0 ? '' : 'none';
|
|
1029
|
+
});
|
|
1030
|
+
|
|
1031
|
+
updateFilterResults(visibleCount, totalCount);
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
function updateFilterResults(visible, total) {
|
|
1035
|
+
var el = document.querySelector('.filter-results');
|
|
1036
|
+
if (!el) return;
|
|
1037
|
+
var searchInput = document.querySelector('.search-input');
|
|
1038
|
+
var isFiltering = activeTags.size > 0 || activeStatus ||
|
|
1039
|
+
(searchInput && searchInput.value.trim().length > 0);
|
|
1040
|
+
el.style.display = isFiltering ? '' : 'none';
|
|
1041
|
+
var vc = el.querySelector('.visible-count');
|
|
1042
|
+
var tc = el.querySelector('.total-count');
|
|
1043
|
+
if (vc) vc.textContent = visible;
|
|
1044
|
+
if (tc) tc.textContent = total;
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
// Keyboard shortcuts
|
|
1048
|
+
function initKeyboardShortcuts() {
|
|
1049
|
+
document.addEventListener('keydown', function(e) {
|
|
1050
|
+
if (e.key === '/' && !e.ctrlKey && !e.metaKey && e.target.tagName !== 'INPUT') {
|
|
1051
|
+
e.preventDefault();
|
|
1052
|
+
var input = document.querySelector('.search-input');
|
|
1053
|
+
if (input) input.focus();
|
|
1054
|
+
}
|
|
943
1055
|
});
|
|
944
1056
|
}
|
|
945
1057
|
|
|
@@ -1024,6 +1136,9 @@ function generateScript(options) {
|
|
|
1024
1136
|
initCalls.push("initTheme();");
|
|
1025
1137
|
}
|
|
1026
1138
|
initCalls.push("initSearch();");
|
|
1139
|
+
initCalls.push("initTagFilter();");
|
|
1140
|
+
initCalls.push("initStatusFilter();");
|
|
1141
|
+
initCalls.push("initKeyboardShortcuts();");
|
|
1027
1142
|
initCalls.push("initCollapse();");
|
|
1028
1143
|
const initScript = `
|
|
1029
1144
|
// Initialize on load
|
|
@@ -1507,6 +1622,98 @@ body {
|
|
|
1507
1622
|
}
|
|
1508
1623
|
.summary-card.pending .value { color: var(--pending); }
|
|
1509
1624
|
|
|
1625
|
+
/* ============================================================================
|
|
1626
|
+
Tag Filter Bar
|
|
1627
|
+
============================================================================ */
|
|
1628
|
+
.tag-bar {
|
|
1629
|
+
margin-bottom: 1rem;
|
|
1630
|
+
padding: 0.75rem 1rem;
|
|
1631
|
+
background: var(--card);
|
|
1632
|
+
border: 1px solid var(--border);
|
|
1633
|
+
border-radius: var(--radius);
|
|
1634
|
+
position: sticky;
|
|
1635
|
+
top: 0;
|
|
1636
|
+
z-index: 10;
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1639
|
+
.tag-bar-header {
|
|
1640
|
+
display: flex;
|
|
1641
|
+
justify-content: space-between;
|
|
1642
|
+
align-items: center;
|
|
1643
|
+
margin-bottom: 0.5rem;
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1646
|
+
.tag-bar-label {
|
|
1647
|
+
font-size: 0.6875rem;
|
|
1648
|
+
text-transform: uppercase;
|
|
1649
|
+
letter-spacing: 0.05em;
|
|
1650
|
+
color: var(--muted-foreground);
|
|
1651
|
+
font-weight: 500;
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
.tag-bar-clear {
|
|
1655
|
+
font-size: 0.75rem;
|
|
1656
|
+
font-weight: 500;
|
|
1657
|
+
color: var(--primary);
|
|
1658
|
+
background: none;
|
|
1659
|
+
border: none;
|
|
1660
|
+
cursor: pointer;
|
|
1661
|
+
padding: 0.125rem 0.5rem;
|
|
1662
|
+
border-radius: var(--radius);
|
|
1663
|
+
transition: all 0.15s ease;
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1666
|
+
.tag-bar-clear:hover {
|
|
1667
|
+
background: var(--muted);
|
|
1668
|
+
}
|
|
1669
|
+
|
|
1670
|
+
.tag-bar-pills {
|
|
1671
|
+
display: flex;
|
|
1672
|
+
flex-wrap: wrap;
|
|
1673
|
+
gap: 0.375rem;
|
|
1674
|
+
}
|
|
1675
|
+
|
|
1676
|
+
.tag-pill {
|
|
1677
|
+
font-size: 0.75rem;
|
|
1678
|
+
font-weight: 500;
|
|
1679
|
+
padding: 0.25rem 0.625rem;
|
|
1680
|
+
background: var(--tag-bg);
|
|
1681
|
+
color: var(--tag-color);
|
|
1682
|
+
border: 1px solid var(--tag-border);
|
|
1683
|
+
border-radius: 9999px;
|
|
1684
|
+
font-family: var(--font-mono);
|
|
1685
|
+
cursor: pointer;
|
|
1686
|
+
transition: all 0.15s ease;
|
|
1687
|
+
}
|
|
1688
|
+
|
|
1689
|
+
.tag-pill:hover {
|
|
1690
|
+
background: var(--success-border);
|
|
1691
|
+
}
|
|
1692
|
+
|
|
1693
|
+
.tag-pill.active {
|
|
1694
|
+
background: var(--primary);
|
|
1695
|
+
color: var(--primary-foreground);
|
|
1696
|
+
border-color: var(--primary);
|
|
1697
|
+
}
|
|
1698
|
+
|
|
1699
|
+
/* ============================================================================
|
|
1700
|
+
Summary Card Status Filter
|
|
1701
|
+
============================================================================ */
|
|
1702
|
+
.summary-card.status-active {
|
|
1703
|
+
box-shadow: 0 0 0 2px var(--background), 0 0 0 4px var(--ring);
|
|
1704
|
+
}
|
|
1705
|
+
|
|
1706
|
+
/* ============================================================================
|
|
1707
|
+
Filter Results Counter
|
|
1708
|
+
============================================================================ */
|
|
1709
|
+
.filter-results {
|
|
1710
|
+
text-align: center;
|
|
1711
|
+
font-size: 0.8125rem;
|
|
1712
|
+
color: var(--muted-foreground);
|
|
1713
|
+
margin-bottom: 1rem;
|
|
1714
|
+
font-weight: 500;
|
|
1715
|
+
}
|
|
1716
|
+
|
|
1510
1717
|
/* ============================================================================
|
|
1511
1718
|
Feature Sections - shadcn accordion style
|
|
1512
1719
|
============================================================================ */
|
|
@@ -1894,8 +2101,10 @@ body {
|
|
|
1894
2101
|
padding: 0;
|
|
1895
2102
|
}
|
|
1896
2103
|
|
|
1897
|
-
.header-actions
|
|
1898
|
-
|
|
2104
|
+
.header-actions,
|
|
2105
|
+
.tag-bar,
|
|
2106
|
+
.filter-results {
|
|
2107
|
+
display: none !important;
|
|
1899
2108
|
}
|
|
1900
2109
|
|
|
1901
2110
|
.feature,
|
|
@@ -2469,6 +2678,28 @@ function renderSummary(args, _deps) {
|
|
|
2469
2678
|
</div>`;
|
|
2470
2679
|
}
|
|
2471
2680
|
|
|
2681
|
+
// src/formatters/html/renderers/tag-bar.ts
|
|
2682
|
+
function renderTagBar(args, deps) {
|
|
2683
|
+
const { tags, totalScenarios } = args;
|
|
2684
|
+
if (tags.length === 0) return "";
|
|
2685
|
+
const pills = tags.map(
|
|
2686
|
+
(tag) => `<button type="button" class="tag-pill" data-tag="${deps.escapeHtml(tag)}">${deps.escapeHtml(tag)}</button>`
|
|
2687
|
+
).join("\n ");
|
|
2688
|
+
return `
|
|
2689
|
+
<div class="tag-bar">
|
|
2690
|
+
<div class="tag-bar-header">
|
|
2691
|
+
<span class="tag-bar-label">Filter by tag</span>
|
|
2692
|
+
<button type="button" class="tag-bar-clear" style="display:none">Clear</button>
|
|
2693
|
+
</div>
|
|
2694
|
+
<div class="tag-bar-pills">
|
|
2695
|
+
${pills}
|
|
2696
|
+
</div>
|
|
2697
|
+
</div>
|
|
2698
|
+
<div class="filter-results" style="display:none">
|
|
2699
|
+
Showing <span class="visible-count">0</span> of <span class="total-count">${totalScenarios}</span> scenarios
|
|
2700
|
+
</div>`;
|
|
2701
|
+
}
|
|
2702
|
+
|
|
2472
2703
|
// src/formatters/html/renderers/error-box.ts
|
|
2473
2704
|
function renderErrorBox(args, deps) {
|
|
2474
2705
|
const body = args.stack != null ? `${deps.escapeHtml(args.message)}
|
|
@@ -2768,6 +2999,15 @@ function buildBody(args, deps) {
|
|
|
2768
2999
|
deps.summaryDeps
|
|
2769
3000
|
)
|
|
2770
3001
|
);
|
|
3002
|
+
const allTags = [
|
|
3003
|
+
...new Set(run.testCases.flatMap((tc) => tc.tags))
|
|
3004
|
+
].sort();
|
|
3005
|
+
parts.push(
|
|
3006
|
+
deps.renderTagBar(
|
|
3007
|
+
{ tags: allTags, totalScenarios: total },
|
|
3008
|
+
deps.tagBarDeps
|
|
3009
|
+
)
|
|
3010
|
+
);
|
|
2771
3011
|
const byFile = groupBy(run.testCases, (tc) => tc.sourceFile);
|
|
2772
3012
|
for (const [file, testCases] of byFile) {
|
|
2773
3013
|
parts.push(
|
|
@@ -2824,12 +3064,15 @@ function createHtmlFormatter(options = {}) {
|
|
|
2824
3064
|
renderScenario: (args) => renderScenario(args, scenarioDeps),
|
|
2825
3065
|
scenarioDeps
|
|
2826
3066
|
};
|
|
3067
|
+
const tagBarDeps = { escapeHtml };
|
|
2827
3068
|
const bodyDeps = {
|
|
2828
3069
|
renderMetaInfo,
|
|
2829
3070
|
renderSummary,
|
|
3071
|
+
renderTagBar,
|
|
2830
3072
|
renderFeature,
|
|
2831
3073
|
metaDeps: { escapeHtml },
|
|
2832
3074
|
summaryDeps: {},
|
|
3075
|
+
tagBarDeps,
|
|
2833
3076
|
featureDeps
|
|
2834
3077
|
};
|
|
2835
3078
|
return {
|