test-reporting 3.2.0__tar.gz → 3.2.1__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.
Files changed (21) hide show
  1. {test_reporting-3.2.0/test_reporting.egg-info → test_reporting-3.2.1}/PKG-INFO +1 -1
  2. {test_reporting-3.2.0 → test_reporting-3.2.1}/reporting/templates/project.html +101 -57
  3. {test_reporting-3.2.0 → test_reporting-3.2.1}/reporting/templates/run.html +7 -7
  4. {test_reporting-3.2.0 → test_reporting-3.2.1}/setup.py +1 -1
  5. {test_reporting-3.2.0 → test_reporting-3.2.1/test_reporting.egg-info}/PKG-INFO +1 -1
  6. {test_reporting-3.2.0 → test_reporting-3.2.1}/LICENSE +0 -0
  7. {test_reporting-3.2.0 → test_reporting-3.2.1}/README.md +0 -0
  8. {test_reporting-3.2.0 → test_reporting-3.2.1}/reporting/__init__.py +0 -0
  9. {test_reporting-3.2.0 → test_reporting-3.2.1}/reporting/classifier.py +0 -0
  10. {test_reporting-3.2.0 → test_reporting-3.2.1}/reporting/cli.py +0 -0
  11. {test_reporting-3.2.0 → test_reporting-3.2.1}/reporting/config.py +0 -0
  12. {test_reporting-3.2.0 → test_reporting-3.2.1}/reporting/plugin.py +0 -0
  13. {test_reporting-3.2.0 → test_reporting-3.2.1}/reporting/publisher.py +0 -0
  14. {test_reporting-3.2.0 → test_reporting-3.2.1}/reporting/storage.py +0 -0
  15. {test_reporting-3.2.0 → test_reporting-3.2.1}/reporting/templates/index.html +0 -0
  16. {test_reporting-3.2.0 → test_reporting-3.2.1}/setup.cfg +0 -0
  17. {test_reporting-3.2.0 → test_reporting-3.2.1}/test_reporting.egg-info/SOURCES.txt +0 -0
  18. {test_reporting-3.2.0 → test_reporting-3.2.1}/test_reporting.egg-info/dependency_links.txt +0 -0
  19. {test_reporting-3.2.0 → test_reporting-3.2.1}/test_reporting.egg-info/entry_points.txt +0 -0
  20. {test_reporting-3.2.0 → test_reporting-3.2.1}/test_reporting.egg-info/requires.txt +0 -0
  21. {test_reporting-3.2.0 → test_reporting-3.2.1}/test_reporting.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: test-reporting
3
- Version: 3.2.0
3
+ Version: 3.2.1
4
4
  Summary: Multi-project test reporting dashboard — collect results locally or push to S3
5
5
  Home-page: https://github.com/amahdy77/test-reporting.git
6
6
  Author: Ashfaqur Mahdy
@@ -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 Test Dashboard</title>
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; }
@@ -157,6 +157,8 @@
157
157
  td { padding: 12px 16px; border-bottom: 1px solid var(--border); vertical-align: middle; }
158
158
  tr:last-child td { border-bottom: none; }
159
159
  tr:hover td { background: var(--bg); }
160
+ tr.clickable-row { cursor: pointer; }
161
+ tr.clickable-row:hover td { background: var(--blue-bg); }
160
162
  .test-name { font-weight: 600; max-width: 280px; overflow: hidden;
161
163
  text-overflow: ellipsis; white-space: nowrap; }
162
164
  .file-name { color: var(--muted); font-size: 12px; margin-top: 2px; }
@@ -271,6 +273,13 @@
271
273
  opacity: 0; transition: opacity .15s; z-index: 200;
272
274
  }
273
275
  [data-tooltip]:hover::after { opacity: 1; }
276
+
277
+ /* ── Expandable tables ── */
278
+ .table-expand-btn { padding: 12px 24px; text-align: center; border-top: 1px solid var(--border);
279
+ cursor: pointer; color: var(--blue); font-size: 13px; font-weight: 600;
280
+ transition: background .1s; }
281
+ .table-expand-btn:hover { background: var(--bg); }
282
+ .table-row-hidden { display: none; }
274
283
  </style>
275
284
  </head>
276
285
  <body>
@@ -325,7 +334,7 @@
325
334
 
326
335
  /* ── Helpers ── */
