test-reporting 3.2.0__tar.gz → 3.2.2__tar.gz
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.
- {test_reporting-3.2.0/test_reporting.egg-info → test_reporting-3.2.2}/PKG-INFO +1 -1
- {test_reporting-3.2.0 → test_reporting-3.2.2}/reporting/templates/project.html +144 -59
- {test_reporting-3.2.0 → test_reporting-3.2.2}/reporting/templates/run.html +7 -7
- {test_reporting-3.2.0 → test_reporting-3.2.2}/setup.py +1 -1
- {test_reporting-3.2.0 → test_reporting-3.2.2/test_reporting.egg-info}/PKG-INFO +1 -1
- {test_reporting-3.2.0 → test_reporting-3.2.2}/LICENSE +0 -0
- {test_reporting-3.2.0 → test_reporting-3.2.2}/README.md +0 -0
- {test_reporting-3.2.0 → test_reporting-3.2.2}/reporting/__init__.py +0 -0
- {test_reporting-3.2.0 → test_reporting-3.2.2}/reporting/classifier.py +0 -0
- {test_reporting-3.2.0 → test_reporting-3.2.2}/reporting/cli.py +0 -0
- {test_reporting-3.2.0 → test_reporting-3.2.2}/reporting/config.py +0 -0
- {test_reporting-3.2.0 → test_reporting-3.2.2}/reporting/plugin.py +0 -0
- {test_reporting-3.2.0 → test_reporting-3.2.2}/reporting/publisher.py +0 -0
- {test_reporting-3.2.0 → test_reporting-3.2.2}/reporting/storage.py +0 -0
- {test_reporting-3.2.0 → test_reporting-3.2.2}/reporting/templates/index.html +0 -0
- {test_reporting-3.2.0 → test_reporting-3.2.2}/setup.cfg +0 -0
- {test_reporting-3.2.0 → test_reporting-3.2.2}/test_reporting.egg-info/SOURCES.txt +0 -0
- {test_reporting-3.2.0 → test_reporting-3.2.2}/test_reporting.egg-info/dependency_links.txt +0 -0
- {test_reporting-3.2.0 → test_reporting-3.2.2}/test_reporting.egg-info/entry_points.txt +0 -0
- {test_reporting-3.2.0 → test_reporting-3.2.2}/test_reporting.egg-info/requires.txt +0 -0
- {test_reporting-3.2.0 → test_reporting-3.2.2}/test_reporting.egg-info/top_level.txt +0 -0
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
|
|
7
7
|
<meta http-equiv="Pragma" content="no-cache" />
|
|
8
8
|
<meta http-equiv="Expires" content="0" />
|
|
9
|
-
<title>Project
|
|
9
|
+
<title>Project - Test Dashboard</title>
|
|
10
10
|
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
|
|
11
11
|
<style>
|
|
12
12
|
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
@@ -139,6 +139,37 @@
|
|
|
139
139
|
.section-explain { font-size: 13px; color: var(--muted); line-height: 1.5; }
|
|
140
140
|
.section-body { padding: 20px 24px; }
|
|
141
141
|
.section-body-flush { }
|
|
142
|
+
|
|
143
|
+
/* Collapsible sections with preview */
|
|
144
|
+
.section-head.collapsible { cursor: pointer; user-select: none; display: flex;
|
|
145
|
+
justify-content: space-between; align-items: flex-start; }
|
|
146
|
+
.section-head.collapsible:hover { background: var(--bg); }
|
|
147
|
+
.section-head-content { flex: 1; }
|
|
148
|
+
.section-toggle { color: var(--muted); font-size: 14px; transition: transform .2s;
|
|
149
|
+
flex-shrink: 0; margin-left: 12px; margin-top: 2px; }
|
|
150
|
+
.section-toggle.collapsed { transform: rotate(-90deg); }
|
|
151
|
+
|
|
152
|
+
/* Preview mode - show partial content */
|
|
153
|
+
.section-body-flush.preview { max-height: 200px; overflow: hidden; position: relative;
|
|
154
|
+
cursor: pointer; transition: max-height .3s ease; }
|
|
155
|
+
.section-body-flush.preview:hover { background: var(--blue-bg); }
|
|
156
|
+
.section-body-flush.preview::after {
|
|
157
|
+
content: 'Click to expand ▼'; position: absolute; bottom: 0; left: 0; right: 0;
|
|
158
|
+
height: 60px; display: flex; align-items: flex-end; justify-content: center;
|
|
159
|
+
padding-bottom: 12px; font-size: 13px; font-weight: 600; color: var(--blue);
|
|
160
|
+
background: linear-gradient(to bottom, transparent, var(--surface) 50%);
|
|
161
|
+
pointer-events: none; transition: opacity .2s;
|
|
162
|
+
}
|
|
163
|
+
.section-body-flush.preview:hover::after { opacity: 0.8; }
|
|
164
|
+
.section-body-flush.expanded { max-height: none; cursor: pointer; }
|
|
165
|
+
.section-body-flush.expanded:hover { background: var(--blue-bg); }
|
|
166
|
+
.section-body-flush.expanded::after {
|
|
167
|
+
content: 'Click to collapse ▲'; position: relative; display: block;
|
|
168
|
+
text-align: center; padding: 16px; font-size: 13px; font-weight: 600;
|
|
169
|
+
color: var(--blue); background: var(--bg); border-top: 1px solid var(--border);
|
|
170
|
+
transition: background .1s;
|
|
171
|
+
}
|
|
172
|
+
.section-body-flush.expanded:hover::after { background: var(--border); }
|
|
142
173
|
|
|
143
174
|
/* ── Two-column grid ── */
|
|
144
175
|
.two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
|
|
@@ -157,6 +188,8 @@
|
|
|
157
188
|
td { padding: 12px 16px; border-bottom: 1px solid var(--border); vertical-align: middle; }
|
|
158
189
|
tr:last-child td { border-bottom: none; }
|
|
159
190
|
tr:hover td { background: var(--bg); }
|
|
191
|
+
tr.clickable-row { cursor: pointer; }
|
|
192
|
+
tr.clickable-row:hover td { background: var(--blue-bg); }
|
|
160
193
|
.test-name { font-weight: 600; max-width: 280px; overflow: hidden;
|
|
161
194
|
text-overflow: ellipsis; white-space: nowrap; }
|
|
162
195
|
.file-name { color: var(--muted); font-size: 12px; margin-top: 2px; }
|
|
@@ -271,6 +304,13 @@
|
|
|
271
304
|
opacity: 0; transition: opacity .15s; z-index: 200;
|
|
272
305
|
}
|
|
273
306
|
[data-tooltip]:hover::after { opacity: 1; }
|
|
307
|
+
|
|
308
|
+
/* ── Expandable tables ── */
|
|
309
|
+
.table-expand-btn { padding: 12px 24px; text-align: center; border-top: 1px solid var(--border);
|
|
310
|
+
cursor: pointer; color: var(--blue); font-size: 13px; font-weight: 600;
|
|
311
|
+
transition: background .1s; }
|
|
312
|
+
.table-expand-btn:hover { background: var(--bg); }
|
|
313
|
+
.table-row-hidden { display: none; }
|
|
274
314
|
</style>
|
|
275
315
|
</head>
|
|
276
316
|
<body>
|
|
@@ -325,7 +365,7 @@
|
|
|
325
365
|
|
|
326
366
|
/* ── Helpers ── */
|
|
327
367
|
function relTime(iso) {
|
|
328
|
-
if (!iso) return '
|
|
368
|
+
if (!iso) return '-';
|
|
329
369
|
const diff = Date.now() - new Date(iso).getTime();
|
|
330
370
|
const m = Math.floor(diff / 60000);
|
|
331
371
|
if (m < 1) return 'Just now';
|
|
@@ -336,12 +376,12 @@
|
|
|
336
376
|
}
|
|
337
377
|
|
|
338
378
|
function fmtDate(iso) {
|
|
339
|
-
if (!iso) return '
|
|
379
|
+
if (!iso) return '-';
|
|
340
380
|
return new Date(iso).toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' });
|
|
341
381
|
}
|
|
342
382
|
|
|
343
383
|
function fmtDur(s) {
|
|
344
|
-
if (!s || s === 0) return '
|
|
384
|
+
if (!s || s === 0) return '-';
|
|
345
385
|
if (s >= 60) return Math.floor(s / 60) + 'm ' + Math.floor(s % 60) + 's';
|
|
346
386
|
return s.toFixed(1) + 's';
|
|
347
387
|
}
|
|
@@ -519,7 +559,7 @@
|
|
|
519
559
|
return hero +
|
|
520
560
|
'<div class="section">' +
|
|
521
561
|
'<div class="section-head">' +
|
|
522
|
-
'<h3>
|
|
562
|
+
'<h3>Recent Test Runs</h3>' +
|
|
523
563
|
'<p class="section-explain">Each group shows all test files that ran together on a given tag. Click a test file to see the full test breakdown.</p>' +
|
|
524
564
|
'</div>' +
|
|
525
565
|
'<div class="section-body">' + regsHtml + '</div>' +
|
|
@@ -533,6 +573,31 @@
|
|
|
533
573
|
ch.classList.toggle('open', open);
|
|
534
574
|
}
|
|
535
575
|
|
|
576
|
+
function toggleTableRows(btn) {
|
|
577
|
+
const table = btn.previousElementSibling;
|
|
578
|
+
const hiddenRows = table.querySelectorAll('.table-row-hidden');
|
|
579
|
+
const isExpanded = hiddenRows[0].style.display === 'table-row';
|
|
580
|
+
|
|
581
|
+
hiddenRows.forEach(function(row) {
|
|
582
|
+
row.style.display = isExpanded ? 'none' : 'table-row';
|
|
583
|
+
});
|
|
584
|
+
|
|
585
|
+
const count = hiddenRows.length;
|
|
586
|
+
btn.textContent = isExpanded
|
|
587
|
+
? 'Show ' + count + ' more ▼'
|
|
588
|
+
: 'Show less ▲';
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
function toggleSectionExpand(body) {
|
|
592
|
+
if (body.classList.contains('preview')) {
|
|
593
|
+
body.classList.remove('preview');
|
|
594
|
+
body.classList.add('expanded');
|
|
595
|
+
} else if (body.classList.contains('expanded')) {
|
|
596
|
+
body.classList.remove('expanded');
|
|
597
|
+
body.classList.add('preview');
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
|
|
536
601
|
function goToRun(runId) {
|
|
537
602
|
if (runId) location.href = 'run.html?r=' + encodeURIComponent(runId) + '&p=' + encodeURIComponent(projectName);
|
|
538
603
|
}
|
|
@@ -567,33 +632,31 @@
|
|
|
567
632
|
'</div>' +
|
|
568
633
|
'</div>' +
|
|
569
634
|
|
|
570
|
-
'<div class="
|
|
571
|
-
'<div class="section">' +
|
|
572
|
-
'<
|
|
573
|
-
|
|
574
|
-
'<p class="section-explain">Failure type breakdown. Real bugs need code fixes; infrastructure issues are environment problems.</p>' +
|
|
575
|
-
'</div>' +
|
|
576
|
-
'<div class="section-body">' +
|
|
577
|
-
((a.failure_type_breakdown || []).length === 0
|
|
578
|
-
? '<p class="empty-section">No failures recorded yet.</p>'
|
|
579
|
-
: '<div class="chart-wrap chart-wrap-sm"><canvas id="failureTypeChart"></canvas></div>') +
|
|
580
|
-
'</div>' +
|
|
635
|
+
'<div class="section">' +
|
|
636
|
+
'<div class="section-head">' +
|
|
637
|
+
'<h3>Why Are Tests Failing?</h3>' +
|
|
638
|
+
'<p class="section-explain">Failure type breakdown. Real bugs need code fixes; infrastructure issues are environment problems.</p>' +
|
|
581
639
|
'</div>' +
|
|
640
|
+
'<div class="section-body">' +
|
|
641
|
+
((a.failure_type_breakdown || []).length === 0
|
|
642
|
+
? '<p class="empty-section">No failures recorded yet.</p>'
|
|
643
|
+
: '<div class="chart-wrap chart-wrap-sm"><canvas id="failureTypeChart"></canvas></div>') +
|
|
644
|
+
'</div>' +
|
|
645
|
+
'</div>' +
|
|
582
646
|
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
'</div>' +
|
|
647
|
+
'<div class="section">' +
|
|
648
|
+
'<div class="section-head">' +
|
|
649
|
+
'<h3>Test File Reliability (Treemap)</h3>' +
|
|
650
|
+
'<p class="section-explain">Each block = one file. Size ∝ test count. Color = pass rate. Worst files at top-left.</p>' +
|
|
651
|
+
'</div>' +
|
|
652
|
+
'<div class="section-body">' +
|
|
653
|
+
renderTreemap(a.file_health || []) +
|
|
591
654
|
'</div>' +
|
|
592
655
|
'</div>' +
|
|
593
656
|
|
|
594
657
|
'<div class="section">' +
|
|
595
658
|
'<div class="section-head">' +
|
|
596
|
-
'<h3>Duration vs Failures
|
|
659
|
+
'<h3>Duration vs Failures - Scatter</h3>' +
|
|
597
660
|
'<p class="section-explain">Each dot = one test. X = avg duration, Y = failure count. Top-right quadrant = highest priority fixes.</p>' +
|
|
598
661
|
'</div>' +
|
|
599
662
|
'<div class="section-body">' +
|
|
@@ -607,10 +670,10 @@
|
|
|
607
670
|
|
|
608
671
|
'<div class="section">' +
|
|
609
672
|
'<div class="section-head">' +
|
|
610
|
-
'<h3>Unreliable Tests
|
|
673
|
+
'<h3>Unreliable Tests - Flaky</h3>' +
|
|
611
674
|
'<p class="section-explain">Tests that pass sometimes and fail other times without code changes. Flaky tests erode trust in your test suite.</p>' +
|
|
612
675
|
'</div>' +
|
|
613
|
-
'<div class="section-body-flush">' +
|
|
676
|
+
'<div class="section-body-flush preview" onclick="toggleSectionExpand(this)">' +
|
|
614
677
|
renderFlakyTable(a.flaky_tests || []) +
|
|
615
678
|
'</div>' +
|
|
616
679
|
'</div>' +
|
|
@@ -618,32 +681,30 @@
|
|
|
618
681
|
'<div class="section">' +
|
|
619
682
|
'<div class="section-head">' +
|
|
620
683
|
'<h3>Tests That Break the Most</h3>' +
|
|
621
|
-
'<p class="section-explain">Highest-priority fixes
|
|
684
|
+
'<p class="section-explain">Highest-priority fixes - resolving these has the biggest positive impact on your overall pass rate.</p>' +
|
|
622
685
|
'</div>' +
|
|
623
|
-
'<div class="section-body-flush">' +
|
|
686
|
+
'<div class="section-body-flush preview" onclick="toggleSectionExpand(this)">' +
|
|
624
687
|
renderHotspotsTable(a.failure_hotspots || []) +
|
|
625
688
|
'</div>' +
|
|
626
689
|
'</div>' +
|
|
627
690
|
|
|
628
|
-
'<div class="
|
|
629
|
-
'<div class="section">' +
|
|
630
|
-
'<
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
renderSlowTable(a.slowest_tests || []) +
|
|
636
|
-
'</div>' +
|
|
691
|
+
'<div class="section">' +
|
|
692
|
+
'<div class="section-head">' +
|
|
693
|
+
'<h3>Slowest Tests</h3>' +
|
|
694
|
+
'<p class="section-explain">Tests taking the longest to run. Good candidates for optimization.</p>' +
|
|
695
|
+
'</div>' +
|
|
696
|
+
'<div class="section-body-flush preview" onclick="toggleSectionExpand(this)">' +
|
|
697
|
+
renderSlowTable(a.slowest_tests || []) +
|
|
637
698
|
'</div>' +
|
|
699
|
+
'</div>' +
|
|
638
700
|
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
'</div>' +
|
|
701
|
+
'<div class="section">' +
|
|
702
|
+
'<div class="section-head">' +
|
|
703
|
+
'<h3>Tests Getting Slower</h3>' +
|
|
704
|
+
'<p class="section-explain">Tests that have become significantly slower over the last 7 days. A slowing test can signal feature degradation.</p>' +
|
|
705
|
+
'</div>' +
|
|
706
|
+
'<div class="section-body-flush preview" onclick="toggleSectionExpand(this)">' +
|
|
707
|
+
renderRegressionTable(a.performance_regressions || []) +
|
|
647
708
|
'</div>' +
|
|
648
709
|
'</div>';
|
|
649
710
|
}
|
|
@@ -750,55 +811,79 @@
|
|
|
750
811
|
|
|
751
812
|
function renderFlakyTable(tests) {
|
|
752
813
|
if (tests.length === 0) return '<p class="empty-section" style="padding:20px">No flaky tests detected.</p>';
|
|
814
|
+
const limit = 5;
|
|
753
815
|
const rows = tests.map(function(t, i) {
|
|
754
|
-
|
|
816
|
+
const hiddenClass = i >= limit ? ' table-row-hidden' : '';
|
|
817
|
+
const clickAttr = t.last_run_id ? ' class="anim-row clickable-row' + hiddenClass + '" onclick="goToRun(\'' + t.last_run_id + '\')"' : ' class="anim-row' + hiddenClass + '"';
|
|
818
|
+
return '<tr' + clickAttr + ' style="animation-delay:' + (i * 0.04) + 's">' +
|
|
755
819
|
'<td><div class="test-name" title="' + t.test_name + '">' + t.test_name + '</div><div class="file-name">' + t.file_name + '</div></td>' +
|
|
756
820
|
'<td><span class="pill pill-yellow">' + t.pass_rate + '% pass rate</span></td>' +
|
|
757
821
|
'<td style="text-align:center">' + t.passed + '</td>' +
|
|
758
822
|
'<td style="text-align:center;color:var(--red)">' + t.failed + '</td>' +
|
|
759
823
|
'<td style="text-align:center">' + t.total_runs + '</td>' +
|
|
760
|
-
'<td style="color:var(--muted);font-size:12px">' + (t.last_failed ? fmtDate(t.last_failed) : '
|
|
824
|
+
'<td style="color:var(--muted);font-size:12px">' + (t.last_failed ? fmtDate(t.last_failed) : '-') + '</td>' +
|
|
761
825
|
'</tr>';
|
|
762
826
|
}).join('');
|
|
763
|
-
|
|
827
|
+
const expandBtn = tests.length > limit
|
|
828
|
+
? '<div class="table-expand-btn" onclick="toggleTableRows(this)">Show ' + (tests.length - limit) + ' more ▼</div>'
|
|
829
|
+
: '';
|
|
830
|
+
return '<table><thead><tr><th>Test</th><th>Consistency</th><th>Passed</th><th>Failed</th><th>Total Runs</th><th>Last Failed</th></tr></thead><tbody>' + rows + '</tbody></table>' + expandBtn;
|
|
764
831
|
}
|
|
765
832
|
|
|
766
833
|
function renderHotspotsTable(tests) {
|
|
767
834
|
if (tests.length === 0) return '<p class="empty-section" style="padding:20px">No failure hotspots detected yet.</p>';
|
|
835
|
+
const limit = 5;
|
|
768
836
|
const rows = tests.map(function(t, i) {
|
|
769
|
-
|
|
837
|
+
const hiddenClass = i >= limit ? ' table-row-hidden' : '';
|
|
838
|
+
const clickAttr = t.last_run_id ? ' class="anim-row clickable-row' + hiddenClass + '" onclick="goToRun(\'' + t.last_run_id + '\')"' : ' class="anim-row' + hiddenClass + '"';
|
|
839
|
+
return '<tr' + clickAttr + ' style="animation-delay:' + (i * 0.04) + 's">' +
|
|
770
840
|
'<td><div class="test-name" title="' + t.test_name + '">' + t.test_name + '</div><div class="file-name">' + t.file_name + '</div></td>' +
|
|
771
841
|
'<td><span class="pill pill-red">' + t.failure_count + ' failures</span></td>' +
|
|
772
842
|
'<td>' + t.failure_label + '</td>' +
|
|
773
|
-
'<td style="color:var(--muted);font-size:12px">' + (t.last_failed ? fmtDate(t.last_failed) : '
|
|
843
|
+
'<td style="color:var(--muted);font-size:12px">' + (t.last_failed ? fmtDate(t.last_failed) : '-') + '</td>' +
|
|
774
844
|
'</tr>';
|
|
775
845
|
}).join('');
|
|
776
|
-
|
|
846
|
+
const expandBtn = tests.length > limit
|
|
847
|
+
? '<div class="table-expand-btn" onclick="toggleTableRows(this)">Show ' + (tests.length - limit) + ' more ▼</div>'
|
|
848
|
+
: '';
|
|
849
|
+
return '<table><thead><tr><th>Test</th><th>Failure Count</th><th>Cause</th><th>Last Failed</th></tr></thead><tbody>' + rows + '</tbody></table>' + expandBtn;
|
|
777
850
|
}
|
|
778
851
|
|
|
779
852
|
function renderSlowTable(tests) {
|
|
780
853
|
if (tests.length === 0) return '<p class="empty-section" style="padding:20px">Not enough data yet.</p>';
|
|
854
|
+
const limit = 5;
|
|
781
855
|
const rows = tests.map(function(t, i) {
|
|
782
|
-
|
|
856
|
+
const hiddenClass = i >= limit ? ' table-row-hidden' : '';
|
|
857
|
+
const clickAttr = t.last_run_id ? ' class="anim-row clickable-row' + hiddenClass + '" onclick="goToRun(\'' + t.last_run_id + '\')"' : ' class="anim-row' + hiddenClass + '"';
|
|
858
|
+
return '<tr' + clickAttr + ' style="animation-delay:' + (i * 0.04) + 's">' +
|
|
783
859
|
'<td><div class="test-name" title="' + t.test_name + '">' + t.test_name + '</div><div class="file-name">' + t.file_name + '</div></td>' +
|
|
784
860
|
'<td style="font-weight:700">' + fmtDur(t.avg_duration) + '</td>' +
|
|
785
861
|
'<td style="color:var(--muted);font-size:12px">' + fmtDur(t.max_duration) + ' max</td>' +
|
|
786
862
|
'</tr>';
|
|
787
863
|
}).join('');
|
|
788
|
-
|
|
864
|
+
const expandBtn = tests.length > limit
|
|
865
|
+
? '<div class="table-expand-btn" onclick="toggleTableRows(this)">Show ' + (tests.length - limit) + ' more ▼</div>'
|
|
866
|
+
: '';
|
|
867
|
+
return '<table><thead><tr><th>Test</th><th>Avg Duration</th><th>Max</th></tr></thead><tbody>' + rows + '</tbody></table>' + expandBtn;
|
|
789
868
|
}
|
|
790
869
|
|
|
791
870
|
function renderRegressionTable(tests) {
|
|
792
871
|
if (tests.length === 0) return '<p class="empty-section" style="padding:20px">No performance regressions detected.</p>';
|
|
872
|
+
const limit = 5;
|
|
793
873
|
const rows = tests.map(function(t, i) {
|
|
794
|
-
|
|
874
|
+
const hiddenClass = i >= limit ? ' table-row-hidden' : '';
|
|
875
|
+
const clickAttr = t.last_run_id ? ' class="anim-row clickable-row' + hiddenClass + '" onclick="goToRun(\'' + t.last_run_id + '\')"' : ' class="anim-row' + hiddenClass + '"';
|
|
876
|
+
return '<tr' + clickAttr + ' style="animation-delay:' + (i * 0.04) + 's">' +
|
|
795
877
|
'<td><div class="test-name" title="' + t.test_name + '">' + t.test_name + '</div><div class="file-name">' + t.file_name + '</div></td>' +
|
|
796
878
|
'<td style="color:var(--muted);font-size:12px">' + fmtDur(t.historical_avg) + '</td>' +
|
|
797
879
|
'<td style="font-weight:700">' + fmtDur(t.recent_avg) + '</td>' +
|
|
798
880
|
'<td><span class="pill pill-red">+' + t.percent_slower + '% slower</span></td>' +
|
|
799
881
|
'</tr>';
|
|
800
882
|
}).join('');
|
|
801
|
-
|
|
883
|
+
const expandBtn = tests.length > limit
|
|
884
|
+
? '<div class="table-expand-btn" onclick="toggleTableRows(this)">Show ' + (tests.length - limit) + ' more ▼</div>'
|
|
885
|
+
: '';
|
|
886
|
+
return '<table><thead><tr><th>Test</th><th>Was</th><th>Now</th><th>Change</th></tr></thead><tbody>' + rows + '</tbody></table>' + expandBtn;
|
|
802
887
|
}
|
|
803
888
|
|
|
804
889
|
/* ═══════════════════════════════════════════════════
|
|
@@ -835,7 +920,7 @@
|
|
|
835
920
|
return '<tr>' +
|
|
836
921
|
'<td>' + fmtDate(run.timestamp) + '</td>' +
|
|
837
922
|
'<td><div style="font-weight:600;font-size:13px">' + run.file_name + '</div></td>' +
|
|
838
|
-
'<td>' + (run.regression_tag || '
|
|
923
|
+
'<td>' + (run.regression_tag || '-') + '</td>' +
|
|
839
924
|
'<td><span class="pill ' + pc + '">' + run.pass_rate.toFixed(0) + '%</span></td>' +
|
|
840
925
|
'<td>' + run.total_tests + '</td>' +
|
|
841
926
|
'<td style="color:var(--red)">' + run.failed + '</td>' +
|
|
@@ -850,7 +935,7 @@
|
|
|
850
935
|
var canvas = document.getElementById(sid);
|
|
851
936
|
if (!canvas) continue;
|
|
852
937
|
var pts = sparklineIds[sid];
|
|
853
|
-
if (pts.length < 2) { canvas.outerHTML = '<span class="sparkline-none-sm"
|
|
938
|
+
if (pts.length < 2) { canvas.outerHTML = '<span class="sparkline-none-sm">-</span>'; continue; }
|
|
854
939
|
new Chart(canvas, {
|
|
855
940
|
type: 'line',
|
|
856
941
|
data: {
|
|
@@ -1041,7 +1126,7 @@
|
|
|
1041
1126
|
|
|
1042
1127
|
document.getElementById('pageTitle').textContent = proj.name;
|
|
1043
1128
|
document.getElementById('lastRun').textContent = 'Last run ' + relTime(proj.last_run);
|
|
1044
|
-
document.title = proj.name + '
|
|
1129
|
+
document.title = proj.name + ' - Test Dashboard';
|
|
1045
1130
|
|
|
1046
1131
|
const analytics = proj.analytics || {};
|
|
1047
1132
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
|
|
7
7
|
<meta http-equiv="Pragma" content="no-cache" />
|
|
8
8
|
<meta http-equiv="Expires" content="0" />
|
|
9
|
-
<title>Run Details
|
|
9
|
+
<title>Run Details - Test Dashboard</title>
|
|
10
10
|
<style>
|
|
11
11
|
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
12
12
|
|
|
@@ -322,14 +322,14 @@
|
|
|
322
322
|
var projectName = params.get('p') || '';
|
|
323
323
|
|
|
324
324
|
function fmtDate(iso) {
|
|
325
|
-
if (!iso) return '
|
|
325
|
+
if (!iso) return '-';
|
|
326
326
|
return new Date(iso).toLocaleString(undefined, {
|
|
327
327
|
month:'short', day:'numeric', year:'numeric',
|
|
328
328
|
hour:'2-digit', minute:'2-digit'
|
|
329
329
|
});
|
|
330
330
|
}
|
|
331
331
|
function fmtDur(s) {
|
|
332
|
-
if (!s || s === 0) return '
|
|
332
|
+
if (!s || s === 0) return '-';
|
|
333
333
|
if (s >= 60) return Math.floor(s/60) + 'm ' + Math.floor(s%60) + 's';
|
|
334
334
|
return s.toFixed(1) + 's';
|
|
335
335
|
}
|
|
@@ -374,13 +374,13 @@
|
|
|
374
374
|
var cls = segClass(f.pass_rate);
|
|
375
375
|
var label = pct > 8 ? f.file_name.replace(/\.py$/, '') : '';
|
|
376
376
|
return '<div class="timeline-seg ' + cls + '" style="flex:' + pct.toFixed(2) + '"'
|
|
377
|
-
+ ' title="' + f.file_name + '
|
|
377
|
+
+ ' title="' + f.file_name + ' - ' + f.pass_rate.toFixed(0) + '% passing (' + f.passed + '/' + f.total + ')"'
|
|
378
378
|
+ ' onclick="scrollToFile(\'' + f.file_name.replace(/'/g, '') + '\')">'
|
|
379
379
|
+ label + '</div>';
|
|
380
380
|
}).join('');
|
|
381
381
|
|
|
382
382
|
return '<div class="timeline-wrap">'
|
|
383
|
-
+ '<div class="timeline-label">Test File Map
|
|
383
|
+
+ '<div class="timeline-label">Test File Map - click to jump</div>'
|
|
384
384
|
+ '<div class="timeline-bar">' + segs + '</div>'
|
|
385
385
|
+ '<div class="timeline-legend">'
|
|
386
386
|
+ '<div class="timeline-legend-item"><div class="legend-dot" style="background:#38a169"></div>Passing (≥95%)</div>'
|
|
@@ -410,7 +410,7 @@
|
|
|
410
410
|
return;
|
|
411
411
|
}
|
|
412
412
|
|
|
413
|
-
document.title = (run.suite_name || 'Run') + '
|
|
413
|
+
document.title = (run.suite_name || 'Run') + ' - Test Dashboard';
|
|
414
414
|
document.getElementById('pageTitle').textContent =
|
|
415
415
|
(run.suite_name || 'Run') + ' · ' + (run.project_name || '');
|
|
416
416
|
document.getElementById('runTime').textContent = fmtDate(run.timestamp);
|
|
@@ -441,7 +441,7 @@
|
|
|
441
441
|
/* Timeline */
|
|
442
442
|
var timeline = buildTimeline(files, total);
|
|
443
443
|
|
|
444
|
-
/* Hero
|
|
444
|
+
/* Hero - ring card + metric cards */
|
|
445
445
|
var rateColor2 = ringColor(rate);
|
|
446
446
|
var ringHtml = buildRing(rate);
|
|
447
447
|
var hero = '<div class="hero">'
|
|
@@ -9,7 +9,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
|
|
|
9
9
|
|
|
10
10
|
setup(
|
|
11
11
|
name='test-reporting',
|
|
12
|
-
version='3.2.
|
|
12
|
+
version='3.2.2',
|
|
13
13
|
description='Multi-project test reporting dashboard — collect results locally or push to S3',
|
|
14
14
|
long_description=long_description,
|
|
15
15
|
long_description_content_type="text/markdown",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|