@@ -29,8 +29,6 @@ export const template = ({
2929 numTodo = 0 ,
3030 results,
3131} ) => {
32- const percent = ( count ) => getPercent ( count , numTests )
33-
3432 return `
3533<!DOCTYPE html>
3634<html>
@@ -40,19 +38,43 @@ export const template = ({
4038 body { font-family: system-ui, -apple-system, sans-serif; background: #f5f5f5; margin: 0; padding: 2rem; }
4139 .container { max-width: 1200px; margin: 0 auto; background: #fff; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.08); padding: 2rem; }
4240 .header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 2rem; }
43- .main-flex { display: flex; align-items: center; gap: 3rem; margin-bottom: 2 .5rem; }
41+ .main-flex { display: flex; align-items: center; gap: 3rem; margin-bottom: 0 .5rem; }
4442 .pie-chart-container { position: relative; width: 200px; height: 200px; background: #fff; border-radius: 50%; box-shadow: 0 2px 8px rgba(0,0,0,0.07); display: flex; align-items: center; justify-content: center; }
45- .pie-legend { display: flex; flex-direction: column; gap: 0.7rem; margin-top: 1.5rem; font-size: 1.1rem; }
46- .pie-legend-item { display: flex; align-items: center; gap: 0.6rem; }
47- .dot { width: 18px; height: 18px; border-radius: 50%; display: inline-block; }
48- .pie-passed { background: #4caf50; }
49- .pie-failed { background: #f44336; }
50- .pie-todo { background: #ff9800; }
51- .pie-stat-label { font-weight: 600; min-width: 60px; display: inline-block; }
52- .pie-stat-value { font-weight: 700; margin-left: 0.5em; }
53- .summary-tiles { display: flex; flex-direction: row; gap: 1.5rem; align-items: center; height: 200px; }
54- .stat { padding: 1.2rem 1.5rem; border-radius: 12px; min-width: 120px; background: #f5f5f5; box-shadow: 0 1px 2px rgba(0,0,0,0.03); display: flex; flex-direction: column; align-items: center; justify-content: center; height: 120px; }
55- .stat.total { background: #e3f2fd; }
43+ .summary-tiles {
44+ display: flex;
45+ flex-direction: row;
46+ gap: 1.2rem;
47+ align-items: center;
48+ justify-content: center;
49+ height: 200px;
50+ }
51+ .stat {
52+ padding: 1.2rem 1.5rem;
53+ border-radius: 12px;
54+ min-width: 120px;
55+ background: #f5f5f5;
56+ box-shadow: 0 1px 2px rgba(0,0,0,0.03);
57+ display: flex;
58+ flex-direction: column;
59+ align-items: center;
60+ justify-content: center;
61+ height: 70px;
62+ cursor: pointer;
63+ transition: box-shadow 0.2s;
64+ border: 2px solid transparent;
65+ }
66+ .stat-percent {
67+ font-size: 1.1em;
68+ font-weight: 600;
69+ margin-top: 0.3em;
70+ text-align: center;
71+ }
72+ .stat.active {
73+ box-shadow: 0 2px 8px rgba(33,150,243,0.13);
74+ border: 2px solid #2196f3;
75+ background: #e3f2fd;
76+ }
77+ .stat.total { background: #e3f2fd; cursor: default; border: 2px solid transparent; }
5678 .stat.passed { background: #e8f5e9; }
5779 .stat.failed { background: #ffebee; }
5880 .stat.todo { background: #fff3e0; }
@@ -61,6 +83,13 @@ export const template = ({
6183 .stat.passed h3, .stat.passed p { color: #4caf50; }
6284 .stat.failed h3, .stat.failed p { color: #f44336; }
6385 .stat.todo h3, .stat.todo p { color: #ff9800; }
86+ .stat.total h3, .stat.total p { color: #2196f3; }
87+ .dot { width: 18px; height: 18px; border-radius: 50%; display: inline-block; }
88+ .pie-passed { background: #4caf50; }
89+ .pie-failed { background: #f44336; }
90+ .pie-todo { background: #ff9800; }
91+ .pie-stat-label { font-weight: 600; min-width: 60px; display: inline-block; }
92+ .pie-stat-value { font-weight: 700; margin-left: 0.5em; }
6493 .test-case { padding: 0.75rem 1rem; border-bottom: 1px solid #eee; }
6594 .test-case:last-child { border-bottom: none; }
6695 .test-name { display: flex; align-items: center; gap: 0.5rem; }
@@ -85,6 +114,7 @@ export const template = ({
85114 .api-table th, .api-table td { text-align: left; padding: 0.5rem; border: 1px solid #e0e0e0; }
86115 .api-table th { background: #f3f4f6; font-weight: 600; }
87116 pre.api-data { margin: 0.5rem 0; padding: 0.5rem; background: #f5f5f5; border-radius: 4px; max-height: 200px; overflow-y: auto; white-space: pre-wrap; }
117+ .hidden { display: none !important; }
88118 </style>
89119</head>
90120<body>
@@ -98,50 +128,31 @@ export const template = ({
98128 <div class="pie-chart-container">
99129 <canvas id="pieChart" width="200" height="200"></canvas>
100130 </div>
101- <div class="pie-legend">
102- <div class="pie-legend-item">
103- <span class="dot pie-passed"></span>
104- <span class="pie-stat-label">Passed</span>
105- <span class="pie-stat-value" id="percent-passed">${ percent (
106- numPassed
107- ) } %</span>
108- </div>
109- <div class="pie-legend-item">
110- <span class="dot pie-failed"></span>
111- <span class="pie-stat-label">Failed</span>
112- <span class="pie-stat-value" id="percent-failed">${ percent (
113- numFailed
114- ) } %</span>
115- </div>
116- <div class="pie-legend-item">
117- <span class="dot pie-todo"></span>
118- <span class="pie-stat-label">Todo</span>
119- <span class="pie-stat-value" id="percent-todo">${ percent (
120- numTodo
121- ) } %</span>
122- </div>
123- </div>
124131 </div>
125132 <div class="summary-tiles">
126- <div class="stat total">
133+ <div class="stat total" data-filter="all" >
127134 <h3>Total</h3>
128135 <p>${ numTests } </p>
136+ <div class="stat-percent" style="color:#2196f3;">${ getPercent ( numTests , numTests ) } %</div>
129137 </div>
130- <div class="stat passed">
138+ <div class="stat passed" data-filter="passed" >
131139 <h3>Passed</h3>
132140 <p>${ numPassed } </p>
141+ <div class="stat-percent" style="color:#4caf50;">${ getPercent ( numPassed , numTests ) } %</div>
133142 </div>
134- <div class="stat failed">
143+ <div class="stat failed" data-filter="failed" >
135144 <h3>Failed</h3>
136145 <p>${ numFailed } </p>
146+ <div class="stat-percent" style="color:#f44336;">${ getPercent ( numFailed , numTests ) } %</div>
137147 </div>
138- <div class="stat todo">
148+ <div class="stat todo" data-filter="todo" >
139149 <h3>Todo</h3>
140150 <p>${ numTodo } </p>
151+ <div class="stat-percent" style="color:#ff9800;">${ getPercent ( numTodo , numTests ) } %</div>
141152 </div>
142153 </div>
143154 </div>
144- <div class="results">
155+ <div class="results" id="results-root" >
145156 ${ renderDescribeGroup ( groupByDescribe ( results ) ) }
146157 </div>
147158 </div>
@@ -177,6 +188,46 @@ export const template = ({
177188 });
178189 })();
179190
191+ document.querySelectorAll('.stat[data-filter]').forEach(tile => {
192+ tile.addEventListener('click', function() {
193+ document.querySelectorAll('.stat[data-filter]').forEach(t => t.classList.remove('active'));
194+ this.classList.add('active');
195+ const filter = this.getAttribute('data-filter');
196+ filterResults(filter);
197+ });
198+ });
199+
200+ function filterResults(filter) {
201+ const root = document.getElementById('results-root');
202+ if (!root) return;
203+ if (filter === 'all') {
204+ root.querySelectorAll('.test-case').forEach(tc => tc.classList.remove('hidden'));
205+ root.querySelectorAll('.describe-group').forEach(dg => dg.classList.remove('hidden'));
206+ return;
207+ }
208+ root.querySelectorAll('.test-case').forEach(tc => tc.classList.add('hidden'));
209+ root.querySelectorAll('.test-case').forEach(tc => {
210+ if (
211+ (filter === 'passed' && tc.querySelector('.test-name.passed')) ||
212+ (filter === 'failed' && tc.querySelector('.test-name.failed')) ||
213+ (filter === 'todo' && tc.querySelector('.test-name.todo'))
214+ ) {
215+ tc.classList.remove('hidden');
216+ }
217+ });
218+ root.querySelectorAll('.describe-group').forEach(dg => {
219+ const hasVisible = dg.querySelectorAll('.test-case:not(.hidden)').length > 0 ||
220+ dg.querySelectorAll('.describe-group:not(.hidden)').length > 0;
221+ if (hasVisible) {
222+ dg.classList.remove('hidden');
223+ } else {
224+ dg.classList.add('hidden');
225+ }
226+ });
227+ }
228+
229+ document.querySelector('.stat.total').classList.add('active');
230+
180231 function toggleDescribeContent(element) {
181232 const content = element.nextElementSibling;
182233 content.classList.toggle('hide');
0 commit comments