327
336
  function relTime(iso) {
328
- if (!iso) return '';
337
+ if (!iso) return '-';
329
338
  const diff = Date.now() - new Date(iso).getTime();
330
339
  const m = Math.floor(diff / 60000);
331
340
  if (m < 1) return 'Just now';
@@ -336,12 +345,12 @@
336
345
  }
337
346
 
338
347
  function fmtDate(iso) {
339
- if (!iso) return '';
348
+ if (!iso) return '-';
340
349
  return new Date(iso).toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' });
341
350
  }
342
351
 
343
352
  function fmtDur(s) {
344
- if (!s || s === 0) return '';
353
+ if (!s || s === 0) return '-';
345
354
  if (s >= 60) return Math.floor(s / 60) + 'm ' + Math.floor(s % 60) + 's';
346
355
  return s.toFixed(1) + 's';
347
356
  }
@@ -519,7 +528,7 @@
519
528
  return hero +
520
529
  '<div class="section">' +
521
530
  '<div class="section-head">' +
522
- '<h3>Regressions</h3>' +
531
+ '<h3>Recent Test Runs</h3>' +
523
532
  '<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
533
  '</div>' +
525
534
  '<div class="section-body">' + regsHtml + '</div>' +
@@ -533,6 +542,21 @@
533
542
  ch.classList.toggle('open', open);
534
543
  }
535
544
 
545
+ function toggleTableRows(btn) {
546
+ const table = btn.previousElementSibling;
547
+ const hiddenRows = table.querySelectorAll('.table-row-hidden');
548
+ const isExpanded = hiddenRows[0].style.display === 'table-row';
549
+
550
+ hiddenRows.forEach(function(row) {
551
+ row.style.display = isExpanded ? 'none' : 'table-row';
552
+ });
553
+
554
+ const count = hiddenRows.length;
555
+ btn.textContent = isExpanded
556
+ ? 'Show ' + count + ' more ▼'
557
+ : 'Show less ▲';
558
+ }
559
+
536
560
  function goToRun(runId) {
537
561
  if (runId) location.href = 'run.html?r=' + encodeURIComponent(runId) + '&p=' + encodeURIComponent(projectName);
538
562
  }
@@ -567,33 +591,31 @@
567
591
  '</div>' +
568
592
  '</div>' +
569
593
 
570
- '<div class="two-col">' +
571
- '<div class="section">' +
572
- '<div class="section-head">' +
573
- '<h3>Why Are Tests Failing?</h3>' +
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>' +
594
+ '<div class="section">' +
595
+ '<div class="section-head">' +
596
+ '<h3>Why Are Tests Failing?</h3>' +
597
+ '<p class="section-explain">Failure type breakdown. Real bugs need code fixes; infrastructure issues are environment problems.</p>' +
581
598
  '</div>' +
599
+ '<div class="section-body">' +
600
+ ((a.failure_type_breakdown || []).length === 0
601
+ ? '<p class="empty-section">No failures recorded yet.</p>'
602
+ : '<div class="chart-wrap chart-wrap-sm"><canvas id="failureTypeChart"></canvas></div>') +
603
+ '</div>' +
604
+ '</div>' +
582
605
 
583
- '<div class="section">' +
584
- '<div class="section-head">' +
585
- '<h3>Test File Reliability (Treemap)</h3>' +
586
- '<p class="section-explain">Each block = one file. Size ∝ test count. Color = pass rate. Worst files at top-left.</p>' +
587
- '</div>' +
588
- '<div class="section-body">' +
589
- renderTreemap(a.file_health || []) +
590
- '</div>' +
606
+ '<div class="section">' +
607
+ '<div class="section-head">' +
608
+ '<h3>Test File Reliability (Treemap)</h3>' +
609
+ '<p class="section-explain">Each block = one file. Size ∝ test count. Color = pass rate. Worst files at top-left.</p>' +
610
+ '</div>' +
611
+ '<div class="section-body">' +
612
+ renderTreemap(a.file_health || []) +
591
613
  '</div>' +
592
614
  '</div>' +
593
615
 
594
616
  '<div class="section">' +
595
617
  '<div class="section-head">' +
596
- '<h3>Duration vs Failures Scatter</h3>' +
618
+ '<h3>Duration vs Failures - Scatter</h3>' +
597
619
  '<p class="section-explain">Each dot = one test. X = avg duration, Y = failure count. Top-right quadrant = highest priority fixes.</p>' +
598
620
  '</div>' +
599
621
  '<div class="section-body">' +
@@ -607,7 +629,7 @@
607
629
 
608
630
  '<div class="section">' +
609
631
  '<div class="section-head">' +
610
- '<h3>Unreliable Tests Flaky</h3>' +
632
+ '<h3>Unreliable Tests - Flaky</h3>' +
611
633
  '<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
634
  '</div>' +
613
635
  '<div class="section-body-flush">' +
@@ -618,32 +640,30 @@
618
640
  '<div class="section">' +
619
641
  '<div class="section-head">' +
620
642
  '<h3>Tests That Break the Most</h3>' +
621
- '<p class="section-explain">Highest-priority fixes resolving these has the biggest positive impact on your overall pass rate.</p>' +
643
+ '<p class="section-explain">Highest-priority fixes - resolving these has the biggest positive impact on your overall pass rate.</p>' +
622
644
  '</div>' +
623
645
  '<div class="section-body-flush">' +
624
646
  renderHotspotsTable(a.failure_hotspots || []) +
625
647
  '</div>' +
626
648
  '</div>' +
627
649
 
628
- '<div class="two-col">' +
629
- '<div class="section">' +
630
- '<div class="section-head">' +
631
- '<h3>Slowest Tests</h3>' +
632
- '<p class="section-explain">Tests taking the longest to run. Good candidates for optimization.</p>' +
633
- '</div>' +
634
- '<div class="section-body-flush">' +
635
- renderSlowTable(a.slowest_tests || []) +
636
- '</div>' +
650
+ '<div class="section">' +
651
+ '<div class="section-head">' +
652
+ '<h3>Slowest Tests</h3>' +
653
+ '<p class="section-explain">Tests taking the longest to run. Good candidates for optimization.</p>' +
654
+ '</div>' +
655
+ '<div class="section-body-flush">' +
656
+ renderSlowTable(a.slowest_tests || []) +
637
657
  '</div>' +
658
+ '</div>' +
638
659
 
639
- '<div class="section">' +
640
- '<div class="section-head">' +
641
- '<h3>Tests Getting Slower</h3>' +
642
- '<p class="section-explain">Tests that have become significantly slower over the last 7 days. A slowing test can signal feature degradation.</p>' +
643
- '</div>' +
644
- '<div class="section-body-flush">' +
645
- renderRegressionTable(a.performance_regressions || []) +
646
- '</div>' +
660
+ '<div class="section">' +
661
+ '<div class="section-head">' +
662
+ '<h3>Tests Getting Slower</h3>' +
663
+ '<p class="section-explain">Tests that have become significantly slower over the last 7 days. A slowing test can signal feature degradation.</p>' +
664
+ '</div>' +
665
+ '<div class="section-body-flush">' +
666
+ renderRegressionTable(a.performance_regressions || []) +
647
667
  '</div>' +
648
668
  '</div>';
649
669
  }
@@ -750,55 +770,79 @@
750
770
 
751
771
  function renderFlakyTable(tests) {
752
772
  if (tests.length === 0) return '<p class="empty-section" style="padding:20px">No flaky tests detected.</p>';
773
+ const limit = 5;
753
774
  const rows = tests.map(function(t, i) {
754
- return '<tr class="anim-row" style="animation-delay:' + (i * 0.04) + 's">' +
775
+ const hiddenClass = i >= limit ? ' table-row-hidden' : '';
776
+ const clickAttr = t.last_run_id ? ' class="anim-row clickable-row' + hiddenClass + '" onclick="goToRun(\'' + t.last_run_id + '\')"' : ' class="anim-row' + hiddenClass + '"';
777
+ return '<tr' + clickAttr + ' style="animation-delay:' + (i * 0.04) + 's">' +
755
778
  '<td><div class="test-name" title="' + t.test_name + '">' + t.test_name + '</div><div class="file-name">' + t.file_name + '</div></td>' +
756
779
  '<td><span class="pill pill-yellow">' + t.pass_rate + '% pass rate</span></td>' +
757
780
  '<td style="text-align:center">' + t.passed + '</td>' +
758
781
  '<td style="text-align:center;color:var(--red)">' + t.failed + '</td>' +
759
782
  '<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) : '') + '</td>' +
783
+ '<td style="color:var(--muted);font-size:12px">' + (t.last_failed ? fmtDate(t.last_failed) : '-') + '</td>' +
761
784
  '</tr>';
762
785
  }).join('');
763
- 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>';
786
+ const expandBtn = tests.length > limit
787
+ ? '<div class="table-expand-btn" onclick="toggleTableRows(this)">Show ' + (tests.length - limit) + ' more ▼</div>'
788
+ : '';
789
+ 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
790
  }
765
791
 
766
792
  function renderHotspotsTable(tests) {
767
793
  if (tests.length === 0) return '<p class="empty-section" style="padding:20px">No failure hotspots detected yet.</p>';
794
+ const limit = 5;
768
795
  const rows = tests.map(function(t, i) {
769
- return '<tr class="anim-row" style="animation-delay:' + (i * 0.04) + 's">' +
796
+ const hiddenClass = i >= limit ? ' table-row-hidden' : '';
797
+ const clickAttr = t.last_run_id ? ' class="anim-row clickable-row' + hiddenClass + '" onclick="goToRun(\'' + t.last_run_id + '\')"' : ' class="anim-row' + hiddenClass + '"';
798
+ return '<tr' + clickAttr + ' style="animation-delay:' + (i * 0.04) + 's">' +
770
799
  '<td><div class="test-name" title="' + t.test_name + '">' + t.test_name + '</div><div class="file-name">' + t.file_name + '</div></td>' +
771
800
  '<td><span class="pill pill-red">' + t.failure_count + ' failures</span></td>' +
772
801
  '<td>' + t.failure_label + '</td>' +
773
- '<td style="color:var(--muted);font-size:12px">' + (t.last_failed ? fmtDate(t.last_failed) : '') + '</td>' +
802
+ '<td style="color:var(--muted);font-size:12px">' + (t.last_failed ? fmtDate(t.last_failed) : '-') + '</td>' +
774
803
  '</tr>';
775
804
  }).join('');
776
- return '<table><thead><tr><th>Test</th><th>Failure Count</th><th>Cause</th><th>Last Failed</th></tr></thead><tbody>' + rows + '</tbody></table>';
805
+ const expandBtn = tests.length > limit
806
+ ? '<div class="table-expand-btn" onclick="toggleTableRows(this)">Show ' + (tests.length - limit) + ' more ▼</div>'
807
+ : '';
808
+ 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
809
  }
778
810
 
779
811
  function renderSlowTable(tests) {
780
812
  if (tests.length === 0) return '<p class="empty-section" style="padding:20px">Not enough data yet.</p>';
813
+ const limit = 5;
781
814
  const rows = tests.map(function(t, i) {
782
- return '<tr class="anim-row" style="animation-delay:' + (i * 0.04) + 's">' +
815
+ const hiddenClass = i >= limit ? ' table-row-hidden' : '';
816
+ const clickAttr = t.last_run_id ? ' class="anim-row clickable-row' + hiddenClass + '" onclick="goToRun(\'' + t.last_run_id + '\')"' : ' class="anim-row' + hiddenClass + '"';
817
+ return '<tr' + clickAttr + ' style="animation-delay:' + (i * 0.04) + 's">' +
783
818
  '<td><div class="test-name" title="' + t.test_name + '">' + t.test_name + '</div><div class="file-name">' + t.file_name + '</div></td>' +
784
819
  '<td style="font-weight:700">' + fmtDur(t.avg_duration) + '</td>' +
785
820
  '<td style="color:var(--muted);font-size:12px">' + fmtDur(t.max_duration) + ' max</td>' +
786
821
  '</tr>';
787
822
  }).join('');
788
- return '<table><thead><tr><th>Test</th><th>Avg Duration</th><th>Max</th></tr></thead><tbody>' + rows + '</tbody></table>';
823
+ const expandBtn = tests.length > limit
824
+ ? '<div class="table-expand-btn" onclick="toggleTableRows(this)">Show ' + (tests.length - limit) + ' more ▼</div>'
825
+ : '';
826
+ return '<table><thead><tr><th>Test</th><th>Avg Duration</th><th>Max</th></tr></thead><tbody>' + rows + '</tbody></table>' + expandBtn;
789
827
  }
790
828
 
791
829
  function renderRegressionTable(tests) {
792
830
  if (tests.length === 0) return '<p class="empty-section" style="padding:20px">No performance regressions detected.</p>';
831
+ const limit = 5;
793
832
  const rows = tests.map(function(t, i) {
794
- return '<tr class="anim-row" style="animation-delay:' + (i * 0.04) + 's">' +
833
+ const hiddenClass = i >= limit ? ' table-row-hidden' : '';
834
+ const clickAttr = t.last_run_id ? ' class="anim-row clickable-row' + hiddenClass + '" onclick="goToRun(\'' + t.last_run_id + '\')"' : ' class="anim-row' + hiddenClass + '"';
835
+ return '<tr' + clickAttr + ' style="animation-delay:' + (i * 0.04) + 's">' +
795
836
  '<td><div class="test-name" title="' + t.test_name + '">' + t.test_name + '</div><div class="file-name">' + t.file_name + '</div></td>' +
796
837
  '<td style="color:var(--muted);font-size:12px">' + fmtDur(t.historical_avg) + '</td>' +
797
838
  '<td style="font-weight:700">' + fmtDur(t.recent_avg) + '</td>' +
798
839
  '<td><span class="pill pill-red">+' + t.percent_slower + '% slower</span></td>' +
799
840
  '</tr>';
800
841
  }).join('');
801
- return '<table><thead><tr><th>Test</th><th>Was</th><th>Now</th><th>Change</th></tr></thead><tbody>' + rows + '</tbody></table>';
842
+ const expandBtn = tests.length > limit
843
+ ? '<div class="table-expand-btn" onclick="toggleTableRows(this)">Show ' + (tests.length - limit) + ' more ▼</div>'
844
+ : '';
845
+ return '<table><thead><tr><th>Test</th><th>Was</th><th>Now</th><th>Change</th></tr></thead><tbody>' + rows + '</tbody></table>' + expandBtn;
802
846
  }
803
847
 
804
848
  /* ═══════════════════════════════════════════════════
@@ -835,7 +879,7 @@
835
879
  return '<tr>' +
836
880
  '<td>' + fmtDate(run.timestamp) + '</td>' +
837
881
  '<td><div style="font-weight:600;font-size:13px">' + run.file_name + '</div></td>' +
838
- '<td>' + (run.regression_tag || '') + '</td>' +
882
+ '<td>' + (run.regression_tag || '-') + '</td>' +
839
883
  '<td><span class="pill ' + pc + '">' + run.pass_rate.toFixed(0) + '%</span></td>' +
840
884
  '<td>' + run.total_tests + '</td>' +
841
885
  '<td style="color:var(--red)">' + run.failed + '</td>' +
@@ -850,7 +894,7 @@
850
894
  var canvas = document.getElementById(sid);
851
895
  if (!canvas) continue;
852
896
  var pts = sparklineIds[sid];
853
- if (pts.length < 2) { canvas.outerHTML = '<span class="sparkline-none-sm">—</span>'; continue; }
897
+ if (pts.length < 2) { canvas.outerHTML = '<span class="sparkline-none-sm">-</span>'; continue; }
854
898
  new Chart(canvas, {
855
899
  type: 'line',
856
900
  data: {
@@ -1041,7 +1085,7 @@
1041
1085
 
1042
1086
  document.getElementById('pageTitle').textContent = proj.name;
1043
1087
  document.getElementById('lastRun').textContent = 'Last run ' + relTime(proj.last_run);
1044
- document.title = proj.name + ' Test Dashboard';
1088
+ document.title = proj.name + ' - Test Dashboard';
1045
1089
 
1046
1090
  const analytics = proj.analytics || {};
1047
1091
 
@@ -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 Test Dashboard</title>
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 + ' ' + f.pass_rate.toFixed(0) + '% passing (' + f.passed + '/' + f.total + ')"'
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 click to jump</div>'
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') + ' Test Dashboard';
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 ring card + metric cards */
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.0',
12
+ version='3.2.1',
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",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: test-reporting
3
- Version: 3.2.0
3
+ Version: 3.2.1
4
4
  Summary: Multi-project test reporting dashboard — collect results locally or push to S3
5
5
  Home-page: https://github.com/amahdy77/test-reporting.git
6
6
  Author: Ashfaqur Mahdy
File without changes
File without changes
File without changes