reporting-labs 0.5.0 → 0.6.1
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/README.md +232 -2
- package/bin/build-template.js +101 -0
- package/bin/cli.js +6 -1
- package/bin/config-template.txt +1 -0
- package/bin/merge.js +173 -0
- package/dist/reporter.d.ts +2 -1
- package/dist/reporter.js +14 -6
- package/dist/template.html +1659 -0
- package/dist/template.js +217 -2
- package/dist/types.d.ts +4 -0
- package/package.json +2 -2
|
@@ -0,0 +1,1659 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en" data-palette="lab">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
6
|
+
<title></title>
|
|
7
|
+
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2064%2064%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%22rl-bg%22%20x1%3D%220%22%20y1%3D%220%22%20x2%3D%221%22%20y2%3D%221%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%231A56DB%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%230A2A6B%22%2F%3E%3C%2FlinearGradient%3E%3CradialGradient%20id%3D%22rl-glow%22%20cx%3D%220.8%22%20cy%3D%220.1%22%20r%3D%220.9%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%23fff%22%20stop-opacity%3D%22.22%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23fff%22%20stop-opacity%3D%220%22%2F%3E%3C%2FradialGradient%3E%3CclipPath%20id%3D%22rl-flask%22%3E%3Cpath%20d%3D%22M25%208h14v14l13.5%2024.5c1.8%203.3-.6%207.5-4.4%207.5H15.9c-3.8%200-6.2-4.2-4.4-7.5L25%2022z%22%2F%3E%3C%2FclipPath%3E%3C%2Fdefs%3E%3Crect%20width%3D%2264%22%20height%3D%2264%22%20rx%3D%2215%22%20fill%3D%22url(%23rl-bg)%22%2F%3E%3Crect%20width%3D%2264%22%20height%3D%2264%22%20rx%3D%2215%22%20fill%3D%22url(%23rl-glow)%22%2F%3E%3Cg%20clip-path%3D%22url(%23rl-flask)%22%3E%3Crect%20x%3D%2217%22%20y%3D%2240%22%20width%3D%227%22%20height%3D%2220%22%20rx%3D%222%22%20fill%3D%22%23fff%22%20fill-opacity%3D%22.55%22%2F%3E%3Crect%20x%3D%2228.5%22%20y%3D%2228%22%20width%3D%227%22%20height%3D%2232%22%20rx%3D%222%22%20fill%3D%22%233DDC8C%22%2F%3E%3Crect%20x%3D%2240%22%20y%3D%2235%22%20width%3D%227%22%20height%3D%2225%22%20rx%3D%222%22%20fill%3D%22%23fff%22%20fill-opacity%3D%22.85%22%2F%3E%3C%2Fg%3E%3Cpath%20d%3D%22M25%208h14v14l13.5%2024.5c1.8%203.3-.6%207.5-4.4%207.5H15.9c-3.8%200-6.2-4.2-4.4-7.5L25%2022z%22%20fill%3D%22none%22%20stroke%3D%22%23fff%22%20stroke-width%3D%223.2%22%20stroke-linejoin%3D%22round%22%2F%3E%3Cpath%20d%3D%22M22%208h20%22%20stroke%3D%22%23fff%22%20stroke-width%3D%223.2%22%20stroke-linecap%3D%22round%22%2F%3E%3Ccircle%20cx%3D%2224%22%20cy%3D%2230%22%20r%3D%222.2%22%20fill%3D%22%23fff%22%20fill-opacity%3D%22.9%22%2F%3E%3C%2Fsvg%3E">
|
|
8
|
+
<style>@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:400;font-display:swap;src:url(data:font/woff2;base64,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) format('woff2')}@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:500;font-display:swap;src:url(data:font/woff2;base64,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) format('woff2')}@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:600;font-display:swap;src:url(data:font/woff2;base64,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) format('woff2')}@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;src:url(data:font/woff2;base64,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) format('woff2')}@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:500;font-display:swap;src:url(data:font/woff2;base64,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) format('woff2')}</style>
|
|
9
|
+
<style>
|
|
10
|
+
/* ---------- palettes: each defines light + dark ---------- */
|
|
11
|
+
:root{
|
|
12
|
+
--radius:6px; --mono:'IBM Plex Mono',ui-monospace,SFMono-Regular,Menlo,monospace;
|
|
13
|
+
--sans:'IBM Plex Sans',system-ui,-apple-system,Segoe UI,Roboto,sans-serif;
|
|
14
|
+
--pass:#1FA971; --fail:#E5405E; --skip:#8B95A5; --flaky:#E39B12;
|
|
15
|
+
--pass-bg:#DDF5EA; --fail-bg:#FDE3E8; --skip-bg:#EDF0F4; --flaky-bg:#FBEFD2; --flaky-ink:#8A5A00;
|
|
16
|
+
/* blue (default): white paper + royal blue */
|
|
17
|
+
--bg:#F2F6FC; --surface:#FFFFFF; --surface-2:#EAF1FB; --line:#D9E3F2; --line-2:#C6D5EA; --ink:#0B1F44; --ink-2:#3F5680; --ink-3:#7A8CAB; --accent:#1A56DB; --accent-ink:#fff;
|
|
18
|
+
--accent-2:#0E3FA9; --accent-deep:#0A2A6B; --accent-tint:#E3ECFF; --accent-soft:#BFD2FF; --band-end:var(--accent);
|
|
19
|
+
--shadow:0 1px 2px rgba(11,31,68,.05),0 8px 24px -12px rgba(26,86,219,.18);
|
|
20
|
+
}
|
|
21
|
+
:root[data-palette=ocean]{ --bg:#F1F6F7; --surface:#FFFFFF; --surface-2:#E6EFF1; --line:#D3E0E4; --line-2:#BFD2D8; --ink:#0F2430; --ink-2:#3F5A66; --ink-3:#6F8894; --accent:#0E8FA6; --accent-2:#0B6F82; --accent-deep:#06404B; --accent-tint:#DDF1F4; --accent-soft:#A9DEE6; --shadow:0 1px 2px rgba(15,36,48,.05),0 8px 24px -12px rgba(14,143,166,.2) }
|
|
22
|
+
:root[data-palette=ember]{ --bg:#F8F4EF; --surface:#FFFFFF; --surface-2:#F0E9E0; --line:#E2D8CB; --line-2:#D2C4B2; --ink:#231C16; --ink-2:#5C5148; --ink-3:#8D8177; --accent:#E0521B; --accent-2:#B53E11; --accent-deep:#5E200A; --accent-tint:#FBE6DC; --accent-soft:#F5C2AB; --shadow:0 1px 2px rgba(35,28,22,.05),0 8px 24px -12px rgba(224,82,27,.2) }
|
|
23
|
+
:root[data-palette=mono]{ --bg:#F4F4F4; --surface:#FFFFFF; --surface-2:#EBEBEB; --line:#DCDCDC; --line-2:#C8C8C8; --ink:#161616; --ink-2:#4F4F4F; --ink-3:#848484; --accent:#161616; --accent-2:#2B2B2B; --accent-deep:#000; --accent-tint:#E8E8E8; --accent-soft:#CFCFCF; --shadow:0 1px 2px rgba(0,0,0,.05),0 8px 24px -12px rgba(0,0,0,.18) }
|
|
24
|
+
|
|
25
|
+
/* dark tokens per palette */
|
|
26
|
+
:root[data-theme=dark], :root:not([data-theme=light]) { color-scheme:light }
|
|
27
|
+
@media (prefers-color-scheme:dark){ :root:not([data-theme=light]){ --_dark:1 } }
|
|
28
|
+
:root[data-theme=dark]{ --_dark:1 }
|
|
29
|
+
@media (prefers-color-scheme:dark){
|
|
30
|
+
:root:not([data-theme=light]){ --bg:#0A1730; --surface:#10213F; --surface-2:#172B50; --line:#22375E; --line-2:#2E4570; --ink:#EAF0FB; --ink-2:#AEBFDD; --ink-3:#7489AE; --accent:#4D8CFF; --accent-ink:#fff; --accent-2:#3572F0; --accent-deep:#071A45; --accent-tint:#183566; --accent-soft:#2C4E8F; --band-end:var(--accent); --shadow:0 1px 2px rgba(0,0,0,.3),0 8px 24px -12px rgba(0,0,0,.5); --pass:#34D07E; --fail:#FF6B85; --flaky:#F8B640; --skip:#6A7D9E; --pass-bg:#0F3A25; --fail-bg:#40192A; --skip-bg:#1B2A47; --flaky-bg:#3E2C08; --flaky-ink:#FFD58A; color-scheme:dark }
|
|
31
|
+
:root:not([data-theme=light])[data-palette=ocean]{ --bg:#07161B; --surface:#0D2027; --surface-2:#132A33; --line:#1E3942; --ink:#E4F1F4; --ink-2:#9DB8C0; --ink-3:#6A8A93; --accent:#2FC4DA; --accent-2:#1A9DB0; --accent-deep:#062A32; --accent-tint:#0F3A43; --accent-soft:#1C5A66; --line-2:#2A4A54 }
|
|
32
|
+
:root:not([data-theme=light])[data-palette=ember]{ --bg:#15100C; --surface:#1E1712; --surface-2:#292019; --line:#3A2E24; --ink:#F3EBE2; --ink-2:#C2B4A5; --ink-3:#8C7E70; --accent:#FF7A38; --accent-2:#D95A1E; --accent-deep:#3A1A0A; --accent-tint:#3A2416; --accent-soft:#5E3520; --line-2:#4A3B2F }
|
|
33
|
+
:root:not([data-theme=light])[data-palette=mono]{ --bg:#0E0E0E; --surface:#161616; --surface-2:#1F1F1F; --line:#2C2C2C; --ink:#F2F2F2; --ink-2:#B3B3B3; --ink-3:#7A7A7A; --accent:#F2F2F2; --accent-ink:#0E0E0E; --accent-2:#2B2B2B; --accent-deep:#000; --accent-tint:#262626; --accent-soft:#3A3A3A; --band-end:#3A3A3A; --line-2:#3A3A3A }
|
|
34
|
+
}
|
|
35
|
+
:root[data-theme=dark]{ --bg:#0A1730; --surface:#10213F; --surface-2:#172B50; --line:#22375E; --line-2:#2E4570; --ink:#EAF0FB; --ink-2:#AEBFDD; --ink-3:#7489AE; --accent:#4D8CFF; --accent-ink:#fff; --accent-2:#3572F0; --accent-deep:#071A45; --accent-tint:#183566; --accent-soft:#2C4E8F; --band-end:var(--accent); --shadow:0 1px 2px rgba(0,0,0,.3),0 8px 24px -12px rgba(0,0,0,.5); --pass:#34D07E; --fail:#FF6B85; --flaky:#F8B640; --skip:#6A7D9E; --pass-bg:#0F3A25; --fail-bg:#40192A; --skip-bg:#1B2A47; --flaky-bg:#3E2C08; --flaky-ink:#FFD58A; color-scheme:dark }
|
|
36
|
+
:root[data-theme=dark][data-palette=ocean]{ --bg:#07161B; --surface:#0D2027; --surface-2:#132A33; --line:#1E3942; --ink:#E4F1F4; --ink-2:#9DB8C0; --ink-3:#6A8A93; --accent:#2FC4DA; --accent-2:#1A9DB0; --accent-deep:#062A32; --accent-tint:#0F3A43; --accent-soft:#1C5A66; --line-2:#2A4A54 }
|
|
37
|
+
:root[data-theme=dark][data-palette=ember]{ --bg:#15100C; --surface:#1E1712; --surface-2:#292019; --line:#3A2E24; --ink:#F3EBE2; --ink-2:#C2B4A5; --ink-3:#8C7E70; --accent:#FF7A38; --accent-2:#D95A1E; --accent-deep:#3A1A0A; --accent-tint:#3A2416; --accent-soft:#5E3520; --line-2:#4A3B2F }
|
|
38
|
+
:root[data-theme=dark][data-palette=mono]{ --bg:#0E0E0E; --surface:#161616; --surface-2:#1F1F1F; --line:#2C2C2C; --ink:#F2F2F2; --ink-2:#B3B3B3; --ink-3:#7A7A7A; --accent:#F2F2F2; --accent-ink:#0E0E0E; --accent-2:#2B2B2B; --accent-deep:#000; --accent-tint:#262626; --accent-soft:#3A3A3A; --band-end:#3A3A3A; --line-2:#3A3A3A }
|
|
39
|
+
*{box-sizing:border-box}
|
|
40
|
+
html,body{margin:0;background:var(--bg);color:var(--ink);font:14px/1.5 var(--sans)}
|
|
41
|
+
button,input,select{font:inherit;color:inherit}
|
|
42
|
+
button{cursor:pointer;background:none;border:0;padding:0}
|
|
43
|
+
a{color:var(--accent)}
|
|
44
|
+
:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
|
|
45
|
+
@media (prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}}
|
|
46
|
+
|
|
47
|
+
/* top nav */
|
|
48
|
+
.nav{position:sticky;top:0;z-index:5;background:var(--surface);border-bottom:1px solid var(--line);padding:0 28px;display:flex;gap:2px;align-items:center}
|
|
49
|
+
.nav button{padding:12px 14px;font-size:13px;color:var(--ink-2);border-bottom:2px solid transparent;margin-bottom:-1px;display:inline-flex;gap:7px;align-items:center}
|
|
50
|
+
.nav button:hover{color:var(--ink)} .nav button[aria-selected=true]{color:var(--ink);border-bottom-color:var(--accent)}
|
|
51
|
+
.nav .cnt{font:11px var(--mono);padding:1px 6px;border-radius:999px;background:var(--surface-2);color:var(--ink-3)}
|
|
52
|
+
.nav .cnt.bad{background:var(--fail-bg);color:var(--fail)}
|
|
53
|
+
.nav .mini-verdict{margin-left:auto;font-size:12px;color:var(--ink-3);display:none}
|
|
54
|
+
.view{display:none} .view.on{display:block}
|
|
55
|
+
.view-pad{max-width:1400px;margin:0 auto;padding:22px 28px 40px}
|
|
56
|
+
.view-pad .grid{margin-top:0}
|
|
57
|
+
.main{margin-top:16px}
|
|
58
|
+
.list{top:64px;max-height:calc(100vh - 76px)}
|
|
59
|
+
/* api table */
|
|
60
|
+
.apitbl{width:100%;border-collapse:collapse;font-size:13px}
|
|
61
|
+
.apitbl th{text-align:left;font-weight:600;color:var(--ink-2);padding:8px 10px;border-bottom:1px solid var(--line);font-size:12px;position:sticky;top:44px;background:var(--surface)}
|
|
62
|
+
.apitbl td{padding:8px 10px;border-bottom:1px solid var(--line);vertical-align:middle}
|
|
63
|
+
.apitbl tr:hover td{background:var(--surface-2)} .apitbl tr{cursor:pointer}
|
|
64
|
+
.apitbl .u{font:12px var(--mono);max-width:520px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
65
|
+
.apitbl .t{color:var(--ink-3);font-size:12px;max-width:260px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
66
|
+
.api-stats{display:flex;gap:16px;margin-bottom:14px;font-size:13px;color:var(--ink-2)} .api-stats b{color:var(--ink);font-variant-numeric:tabular-nums}
|
|
67
|
+
.api-stats .bad b{color:var(--fail)}
|
|
68
|
+
@media (max-width:700px){.nav{overflow-x:auto;padding:0 12px} .nav button{padding:10px 10px;white-space:nowrap}}
|
|
69
|
+
@media print{.nav{display:none} .view{display:block!important}}
|
|
70
|
+
|
|
71
|
+
/* verdict row with donut */
|
|
72
|
+
.vrow{display:flex;align-items:center;gap:32px;flex-wrap:wrap}
|
|
73
|
+
.vrow .vleft{flex:1;min-width:280px}
|
|
74
|
+
.vrow .donut{gap:14px} .vrow .donut svg{width:96px;height:96px}
|
|
75
|
+
.vrow .donut .c{font-size:17px} .vrow .donut .cl{font-size:8px}
|
|
76
|
+
.vrow .donut .legend{font-size:12px;gap:2px 8px}
|
|
77
|
+
/* breakdown tabs */
|
|
78
|
+
.bk-tabs{display:flex;gap:2px;flex-wrap:wrap;margin:-4px 0 14px}
|
|
79
|
+
.bk-tabs button{padding:5px 10px;font-size:12px;border-radius:999px;color:var(--ink-2)}
|
|
80
|
+
.bk-tabs button:hover{background:var(--surface-2)} .bk-tabs button[aria-selected=true]{background:var(--ink);color:var(--bg)}
|
|
81
|
+
.dim .row{grid-template-columns:110px 1fr 56px}
|
|
82
|
+
.attn .proj{font:10px var(--mono);color:var(--ink-3);background:var(--surface-2);padding:1px 5px;border-radius:3px;margin-left:6px}
|
|
83
|
+
.card.tight{padding:14px 20px}
|
|
84
|
+
|
|
85
|
+
/* outcome stripe above header */
|
|
86
|
+
.stripe{display:flex;height:4px} .stripe i{display:block;height:100%}
|
|
87
|
+
.hdr{border-top:0}
|
|
88
|
+
.hdr .ctl{display:flex;gap:6px;align-items:center}
|
|
89
|
+
.hdr select.pal{padding:6px 8px;border:1px solid var(--line);border-radius:var(--radius);background:var(--surface);font-size:12px;color:var(--ink-2)}
|
|
90
|
+
.btn{display:inline-flex;align-items:center;gap:6px;padding:7px 11px;border:1px solid var(--line);border-radius:var(--radius);font-size:12px;color:var(--ink-2);background:var(--surface)}
|
|
91
|
+
.btn:hover{border-color:var(--accent);color:var(--ink)} .btn.primary{background:var(--accent);color:var(--accent-ink);border-color:var(--accent)}
|
|
92
|
+
.btn.done{border-color:var(--pass);color:var(--pass)}
|
|
93
|
+
/* verdict */
|
|
94
|
+
.verdict .big{font-variant-numeric:tabular-nums;font-size:40px;letter-spacing:-.03em}
|
|
95
|
+
.verdict .big small{font-size:18px;font-weight:500;color:var(--ink-3);letter-spacing:0;margin-left:2px}
|
|
96
|
+
.pills{margin-top:18px}
|
|
97
|
+
.pill[aria-pressed=true]{background:var(--ink);color:var(--bg);border-color:var(--ink)} .pill[aria-pressed=true] .n{color:var(--bg)}
|
|
98
|
+
/* cards: status rail on left */
|
|
99
|
+
.card{position:relative;box-shadow:none}
|
|
100
|
+
.card.warn-rail::before,.card.fail-rail::before{content:"";position:absolute;left:0;top:10px;bottom:10px;width:3px;border-radius:0 2px 2px 0;background:var(--fail)}
|
|
101
|
+
.card.warn-rail::before{background:var(--flaky)}
|
|
102
|
+
.card h2{letter-spacing:.01em}
|
|
103
|
+
.badge.flaky{color:var(--flaky-ink)}
|
|
104
|
+
/* donut with gaps */
|
|
105
|
+
.donut svg circle{stroke-linecap:butt}
|
|
106
|
+
/* failure clusters */
|
|
107
|
+
.clu{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}
|
|
108
|
+
.clu li{border:1px solid var(--line);border-radius:var(--radius);padding:8px 10px}
|
|
109
|
+
.clu .msg{font:12px/1.45 var(--mono);white-space:pre-wrap;word-break:break-word;color:var(--ink);max-height:3em;overflow:hidden}
|
|
110
|
+
.clu .who{display:flex;flex-wrap:wrap;gap:4px;margin-top:6px}
|
|
111
|
+
.clu .who button{font-size:11px;padding:2px 7px;border-radius:999px;background:var(--fail-bg);color:var(--fail)} .clu .who button:hover{outline:1px solid var(--fail)}
|
|
112
|
+
.clu .n{font-size:12px;color:var(--ink-3);margin-left:auto}
|
|
113
|
+
.clu .top{display:flex;gap:8px;align-items:baseline}
|
|
114
|
+
/* detail actions */
|
|
115
|
+
.detail .actions{display:flex;gap:6px;margin-left:auto}
|
|
116
|
+
.detail .titlebar{display:flex;align-items:flex-start;gap:10px}
|
|
117
|
+
.kbd{font:11px var(--mono);border:1px solid var(--line);border-radius:3px;padding:0 4px;color:var(--ink-3)}
|
|
118
|
+
.hint-kbd{font-size:11px;color:var(--ink-3);padding:8px 12px;border-top:1px solid var(--line)}
|
|
119
|
+
/* toast */
|
|
120
|
+
.toast{position:fixed;bottom:18px;left:50%;transform:translateX(-50%);background:var(--ink);color:var(--bg);padding:8px 14px;border-radius:999px;font-size:13px;z-index:20}
|
|
121
|
+
/* print */
|
|
122
|
+
@media print{ .hdr .ctl,.tools,.strip-cap,.hint-kbd,.detail .actions{display:none} .main{grid-template-columns:1fr} .list{position:static;max-height:none;border:0} .items{overflow:visible} body{background:#fff} .card{break-inside:avoid} }
|
|
123
|
+
|
|
124
|
+
/* ---------- header ---------- */
|
|
125
|
+
.hdr{display:flex;align-items:center;gap:16px;padding:14px 28px;border-bottom:1px solid var(--line);background:var(--surface)}
|
|
126
|
+
.hdr img{height:28px}
|
|
127
|
+
.hdr h1{font-size:16px;font-weight:600;margin:0}
|
|
128
|
+
.hdr .hmeta{display:flex;gap:6px;flex-wrap:wrap;margin-left:8px}
|
|
129
|
+
.chip{font:12px/1 var(--mono);padding:5px 8px;border-radius:4px;background:var(--surface-2);color:var(--ink-2)}
|
|
130
|
+
.chip b{color:var(--ink);font-weight:500}
|
|
131
|
+
.hdr .spacer{flex:1}
|
|
132
|
+
.hdr .when{color:var(--ink-3);font-size:12px}
|
|
133
|
+
.tbtn{width:32px;height:32px;border-radius:var(--radius);border:1px solid var(--line);display:grid;place-items:center;color:var(--ink-2)}
|
|
134
|
+
.tbtn:hover{background:var(--surface-2)}
|
|
135
|
+
|
|
136
|
+
/* ---------- summary ---------- */
|
|
137
|
+
.sum{padding:28px 28px 20px;max-width:1400px;margin:0 auto}
|
|
138
|
+
.verdict{display:flex;align-items:baseline;gap:14px;flex-wrap:wrap}
|
|
139
|
+
.verdict .big{font-size:34px;font-weight:600;letter-spacing:-.02em;line-height:1.1}
|
|
140
|
+
.verdict .big.ok{color:var(--pass)} .verdict .big.bad{color:var(--fail)}
|
|
141
|
+
.verdict .sub{font-size:15px;color:var(--ink-2)}
|
|
142
|
+
.pills{display:flex;gap:8px;margin-top:16px;flex-wrap:wrap}
|
|
143
|
+
.pill{display:inline-flex;align-items:center;gap:8px;padding:6px 12px 6px 8px;border:1px solid var(--line);border-radius:999px;background:var(--surface);font-size:13px;color:var(--ink-2)}
|
|
144
|
+
.pill .n{font-weight:600;color:var(--ink);font-variant-numeric:tabular-nums}
|
|
145
|
+
.pill .dot{width:8px;height:8px;border-radius:50%}
|
|
146
|
+
.pill[aria-pressed=true]{border-color:var(--ink);color:var(--ink)}
|
|
147
|
+
.pill:hover{background:var(--surface-2)}
|
|
148
|
+
|
|
149
|
+
/* run strip: the hero */
|
|
150
|
+
.strip{margin-top:22px;display:grid;grid-template-columns:repeat(auto-fill,14px);gap:3px}
|
|
151
|
+
.cell{width:14px;height:20px;border-radius:3px;background:var(--skip);transition:transform .08s}
|
|
152
|
+
.cell.passed{background:var(--pass)} .cell.failed,.cell.timedOut,.cell.interrupted{background:var(--fail)} .cell.flaky{background:var(--flaky)}
|
|
153
|
+
.cell:hover{transform:scaleY(1.25)} .cell.dim{opacity:.18}
|
|
154
|
+
.strip-cap{margin-top:8px;font-size:12px;color:var(--ink-3)}
|
|
155
|
+
|
|
156
|
+
/* widgets row */
|
|
157
|
+
.widgets{display:grid;grid-template-columns:2fr 1fr;gap:16px;margin-top:22px}
|
|
158
|
+
@media (max-width:900px){.widgets{grid-template-columns:1fr}}
|
|
159
|
+
.card{background:var(--surface);border:1px solid var(--line);border-radius:8px;padding:18px 20px}
|
|
160
|
+
.card h2{font-size:11.5px;font-weight:600;margin:0 0 14px;color:var(--ink-3);text-transform:uppercase;letter-spacing:.06em}
|
|
161
|
+
.tl{width:100%;height:auto;display:block}
|
|
162
|
+
.tl rect.r{rx:2}
|
|
163
|
+
.tl .lane{fill:var(--surface-2)}
|
|
164
|
+
.tl text{font:11px var(--mono);fill:var(--ink-3)}
|
|
165
|
+
.slow{list-style:none;margin:0;padding:0}
|
|
166
|
+
.slow li{display:flex;gap:10px;align-items:center;padding:6px 0;border-top:1px solid var(--line);font-size:13px}
|
|
167
|
+
.slow li:first-child{border-top:0}
|
|
168
|
+
.slow .bar{height:6px;border-radius:3px;background:var(--accent);opacity:.7}
|
|
169
|
+
.slow .t{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
170
|
+
.slow .d{font:12px var(--mono);color:var(--ink-3)}
|
|
171
|
+
.slow button{text-align:left;width:100%;display:flex;gap:10px;align-items:center}
|
|
172
|
+
.slow button:hover .t{color:var(--accent)}
|
|
173
|
+
.proj{display:flex;flex-direction:column;gap:8px}
|
|
174
|
+
.proj .row{display:flex;align-items:center;gap:10px;font-size:13px}
|
|
175
|
+
.proj .name{width:110px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
176
|
+
.proj .bar{flex:1;height:10px;display:flex;border-radius:3px;overflow:hidden;background:var(--skip-bg)}
|
|
177
|
+
.proj .bar i{display:block;height:100%}
|
|
178
|
+
.section{margin-top:16px}
|
|
179
|
+
.section .body{color:var(--ink-2)}
|
|
180
|
+
|
|
181
|
+
/* ---------- main split ---------- */
|
|
182
|
+
.main{display:grid;grid-template-columns:380px 1fr;max-width:1400px;margin:8px auto 40px;padding:0 28px;gap:16px;min-height:60vh}
|
|
183
|
+
@media (max-width:900px){.main{grid-template-columns:1fr}}
|
|
184
|
+
.list{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);display:flex;flex-direction:column;overflow:hidden;position:sticky;top:12px;max-height:calc(100vh - 24px)}
|
|
185
|
+
.tools{padding:10px;border-bottom:1px solid var(--line);display:flex;gap:8px;flex-wrap:wrap}
|
|
186
|
+
.tools input{flex:1;min-width:120px;padding:7px 10px;border:1px solid var(--line);border-radius:var(--radius);background:var(--bg)}
|
|
187
|
+
.tools select{padding:7px 8px;border:1px solid var(--line);border-radius:var(--radius);background:var(--bg)}
|
|
188
|
+
.items{overflow:auto;flex:1}
|
|
189
|
+
.file{padding:10px 12px 4px;font:12px var(--mono);color:var(--ink-3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;position:sticky;top:0;background:var(--surface)}
|
|
190
|
+
.item{display:flex;gap:10px;align-items:flex-start;width:100%;text-align:left;padding:8px 12px;border-left:3px solid transparent}
|
|
191
|
+
.item:hover{background:var(--surface-2)}
|
|
192
|
+
.item[aria-current=true]{background:var(--surface-2);border-left-color:var(--accent)}
|
|
193
|
+
.item .st{width:10px;height:10px;border-radius:50%;margin-top:5px;flex:none}
|
|
194
|
+
.st.passed{background:var(--pass)} .st.failed,.st.timedOut,.st.interrupted{background:var(--fail)} .st.skipped{background:var(--skip)} .st.flaky{background:var(--flaky)}
|
|
195
|
+
.item .tt{flex:1;min-width:0}
|
|
196
|
+
.item .tt .p{font-size:11px;color:var(--ink-3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
197
|
+
.item .tt .n{font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
198
|
+
.item .d{font:11px var(--mono);color:var(--ink-3);margin-top:3px}
|
|
199
|
+
.empty{padding:40px 20px;text-align:center;color:var(--ink-3)}
|
|
200
|
+
.nudge{font-size:var(--fs-s);color:var(--ink-2);background:var(--surface-2);border:1px dashed var(--line);border-radius:var(--radius);padding:10px 12px;margin-bottom:10px;line-height:1.5} .nudge code{font-family:var(--mono);font-size:12px} .nudge b{color:var(--ink)}
|
|
201
|
+
|
|
202
|
+
/* ---------- detail ---------- */
|
|
203
|
+
.detail{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);padding:22px;min-width:0}
|
|
204
|
+
.crumb{font-size:12px;color:var(--ink-3)} .crumb span+span::before{content:" / ";color:var(--line)}
|
|
205
|
+
.detail h3{font-size:20px;font-weight:600;margin:6px 0 10px;letter-spacing:-.01em}
|
|
206
|
+
.badges{display:flex;gap:6px;flex-wrap:wrap;align-items:center;margin-bottom:18px}
|
|
207
|
+
.badge{font-size:12px;padding:3px 9px;border-radius:999px;font-weight:500}
|
|
208
|
+
.badge.passed{background:var(--pass-bg);color:var(--pass)} .badge.failed,.badge.timedOut,.badge.interrupted{background:var(--fail-bg);color:var(--fail)}
|
|
209
|
+
.badge.skipped{background:var(--skip-bg);color:var(--ink-2)} .badge.flaky{background:var(--flaky-bg);color:#9A6A00}
|
|
210
|
+
.badge.tag{background:var(--surface-2);color:var(--ink-2);font-family:var(--mono)}
|
|
211
|
+
.loc{font:12px var(--mono);color:var(--ink-3)}
|
|
212
|
+
.tabs{display:flex;gap:4px;border-bottom:1px solid var(--line);margin-bottom:16px}
|
|
213
|
+
.tab{padding:8px 12px;font-size:13px;color:var(--ink-2);border-bottom:2px solid transparent;margin-bottom:-1px}
|
|
214
|
+
.tab[aria-selected=true]{color:var(--ink);border-bottom-color:var(--accent)}
|
|
215
|
+
.detail h4{font-size:13px;font-weight:600;color:var(--ink-2);margin:20px 0 8px}
|
|
216
|
+
.err{background:var(--fail-bg);border:1px solid var(--line);padding:12px 14px;border-radius:var(--radius);font:12.5px/1.55 var(--mono);white-space:pre-wrap;word-break:break-word;color:var(--ink)}
|
|
217
|
+
.err+.err{margin-top:10px}
|
|
218
|
+
.err details{margin-top:8px} .err summary{cursor:pointer;color:var(--ink-2);font-family:var(--sans);font-size:12px}
|
|
219
|
+
.err .stack{color:var(--ink-2);margin-top:6px}
|
|
220
|
+
.steps{list-style:none;margin:0;padding:0}
|
|
221
|
+
.steps ul{list-style:none;margin:0;padding-left:18px;border-left:1px solid var(--line)}
|
|
222
|
+
.step{display:flex;gap:8px;align-items:center;padding:4px 6px;border-radius:4px;font-size:13px}
|
|
223
|
+
.step:hover{background:var(--surface-2)}
|
|
224
|
+
.step .tw{width:14px;color:var(--ink-3);font-size:10px;text-align:center;flex:none}
|
|
225
|
+
.step .cat{font:11px var(--mono);color:var(--ink-3);background:var(--surface-2);padding:1px 5px;border-radius:3px}
|
|
226
|
+
.step .t{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
227
|
+
.step .d{font:11px var(--mono);color:var(--ink-3)}
|
|
228
|
+
.step.bad{color:var(--fail)} .step.bad .t{font-weight:500}
|
|
229
|
+
.step .e{font:12px var(--mono);color:var(--fail);padding:2px 0 6px 28px;white-space:pre-wrap}
|
|
230
|
+
li.collapsed>ul{display:none}
|
|
231
|
+
.att{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:10px}
|
|
232
|
+
.att figure{margin:0;border:1px solid var(--line);border-radius:var(--radius);overflow:hidden;background:var(--surface-2)}
|
|
233
|
+
.att img{width:100%;display:block;aspect-ratio:16/10;object-fit:cover;cursor:zoom-in}
|
|
234
|
+
.att figcaption{font:11px var(--mono);padding:6px 8px;color:var(--ink-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
235
|
+
.att .file{padding:12px;position:static;background:none}
|
|
236
|
+
.att .file a{font:12px var(--mono)}
|
|
237
|
+
.txt{background:var(--surface-2);padding:10px 12px;border-radius:var(--radius);font:12px/1.5 var(--mono);white-space:pre-wrap;max-height:260px;overflow:auto}
|
|
238
|
+
.lb{position:fixed;inset:0;background:rgba(0,0,0,.85);display:grid;place-items:center;z-index:10;cursor:zoom-out}
|
|
239
|
+
.bugdlg{position:fixed;inset:0;background:rgba(10,20,40,.55);display:grid;place-items:center;z-index:11;padding:20px}
|
|
240
|
+
.bug-box{background:var(--surface);color:var(--ink);border-radius:12px;width:min(860px,100%);max-height:92vh;display:flex;flex-direction:column;box-shadow:0 30px 80px -20px rgba(0,0,0,.5);border:1px solid var(--line)}
|
|
241
|
+
.bug-head{display:flex;align-items:center;gap:12px;padding:14px 18px;border-bottom:1px solid var(--line)} .bug-head h3{margin:0;font-size:16px} .bug-head .hint{flex:1;color:var(--ink-3);font-size:12px}
|
|
242
|
+
.bug-tools{display:flex;align-items:center;gap:8px;padding:10px 18px;border-bottom:1px solid var(--line)} .bug-tools .grow{flex:1}
|
|
243
|
+
.bug-ta{flex:1;min-height:360px;margin:0;padding:14px 18px;border:0;resize:none;background:var(--surface-2);color:var(--ink);font:12.5px/1.55 var(--mono);outline:none;border-radius:0 0 12px 12px;white-space:pre}
|
|
244
|
+
.btn.primary{background:var(--accent);border-color:var(--accent);color:#fff} .btn.primary.done{background:var(--pass);border-color:var(--pass)}
|
|
245
|
+
.detail .actions .btn{cursor:pointer}
|
|
246
|
+
.lb img{max-width:95vw;max-height:95vh;border-radius:4px}
|
|
247
|
+
.kv{display:grid;grid-template-columns:auto 1fr;gap:4px 14px;font-size:13px}
|
|
248
|
+
.kv dt{color:var(--ink-3)} .kv dd{margin:0}
|
|
249
|
+
|
|
250
|
+
/* overview grid */
|
|
251
|
+
.grid{display:grid;grid-template-columns:repeat(12,1fr);gap:14px;margin-top:22px;align-items:start}
|
|
252
|
+
.grid>.card{grid-column:span 4;min-width:0}
|
|
253
|
+
.grid>.card.w6{grid-column:span 6} .grid>.card.w8{grid-column:span 8} .grid>.card.w12{grid-column:span 12}
|
|
254
|
+
@media (max-width:1100px){.grid>.card,.grid>.card.w6,.grid>.card.w8{grid-column:span 6}}
|
|
255
|
+
@media (max-width:760px){.grid>.card,.grid>.card.w6,.grid>.card.w8,.grid>.card.w12{grid-column:span 12}}
|
|
256
|
+
.card h2 .hint{font-weight:400;color:var(--ink-3);margin-left:8px;text-transform:none;letter-spacing:0;font-size:12px}
|
|
257
|
+
/* donut */
|
|
258
|
+
.donut{display:flex;align-items:center;gap:18px}
|
|
259
|
+
.donut svg{width:132px;height:132px;flex:none}
|
|
260
|
+
.donut .legend{display:grid;grid-template-columns:auto auto auto;gap:4px 10px;font-size:13px;align-items:center}
|
|
261
|
+
.donut .legend .dot{width:10px;height:10px;border-radius:2px}
|
|
262
|
+
.donut .legend .n{font-variant-numeric:tabular-nums;font-weight:600;text-align:right}
|
|
263
|
+
.donut .legend .pc{color:var(--ink-3);font:12px var(--mono)}
|
|
264
|
+
.donut .legend button{display:contents} .donut .legend button:hover span{color:var(--accent)}
|
|
265
|
+
.donut .c{font-size:22px;font-weight:600;fill:var(--ink)} .donut .cl{font-size:10px;fill:var(--ink-3)}
|
|
266
|
+
/* stacked bars (dimensions) */
|
|
267
|
+
.dim{display:flex;flex-direction:column;gap:9px}
|
|
268
|
+
.dim .row{display:grid;grid-template-columns:76px 1fr 44px;gap:10px;align-items:center;font-size:13px;width:100%;text-align:left;border-radius:4px;padding:2px 4px;margin:-2px -4px}
|
|
269
|
+
.dim .row:hover{background:var(--surface-2)}
|
|
270
|
+
.dim .row[aria-pressed=true]{background:var(--surface-2);outline:1px solid var(--line)}
|
|
271
|
+
.dim .k{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
272
|
+
.dim .bar{height:14px;display:flex;border-radius:3px;overflow:hidden;background:var(--skip-bg)}
|
|
273
|
+
.dim .bar i{display:block;height:100%}
|
|
274
|
+
.dim .n{font:12px var(--mono);color:var(--ink-3);text-align:right}
|
|
275
|
+
.dim .n b{color:var(--fail);font-weight:600}
|
|
276
|
+
.legend-inline{display:flex;gap:12px;font-size:11px;color:var(--ink-3);margin-top:10px}
|
|
277
|
+
.legend-inline span::before{content:"";display:inline-block;width:8px;height:8px;border-radius:2px;margin-right:5px;background:var(--c)}
|
|
278
|
+
/* histogram */
|
|
279
|
+
.hist{display:flex;align-items:flex-end;gap:6px;height:110px;padding-top:6px}
|
|
280
|
+
.hist .b{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:flex-end;height:100%;gap:4px}
|
|
281
|
+
.hist .b i{display:block;width:100%;border-radius:3px 3px 0 0;background:var(--accent);opacity:.75;min-height:2px}
|
|
282
|
+
.hist .b i.slow{background:var(--flaky)}
|
|
283
|
+
.hist .b .l{font:10px var(--mono);color:var(--ink-3);white-space:nowrap}
|
|
284
|
+
.hist .b .v{font:11px var(--mono);color:var(--ink-2)}
|
|
285
|
+
/* attention */
|
|
286
|
+
.attn{list-style:none;margin:0;padding:0}
|
|
287
|
+
.attn li{border-top:1px solid var(--line)} .attn li:first-child{border-top:0}
|
|
288
|
+
.attn button{width:100%;text-align:left;padding:8px 0;display:grid;grid-template-columns:auto 1fr auto;gap:10px;align-items:center}
|
|
289
|
+
.attn button:hover .t{color:var(--accent)}
|
|
290
|
+
.attn .t{font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
291
|
+
.attn .m{font:11px var(--mono);color:var(--ink-3)}
|
|
292
|
+
.attn .sev{font-size:11px;padding:2px 7px;border-radius:999px;font-weight:600;background:var(--fail-bg);color:var(--fail);white-space:nowrap}
|
|
293
|
+
.attn .ok{color:var(--pass);font-size:13px;padding:6px 0}
|
|
294
|
+
/* tags */
|
|
295
|
+
.tags{display:flex;flex-wrap:wrap;gap:6px}
|
|
296
|
+
.tags button{display:inline-flex;align-items:center;gap:6px;font:12px var(--mono);padding:4px 8px;border:1px solid var(--line);border-radius:4px;background:var(--surface)}
|
|
297
|
+
.tags button:hover{border-color:var(--accent)}
|
|
298
|
+
.tags .bar{width:40px;height:5px;border-radius:3px;background:var(--skip-bg);display:flex;overflow:hidden}
|
|
299
|
+
.tags .bar i{display:block;height:100%}
|
|
300
|
+
/* meta chips in detail */
|
|
301
|
+
.metas{display:flex;flex-wrap:wrap;gap:6px;margin:-8px 0 18px}
|
|
302
|
+
.meta{display:inline-flex;align-items:center;gap:6px;font-size:12px;padding:4px 9px;border:1px solid var(--line);border-radius:4px;background:var(--surface-2)}
|
|
303
|
+
.meta .k{color:var(--ink-3)} .meta .v{font-weight:500}
|
|
304
|
+
.meta.priority .v,.meta.severity .v{color:var(--fail)}
|
|
305
|
+
.meta.priority.low .v,.meta.severity.low .v{color:var(--ink)}
|
|
306
|
+
|
|
307
|
+
/* videos, traces, visual compare */
|
|
308
|
+
.vids{display:grid;grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:12px}
|
|
309
|
+
.vids figure{margin:0;border:1px solid var(--line);border-radius:var(--radius);overflow:hidden;background:#000}
|
|
310
|
+
.vids video{width:100%;display:block;max-height:420px;background:#000}
|
|
311
|
+
.vids figcaption{font:11px var(--mono);padding:6px 8px;color:var(--ink-2);background:var(--surface-2)}
|
|
312
|
+
.trace-card{border:1px solid var(--line);border-radius:var(--radius);padding:12px 14px;display:flex;flex-direction:column;gap:8px;font-size:13px}
|
|
313
|
+
.trace-how{color:var(--ink-2);font-size:12px} .trace-how code{font:12px var(--mono);background:var(--surface-2);padding:1px 5px;border-radius:3px}
|
|
314
|
+
.trace-card .dl{align-self:flex-start;font-size:12px;padding:6px 10px;border:1px solid var(--accent);border-radius:var(--radius);text-decoration:none}
|
|
315
|
+
.trace-card .dl:hover{background:var(--accent);color:#fff}
|
|
316
|
+
.cmp-tabs{display:flex;gap:4px;border-bottom:1px solid var(--line);margin-bottom:12px}
|
|
317
|
+
.cmp-slider{position:relative;overflow:hidden;border:1px solid var(--line);border-radius:var(--radius);background:var(--surface-2);user-select:none}
|
|
318
|
+
.cmp-slider img{width:100%;display:block}
|
|
319
|
+
.cmp-top{position:absolute;inset:0 auto 0 0;overflow:hidden;width:50%} .cmp-top img{width:auto;height:100%;max-width:none}
|
|
320
|
+
.cmp-slider{aspect-ratio:auto}
|
|
321
|
+
.cmp-handle{position:absolute;top:0;bottom:0;width:2px;background:var(--accent);left:50%;pointer-events:none}
|
|
322
|
+
.cmp-handle::after{content:"⇔";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);background:var(--accent);color:#fff;border-radius:999px;width:26px;height:26px;display:grid;place-items:center;font-size:13px}
|
|
323
|
+
.cmp input[type=range]{width:100%;margin:8px 0 0;accent-color:var(--accent)}
|
|
324
|
+
.cmp-cap{display:flex;justify-content:space-between;font:11px var(--mono);color:var(--ink-3)}
|
|
325
|
+
.cmp-side{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:10px}
|
|
326
|
+
.cmp-side figure,.cmp-one{margin:0;border:1px solid var(--line);border-radius:var(--radius);overflow:hidden;background:var(--surface-2)}
|
|
327
|
+
.cmp-side img,.cmp-one img{width:100%;display:block;cursor:zoom-in}
|
|
328
|
+
.cmp-side figcaption{font:11px var(--mono);padding:5px 8px;color:var(--ink-2)}
|
|
329
|
+
|
|
330
|
+
/* project block */
|
|
331
|
+
.hdr .proj-blk{display:flex;flex-direction:column;line-height:1.25}
|
|
332
|
+
.hdr .proj-blk h1{font-size:15px}
|
|
333
|
+
.hdr .proj-blk .sub{font-size:12px;color:var(--ink-3)} .hdr .proj-blk .sub a{color:var(--ink-3)}
|
|
334
|
+
/* trend */
|
|
335
|
+
.trend svg{width:100%;height:auto;display:block} .trend text{font:10px var(--mono);fill:var(--ink-3)}
|
|
336
|
+
.trend .grid line{stroke:var(--line)} .trend .pass{fill:none;stroke:var(--pass);stroke-width:2}
|
|
337
|
+
.trend .fail{fill:none;stroke:var(--fail);stroke-width:1.5;stroke-dasharray:3 3}
|
|
338
|
+
.trend .pt{fill:var(--surface);stroke:var(--pass);stroke-width:2} .trend .now{fill:var(--accent);stroke:var(--accent)}
|
|
339
|
+
.trend .dur{fill:var(--accent);opacity:.18}
|
|
340
|
+
.trend-cap{display:flex;gap:14px;font-size:11px;color:var(--ink-3);margin-top:8px}
|
|
341
|
+
/* workers */
|
|
342
|
+
.wk{display:flex;flex-direction:column;gap:8px}
|
|
343
|
+
.wk .row{display:grid;grid-template-columns:36px 1fr 120px;gap:10px;align-items:center;font-size:12px}
|
|
344
|
+
.wk .k{font:12px var(--mono);color:var(--ink-3)} .wk .bar{height:12px;display:flex;border-radius:3px;overflow:hidden;background:var(--skip-bg)} .wk .bar i{display:block;height:100%}
|
|
345
|
+
.wk .n{font:11px var(--mono);color:var(--ink-3);text-align:right}
|
|
346
|
+
.wk-sum{font-size:13px;color:var(--ink-2);margin-bottom:10px}
|
|
347
|
+
/* list: group toggle + folder tree */
|
|
348
|
+
.tools .seg,.bug-tools .seg{display:inline-flex;border:1px solid var(--line);border-radius:var(--radius);overflow:hidden}
|
|
349
|
+
.tools .seg button,.bug-tools .seg button{padding:6px 10px;font-size:12px;color:var(--ink-2);cursor:pointer} .tools .seg button[aria-pressed=true],.bug-tools .seg button[aria-pressed=true]{background:var(--surface-2);color:var(--ink)}
|
|
350
|
+
.folder{display:flex;align-items:center;gap:6px;padding:8px 12px 4px;font:12px var(--mono);color:var(--ink-2);width:100%;text-align:left}
|
|
351
|
+
.folder .cnt{margin-left:auto;display:flex;gap:6px} .folder .cnt b{color:var(--fail)} .folder .cnt span{color:var(--ink-3)}
|
|
352
|
+
.folder .tw{font-size:9px;color:var(--ink-3)}
|
|
353
|
+
.folder+.folder,.folder+.file{margin-left:0}
|
|
354
|
+
.suite{display:flex;align-items:center;gap:6px;padding:7px 12px 3px;font-size:12px;color:var(--ink-2)} .suite .sn{font-weight:500;color:var(--ink)} .suite .tw{font-size:9px;color:var(--ink-3)} .suite .cnt{margin-left:auto;display:flex;gap:6px} .suite .cnt b{color:var(--fail)} .suite .cnt span{color:var(--ink-3)}
|
|
355
|
+
.tree-indent{padding-left:14px;border-left:1px solid var(--line);margin-left:16px}
|
|
356
|
+
.file-row{display:flex;align-items:center;gap:6px;padding:6px 12px 2px;font:12px var(--mono);color:var(--ink-3);width:100%;text-align:left}
|
|
357
|
+
.file-row .mini{display:flex;gap:2px;margin-left:auto} .file-row .mini i{width:6px;height:6px;border-radius:50%;display:block}
|
|
358
|
+
/* links in meta */
|
|
359
|
+
.meta a{color:var(--accent);text-decoration:none;font-weight:500} .meta a:hover{text-decoration:underline}
|
|
360
|
+
.meta a::after{content:"↗";font-size:10px;margin-left:3px;color:var(--ink-3)}
|
|
361
|
+
/* logs */
|
|
362
|
+
.logs{background:var(--surface-2);border-radius:var(--radius);padding:8px 0;font:12px/1.55 var(--mono);max-height:320px;overflow:auto}
|
|
363
|
+
.logs .ln{display:grid;grid-template-columns:78px 1fr;gap:12px;padding:1px 12px}
|
|
364
|
+
.logs .ln:hover{background:var(--surface)} .logs .ts{color:var(--ink-3)} .logs .lm{white-space:pre-wrap;word-break:break-word}
|
|
365
|
+
.logs .ln.err .lm{color:var(--fail)} .logs .ln.warn .lm{color:#9A6A00} .logs.plain .ln{grid-template-columns:1fr}
|
|
366
|
+
/* data tables */
|
|
367
|
+
.tbl-wrap{overflow:auto;border:1px solid var(--line);border-radius:var(--radius);max-height:360px}
|
|
368
|
+
table.tbl{border-collapse:collapse;font-size:12.5px;width:100%;min-width:100%}
|
|
369
|
+
.tbl th{position:sticky;top:0;background:var(--surface-2);text-align:left;font-weight:600;padding:7px 10px;border-bottom:1px solid var(--line);white-space:nowrap}
|
|
370
|
+
.tbl td{padding:6px 10px;border-bottom:1px solid var(--line);font-family:var(--mono);font-size:12px;white-space:nowrap;max-width:360px;overflow:hidden;text-overflow:ellipsis}
|
|
371
|
+
.tbl tr:last-child td{border-bottom:0} .tbl td.mask{color:var(--ink-3);letter-spacing:1px}
|
|
372
|
+
.kv2{display:grid;grid-template-columns:max-content 1fr;gap:4px 16px;font-size:13px;border:1px solid var(--line);border-radius:var(--radius);padding:10px 12px}
|
|
373
|
+
.kv2 dt{color:var(--ink-3)} .kv2 dd{margin:0;font-family:var(--mono);font-size:12px;word-break:break-all}
|
|
374
|
+
.mask-note{font-size:11px;color:var(--ink-3);margin-top:6px}
|
|
375
|
+
/* api panel */
|
|
376
|
+
.api{border:1px solid var(--line);border-radius:var(--radius);margin-bottom:10px;overflow:hidden}
|
|
377
|
+
.api-head{display:flex;align-items:center;gap:10px;padding:9px 12px;background:var(--surface-2);cursor:pointer;width:100%;text-align:left}
|
|
378
|
+
.api-head .m{font:11px/1 var(--mono);font-weight:600;padding:4px 7px;border-radius:3px;color:#fff;background:var(--ink-3)}
|
|
379
|
+
.api-head .m.GET{background:#2A7FBF} .api-head .m.POST{background:var(--pass)} .api-head .m.PUT,.api-head .m.PATCH{background:#C77D14} .api-head .m.DELETE{background:var(--fail)}
|
|
380
|
+
.api-head .u{flex:1;font:12px var(--mono);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
381
|
+
.api-head .sc{font:12px var(--mono);font-weight:600} .api-head .sc.ok{color:var(--pass)} .api-head .sc.bad{color:var(--fail)} .api-head .sc.warn{color:#9A6A00}
|
|
382
|
+
.api-head .d{font:11px var(--mono);color:var(--ink-3)}
|
|
383
|
+
.api-body{display:grid;grid-template-columns:1fr 1fr;gap:0}
|
|
384
|
+
@media (max-width:900px){.api-body{grid-template-columns:1fr}}
|
|
385
|
+
.api-col{padding:10px 12px;min-width:0} .api-col+.api-col{border-left:1px solid var(--line)}
|
|
386
|
+
.api-col h5{margin:0 0 6px;font-size:11px;font-weight:600;color:var(--ink-3)}
|
|
387
|
+
.api-col pre{margin:0 0 10px;background:var(--surface-2);padding:8px 10px;border-radius:4px;font:11.5px/1.5 var(--mono);white-space:pre-wrap;word-break:break-all;max-height:260px;overflow:auto}
|
|
388
|
+
.api.collapsed .api-body,.api.collapsed .api-tools{display:none}
|
|
389
|
+
.api-tools{display:flex;gap:8px;padding:8px 12px;border-top:1px solid var(--line);background:var(--surface)} .api-tools .btn{padding:5px 10px;cursor:pointer} .api-tools .btn.done{color:var(--pass);border-color:var(--pass)}
|
|
390
|
+
/* bdd */
|
|
391
|
+
.step .kw{font-weight:600;color:var(--accent);margin-right:4px} .step .kw.and{color:var(--ink-3)}
|
|
392
|
+
.badge.scenario{background:var(--surface-2);color:var(--ink-2)}
|
|
393
|
+
.tools .dims{display:flex;gap:6px;flex-wrap:wrap;width:100%}
|
|
394
|
+
.tools .dims select{flex:1;min-width:90px}
|
|
395
|
+
|
|
396
|
+
/* ---------- blue & white skin ---------- */
|
|
397
|
+
:root{--radius:10px}
|
|
398
|
+
html,body{-webkit-font-smoothing:antialiased}
|
|
399
|
+
.card,.list,.detail{border-radius:var(--radius);box-shadow:var(--shadow)}
|
|
400
|
+
.card h2{color:var(--accent-2);font-size:12px;font-weight:600;letter-spacing:.07em;display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}
|
|
401
|
+
.card h2 .hint{margin-left:0}
|
|
402
|
+
.card h2 .hint.badge{margin-left:auto;font:600 11px var(--mono);padding:2px 8px;border-radius:999px;background:var(--fail-bg);color:var(--fail)}
|
|
403
|
+
.card.fail-rail::before,.card.warn-rail::before{display:none}
|
|
404
|
+
/* top band: stripe + header + nav on a deep accent gradient */
|
|
405
|
+
.band{background:linear-gradient(115deg,var(--accent-deep) 0%,var(--accent-2) 55%,var(--band-end) 100%);color:#fff;position:relative}
|
|
406
|
+
.band::after{content:"";position:absolute;inset:0;background:radial-gradient(700px 260px at 85% -40%,rgba(255,255,255,.18),transparent 60%),radial-gradient(400px 200px at 10% 120%,rgba(255,255,255,.10),transparent 60%);pointer-events:none}
|
|
407
|
+
.band>*{position:relative;z-index:1}
|
|
408
|
+
.stripe{opacity:.9}
|
|
409
|
+
.hdr{background:transparent;border-bottom:0;color:#fff;max-width:1400px;margin:0 auto;padding:18px 28px 0;gap:14px}
|
|
410
|
+
.hdr h1,.hdr .proj-blk h1{color:#fff;font-size:20px;font-weight:600;letter-spacing:-.01em;line-height:1.2}
|
|
411
|
+
.hdr .proj-blk .sub,.hdr .proj-blk .sub a,.hdr .when{color:rgba(255,255,255,.78)}
|
|
412
|
+
.hdr .logo{width:42px;height:42px;border-radius:11px;flex:none;box-shadow:0 0 0 1px rgba(255,255,255,.35),0 6px 16px -6px rgba(0,0,0,.45)} .hdr .logo svg{width:42px;height:42px;display:block;border-radius:11px}
|
|
413
|
+
.hdr img.logo.brand{width:auto;max-width:180px;height:42px;object-fit:contain;border-radius:8px;background:#fff;padding:4px;box-sizing:border-box}
|
|
414
|
+
.hdr img{height:32px;border-radius:6px}
|
|
415
|
+
.hdr .chip{background:rgba(255,255,255,.12);border:1px solid rgba(255,255,255,.22);color:rgba(255,255,255,.85);border-radius:999px;padding:4px 9px}
|
|
416
|
+
.hdr .chip b{color:#fff}
|
|
417
|
+
.hdr .btn{background:rgba(255,255,255,.12);border-color:rgba(255,255,255,.28);color:#fff;border-radius:9px;padding:8px 12px;font-weight:500}
|
|
418
|
+
.hdr .btn:hover{background:rgba(255,255,255,.2);color:#fff}
|
|
419
|
+
.hdr .btn.done{background:var(--pass);border-color:var(--pass);color:#fff}
|
|
420
|
+
.hdr select.pal{background:rgba(255,255,255,.12);border-color:rgba(255,255,255,.28);color:#fff;border-radius:9px;padding:7px 8px}
|
|
421
|
+
.hdr select.pal option{color:var(--ink);background:var(--surface)}
|
|
422
|
+
.hdr .tbtn{border-color:rgba(255,255,255,.28);background:rgba(255,255,255,.12);color:#fff;border-radius:9px;width:34px;height:34px}
|
|
423
|
+
.hdr .tbtn:hover{background:rgba(255,255,255,.2)}
|
|
424
|
+
.nav{background:transparent;border-bottom:0;max-width:1400px;margin:0 auto;padding:0 28px;gap:4px;position:static}
|
|
425
|
+
.nav>div{display:flex;gap:4px;margin-top:16px;overflow-x:auto;width:100%}
|
|
426
|
+
.nav button{padding:10px 14px 12px;font-size:13.5px;font-weight:500;color:rgba(255,255,255,.75);border-bottom:0;margin-bottom:0;border-radius:9px 9px 0 0;white-space:nowrap}
|
|
427
|
+
.nav button:hover{color:#fff;background:rgba(255,255,255,.1)}
|
|
428
|
+
.nav button[aria-selected=true]{background:var(--bg);color:var(--accent-2)}
|
|
429
|
+
.nav .cnt{background:rgba(255,255,255,.16);color:#fff;font-size:11.5px;padding:1px 7px}
|
|
430
|
+
.nav button[aria-selected=true] .cnt{background:var(--accent-tint);color:var(--accent-2)}
|
|
431
|
+
.nav .cnt.bad{background:var(--fail);color:#fff}
|
|
432
|
+
.nav button[aria-selected=true] .cnt.bad{background:var(--fail);color:#fff}
|
|
433
|
+
@media (max-width:700px){.nav{padding:0 16px} .hdr{padding:14px 16px 0;flex-wrap:wrap;gap:10px} .hdr h1,.hdr .proj-blk h1{font-size:17px} .hdr .when,.hdr .spacer{display:none} .hdr .hmeta{width:100%;margin-left:0} .hdr .ctl{margin-left:auto} .hdr .proj-blk{flex:1;min-width:0}}
|
|
434
|
+
/* KPI tiles replace the verdict row */
|
|
435
|
+
.sum{padding:22px 28px 20px}
|
|
436
|
+
.kpis{display:grid;grid-template-columns:repeat(6,1fr);gap:14px}
|
|
437
|
+
.kpi{position:relative;overflow:hidden;text-align:left;background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);padding:14px 16px 14px 20px;box-shadow:var(--shadow);display:block;font-size:inherit;color:var(--ink);transition:transform .12s,box-shadow .12s}
|
|
438
|
+
.kpi::before{content:"";position:absolute;left:0;top:0;bottom:0;width:4px;background:var(--c,var(--accent))}
|
|
439
|
+
.kpi:hover{transform:translateY(-1px);box-shadow:0 2px 4px rgba(11,31,68,.06),0 14px 28px -14px rgba(26,86,219,.3)}
|
|
440
|
+
.kpi .l{font-size:11.5px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-3)}
|
|
441
|
+
.kpi .v{font-size:28px;font-weight:600;line-height:1.15;letter-spacing:-.02em;margin-top:6px;color:var(--ink);font-variant-numeric:tabular-nums}
|
|
442
|
+
.kpi .v small{font-size:13px;font-weight:500;color:var(--ink-3);letter-spacing:0;margin-left:4px}
|
|
443
|
+
.kpi .d{font-size:12px;color:var(--ink-3);margin-top:4px}
|
|
444
|
+
.kpi .d.up{color:var(--pass)} .kpi .d.down{color:var(--fail)}
|
|
445
|
+
.kpi[aria-pressed=true]{border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-tint),var(--shadow)}
|
|
446
|
+
.kpi.hero{grid-column:span 2;background:linear-gradient(135deg,var(--accent) 0%,var(--accent-2) 100%);border-color:transparent;color:#fff;display:flex;align-items:center;gap:18px;padding:16px 20px}
|
|
447
|
+
.kpi.hero::before{display:none}
|
|
448
|
+
.kpi.hero .l,.kpi.hero .d{color:rgba(255,255,255,.8)} .kpi.hero .v{color:#fff;font-size:38px} .kpi.hero .v small{color:rgba(255,255,255,.78)}
|
|
449
|
+
.kpi.hero .body{flex:1;min-width:0}
|
|
450
|
+
.kpi.hero .ring{width:84px;height:84px;flex:none} .kpi.hero .ring svg{width:84px;height:84px;display:block}
|
|
451
|
+
.kpi.hero .ring text{fill:#fff;font-weight:600;font-size:17px;font-family:var(--sans)}
|
|
452
|
+
.kpi.hero .mini{margin-top:8px;height:6px;border-radius:999px;background:rgba(255,255,255,.22);overflow:hidden;display:flex} .kpi.hero .mini i{display:block;height:100%}
|
|
453
|
+
.kpi.hero[aria-pressed=true]{box-shadow:0 0 0 3px var(--accent-soft),var(--shadow)}
|
|
454
|
+
:root[data-palette=mono] .kpi.hero{background:linear-gradient(135deg,var(--accent-2),var(--accent-deep))}
|
|
455
|
+
@media (max-width:1100px){.kpis{grid-template-columns:repeat(3,1fr)} .kpi.hero{grid-column:span 3}}
|
|
456
|
+
@media (max-width:640px){.sum{padding:16px 16px 12px} .kpis{grid-template-columns:repeat(2,1fr)} .kpi.hero{grid-column:span 2}}
|
|
457
|
+
/* run strip */
|
|
458
|
+
.strip{margin-top:18px} .cell{height:14px;border-radius:3px}
|
|
459
|
+
/* overview cards */
|
|
460
|
+
.grid{gap:16px;margin-top:18px;align-items:stretch} .grid>.card{display:flex;flex-direction:column;min-height:0} .grid>.card>h2{flex:none}
|
|
461
|
+
.attn button{padding:10px 6px;gap:12px;border-radius:8px;margin:0 -6px;width:calc(100% + 12px)}
|
|
462
|
+
.attn button:hover{background:var(--surface-2)} .attn button:hover .t{color:var(--ink)}
|
|
463
|
+
.attn .t{font-weight:500}
|
|
464
|
+
.attn .sev{font:600 11px var(--mono);padding:3px 8px;border-radius:6px}
|
|
465
|
+
.attn .sev.p0{background:var(--fail);color:#fff}
|
|
466
|
+
.attn .proj{display:inline-block;flex-direction:row;width:auto;border-radius:4px;padding:1px 6px;font-size:11px;margin-left:8px;vertical-align:1px}
|
|
467
|
+
.attn .m{font:12px var(--sans);color:var(--ink-3);display:inline-flex;align-items:center;gap:6px}
|
|
468
|
+
.attn .av{display:inline-grid;place-items:center;width:22px;height:22px;border-radius:50%;background:var(--accent-tint);color:var(--accent-2);font-size:10px;font-weight:600;text-transform:uppercase}
|
|
469
|
+
.clu{gap:10px}
|
|
470
|
+
.clu li{border-left:1px solid var(--line);border-radius:10px;padding:10px 12px}
|
|
471
|
+
.clu .top{align-items:flex-start} .clu .msg{font-size:12.5px}
|
|
472
|
+
.clu .n{font:600 11px var(--mono);padding:2px 8px;border-radius:999px;background:var(--fail-bg);color:var(--fail);white-space:nowrap}
|
|
473
|
+
.clu .who{gap:6px;margin-top:8px}
|
|
474
|
+
.clu .who button{font-size:11.5px;padding:3px 9px;background:var(--accent-tint);color:var(--accent-2)} .clu .who button:hover{outline:0;background:var(--accent-soft)}
|
|
475
|
+
.btn.more{margin-top:12px;border-color:var(--line-2);color:var(--accent-2);font-weight:500;font-size:12.5px;padding:7px 12px;border-radius:8px}
|
|
476
|
+
.bk-tabs{gap:4px;padding:4px;background:var(--surface-2);border-radius:10px;width:max-content;max-width:100%}
|
|
477
|
+
.bk-tabs button{padding:5px 11px;font-size:12.5px;font-weight:500;border-radius:7px}
|
|
478
|
+
.bk-tabs button[aria-selected=true]{background:var(--surface);color:var(--accent-2);box-shadow:0 1px 3px rgba(11,31,68,.12)}
|
|
479
|
+
.bk-tabs button:hover{background:var(--surface)}
|
|
480
|
+
.dim{gap:6px} .dim .row{padding:6px 8px;margin:0;border-radius:8px;grid-template-columns:110px 1fr 64px;gap:12px}
|
|
481
|
+
.dim .k{font:600 12.5px var(--mono);color:var(--ink-2)} .dim .bar{height:12px;border-radius:999px;background:var(--surface-2)}
|
|
482
|
+
.dim .row[aria-pressed=true]{background:var(--accent-tint);outline:0}
|
|
483
|
+
.legend-inline{font-size:12px;gap:14px;margin-top:12px} .legend-inline span::before{width:9px;height:9px;border-radius:3px;margin-right:6px}
|
|
484
|
+
.slow li{padding:9px 0} .slow button{display:grid;grid-template-columns:1fr auto;gap:10px;align-items:start}
|
|
485
|
+
.slow .t{white-space:normal}
|
|
486
|
+
.slow .bar{display:block;height:5px;border-radius:999px;background:var(--accent-soft);opacity:1;margin-top:6px;position:relative;overflow:hidden;width:100%!important}
|
|
487
|
+
.slow .bar i{position:absolute;inset:0;width:var(--w);background:var(--accent);border-radius:999px}
|
|
488
|
+
.slow button:hover .t{color:var(--accent-2)}
|
|
489
|
+
.trend .grid line{stroke-dasharray:2 4} .trend text{font-size:11px}
|
|
490
|
+
.trend{position:relative} .trend .area{fill:var(--pass);opacity:.12;pointer-events:none} .trend .dur{fill:var(--accent);opacity:.14} .trend .hit{cursor:crosshair} .trend .hit:hover{fill:var(--accent);fill-opacity:.06} .trend .guide{stroke:var(--accent);stroke-width:1;stroke-dasharray:3 3;pointer-events:none}
|
|
491
|
+
.ttip{position:absolute;z-index:6;min-width:200px;max-width:240px;background:var(--surface);border:1px solid var(--line-2);border-radius:10px;box-shadow:0 10px 30px -10px rgba(11,31,68,.35);padding:10px 12px;font-size:12.5px;pointer-events:none}
|
|
492
|
+
.ttip .tt-h{font-weight:600;display:flex;justify-content:space-between;gap:10px;align-items:baseline} .ttip .tt-h span{font:11px var(--mono);color:var(--ink-3);font-weight:400}
|
|
493
|
+
.ttip .tt-big{font-size:20px;font-weight:600;margin:4px 0 6px;font-variant-numeric:tabular-nums} .ttip .tt-big small{font-size:11.5px;font-weight:400;color:var(--ink-3)}
|
|
494
|
+
.ttip .tt-row{display:flex;align-items:center;gap:8px;padding:2px 0;color:var(--ink-2)} .ttip .tt-row i{width:8px;height:8px;border-radius:2px;flex:none} .ttip .tt-row b{margin-left:auto;font-variant-numeric:tabular-nums;color:var(--ink)}
|
|
495
|
+
.trend .pass{stroke-width:2.2} .trend .pt.now{r:4.5}
|
|
496
|
+
.trend-cap{font-size:12px;gap:16px}
|
|
497
|
+
.section .body code{font:12.5px var(--mono);background:var(--accent-tint);color:var(--accent-2);padding:1px 6px;border-radius:5px}
|
|
498
|
+
.hist .b i{opacity:.85;border-radius:4px 4px 0 0}
|
|
499
|
+
.wk .bar,.proj .bar{border-radius:999px}
|
|
500
|
+
/* tests view */
|
|
501
|
+
.main{margin-top:20px}
|
|
502
|
+
.list{top:12px;max-height:calc(100vh - 24px)}
|
|
503
|
+
.tools{padding:12px;gap:8px;background:var(--surface)}
|
|
504
|
+
.tools input,.tools select{border-radius:8px;background:var(--bg);border-color:var(--line)}
|
|
505
|
+
.tools input:focus,.tools select:focus{border-color:var(--accent);outline:0;box-shadow:0 0 0 3px var(--accent-tint)}
|
|
506
|
+
.tools .seg,.bug-tools .seg{border-radius:8px} .tools .seg button[aria-pressed=true],.bug-tools .seg button[aria-pressed=true]{background:var(--accent-tint);color:var(--accent-2);font-weight:500}
|
|
507
|
+
.item{border-left-width:3px;padding:9px 12px}
|
|
508
|
+
.item[aria-current=true]{background:var(--accent-tint);border-left-color:var(--accent)}
|
|
509
|
+
.item .tt .n{font-weight:500}
|
|
510
|
+
.file{background:var(--surface);color:var(--accent-2);font-weight:500}
|
|
511
|
+
.hint-kbd{background:var(--surface-2)} .kbd{background:var(--surface);border-color:var(--line-2);border-bottom-width:2px;border-radius:5px;padding:0 5px}
|
|
512
|
+
.detail{padding:24px 26px}
|
|
513
|
+
.detail h3{font-size:21px}
|
|
514
|
+
.badge{font-weight:600;font-size:11.5px}
|
|
515
|
+
.badge.tag{font-weight:500}
|
|
516
|
+
.tabs{gap:6px} .tab{border-radius:8px 8px 0 0;font-weight:500}
|
|
517
|
+
.tab[aria-selected=true]{color:var(--accent-2);border-bottom-color:var(--accent)}
|
|
518
|
+
.detail h4{color:var(--accent-2);text-transform:uppercase;letter-spacing:.06em;font-size:11.5px}
|
|
519
|
+
.err{border-radius:8px}
|
|
520
|
+
.meta{border-radius:8px;background:var(--surface)}
|
|
521
|
+
.meta .k{text-transform:uppercase;font-size:10.5px;letter-spacing:.05em}
|
|
522
|
+
.step{border-radius:6px} .step .cat{border-radius:4px}
|
|
523
|
+
.api{border-radius:10px} .api-head .m{border-radius:5px}
|
|
524
|
+
.att figure,.vids figure,.trace-card,.cmp-slider,.cmp-side figure,.cmp-one,.tbl-wrap,.kv2{border-radius:10px}
|
|
525
|
+
/* failures / api tables */
|
|
526
|
+
.apitbl th{color:var(--accent-2);text-transform:uppercase;letter-spacing:.06em;font-size:11px;background:var(--surface);top:0}
|
|
527
|
+
.apitbl td{padding:10px} .apitbl tr:hover td{background:var(--accent-tint)}
|
|
528
|
+
.api-stats{gap:10px;flex-wrap:wrap} .api-stats span{background:var(--surface);border:1px solid var(--line);border-radius:999px;padding:5px 12px;box-shadow:var(--shadow)}
|
|
529
|
+
.api-stats b{margin-right:4px}
|
|
530
|
+
.view-pad{padding-top:20px}
|
|
531
|
+
/* misc */
|
|
532
|
+
.toast{background:var(--accent-2);color:#fff}
|
|
533
|
+
.lb img{border-radius:10px}
|
|
534
|
+
@media print{ .band{background:#fff!important;color:var(--ink)} .hdr h1,.hdr .proj-blk h1,.hdr .when,.hdr .proj-blk .sub{color:var(--ink)} .nav{display:none} .kpi.hero{background:var(--accent)!important} }
|
|
535
|
+
|
|
536
|
+
/* ---------- triage lists: plain, dense, table-like ---------- */
|
|
537
|
+
.attn-wrap{display:flex;flex-direction:column;flex:1;min-height:0}
|
|
538
|
+
.attn2{width:100%;border-collapse:collapse;font-size:13px}
|
|
539
|
+
.attn2 tr{cursor:pointer} .attn2 tr:hover td{background:var(--surface-2)} .attn2 tr:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
|
|
540
|
+
.attn2 td{padding:9px 8px;border-top:1px solid var(--line);vertical-align:top} .attn2 tr:first-child td{border-top:0}
|
|
541
|
+
.attn2 td:first-child{border-radius:6px 0 0 6px} .attn2 td:last-child{border-radius:0 6px 6px 0}
|
|
542
|
+
.attn2 .pr{width:96px;white-space:nowrap;font-size:12.5px;line-height:1.35} .attn2 .pr .dot{display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:7px}
|
|
543
|
+
.attn2 .pr span{font-weight:600;color:var(--ink)} .attn2 .pr small{display:block;color:var(--ink-3);font-size:11.5px;padding-left:15px}
|
|
544
|
+
.attn2 .tt .n{font-weight:500;color:var(--ink);line-height:1.35} .attn2 .tt .s{font-size:12px;color:var(--ink-3);margin-top:2px} .attn2 .tt .s b.new{color:var(--fail);font-weight:600} .attn2 .tt .s .rsn{color:var(--ink-2)}
|
|
545
|
+
.attn2 .ow{text-align:right;color:var(--ink-3);font-size:12.5px;white-space:nowrap;width:1%;padding-top:10px}
|
|
546
|
+
.attn-foot{margin-top:auto;padding-top:12px;border-top:1px solid var(--line)} .attn-foot button{font-size:12.5px;font-weight:500;color:var(--accent-2)} .attn-foot button:hover{text-decoration:underline}
|
|
547
|
+
.clu2{list-style:none;margin:0;padding:0}
|
|
548
|
+
.clu2 li{display:grid;grid-template-columns:44px 1fr;gap:12px;padding:11px 0;border-top:1px solid var(--line)} .clu2 li:first-child{border-top:0;padding-top:2px}
|
|
549
|
+
.clu2 .n{font-size:20px;font-weight:600;color:var(--fail);font-variant-numeric:tabular-nums;line-height:1.1} .clu2 .n small{display:block;font-size:10.5px;color:var(--ink-3);font-weight:500;letter-spacing:.04em;margin-top:1px}
|
|
550
|
+
.clu2 .b{min-width:0} .clu2 .msg{font:12.5px/1.45 var(--mono);color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
551
|
+
.clu2 .who{font-size:12.5px;color:var(--ink-2);margin-top:4px;line-height:1.6} .clu2 .who button{color:var(--accent-2);font-weight:500} .clu2 .who button:hover{text-decoration:underline} .clu2 .who button small{color:var(--ink-3);font-weight:400;font-size:11px}
|
|
552
|
+
.clu2 .who .sep{color:var(--line-2);margin:0 7px} .clu2 .who .ex{color:var(--ink-3)}
|
|
553
|
+
@media (max-width:640px){.attn2 .ow{display:none} .attn2 .pr{width:72px} .attn2 .pr small{display:none}}
|
|
554
|
+
/* ---------- run status, errors outside tests, snippets ---------- */
|
|
555
|
+
.att-err{padding:12px 14px;background:var(--fail-bg);color:var(--ink);border-radius:8px 8px 0 0;line-height:1.5} .att-err code{font:12px var(--mono);background:var(--surface);padding:1px 5px;border-radius:4px}
|
|
556
|
+
.runbanner{margin-bottom:14px;padding:10px 14px;border-radius:10px;background:var(--flaky-bg);color:var(--flaky-ink);border:1px solid color-mix(in srgb,var(--flaky) 40%,transparent)}
|
|
557
|
+
.note{padding:10px 14px;border-radius:8px;margin-bottom:10px;border:1px solid var(--line)} .note.ok{background:var(--pass-bg);color:var(--ink)} .note.warn{background:var(--flaky-bg);color:var(--flaky-ink)}
|
|
558
|
+
.badge.xfail{background:var(--flaky-bg);color:var(--flaky-ink)}
|
|
559
|
+
.errwrap+.errwrap{margin-top:14px}
|
|
560
|
+
.why{border:1px solid var(--line);border-radius:var(--radius);padding:10px 14px;margin-bottom:10px;background:var(--surface)}
|
|
561
|
+
.why-c{font-size:12.5px;color:var(--ink);margin-bottom:2px;line-height:1.4} .why-c .why-k{margin-right:2px}
|
|
562
|
+
.why-l{display:flex;align-items:center;gap:8px;margin-bottom:4px} .why-k{font-size:12px;font-weight:600;color:var(--fail)} .why-a{font:11.5px var(--mono);color:var(--ink-3)}
|
|
563
|
+
.why-s{font-size:var(--fs);color:var(--ink);line-height:1.45} .why-h{font-size:12.5px;color:var(--ink-2);margin-top:4px;line-height:1.45}
|
|
564
|
+
.why.assertion .why-k,.why.visual .why-k{color:#9A6A00}
|
|
565
|
+
.why.script .why-k,.why.thrown .why-k,.why.file .why-k{color:var(--ink-2)}
|
|
566
|
+
.errloc{font-family:var(--mono);color:var(--ink-3);margin-bottom:6px} .errloc a{color:var(--accent-2);text-decoration:none} .errloc a:hover{text-decoration:underline}
|
|
567
|
+
.snip{margin:10px 0 0;background:var(--surface-2);border:1px solid var(--line);border-radius:8px;padding:10px 12px;font-family:var(--mono);line-height:1.55;white-space:pre;overflow:auto;color:var(--ink-2)}
|
|
568
|
+
/* ---------- triage extras: history, diff, export, env, heatmap ---------- */
|
|
569
|
+
.kpi .sp{position:absolute;right:14px;top:14px;opacity:.9} .kpi.hero .sp{right:16px;top:14px}
|
|
570
|
+
.kpi .sp svg{display:block}
|
|
571
|
+
.badge.since{background:none;padding:0;border-radius:0;font-weight:500;font-size:12.5px} .badge.since.new{color:var(--fail);font-weight:600} .badge.since.known{color:var(--ink-3)}
|
|
572
|
+
.since-txt{font-size:12.5px;white-space:nowrap} .since-txt.new{color:var(--fail);font-weight:600} .since-txt.known{color:var(--ink-2)}
|
|
573
|
+
.attn .tag.since{margin-left:8px;flex:none} .attn .t{display:flex;align-items:center;min-width:0} .attn .t .tt{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0} .attn .t .proj{flex:none}
|
|
574
|
+
.detail h4 .hint{margin-left:8px;font-weight:400;text-transform:none;letter-spacing:0;color:var(--ink-3);font-size:12px}
|
|
575
|
+
.dots{display:inline-flex;gap:3px;align-items:center;vertical-align:middle} .dots i{display:block;width:8px;height:8px;border-radius:2px;background:var(--skip-bg)}
|
|
576
|
+
.dots i.p{background:var(--pass)} .dots i.f{background:var(--fail)} .dots i.k{background:var(--flaky)} .dots i.s{background:var(--skip)} .dots i.n{background:transparent;border:1px solid var(--line-2)}
|
|
577
|
+
.badges .dots{margin-left:2px;margin-right:4px}
|
|
578
|
+
.flk{list-style:none;margin:0;padding:0} .flk li{border-top:1px solid var(--line)} .flk li:first-child{border-top:0}
|
|
579
|
+
.flk button{width:100%;text-align:left;padding:9px 4px;display:grid;grid-template-columns:1fr auto;gap:4px 12px;align-items:center}
|
|
580
|
+
.flk .t{font-size:13px;font-weight:500;color:var(--ink)} .flk .m{grid-column:1/-1;font-size:12px;color:var(--ink-3)}
|
|
581
|
+
.own{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:10px} .own li{border:1px solid var(--line);border-radius:10px;min-width:0}
|
|
582
|
+
.own button{width:100%;text-align:left;padding:10px 12px;display:grid;grid-template-columns:1fr auto;gap:2px 12px;align-items:center;border-radius:10px}
|
|
583
|
+
.own button:hover{background:var(--surface-2)}
|
|
584
|
+
.own .nm{font-weight:600} .own .cnts{font-size:12.5px;color:var(--ink-3);white-space:nowrap} .own .cnts b{font-weight:600}
|
|
585
|
+
.own .cnts b.f{color:var(--fail)} .own .cnts b.k{color:var(--flaky-ink)}
|
|
586
|
+
.own .ts{grid-column:1/-1;font-size:12px;color:var(--ink-3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
587
|
+
.fx-tools{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:-4px} .fx-tools .fx-sum{font-size:13px;color:var(--ink-2);font-weight:500} .fx-tools .spacer{flex:1}
|
|
588
|
+
a.btn{text-decoration:none}
|
|
589
|
+
.skp{list-style:none;margin:0;padding:0} .skp li{border-top:1px solid var(--line)} .skp li:first-child{border-top:0}
|
|
590
|
+
.skp button{width:100%;text-align:left;padding:8px 4px;display:flex;flex-direction:column;gap:2px}
|
|
591
|
+
.skp .t{font-size:13px;font-weight:500;color:var(--ink)} .skp .r{font-size:12px;color:var(--ink-3)}
|
|
592
|
+
.gchart .gchart-head{display:flex;justify-content:space-between;align-items:flex-start;gap:12px}
|
|
593
|
+
.gchart .gchart-head h2{margin:0}
|
|
594
|
+
.gchart .gchart-sub{color:var(--ink-3);font-size:12px;margin-top:4px}
|
|
595
|
+
.gchart .gchart-body{margin-top:14px}
|
|
596
|
+
.gchart .empty{padding:22px 0;color:var(--ink-3);text-align:center}
|
|
597
|
+
.graphs-grid .card{background:var(--surface)}
|
|
598
|
+
.kv.env{grid-template-columns:max-content 1fr;gap:8px 16px} .kv.env dt{font-size:11.5px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;padding-top:1px} .kv.env dd{font:12.5px var(--mono);word-break:break-word} .kv.env a{color:var(--accent-2)}
|
|
599
|
+
.hm-wrap{overflow-x:auto} .hm{border-collapse:separate;border-spacing:4px;font-size:12.5px;min-width:100%}
|
|
600
|
+
.hm th{font-weight:600;color:var(--ink-2);text-align:left;padding:4px 8px;white-space:nowrap} .hm thead th{font:600 11px var(--mono);color:var(--ink-3);text-align:center;letter-spacing:.03em}
|
|
601
|
+
.hm td{padding:0;border-radius:8px;text-align:center;min-width:90px} .hm td button{width:100%;padding:9px 8px;font-variant-numeric:tabular-nums;border-radius:8px} .hm td small{color:inherit;opacity:.65;margin-left:2px}
|
|
602
|
+
.hm td.ok{background:var(--pass-bg);color:var(--pass)} .hm td.warn{background:var(--flaky-bg);color:var(--flaky-ink)} .hm td.bad{background:color-mix(in srgb,var(--fail) calc(var(--a,.5)*100%),var(--surface))} .hm td b{color:inherit}
|
|
603
|
+
.grid>.fx-tools{grid-column:span 12}
|
|
604
|
+
.hm td.none{color:var(--ink-3);padding:9px 8px;background:var(--surface-2)}
|
|
605
|
+
.hm td button:hover{outline:2px solid var(--accent);outline-offset:-2px}
|
|
606
|
+
.ediff{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:10px}
|
|
607
|
+
.ediff .side{border:1px solid var(--line);border-radius:8px;overflow:hidden}
|
|
608
|
+
.ediff .lbl{font:600 11px var(--mono);letter-spacing:.04em;padding:6px 10px;border-bottom:1px solid var(--line)}
|
|
609
|
+
.ediff .exp .lbl{background:var(--pass-bg);color:var(--pass)} .ediff .rcv .lbl{background:var(--fail-bg);color:var(--fail)}
|
|
610
|
+
.ediff .val{font:12.5px/1.6 var(--mono);padding:10px 12px;white-space:pre-wrap;word-break:break-word;color:var(--ink)}
|
|
611
|
+
.ediff mark{border-radius:3px;padding:0 1px;color:inherit} .ediff mark.del{background:var(--pass-bg);text-decoration:line-through;text-decoration-color:var(--pass)} .ediff mark.ins{background:var(--fail-bg);box-shadow:inset 0 -2px var(--fail)}
|
|
612
|
+
.ediff.lines{display:block;border:1px solid var(--line);border-radius:8px;overflow:hidden;font:12.5px/1.55 var(--mono);white-space:pre-wrap;word-break:break-word}
|
|
613
|
+
.ediff.lines .ln{padding:1px 12px} .ediff.lines .ln.exp{background:var(--pass-bg);color:var(--pass)} .ediff.lines .ln.rcv{background:var(--fail-bg);color:var(--fail)} .ediff.lines .ln.hunk{color:var(--ink-3)}
|
|
614
|
+
.errfull{margin-bottom:10px} .errfull summary{cursor:pointer;font-size:12px;color:var(--ink-2);margin-bottom:6px}
|
|
615
|
+
.step .tb{width:96px;height:6px;border-radius:999px;background:var(--surface-2);overflow:hidden;flex:none} .step .tb i{display:block;height:100%;background:var(--accent);border-radius:999px;opacity:.85} .step .tb i.slow{background:var(--flaky);opacity:1}
|
|
616
|
+
@media (max-width:700px){.ediff{grid-template-columns:1fr} .step .tb{width:48px} .kpi .sp{display:none}}
|
|
617
|
+
@media print{.fx-tools .btn{display:none}}
|
|
618
|
+
|
|
619
|
+
/* ---------- typography system: 3 sizes, sentence-case headings, weight for hierarchy, mono only for data ---------- */
|
|
620
|
+
:root{--fs:13.5px;--fs-s:12px;--fs-n:28px;--fs-n2:20px}
|
|
621
|
+
html,body{font-size:var(--fs)}
|
|
622
|
+
/* sizes: everything secondary is 12px, everything primary is 13.5px */
|
|
623
|
+
.hint,.card h2 .hint,.strip-cap,.legend-inline,.trend-cap,.kpi .l,.kpi .d,.chip,.hdr .when,.hdr .proj-blk .sub,.nav .cnt,.badge,.badge.tag,.badge.since,.since-txt,.loc,.crumb,.meta,.meta .k,.item .tt .p,.item .d,.file,.folder,.file-row,.kbd,.hint-kbd,.step .cat,.step .d,.step .e,.att figcaption,.vids figcaption,.cmp-cap,.cmp-side figcaption,.api-head .m,.api-head .d,.api-head .sc,.api-col h5,.api-col pre,.hist .l,.hist .v,.wk .k,.wk .n,.wk-sum,.dim .n,.dim .k,.tags button,.mask-note,.trace-how,.trace-how code,.tbl td,.kv2 dd,.logs,.txt,.apitbl th,.apitbl .u,.apitbl .t,.attn2 .pr,.attn2 .pr small,.attn2 .tt .s,.attn2 .ow,.clu2 .n small,.clu2 .msg,.clu2 .who,.clu2 .who button small,.flk .m,.skp .r,.own .cnts,.own .ts,.kv.env dt,.kv.env dd,.hm thead th,.hm td button,.ediff .lbl,.ediff .val,.ediff.lines,.errfull summary,.ttip,.ttip .tt-h span,.ttip .tt-big small,.tt-row,.fx-tools .fx-sum,.attn-foot button,.btn,.hdr .btn,.hdr select.pal,.bk-tabs button,.tools .seg button,.tools input,.tools select,.detail .actions .btn,.section .body code,.err summary,.err .stack,.dots+*{font-size:var(--fs-s)}
|
|
624
|
+
.err,.step,.tab,.nav button,.item .tt .n,.attn2,.attn2 .tt .n,.flk .t,.skp .t,.slow li,.slow .t,.own .nm,.api-stats,.apitbl,.apitbl td,.section .body,.kv,.kv2,.proj .row,.detail h4,.tools input,.tools select,.clu2 .who,.ttip .tt-h,.pill,.empty,.ok,.hm,.hm th,.trace-card,.attn-foot button,.fx-tools .fx-sum{font-size:var(--fs)}
|
|
625
|
+
.kpi .v,.kpi.hero .v{font-size:var(--fs-n)} .kpi .v small{font-size:var(--fs-s)}
|
|
626
|
+
.clu2 .n,.ttip .tt-big{font-size:var(--fs-n2)} .detail h3{font-size:20px} .hdr h1,.hdr .proj-blk h1{font-size:18px}
|
|
627
|
+
/* headings: sentence case, semibold, ink. Uppercase only on table headers */
|
|
628
|
+
.card h2,.detail h4,.kpi .l,.meta .k,.kv.env dt,.api-col h5,.ediff .lbl,.hm thead th{text-transform:none;letter-spacing:0}
|
|
629
|
+
.card h2{font-size:14px;font-weight:600;color:var(--ink);margin-bottom:12px}
|
|
630
|
+
.detail h4{font-weight:600;color:var(--ink);margin:22px 0 8px}
|
|
631
|
+
.kpi .l{font-weight:500;color:var(--ink-3)} .kpi.hero .l{color:rgba(255,255,255,.8)}
|
|
632
|
+
.meta .k,.kv.env dt,.api-col h5{font-weight:500;color:var(--ink-3)}
|
|
633
|
+
.apitbl th{text-transform:uppercase;letter-spacing:.05em;font-size:11.5px;font-weight:600;color:var(--ink-3)}
|
|
634
|
+
.hm thead th{font-weight:600;color:var(--ink-2);font-family:var(--sans)}
|
|
635
|
+
/* weight carries hierarchy: titles 500, body 400, numbers 600. Blue text only on links */
|
|
636
|
+
.attn2 .tt .n,.flk .t,.skp .t,.slow .t,.item .tt .n,.own .nm,.clu2 .who button,.attn-foot button{font-weight:500}
|
|
637
|
+
.kpi .v,.clu2 .n,.ttip .tt-big,.own .cnts b,.dim .n b,.api-stats b{font-weight:600}
|
|
638
|
+
.file{color:var(--ink-2);font-weight:500} .step .kw{color:var(--ink);font-weight:600} .step .kw.and{color:var(--ink-3);font-weight:500}
|
|
639
|
+
.nav button[aria-selected=true]{color:var(--ink)} .nav button[aria-selected=true] .cnt{background:var(--surface-2);color:var(--ink-2)}
|
|
640
|
+
.bk-tabs button[aria-selected=true],.tools .seg button[aria-pressed=true]{color:var(--ink)}
|
|
641
|
+
.tab[aria-selected=true]{color:var(--ink)} .section .body code{color:var(--ink-2);background:var(--surface-2)}
|
|
642
|
+
.ttip .tt-h{font-weight:600} .attn2 .pr span{font-weight:600}
|
|
643
|
+
/* mono only where the text is data: paths, ids, durations, errors, payloads */
|
|
644
|
+
.nav .cnt,.chip,.step .cat,.folder,.item .d,.dim .k,.wk .n,.wk-sum,.attn2 .pr,.clu2 .n small,.flk .m,.own .cnts,.ediff .lbl,.ttip .tt-h span,.tags button,.hint-kbd,.trace-how,.api-col h5,.meta .k,.kv.env dt,.apitbl th,.hm thead th,.hm td button{font-family:var(--sans)}
|
|
645
|
+
.chip b,.loc,.file,.file-row,.kbd,.slow .d,.step .d,.hist .l,.wk .k,.tbl td,.kv2 dd,.kv.env dd,.logs,.txt,.err,.ediff .val,.ediff.lines,.clu2 .msg,.apitbl .u,.api-head .m,.api-head .sc,.api-head .d,.api-col pre,.badge.tag,.trend text,.tl text,.attn2 .tt .s .mono,.trace-how code{font-family:var(--mono)}
|
|
646
|
+
.chip{font-family:var(--sans)} .chip b{font-weight:500}
|
|
647
|
+
__RL_ACCENT_CSS____RL_CUSTOM_CSS__</style>
|
|
648
|
+
</head>
|
|
649
|
+
<body>
|
|
650
|
+
<div id="app"></div>
|
|
651
|
+
<template id="rl-logo"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><defs><linearGradient id="rl-bg" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="#1A56DB"/><stop offset="1" stop-color="#0A2A6B"/></linearGradient><radialGradient id="rl-glow" cx="0.8" cy="0.1" r="0.9"><stop offset="0" stop-color="#fff" stop-opacity=".22"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></radialGradient><clipPath id="rl-flask"><path d="M25 8h14v14l13.5 24.5c1.8 3.3-.6 7.5-4.4 7.5H15.9c-3.8 0-6.2-4.2-4.4-7.5L25 22z"/></clipPath></defs><rect width="64" height="64" rx="15" fill="url(#rl-bg)"/><rect width="64" height="64" rx="15" fill="url(#rl-glow)"/><g clip-path="url(#rl-flask)"><rect x="17" y="40" width="7" height="20" rx="2" fill="#fff" fill-opacity=".55"/><rect x="28.5" y="28" width="7" height="32" rx="2" fill="#3DDC8C"/><rect x="40" y="35" width="7" height="25" rx="2" fill="#fff" fill-opacity=".85"/></g><path d="M25 8h14v14l13.5 24.5c1.8 3.3-.6 7.5-4.4 7.5H15.9c-3.8 0-6.2-4.2-4.4-7.5L25 22z" fill="none" stroke="#fff" stroke-width="3.2" stroke-linejoin="round"/><path d="M22 8h20" stroke="#fff" stroke-width="3.2" stroke-linecap="round"/><circle cx="24" cy="30" r="2.2" fill="#fff" fill-opacity=".9"/></svg></template>
|
|
652
|
+
<script id="rl-data" type="application/json">__RL_DATA__</script>
|
|
653
|
+
<script>
|
|
654
|
+
(function(){
|
|
655
|
+
const data = JSON.parse(document.getElementById('rl-data').textContent);
|
|
656
|
+
const $ = (s,el=document)=>el.querySelector(s);
|
|
657
|
+
const h = (tag, attrs={}, ...kids)=>{const e=document.createElement(tag);for(const [k,v] of Object.entries(attrs)){if(k==='class')e.className=v;else if(k==='html')e.innerHTML=v;else if(k.startsWith('on'))e.addEventListener(k.slice(2),v);else if(v!==false&&v!=null)e.setAttribute(k,v);}for(const k of kids.flat(Infinity)){if(k==null)continue;e.append(k.nodeType?k:document.createTextNode(k));}return e;};
|
|
658
|
+
const ms = n => n<1000? Math.round(n)+'ms' : n<60000 ? (n/1000).toFixed(1)+'s' : Math.floor(n/60000)+'m '+Math.round((n%60000)/1000)+'s';
|
|
659
|
+
const isFail = s => s==='failed'||s==='timedOut'||s==='interrupted';
|
|
660
|
+
const colorOf = k => k==='passed'?'var(--pass)':k==='flaky'?'var(--flaky)':k==='skipped'?'var(--skip)':'var(--fail)';
|
|
661
|
+
const bucket = t => isFail(t.outcome)?'failed':t.outcome;
|
|
662
|
+
const label = {passed:'Passed',failed:'Failed',flaky:'Flaky',skipped:'Skipped',timedOut:'Timed out',interrupted:'Interrupted'};
|
|
663
|
+
const HIST = data.history||[];
|
|
664
|
+
const HRUNS = HIST.filter(e=>e&&e.tests); // entries that carry per-test outcomes; the last one is this run
|
|
665
|
+
const PREV = HRUNS.length>1 ? HRUNS.slice(0,-1) : []; // earlier runs only
|
|
666
|
+
const runLabel = e => e.label || new Date(e.time).toLocaleDateString(undefined,{month:'short',day:'numeric'});
|
|
667
|
+
|
|
668
|
+
const state = { q:'', status:'all', project:'all', dims:{}, selected:null, retry:null, group:'file', open:{}, view:'overview' };
|
|
669
|
+
const DIMS = data.options.dimensions.filter(d=>data.tests.some(t=>t.meta[d]));
|
|
670
|
+
const dimValues = d => { const vals=[...new Set(data.tests.map(t=>t.meta[d]).filter(Boolean))]; const order=(data.options.dimensionOrder[d]||[]).map(x=>x.toLowerCase()); return vals.sort((a,b)=>{ const ia=order.indexOf(a.toLowerCase()), ib=order.indexOf(b.toLowerCase()); if(ia>-1||ib>-1) return (ia===-1?99:ia)-(ib===-1?99:ib); return a.localeCompare(b); }); };
|
|
671
|
+
const rank = t => { const p=(t.meta.priority||'').toUpperCase(), sv=(t.meta.severity||'').toLowerCase(); const po=data.options.dimensionOrder.priority.indexOf(p), so=data.options.dimensionOrder.severity.map(x=>x.toLowerCase()).indexOf(sv); return (po===-1?9:po)*10+(so===-1?9:so); };
|
|
672
|
+
const params = new URLSearchParams(location.hash.slice(1));
|
|
673
|
+
if(params.get('t')) { state.selected = params.get('t'); state.view='tests'; }
|
|
674
|
+
if(params.get('view')) state.view = params.get('view');
|
|
675
|
+
|
|
676
|
+
try{ const p=localStorage.getItem('rl-palette'); if(p) document.documentElement.setAttribute('data-palette',p); const th=localStorage.getItem('rl-theme'); if(th) document.documentElement.setAttribute('data-theme',th); }catch(e){}
|
|
677
|
+
const app = $('#app');
|
|
678
|
+
app.append(h('div',{class:'band'}, stripe(), header(), nav()),
|
|
679
|
+
h('div',{class:'view','data-view':'overview'}, summary()),
|
|
680
|
+
h('div',{class:'view','data-view':'tests'}, main()),
|
|
681
|
+
h('div',{class:'view','data-view':'failures'}, h('div',{class:'view-pad'}, failuresView())),
|
|
682
|
+
h('div',{class:'view','data-view':'api'}, h('div',{class:'view-pad'}, apiView())),
|
|
683
|
+
h('div',{class:'view','data-view':'graphs'}, graphsView()),
|
|
684
|
+
hasTimelineView()? h('div',{class:'view','data-view':'timeline'}, h('div',{class:'view-pad'}, timelineView())) : null);
|
|
685
|
+
select(state.selected || firstInteresting(), true);
|
|
686
|
+
showView(state.view);
|
|
687
|
+
window.addEventListener('keydown', e=>{
|
|
688
|
+
if(e.key==='Escape'){const lb=$('.lb'); if(lb) lb.remove(); return;}
|
|
689
|
+
const tag=(e.target.tagName||'').toLowerCase(); if(tag==='input'||tag==='select'||tag==='textarea') return;
|
|
690
|
+
if(e.key==='/'){ e.preventDefault(); showView('tests'); $('.tools input').focus(); return; }
|
|
691
|
+
const vk={'1':'overview','2':'tests','3':'failures','4':'api','5':'graphs','6':'timeline'}[e.key]; if(vk&&document.querySelector('.nav button[data-view='+vk+']')){ showView(vk); return; }
|
|
692
|
+
if(e.key==='f'){ state.status=state.status==='failed'?'all':'failed'; refresh(); return; }
|
|
693
|
+
if(e.key==='j'||e.key==='k'){ const ids=[...document.querySelectorAll('.item')].map(i=>i.dataset.id); if(!ids.length) return; let i=ids.indexOf(state.selected); i=e.key==='j'?Math.min(ids.length-1,i+1):Math.max(0,i-1); select(ids[i]); }
|
|
694
|
+
});
|
|
695
|
+
|
|
696
|
+
/* ---------- header ---------- */
|
|
697
|
+
function setHash(){ const p=new URLSearchParams(); if(state.view!=='overview') p.set('view',state.view); if(state.selected&&state.view==='tests') p.set('t',state.selected); const hs=p.toString(); history.replaceState(null,'',hs?'#'+hs:location.pathname+location.search); }
|
|
698
|
+
function showView(v){
|
|
699
|
+
if(!document.querySelector('.view[data-view='+v+']')) v='overview';
|
|
700
|
+
state.view=v; document.querySelectorAll('.view').forEach(el=>el.classList.toggle('on',el.dataset.view===v));
|
|
701
|
+
document.querySelectorAll('.nav button[data-view]').forEach(b=>b.setAttribute('aria-selected',b.dataset.view===v));
|
|
702
|
+
setHash(); try{window.scrollTo(0,0);}catch(e){}
|
|
703
|
+
}
|
|
704
|
+
function nav(){
|
|
705
|
+
const s=data.stats, f=s.failed+s.timedOut+s.interrupted, apiN=data.tests.reduce((a,t)=>a+t.results.reduce((b,r)=>b+r.api.length,0),0);
|
|
706
|
+
const tabs=[['overview','Overview',null],['tests','Tests',s.total],['failures','Failures',f+s.flaky,f>0],['api','API',apiN],['graphs','Graphs',null],['timeline','Timeline',null]].filter(t=>(t[0]!=='api'||apiN>0)&&(t[0]!=='timeline'||hasTimelineView())&&(t[0]!=='graphs'||data.tests.length>0));
|
|
707
|
+
return h('nav',{class:'nav'}, h('div',{}, tabs.map(([v,l,n,bad])=>h('button',{'data-view':v,'aria-selected':state.view===v,onclick:()=>showView(v)}, l, n!=null?h('span',{class:'cnt'+(bad?' bad':'')},n):null))));
|
|
708
|
+
}
|
|
709
|
+
function failuresView(){
|
|
710
|
+
const bad=data.tests.filter(t=>isFail(t.outcome)||t.outcome==='flaky');
|
|
711
|
+
if(!bad.length) return h('div',{class:'card'}, h('div',{style:'font-size:18px;color:var(--pass);font-weight:600'},'No failures.'), h('div',{style:'color:var(--ink-3);margin-top:6px'},'Every test that ran passed on the first attempt.'));
|
|
712
|
+
const cl=failureClusters();
|
|
713
|
+
const grid=h('div',{class:'grid'});
|
|
714
|
+
grid.append(h('div',{class:'w12 fx-tools'}, h('span',{class:'fx-sum'}, bad.length+' failed or flaky', PREV.length? ' · '+bad.filter(t=>isFail(t.outcome)&&sinceInfo(t).kind==='new').length+' new since '+runLabel(PREV[PREV.length-1]) : ''), h('span',{class:'spacer'}),
|
|
715
|
+
h('button',{class:'btn',onclick:exportCsv,title:'Failures as CSV for Jira or a sheet'},'Download CSV'), h('button',{class:'btn',onclick:exportJson,title:'Failures as JSON'},'Download JSON'), h('button',{class:'btn primary',onclick:e=>copyText(summaryMarkdown(),e.currentTarget,'Copied for Slack')},'Copy summary')));
|
|
716
|
+
if(cl.length) grid.append(h('div',{class:'card w6 fail-rail'}, h('h2',{},'Failure clusters', h('span',{class:'hint'},cl.length+' distinct error'+(cl.length>1?'s':''))), clustersView(cl)));
|
|
717
|
+
if(DIMS.length) grid.append(h('div',{class:'card w6 fail-rail'}, h('h2',{},'Needs attention', h('span',{class:'hint'},'ranked by priority and severity')), attention()));
|
|
718
|
+
const oc=ownerCard(); if(oc) grid.append(oc);
|
|
719
|
+
const rows=[...bad].sort((a,b)=>rank(a)-rank(b)||b.duration-a.duration);
|
|
720
|
+
grid.append(h('div',{class:'card w12'}, h('h2',{},rows.length+' failed or flaky tests'), h('table',{class:'apitbl'},
|
|
721
|
+
h('thead',{}, h('tr',{}, ['','Test','Spec','Priority','Owner','Ticket','Attempts',PREV.length?'Since':'',HRUNS.length>1?'History':'',''].map(x=>h('th',{},x)))),
|
|
722
|
+
h('tbody',{}, rows.map(t=>{ const e=t.results[t.results.length-1].errors[0]; return h('tr',{onclick:()=>select(t.id)},
|
|
723
|
+
h('td',{}, h('span',{class:'st '+t.outcome,style:'display:inline-block'})), h('td',{}, h('div',{},t.title), h('div',{class:'t',title:e?e.message:''}, e? e.message.split('\n')[0].slice(0,110):'')),
|
|
724
|
+
h('td',{class:'t'},t.file.split('/').pop()+(data.projects.length>1?' · '+t.project:'')), h('td',{},[t.meta.priority,t.meta.severity].filter(Boolean).join(' · ')), h('td',{},t.meta.owner||''), h('td',{},t.meta.story||t.meta.issue||''), h('td',{},t.results.length), PREV.length?h('td',{},(()=>{ const si=sinceInfo(t); return si? h('span',{class:'since-txt '+si.kind}, si.kind==='new'?'new':runLabel(si.since)) : h('span',{class:'t'},'–'); })()):null, HRUNS.length>1?h('td',{},dots(t,10)):null, h('td',{class:'t'},ms(t.duration))); })))));
|
|
725
|
+
return grid;
|
|
726
|
+
}
|
|
727
|
+
function apiView(){
|
|
728
|
+
const calls=[]; for(const t of data.tests) for(const r of t.results) for(const c of r.api) calls.push({c,t,r});
|
|
729
|
+
if(!calls.length) return h('div',{class:'card'},h('b',{},'No API calls recorded.'),' Add ',h('code',{},"import 'reporting-labs/auto'"),' to playwright.config.ts and every request.get / request.post / page.request call shows up here with headers, bodies and a cURL command. Calls made with other clients can be recorded with api().');
|
|
730
|
+
const bad=calls.filter(x=>(x.c.status||0)>=400).length, avg=Math.round(calls.reduce((a,x)=>a+(x.c.duration||0),0)/calls.length), slow=calls.filter(x=>(x.c.duration||0)>1000).length;
|
|
731
|
+
calls.sort((a,b)=>((b.c.status||0)>=400)-((a.c.status||0)>=400)||(b.c.duration||0)-(a.c.duration||0));
|
|
732
|
+
const byHost=new Map(); for(const x of calls){ try{ const hst=new URL(x.c.url).host; byHost.set(hst,(byHost.get(hst)||0)+1);}catch(e){} }
|
|
733
|
+
return h('div',{}, h('div',{class:'api-stats'}, h('span',{},h('b',{},calls.length),' calls'), h('span',{class:bad?'bad':''},h('b',{},bad),' failed (4xx/5xx)'), h('span',{},h('b',{},ms(avg)),' avg'), h('span',{},h('b',{},slow),' over 1s'), h('span',{},h('b',{},byHost.size),' host'+(byHost.size===1?'':'s'))),
|
|
734
|
+
h('div',{class:'card w12'}, h('table',{class:'apitbl'}, h('thead',{}, h('tr',{}, ['Method','URL','Status','Time','Test'].map(x=>h('th',{},x)))),
|
|
735
|
+
h('tbody',{}, calls.map(({c,t})=>{ const st=c.status||0, cls=st>=400?'bad':st>=300?'warn':'ok'; return h('tr',{onclick:()=>select(t.id)},
|
|
736
|
+
h('td',{}, h('span',{class:'m '+c.method.toUpperCase(),style:'font:11px var(--mono);font-weight:600;padding:3px 6px;border-radius:3px;color:#fff;background:'+({GET:'#2A7FBF',POST:'var(--pass)',PUT:'#C77D14',PATCH:'#C77D14',DELETE:'var(--fail)'}[c.method.toUpperCase()]||'var(--ink-3)')},c.method.toUpperCase())),
|
|
737
|
+
h('td',{class:'u',title:c.url},c.url), h('td',{}, h('span',{class:'sc '+cls,style:'font:12px var(--mono);font-weight:600;color:'+(cls==='bad'?'var(--fail)':cls==='warn'?'var(--flaky-ink)':'var(--pass)')},st||'—')), h('td',{class:'t'},c.duration!=null?ms(c.duration):'—'), h('td',{class:'t',title:t.title},t.title)); })))));
|
|
738
|
+
}
|
|
739
|
+
function timelineView(){
|
|
740
|
+
const W=data.options.widgets, cards=[];
|
|
741
|
+
if(W.timeline!==false) cards.push(h('div',{class:'card w12'}, h('h2',{},'Timeline by worker'), timeline()), h('div',{class:'card w6'}, h('h2',{},'Workers'), workers()));
|
|
742
|
+
if(W.durations!==false) cards.push(h('div',{class:W.timeline!==false?'card w6':'card w12'}, h('h2',{},'Duration spread'), histogram()));
|
|
743
|
+
return h('div',{class:'grid'}, cards);
|
|
744
|
+
}
|
|
745
|
+
function hasTimelineView(){ return data.options.widgets.timeline!==false || data.options.widgets.durations!==false; }
|
|
746
|
+
|
|
747
|
+
/* ---------- Graphs tab: 4 presentation-ready charts with PNG download ---------- */
|
|
748
|
+
function gEsc(s){ return String(s==null?'':s).replace(/[&<>"']/g, c => ({ '&':'&','<':'<','>':'>','"':'"',"'":'''}[c])); }
|
|
749
|
+
function graphsView(){
|
|
750
|
+
return h('div',{class:'view-pad'},
|
|
751
|
+
h('div',{class:'grid graphs-grid'},
|
|
752
|
+
chartCard('outcomes-by-priority', 'Outcomes by priority', 'Stacked pass / fail / flaky / skipped for each priority tier.', chartPriorityOutcome),
|
|
753
|
+
chartCard('failure-categories', 'Failure categories', 'What kinds of failures are hurting the suite.', chartFailureCategories),
|
|
754
|
+
chartCard('duration-distribution','Duration distribution', 'How test durations are spread across the run.', chartDurationHistogram),
|
|
755
|
+
chartCard('trend-by-priority', 'Pass rate trend by priority', 'How each priority tier trends over the last runs.', chartTrendByPriority),
|
|
756
|
+
chartCard('owner-leaderboard', 'Owner leaderboard', 'Failures and flakes ranked by owner. Add meta({owner:...}) to see this.', chartOwnerLeaderboard),
|
|
757
|
+
));
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
/* Chart 5: horizontal stacked bar per owner — total tests, failed vs flaky highlighted */
|
|
761
|
+
function chartOwnerLeaderboard(){
|
|
762
|
+
const rows = new Map();
|
|
763
|
+
for(const t of data.tests){
|
|
764
|
+
const o = (t.meta.owner||'').toString().trim(); if(!o) continue;
|
|
765
|
+
let r = rows.get(o); if(!r){ r={owner:o, total:0, failed:0, flaky:0, passed:0, skipped:0}; rows.set(o,r); }
|
|
766
|
+
r.total++;
|
|
767
|
+
if(isFail(t.outcome)) r.failed++;
|
|
768
|
+
else if(t.outcome==='flaky') r.flaky++;
|
|
769
|
+
else if(t.outcome==='skipped') r.skipped++;
|
|
770
|
+
else if(t.outcome==='passed') r.passed++;
|
|
771
|
+
}
|
|
772
|
+
const list = [...rows.values()].sort((a,b)=> (b.failed - a.failed) || (b.flaky - a.flaky) || (b.total - a.total));
|
|
773
|
+
if(!list.length) return null;
|
|
774
|
+
const maxTotal = Math.max(...list.map(r=>r.total));
|
|
775
|
+
const W=520, rowH=28, gap=8, labW=110, barW=W-labW-70;
|
|
776
|
+
const H = list.length*(rowH+gap)+30;
|
|
777
|
+
const parts = list.map((r,i)=>{
|
|
778
|
+
const y=i*(rowH+gap)+14, scale=barW/maxTotal;
|
|
779
|
+
const passedW = r.passed*scale, flakyW = r.flaky*scale, failedW = r.failed*scale, skippedW = r.skipped*scale;
|
|
780
|
+
let x = labW;
|
|
781
|
+
const segs=[];
|
|
782
|
+
if(passedW>0){ segs.push('<rect x="'+x+'" y="'+y+'" width="'+passedW+'" height="'+rowH+'" fill="var(--pass)" rx="3"><title>'+gEsc(r.owner)+' · '+r.passed+' passed</title></rect>'); x+=passedW; }
|
|
783
|
+
if(flakyW>0){ segs.push('<rect x="'+x+'" y="'+y+'" width="'+flakyW+'" height="'+rowH+'" fill="var(--flaky)"><title>'+gEsc(r.owner)+' · '+r.flaky+' flaky</title></rect>'); x+=flakyW; }
|
|
784
|
+
if(failedW>0){ segs.push('<rect x="'+x+'" y="'+y+'" width="'+failedW+'" height="'+rowH+'" fill="var(--fail)"><title>'+gEsc(r.owner)+' · '+r.failed+' failed</title></rect>'); x+=failedW; }
|
|
785
|
+
if(skippedW>0){segs.push('<rect x="'+x+'" y="'+y+'" width="'+skippedW+'" height="'+rowH+'" fill="var(--skip)"><title>'+gEsc(r.owner)+' · '+r.skipped+' skipped</title></rect>'); x+=skippedW; }
|
|
786
|
+
return '<text x="0" y="'+(y+rowH/2+4)+'" fill="var(--ink)" font-size="12" font-weight="600">'+gEsc(r.owner)+'</text>'+segs.join('')+
|
|
787
|
+
'<text x="'+(labW+barW+8)+'" y="'+(y+rowH/2+4)+'" fill="var(--ink-2)" font-size="12" font-variant-numeric="tabular-nums">'+r.total+'</text>';
|
|
788
|
+
}).join('');
|
|
789
|
+
const legendPairs = [['Passed','var(--pass)'],['Flaky','var(--flaky)'],['Failed','var(--fail)'],['Skipped','var(--skip)']];
|
|
790
|
+
const hasKind = { Passed:list.some(r=>r.passed>0), Flaky:list.some(r=>r.flaky>0), Failed:list.some(r=>r.failed>0), Skipped:list.some(r=>r.skipped>0) };
|
|
791
|
+
const legend = legendPairs.filter(([n])=>hasKind[n]).map(([n,c],i)=>'<g transform="translate('+(labW+i*90)+','+(H-4)+')"><rect width="10" height="10" y="-9" fill="'+c+'"/><text x="14" y="0" font-size="11" fill="var(--ink-2)">'+n+'</text></g>').join('');
|
|
792
|
+
return h('div',{class:'gchart-body',html:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 '+W+' '+(H+14)+'" width="100%">'+parts+legend+'</svg>'});
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
function chartCard(id, title, sub, chartFn){
|
|
796
|
+
const chart = chartFn();
|
|
797
|
+
const empty = !chart;
|
|
798
|
+
return h('div',{class:'card w6 gchart','data-chart':id},
|
|
799
|
+
h('div',{class:'gchart-head'},
|
|
800
|
+
h('div',{},
|
|
801
|
+
h('h2',{},title),
|
|
802
|
+
h('div',{class:'gchart-sub'},sub)),
|
|
803
|
+
empty? null : h('button',{class:'btn',title:'Download this chart as a PNG image',
|
|
804
|
+
onclick:e=>downloadChartPng(id, title, e.currentTarget)},'Download PNG')),
|
|
805
|
+
empty? h('div',{class:'empty'},'Not enough data yet. Add meta({ priority }) or run the suite once more.') : chart);
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
/* Chart 1: horizontal stacked bar per priority (P0..P4 in order, plus 'no priority') */
|
|
809
|
+
function chartPriorityOutcome(){
|
|
810
|
+
const order = ['P0','P1','P2','P3','P4'];
|
|
811
|
+
const outs = ['passed','flaky','failed','timedOut','interrupted','skipped'];
|
|
812
|
+
const colors= {passed:'var(--pass)', flaky:'var(--flaky)', failed:'var(--fail)', timedOut:'var(--fail)', interrupted:'var(--fail)', skipped:'var(--skip)'};
|
|
813
|
+
const buckets = new Map();
|
|
814
|
+
const put=(k,o)=>{ let m=buckets.get(k); if(!m){ m={}; for(const x of outs) m[x]=0; buckets.set(k,m); } m[o]=(m[o]||0)+1; };
|
|
815
|
+
for(const t of data.tests){ const p=(t.meta.priority||'').toString().trim().toUpperCase(); put(order.includes(p)? p : 'No priority', t.outcome); }
|
|
816
|
+
const rows = [...order.filter(k=>buckets.has(k)), ...(buckets.has('No priority')?['No priority']:[])];
|
|
817
|
+
if(!rows.length) return null;
|
|
818
|
+
const maxN = Math.max(...rows.map(r=>outs.reduce((a,o)=>a+buckets.get(r)[o],0)));
|
|
819
|
+
const W=520, rowH=34, gap=10, labW=90, barW=W-labW-70;
|
|
820
|
+
const H = rows.length*(rowH+gap)+30;
|
|
821
|
+
const parts = rows.map((r,i)=>{
|
|
822
|
+
const y=i*(rowH+gap)+18, m=buckets.get(r), tot=outs.reduce((a,o)=>a+m[o],0), scale=barW/maxN;
|
|
823
|
+
let x=labW;
|
|
824
|
+
const segs=[]; for(const o of outs){ const w=m[o]*scale; if(w<=0) continue; segs.push('<rect x="'+x+'" y="'+y+'" width="'+w+'" height="'+rowH+'" fill="'+colors[o]+'" data-outcome="'+o+'"><title>'+r+' · '+label[o]+' '+m[o]+'</title></rect>'); x+=w; }
|
|
825
|
+
return '<text x="0" y="'+(y+rowH/2+4)+'" fill="var(--ink)" font-size="12" font-weight="600">'+r+'</text>'+
|
|
826
|
+
segs.join('')+
|
|
827
|
+
'<text x="'+(labW+barW+8)+'" y="'+(y+rowH/2+4)+'" fill="var(--ink-2)" font-size="12" font-variant-numeric="tabular-nums">'+tot+'</text>';
|
|
828
|
+
}).join('');
|
|
829
|
+
const legend = outs.filter(o=>rows.some(r=>buckets.get(r)[o]>0)).map(o=>'<g><rect width="10" height="10" fill="'+colors[o]+'"/><text x="14" y="9" fill="var(--ink-2)" font-size="11">'+label[o]+'</text></g>');
|
|
830
|
+
const legendSvg = '<g transform="translate('+labW+','+(H-2)+')">'+legend.map((g,i)=>'<g transform="translate('+(i*90)+',0)">'+g.slice(3,-4)+'</g>').join('')+'</g>';
|
|
831
|
+
return h('div',{class:'gchart-body',html:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 '+W+' '+(H+18)+'" width="100%">'+parts+legendSvg+'</svg>'});
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
/* Chart 2: horizontal bar of the 18 error 'kinds' from explainError, sorted by count desc */
|
|
835
|
+
function chartFailureCategories(){
|
|
836
|
+
const counts = new Map();
|
|
837
|
+
for(const t of data.tests){ const r=t.results[t.results.length-1], e=r&&r.errors[0]; if(!e||!e.explain) continue; const k=e.explain.label||e.explain.kind||'other'; counts.set(k,(counts.get(k)||0)+1); }
|
|
838
|
+
const rows=[...counts.entries()].sort((a,b)=>b[1]-a[1]);
|
|
839
|
+
if(!rows.length) return null;
|
|
840
|
+
const maxN = rows[0][1];
|
|
841
|
+
const W=520, rowH=22, gap=6, labW=200, barW=W-labW-40;
|
|
842
|
+
const H = rows.length*(rowH+gap)+8;
|
|
843
|
+
const parts = rows.map(([k,n],i)=>{
|
|
844
|
+
const y=i*(rowH+gap)+8, w=Math.max(2, n/maxN*barW);
|
|
845
|
+
return '<text x="0" y="'+(y+rowH/2+4)+'" fill="var(--ink)" font-size="12">'+gEsc(k)+'</text>'+
|
|
846
|
+
'<rect x="'+labW+'" y="'+y+'" width="'+w+'" height="'+rowH+'" fill="var(--fail)" rx="3"><title>'+gEsc(k)+' · '+n+'</title></rect>'+
|
|
847
|
+
'<text x="'+(labW+w+6)+'" y="'+(y+rowH/2+4)+'" fill="var(--ink-2)" font-size="12" font-variant-numeric="tabular-nums">'+n+'</text>';
|
|
848
|
+
}).join('');
|
|
849
|
+
return h('div',{class:'gchart-body',html:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 '+W+' '+H+'" width="100%">'+parts+'</svg>'});
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
/* Chart 3: duration histogram — bars for 5 buckets across all tests */
|
|
853
|
+
function chartDurationHistogram(){
|
|
854
|
+
if(!data.tests.length) return null;
|
|
855
|
+
const buckets = [
|
|
856
|
+
{label:'< 1s', min:0, max:1000},
|
|
857
|
+
{label:'1-3s', min:1000, max:3000},
|
|
858
|
+
{label:'3-10s', min:3000, max:10000},
|
|
859
|
+
{label:'10-30s', min:10000,max:30000},
|
|
860
|
+
{label:'30s+', min:30000,max:Infinity},
|
|
861
|
+
];
|
|
862
|
+
const counts = buckets.map(()=>0);
|
|
863
|
+
for(const t of data.tests){ const d=t.duration||0; for(let i=0;i<buckets.length;i++){ if(d>=buckets[i].min && d<buckets[i].max){ counts[i]++; break; } } }
|
|
864
|
+
const maxN = Math.max(1,...counts);
|
|
865
|
+
const W=520, colW=80, gap=16, padL=32, padT=24, padB=36, chartH=180;
|
|
866
|
+
const H = chartH+padT+padB;
|
|
867
|
+
const bars = counts.map((n,i)=>{
|
|
868
|
+
const x=padL+i*(colW+gap), h=n/maxN*chartH, y=padT+chartH-h;
|
|
869
|
+
return '<rect x="'+x+'" y="'+y+'" width="'+colW+'" height="'+h+'" fill="var(--accent)" rx="3"><title>'+buckets[i].label+' · '+n+' tests</title></rect>'+
|
|
870
|
+
(n>0?'<text x="'+(x+colW/2)+'" y="'+(y-4)+'" text-anchor="middle" fill="var(--ink)" font-size="12" font-weight="600" font-variant-numeric="tabular-nums">'+n+'</text>':'')+
|
|
871
|
+
'<text x="'+(x+colW/2)+'" y="'+(padT+chartH+22)+'" text-anchor="middle" fill="var(--ink-2)" font-size="12">'+buckets[i].label+'</text>';
|
|
872
|
+
}).join('');
|
|
873
|
+
return h('div',{class:'gchart-body',html:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 '+W+' '+H+'" width="100%">'+bars+'</svg>'});
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
/* Chart 4: multi-line — pass rate per priority over the last N history entries */
|
|
877
|
+
function chartTrendByPriority(){
|
|
878
|
+
const hist = data.history || [];
|
|
879
|
+
if(hist.length < 2) return null;
|
|
880
|
+
const orders = ['P0','P1','P2','P3','P4'];
|
|
881
|
+
const seenPri = new Set();
|
|
882
|
+
for(const t of data.tests){ const p=(t.meta.priority||'').toString().trim().toUpperCase(); if(orders.includes(p)) seenPri.add(p); }
|
|
883
|
+
const priorities = orders.filter(p=>seenPri.has(p));
|
|
884
|
+
if(!priorities.length) return null;
|
|
885
|
+
const colors = { P0:'#E5405E', P1:'#F59E0B', P2:'#3B82F6', P3:'#8B95A5', P4:'#6B7280' };
|
|
886
|
+
const currentTests = new Map(data.tests.map(t=>[t.key, (t.meta.priority||'').toString().trim().toUpperCase()]));
|
|
887
|
+
const series = priorities.map(pri=>{
|
|
888
|
+
const points = hist.map(e=>{
|
|
889
|
+
let p=0,f=0; for(const [key,val] of Object.entries(e.tests||{})){ if(currentTests.get(key)!==pri) continue; const outcome=val[0]||''; if(outcome==='p') p++; else if(outcome==='f'||outcome==='t'||outcome==='i') f++; }
|
|
890
|
+
const ran = p+f; return ran? Math.round(p/ran*100) : null;
|
|
891
|
+
});
|
|
892
|
+
return { pri, color: colors[pri]||'#888', points };
|
|
893
|
+
}).filter(sr=>sr.points.some(v=>v!==null));
|
|
894
|
+
if(!series.length) return null;
|
|
895
|
+
const W=520, padL=36, padR=24, padT=16, padB=28, chartH=180;
|
|
896
|
+
const H = chartH+padT+padB;
|
|
897
|
+
const N = hist.length;
|
|
898
|
+
const xAt = i => padL + (N===1? 0 : i*((W-padL-padR)/(N-1)));
|
|
899
|
+
const yAt = pct => padT + (100-pct)/100*chartH;
|
|
900
|
+
const grid = [0,25,50,75,100].map(y=>'<line x1="'+padL+'" x2="'+(W-padR)+'" y1="'+yAt(y)+'" y2="'+yAt(y)+'" stroke="var(--line)" stroke-dasharray="2 3"/><text x="'+(padL-6)+'" y="'+(yAt(y)+3)+'" text-anchor="end" font-size="10" fill="var(--ink-3)">'+y+'%</text>').join('');
|
|
901
|
+
const lines = series.map(sr=>{
|
|
902
|
+
// A series may start with (or contain) nulls — runs where this priority
|
|
903
|
+
// had no tests. Each stretch after a gap must restart with M, or the
|
|
904
|
+
// path begins with L and the browser rejects it.
|
|
905
|
+
let pen=false;
|
|
906
|
+
const d = sr.points.map((v,i)=>{ if(v===null){ pen=false; return null; } const cmd=pen?'L':'M'; pen=true; return cmd+xAt(i)+' '+yAt(v); }).filter(Boolean).join(' ');
|
|
907
|
+
const dots = sr.points.map((v,i)=> v===null? '' : '<circle cx="'+xAt(i)+'" cy="'+yAt(v)+'" r="2.5" fill="'+sr.color+'"><title>'+sr.pri+' · '+v+'% at run '+(i+1)+'</title></circle>').join('');
|
|
908
|
+
return '<path d="'+d+'" fill="none" stroke="'+sr.color+'" stroke-width="2" stroke-linejoin="round" stroke-linecap="round"/>'+dots;
|
|
909
|
+
}).join('');
|
|
910
|
+
const legend = series.map((sr,i)=>'<g transform="translate('+(padL+i*70)+','+(H-8)+')"><rect width="10" height="10" y="-9" fill="'+sr.color+'"/><text x="14" y="0" font-size="11" fill="var(--ink-2)">'+sr.pri+'</text></g>').join('');
|
|
911
|
+
return h('div',{class:'gchart-body',html:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 '+W+' '+H+'" width="100%">'+grid+lines+legend+'</svg>'});
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
/* PNG download: serialize the chart's SVG, draw onto a canvas at 2x, trigger download. */
|
|
915
|
+
function downloadChartPng(chartId, title, btn){
|
|
916
|
+
const card = document.querySelector('[data-chart="'+chartId+'"]');
|
|
917
|
+
const src = card && card.querySelector('svg');
|
|
918
|
+
if(!src) return;
|
|
919
|
+
const label = btn.textContent; btn.textContent = 'Rendering…'; btn.disabled = true;
|
|
920
|
+
const clone = src.cloneNode(true);
|
|
921
|
+
clone.setAttribute('xmlns','http://www.w3.org/2000/svg');
|
|
922
|
+
// Inline computed colors so CSS var() references resolve inside the standalone SVG.
|
|
923
|
+
const cs = getComputedStyle(document.documentElement);
|
|
924
|
+
const varRe = /var\(--([a-z0-9-]+)\)/gi;
|
|
925
|
+
const walk = el => { for(const a of ['fill','stroke']){ const v=el.getAttribute(a); if(v && varRe.test(v)){ el.setAttribute(a, v.replace(varRe,(_,n)=>cs.getPropertyValue('--'+n).trim() || 'currentColor')); } } for(const c of el.children) walk(c); };
|
|
926
|
+
walk(clone);
|
|
927
|
+
// Ensure the SVG has explicit width/height (in px) for correct raster size.
|
|
928
|
+
const vb = clone.viewBox && clone.viewBox.baseVal;
|
|
929
|
+
const w = (vb && vb.width) || 800, hpx = (vb && vb.height) || 400;
|
|
930
|
+
const scale = 2;
|
|
931
|
+
clone.setAttribute('width', w); clone.setAttribute('height', hpx);
|
|
932
|
+
const xml = new XMLSerializer().serializeToString(clone);
|
|
933
|
+
const svgBlob = new Blob([xml], {type:'image/svg+xml;charset=utf-8'});
|
|
934
|
+
const url = URL.createObjectURL(svgBlob);
|
|
935
|
+
const img = new Image();
|
|
936
|
+
img.onload = () => {
|
|
937
|
+
const canvas = document.createElement('canvas');
|
|
938
|
+
canvas.width = w*scale; canvas.height = hpx*scale;
|
|
939
|
+
const ctx = canvas.getContext('2d');
|
|
940
|
+
ctx.fillStyle = cs.getPropertyValue('--surface').trim() || '#ffffff';
|
|
941
|
+
ctx.fillRect(0,0,canvas.width,canvas.height);
|
|
942
|
+
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
|
|
943
|
+
URL.revokeObjectURL(url);
|
|
944
|
+
canvas.toBlob(b => {
|
|
945
|
+
const a = document.createElement('a');
|
|
946
|
+
a.href = URL.createObjectURL(b); a.download = 'reporting-labs-'+chartId+'.png'; a.click();
|
|
947
|
+
URL.revokeObjectURL(a.href);
|
|
948
|
+
btn.textContent = label; btn.disabled = false;
|
|
949
|
+
}, 'image/png');
|
|
950
|
+
};
|
|
951
|
+
img.onerror = () => { btn.textContent = 'PNG failed'; btn.disabled = false; URL.revokeObjectURL(url); };
|
|
952
|
+
img.src = url;
|
|
953
|
+
}
|
|
954
|
+
function stripe(){
|
|
955
|
+
const s=data.stats, f=s.failed+s.timedOut+s.interrupted, tot=s.total||1;
|
|
956
|
+
return h('div',{class:'stripe','aria-hidden':'true'}, [['passed',s.passed],['flaky',s.flaky],['failed',f],['skipped',s.skipped]].filter(x=>x[1]).map(([k,n])=>h('i',{style:'width:'+(n/tot*100)+'%;background:'+colorOf(k)})));
|
|
957
|
+
}
|
|
958
|
+
function isDark(){ return getComputedStyle(document.documentElement).getPropertyValue('--_dark').trim()==='1'; }
|
|
959
|
+
function copyText(txt,btn,done){ const ok=()=>{ if(btn){ const o=btn.textContent; btn.textContent=done||'Copied'; btn.classList.add('done'); setTimeout(()=>{btn.textContent=o;btn.classList.remove('done');},1400);} };
|
|
960
|
+
if(navigator.clipboard&&navigator.clipboard.writeText) navigator.clipboard.writeText(txt).then(ok,()=>fallback()); else fallback();
|
|
961
|
+
function fallback(){ const ta=h('textarea',{style:'position:fixed;opacity:0'},txt); document.body.append(ta); ta.select(); try{document.execCommand('copy');ok();}catch(e){} ta.remove(); } }
|
|
962
|
+
function summaryMarkdown(){
|
|
963
|
+
const s=data.stats, f=s.failed+s.timedOut+s.interrupted, ran=s.total-s.skipped, rate=ran?Math.round(s.passed/ran*100):0;
|
|
964
|
+
const meta=Object.entries(data.metadata).map(([k,v])=>k+': '+v).join(' · ');
|
|
965
|
+
const lines=['*'+data.title+'* — '+((data.runStatus==='interrupted'||data.runStatus==='timedout')?':warning: run '+data.runStatus+' · ':'')+(f?':red_circle:':':large_green_circle:')+' '+rate+'% passed ('+s.passed+'/'+ran+')'+(f?', '+f+' failed'+(PREV.length?' ('+data.tests.filter(t=>isFail(t.outcome)&&sinceInfo(t).kind==='new').length+' new)':''):'')+(s.flaky?', '+s.flaky+' flaky':'')+(s.skipped?', '+s.skipped+' skipped':'')+' · '+ms(data.duration)+(meta?' · '+meta:'')];
|
|
966
|
+
const bad=data.tests.filter(t=>isFail(t.outcome)).sort((a,b)=>rank(a)-rank(b)).slice(0,10);
|
|
967
|
+
if(bad.length){ lines.push('Failures:'); for(const t of bad) lines.push('• '+[t.meta.priority,t.meta.severity].filter(Boolean).join('/')+(t.meta.priority||t.meta.severity?' ':'')+t.title+(t.meta.owner?' ('+t.meta.owner+')':'')+(t.meta.story?' '+t.meta.story:'')); if(f>bad.length) lines.push('… and '+(f-bad.length)+' more'); }
|
|
968
|
+
const owners=byOwner(); if(owners.length>1||(owners.length===1&&owners[0].owner!=='unassigned')) lines.push('By owner: '+owners.map(o=>o.owner+' '+(o.failed?o.failed:'')+(o.failed&&o.flaky?'+':'')+(o.flaky?o.flaky+' flaky':'')).join(' · '));
|
|
969
|
+
return lines.join('\n');
|
|
970
|
+
}
|
|
971
|
+
function header(){
|
|
972
|
+
const html = document.documentElement;
|
|
973
|
+
const toggle = h('button',{class:'tbtn',title:'Toggle light/dark','aria-label':'Toggle theme',onclick:()=>{
|
|
974
|
+
const next=isDark()?'light':'dark'; html.setAttribute('data-theme', next); try{localStorage.setItem('rl-theme',next);}catch(e){}
|
|
975
|
+
}}, '◐');
|
|
976
|
+
const pal = h('select',{class:'pal','aria-label':'Palette',onchange:e=>{ html.setAttribute('data-palette',e.target.value); try{localStorage.setItem('rl-palette',e.target.value);}catch(e){} }},
|
|
977
|
+
[['lab','Blue'],['ocean','Ocean'],['ember','Ember'],['mono','Mono']].map(([v,l])=>h('option',{value:v,selected:html.getAttribute('data-palette')===v},l)));
|
|
978
|
+
const copy = h('button',{class:'btn',onclick:e=>copyText(summaryMarkdown(),e.currentTarget,'Copied for Slack')}, 'Copy summary');
|
|
979
|
+
return h('header',{class:'hdr'},
|
|
980
|
+
data.options.logo ? h('img',{class:'logo brand',src:data.options.logo,alt:''}) : h('div',{class:'logo',title:'Generated by reportingLabs','aria-label':'reportingLabs'}, document.getElementById('rl-logo').content.cloneNode(true)),
|
|
981
|
+
data.options.project ? h('div',{class:'proj-blk'}, h('h1',{}, data.title),
|
|
982
|
+
h('div',{class:'sub'}, [data.options.project.name, data.options.project.version?'v'+data.options.project.version:null, data.options.project.team].filter(Boolean).join(' · '),
|
|
983
|
+
data.options.project.url? [' · ', h('a',{href:data.options.project.url,target:'_blank',rel:'noopener'}, data.options.project.url.replace(/^https?:\/\//,''))] : null),
|
|
984
|
+
data.options.project.description? h('div',{class:'sub desc'}, data.options.project.description) : null)
|
|
985
|
+
: h('h1',{}, data.title),
|
|
986
|
+
h('div',{class:'hmeta'}, Object.entries(data.metadata).map(([k,v])=>h('span',{class:'chip'}, k+' ', h('b',{},v)))),
|
|
987
|
+
h('div',{class:'spacer'}),
|
|
988
|
+
h('span',{class:'when'}, new Date(data.startTime).toLocaleString()+' · '+ms(data.duration)+' · '+data.workers+' worker'+(data.workers===1?'':'s')),
|
|
989
|
+
h('div',{class:'ctl'}, copy, pal, toggle));
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
/* ---------- summary ---------- */
|
|
993
|
+
function summary(){
|
|
994
|
+
const s = data.stats;
|
|
995
|
+
const failed = s.failed+s.timedOut+s.interrupted;
|
|
996
|
+
const ran = s.total - s.skipped;
|
|
997
|
+
const ok = failed===0;
|
|
998
|
+
const rate = ran? Math.round(s.passed/ran*100):0;
|
|
999
|
+
const parts=[]; if(failed)parts.push(failed+' failed'); if(s.flaky)parts.push(s.flaky+' flaky'); if(s.skipped)parts.push(s.skipped+' skipped');
|
|
1000
|
+
const nClu=failureClusters().length;
|
|
1001
|
+
const nNew=PREV.length? data.tests.filter(t=>isFail(t.outcome)&&sinceInfo(t).kind==='new').length : null;
|
|
1002
|
+
const notRun=data.tests.filter(t=>!t.results.length||t.outcome==='interrupted').length;
|
|
1003
|
+
const banner=(data.runStatus==='interrupted'||data.runStatus==='timedout')? h('div',{class:'runbanner'}, h('b',{}, data.runStatus==='timedout'?'Global timeout hit.':'Run was interrupted.'), ' '+(notRun?notRun+' test'+(notRun>1?'s':'')+' did not finish, so the numbers below are partial.':'The numbers below may be partial.')) : null;
|
|
1004
|
+
const el = h('section',{class:'sum'}, banner,
|
|
1005
|
+
h('div',{class:'kpis'},
|
|
1006
|
+
hero(),
|
|
1007
|
+
pill('passed','Passed',s.passed,'var(--pass)', ok&&s.passed? 'Every test on first attempt' : 'On first attempt', '', hseries(e=>e.passed)),
|
|
1008
|
+
pill('failed','Failed',failed,'var(--fail)', failed? (nNew!=null? nNew+' new · '+(failed-nNew)+' known' : nClu+' root cause'+(nClu===1?'':'s')) : 'Nothing broke', failed?'down':'', hseries(e=>e.failed)),
|
|
1009
|
+
pill('flaky','Flaky',s.flaky,'var(--flaky)', s.flaky? 'Passed on retry' : 'No retries needed', '', hseries(e=>e.flaky)),
|
|
1010
|
+
pill('skipped','Skipped',s.skipped,'var(--skip)', s.skipped? 'Not executed' : 'Everything ran', '', hseries(e=>e.skipped))));
|
|
1011
|
+
if(data.options.widgets.runStrip && data.tests.length){
|
|
1012
|
+
const strip = h('div',{class:'strip',id:'strip'}, data.tests.map(t=>h('button',{class:'cell '+t.outcome,'data-id':t.id,title:t.title+' · '+label[t.outcome]+' · '+ms(t.duration),'aria-label':t.title,onclick:()=>select(t.id)})));
|
|
1013
|
+
el.append(strip, h('div',{class:'strip-cap'}, 'Every test in run order. Hover for details, click to open.'));
|
|
1014
|
+
}
|
|
1015
|
+
const W=data.options.widgets, g=[];
|
|
1016
|
+
const hasFail=data.tests.some(t=>isFail(t.outcome)||t.outcome==='flaky');
|
|
1017
|
+
if(W.attention && hasFail) g.push(h('div',{class:'card w6 fail-rail'}, h('h2',{},'Needs attention', h('span',{class:'hint'},(failed+s.flaky)+' open · ranked by priority and severity')), attention(8)));
|
|
1018
|
+
const clusters=failureClusters(); if(clusters.length) g.push(h('div',{class:'card w6 fail-rail'}, h('h2',{},'Failure clusters', h('span',{class:'hint'},clusters.length+' root cause'+(clusters.length>1?'s':'')+' · '+clusters.reduce((a,c)=>a+c.tests.length,0)+' failures')), clustersView(clusters.slice(0,6)), clusters.length>6?h('div',{class:'attn-foot'}, h('button',{onclick:()=>showView('failures')},'View all '+clusters.length+' clusters →')):null));
|
|
1019
|
+
if(W.dimensions) g.push(h('div',{class:'card w8'}, h('h2',{},'Breakdown', h('span',{class:'hint'},'click a row to filter')), breakdown()));
|
|
1020
|
+
if(W.slowest){ const reg=regressions().length; g.push(h('div',{class:'card'}, h('h2',{},'Slowest tests', reg?h('span',{class:'hint badge'},reg+' got slower'):null), tabbed([['slow','Slowest',slowest],['reg','Got slower'+(reg?' ('+reg+')':''),slowerView]]))); }
|
|
1021
|
+
if(W.flaky!==false && HRUNS.length>1) g.push(h('div',{class:'card'}, h('h2',{},'Flakiest tests', h('span',{class:'hint'},'last '+Math.min(10,HRUNS.length)+' runs')), flakiest()));
|
|
1022
|
+
if(W.skipped!==false) { const sc=skippedCard(); if(sc) g.push(sc); }
|
|
1023
|
+
if(W.environment!==false) { const ec=envCard(); if(ec) g.push(ec); }
|
|
1024
|
+
if(data.history.length>1) g.push(h('div',{class:'card w12'}, h('h2',{},'Trend', h('span',{class:'hint'},'last '+data.history.length+' runs')), trend()));
|
|
1025
|
+
else if(data.history.length===1) g.push(h('div',{class:'card w12'}, h('h2',{},'Trend', h('span',{class:'hint'},'from the second run')), h('div',{class:'nudge'}, h('b',{},'First run recorded.'),' Run the suite once more and this card shows the pass-rate trend, and every failure gets "new this run" or "failing since #…", last-10-runs dots, a Flakiest tests card and a Got slower tab. History lives in ',h('code',{},data.historyFile||'reporting-labs.history.json'),', commit it or cache it in CI.')));
|
|
1026
|
+
const ge=data.globalErrors||[], go=data.globalOutput||[];
|
|
1027
|
+
if(ge.length||go.some(x=>x.stream==='err')) g.unshift(h('div',{class:'card w12 fail-rail'}, h('h2',{}, ge.length? ge.length+' error'+(ge.length>1?'s':'')+' outside tests' : 'Output outside tests', h('span',{class:'hint'},'spec files that failed to load, global setup, worker crashes')),
|
|
1028
|
+
...ge.map(errorView), go.length? h('details',{class:'errfull'}, h('summary',{},'Console output outside tests ('+go.length+' chunks)'), h('pre',{class:'txt'}, go.map(x=>(x.stream==='err'?'[stderr] ':'')+x.text).join(''))) : null));
|
|
1029
|
+
if(g.length) el.append(h('div',{class:'grid'}, g));
|
|
1030
|
+
for(const sec of data.options.sections) el.append(h('div',{class:'card section'}, h('h2',{},sec.title), h('div',{class:'body',html:sec.html})));
|
|
1031
|
+
return el;
|
|
1032
|
+
}
|
|
1033
|
+
function pill(key,text,n,color,sub,tone,series){
|
|
1034
|
+
return h('button',{class:'pill kpi','aria-pressed':state.status===key,'data-k':key,style:'--c:'+color,title:'Show '+text.toLowerCase()+' tests',onclick:()=>{state.status=key;refresh();if(key!=='all')showView('tests');}},
|
|
1035
|
+
series? spark(series,color) : null, h('div',{class:'l'},text), h('div',{class:'v'},n), h('div',{class:'d '+(tone||'')},sub||''));
|
|
1036
|
+
}
|
|
1037
|
+
function initials(name){ return (name||'').split(/[\s\-–—·]+/).filter(Boolean).slice(0,2).map(w=>w[0]).join('').toUpperCase()||'R'; }
|
|
1038
|
+
function prevRun(){
|
|
1039
|
+
const H=data.history||[]; if(H.length<2) return null;
|
|
1040
|
+
const cur=H[H.length-1]; for(let i=H.length-2;i>=0;i--){ if(!cur.label||H[i].label!==cur.label) return H[i]; }
|
|
1041
|
+
return H[H.length-2];
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
/* ---------- run history per test ---------- */
|
|
1045
|
+
function runsOf(t){ return HRUNS.map(e=>({e, r:(t.key&&e.tests[t.key])||null})); }
|
|
1046
|
+
/* new vs known: walk back through earlier runs while the test kept failing */
|
|
1047
|
+
function sinceInfo(t){
|
|
1048
|
+
if(!PREV.length||!isFail(t.outcome)) return null;
|
|
1049
|
+
let since=null, seen=false;
|
|
1050
|
+
for(let i=PREV.length-1;i>=0;i--){ const r=PREV[i].tests[t.key]; if(!r) continue; seen=true; if(r[0]==='f') since=PREV[i]; else break; }
|
|
1051
|
+
if(!seen) return {kind:'new', label:'New test'};
|
|
1052
|
+
return since ? {kind:'known', since, label:'since '+runLabel(since)} : {kind:'new', label:'New'};
|
|
1053
|
+
}
|
|
1054
|
+
function sinceBadge(t, cls){
|
|
1055
|
+
const si=sinceInfo(t); if(!si) return null;
|
|
1056
|
+
return h('span',{class:(cls||'badge')+' since '+si.kind, title:si.kind==='new'?'Passed in the previous run':'Has been failing since '+runLabel(si.since)}, si.kind==='new'?'NEW':si.label);
|
|
1057
|
+
}
|
|
1058
|
+
/* last N runs as dots */
|
|
1059
|
+
function dots(t, n){
|
|
1060
|
+
const rs=runsOf(t).slice(-(n||10)); if(rs.length<2) return null;
|
|
1061
|
+
return h('span',{class:'dots','aria-label':'Last '+rs.length+' runs'}, rs.map(({e,r})=>h('i',{class:r?r[0]:'n', title:runLabel(e)+' · '+(r?({p:'passed',f:'failed',k:'flaky',s:'skipped'})[r[0]]:'not run')})));
|
|
1062
|
+
}
|
|
1063
|
+
function flakyScore(t){
|
|
1064
|
+
const rs=runsOf(t).map(x=>x.r&&x.r[0]).filter(c=>c&&c!=='s'); let k=0, flips=0;
|
|
1065
|
+
for(let i=0;i<rs.length;i++){ if(rs[i]==='k') k++; if(i&&rs[i]!==rs[i-1]&&(rs[i]!=='k'&&rs[i-1]!=='k')) flips++; }
|
|
1066
|
+
return {k, flips, runs:rs.length, score:k*2+flips};
|
|
1067
|
+
}
|
|
1068
|
+
function flakiest(){
|
|
1069
|
+
if(HRUNS.length<2) return h('div',{class:'empty'},'Run a few more times: flaky history builds up from reporting-labs.history.json.');
|
|
1070
|
+
const rows=data.tests.map(t=>({t, f:flakyScore(t)})).filter(x=>x.f.score>0).sort((a,b)=>b.f.score-a.f.score||b.f.k-a.f.k).slice(0,6);
|
|
1071
|
+
if(!rows.length) return h('div',{class:'ok'},'Nothing flaked across the last '+HRUNS.length+' runs.');
|
|
1072
|
+
return h('ul',{class:'flk'}, rows.map(({t,f})=>h('li',{}, h('button',{onclick:()=>select(t.id)},
|
|
1073
|
+
h('span',{class:'t'}, t.title),
|
|
1074
|
+
dots(t,10),
|
|
1075
|
+
h('span',{class:'m'}, (data.projects.length>1? t.project+' · ' : '')+(f.k?f.k+' flaky':'')+(f.k&&f.flips?' · ':'')+(f.flips?f.flips+' flip'+(f.flips>1?'s':''):'')+' in '+f.runs+' runs')))));
|
|
1076
|
+
}
|
|
1077
|
+
/* duration regression vs the previous run that has this test */
|
|
1078
|
+
function lastDur(t){ const r=t.results[t.results.length-1]; return r?r.duration:t.duration; }
|
|
1079
|
+
function prevDur(t){ for(let i=PREV.length-1;i>=0;i--){ const r=PREV[i].tests[t.key]; if(r&&r[0]!=='s') return {ms:r[1], e:PREV[i]}; } return null; }
|
|
1080
|
+
function regressions(){
|
|
1081
|
+
const out=[]; for(const t of data.tests){ if(t.outcome==='skipped') continue; const p=prevDur(t); if(!p||p.ms<=0) continue; const cur=lastDur(t); if(cur>=p.ms*2&&cur-p.ms>=500) out.push({t,prev:p.ms,cur,ratio:cur/p.ms}); }
|
|
1082
|
+
return out.sort((a,b)=>b.ratio-a.ratio);
|
|
1083
|
+
}
|
|
1084
|
+
function slowerView(){
|
|
1085
|
+
if(!PREV.length) return h('div',{class:'empty'},'Needs a previous run to compare against.');
|
|
1086
|
+
const rows=regressions().slice(0,6);
|
|
1087
|
+
if(!rows.length) return h('div',{class:'ok'},'No test got 2× slower than last run.');
|
|
1088
|
+
return h('ul',{class:'slow'}, rows.map(({t,prev,cur,ratio})=>h('li',{}, h('button',{onclick:()=>select(t.id)},
|
|
1089
|
+
h('span',{}, h('span',{class:'t'},t.title), h('span',{class:'bar',style:'--w:'+Math.min(100,Math.round(prev/cur*100))+'%'}, h('i',{style:'background:var(--flaky)'}))),
|
|
1090
|
+
h('span',{class:'d'}, h('b',{style:'color:var(--fail)'},'×'+(ratio>=10?Math.round(ratio):ratio.toFixed(1))), ' ', ms(prev)+' → '+ms(cur))))));
|
|
1091
|
+
}
|
|
1092
|
+
/* sparklines from the whole history (counts, no per-test data needed) */
|
|
1093
|
+
function spark(series, color, w, h2){
|
|
1094
|
+
w=w||64; h2=h2||20; const n=series.length; if(n<3) return null;
|
|
1095
|
+
const max=Math.max(...series,1), min=Math.min(...series,0); if(Math.max(...series)===Math.min(...series)) return null;
|
|
1096
|
+
const x=i=>1+i/(n-1)*(w-2), y=v=>h2-2-(max===min?0.5:(v-min)/(max-min))*(h2-4);
|
|
1097
|
+
const pts=series.map((v,i)=>x(i)+','+y(v)).join(' ');
|
|
1098
|
+
return h('span',{class:'sp','aria-hidden':'true',html:'<svg viewBox="0 0 '+w+' '+h2+'" width="'+w+'" height="'+h2+'"><polyline points="'+pts+'" fill="none" stroke="'+color+'" stroke-width="1.5" stroke-linejoin="round" stroke-linecap="round" opacity=".9"/><circle cx="'+x(n-1)+'" cy="'+y(series[n-1])+'" r="2.2" fill="'+color+'"/></svg>'});
|
|
1099
|
+
}
|
|
1100
|
+
function hseries(f){ return HIST.slice(-12).map(f); }
|
|
1101
|
+
/* owner rollup for the Failures view and the copied summary */
|
|
1102
|
+
function byOwner(){
|
|
1103
|
+
const m=new Map();
|
|
1104
|
+
for(const t of data.tests){ if(!isFail(t.outcome)&&t.outcome!=='flaky') continue; const o=t.meta.owner||'unassigned'; const e=m.get(o)||{owner:o,failed:0,flaky:0,tests:[]}; if(isFail(t.outcome)) e.failed++; else e.flaky++; e.tests.push(t); m.set(o,e); }
|
|
1105
|
+
return [...m.values()].sort((a,b)=>b.failed-a.failed||b.flaky-a.flaky||a.owner.localeCompare(b.owner));
|
|
1106
|
+
}
|
|
1107
|
+
function ownerCard(){
|
|
1108
|
+
const rows=byOwner(); if(!rows.length) return null;
|
|
1109
|
+
return h('div',{class:'card w12'}, h('h2',{},'By owner', h('span',{class:'hint'},rows.length+' owner'+(rows.length>1?'s':'')+' to ping')),
|
|
1110
|
+
h('ul',{class:'own'}, rows.map(o=>h('li',{}, h('button',{onclick:()=>{ if(o.owner!=='unassigned'&&DIMS.includes('owner')) state.dims.owner=o.owner; state.status='failed'; refresh(); showView('tests'); }},
|
|
1111
|
+
h('span',{class:'nm'},o.owner),
|
|
1112
|
+
h('span',{class:'cnts'}, [o.failed?h('b',{class:'f'},o.failed+' failed'):null, o.failed&&o.flaky?' · ':null, o.flaky?h('b',{class:'k'},o.flaky+' flaky'):null]),
|
|
1113
|
+
h('span',{class:'ts'}, o.tests.slice(0,3).map(t=>t.title).join(' · ')+(o.tests.length>3?' · +'+(o.tests.length-3):'')))))));
|
|
1114
|
+
}
|
|
1115
|
+
/* export */
|
|
1116
|
+
function download(name, text, type){
|
|
1117
|
+
const blob=new Blob([text],{type:type||'text/plain'}); const url=URL.createObjectURL(blob);
|
|
1118
|
+
const a=h('a',{href:url,download:name,style:'display:none'}); document.body.append(a); a.click(); setTimeout(()=>{URL.revokeObjectURL(url); a.remove();},500);
|
|
1119
|
+
}
|
|
1120
|
+
function csvCell(v){ v=v==null?'':String(v); return /[",\n]/.test(v)? '"'+v.replace(/"/g,'""')+'"' : v; }
|
|
1121
|
+
function failureRows(){
|
|
1122
|
+
const bad=data.tests.filter(t=>isFail(t.outcome)||t.outcome==='flaky').sort((a,b)=>rank(a)-rank(b));
|
|
1123
|
+
return bad.map(t=>{ const r=t.results[t.results.length-1], e=r&&r.errors[0], si=sinceInfo(t);
|
|
1124
|
+
return { title:t.title, suite:t.path.join(' > '), file:t.file, line:t.line, project:t.project, outcome:label[t.outcome], since:si?(si.kind==='new'?'new':runLabel(si.since)):'', priority:t.meta.priority||'', severity:t.meta.severity||'', owner:t.meta.owner||'', feature:t.meta.feature||'', story:t.meta.story||t.meta.issue||'', epic:t.meta.epic||'', attempts:t.results.length, duration_ms:Math.round(t.duration), reason:e&&e.explain?e.explain.label:'', why:e&&e.explain?e.explain.summary:'', error:e?e.message.split('\n')[0]:'', tags:t.tags.join(' ') }; });
|
|
1125
|
+
}
|
|
1126
|
+
function exportCsv(){ const rows=failureRows(); if(!rows.length) return; const cols=Object.keys(rows[0]); download(fileStem()+'-failures.csv', [cols.join(','), ...rows.map(r=>cols.map(c=>csvCell(r[c])).join(','))].join('\n'), 'text/csv'); }
|
|
1127
|
+
function exportJson(){ const rows=failureRows().map(r=>{ const t=data.tests.find(x=>x.title===r.title&&x.project===r.project&&x.file===r.file); const res=t&&t.results[t.results.length-1]; return Object.assign({}, r, {errorFull:res&&res.errors[0]?res.errors[0].message:''}); });
|
|
1128
|
+
download(fileStem()+'-failures.json', JSON.stringify({title:data.title, generatedAt:new Date(data.generatedAt).toISOString(), metadata:data.metadata, stats:data.stats, failures:rows},null,2), 'application/json'); }
|
|
1129
|
+
function fileStem(){ return (data.title||'report').toLowerCase().replace(/[^a-z0-9]+/g,'-').replace(/^-|-$/g,'').slice(0,40)||'report'; }
|
|
1130
|
+
/* expected vs received diff */
|
|
1131
|
+
function tokenDiff(a,b){
|
|
1132
|
+
const byChar=a.length<=160&&b.length<=160;
|
|
1133
|
+
const ta=byChar?[...a]:a.split(/(\s+)/).filter(x=>x!==''), tb=byChar?[...b]:b.split(/(\s+)/).filter(x=>x!=='');
|
|
1134
|
+
const n=ta.length, m=tb.length; if(n*m>250000) return null;
|
|
1135
|
+
const L=Array.from({length:n+1},()=>new Uint16Array(m+1));
|
|
1136
|
+
for(let i=n-1;i>=0;i--) for(let j=m-1;j>=0;j--) L[i][j]=ta[i]===tb[j]?L[i+1][j+1]+1:Math.max(L[i+1][j],L[i][j+1]);
|
|
1137
|
+
const A=[], B=[]; let i=0,j=0;
|
|
1138
|
+
while(i<n&&j<m){ if(ta[i]===tb[j]){A.push([ta[i],0]);B.push([tb[j],0]);i++;j++;} else if(L[i+1][j]>=L[i][j+1]){A.push([ta[i],1]);i++;} else {B.push([tb[j],1]);j++;} }
|
|
1139
|
+
while(i<n){A.push([ta[i++],1]);} while(j<m){B.push([tb[j++],1]);}
|
|
1140
|
+
const join=(arr,cls)=>{ const out=[]; for(const [t,d] of arr){ const last=out[out.length-1]; if(last&&last.d===d) last.t+=t; else out.push({t,d}); } return out.map(x=>x.d?h('mark',{class:cls},x.t):x.t); };
|
|
1141
|
+
return {a:join(A,'del'), b:join(B,'ins')};
|
|
1142
|
+
}
|
|
1143
|
+
function errorView(e){ return h('div',{class:'errwrap'}, whyView(e.explain), errorWhere(e), errorBody(e), e.snippet? h('pre',{class:'snip'}, e.snippet) : null); }
|
|
1144
|
+
function whyView(x){
|
|
1145
|
+
if(!x) return null;
|
|
1146
|
+
return h('div',{class:'why '+x.kind}, h('div',{class:'why-l'}, h('span',{class:'why-k'},x.label), x.action? h('code',{class:'why-a'},x.action):null),
|
|
1147
|
+
h('div',{class:'why-s'},x.summary), x.hint? h('div',{class:'why-h'},x.hint):null);
|
|
1148
|
+
}
|
|
1149
|
+
function errorWhere(e){
|
|
1150
|
+
if(!e.location) return null;
|
|
1151
|
+
const l=e.location, txt=l.file+':'+l.line+(l.column?':'+l.column:'');
|
|
1152
|
+
const href=vscodeHref(l.file, l.line, l.column);
|
|
1153
|
+
return h('div',{class:'errloc'}, 'at ', href? h('a',{href,title:'Open in VS Code'},txt) : h('span',{},txt));
|
|
1154
|
+
}
|
|
1155
|
+
function errorBody(e){
|
|
1156
|
+
const msg=e.message||'';
|
|
1157
|
+
const box=h('div',{class:'err'}, msg, e.stack&&e.stack!==msg? h('details',{}, h('summary',{},'Stack trace'), h('div',{class:'stack'},e.stack)) : null);
|
|
1158
|
+
const ex=msg.match(/^(Expected[^:\n]{0,40}):[ \t]*(.+)$/m), rc=msg.match(/^(Received[^:\n]{0,40}):[ \t]*(.+)$/m);
|
|
1159
|
+
if(ex&&rc&&ex[2].trim()&&rc[2].trim()&&ex[2].length<2000&&rc[2].length<2000){
|
|
1160
|
+
const d=tokenDiff(ex[2].trim(), rc[2].trim());
|
|
1161
|
+
if(d){ return h('div',{}, h('div',{class:'ediff'},
|
|
1162
|
+
h('div',{class:'side exp'}, h('div',{class:'lbl'},ex[1]), h('div',{class:'val'},d.a)),
|
|
1163
|
+
h('div',{class:'side rcv'}, h('div',{class:'lbl'},rc[1]), h('div',{class:'val'},d.b))),
|
|
1164
|
+
h('details',{class:'errfull'}, h('summary',{},'Full message'), box)); }
|
|
1165
|
+
}
|
|
1166
|
+
const lines=msg.split('\n');
|
|
1167
|
+
if(lines.some(l=>/^- /.test(l))&&lines.some(l=>/^\+ /.test(l))){
|
|
1168
|
+
return h('div',{}, h('div',{class:'ediff lines'}, lines.map(l=>h('div',{class:'ln '+(/^- /.test(l)?'exp':/^\+ /.test(l)?'rcv':/^@@/.test(l)?'hunk':'')},l))), h('details',{class:'errfull'}, h('summary',{},'Full message'), box));
|
|
1169
|
+
}
|
|
1170
|
+
return box;
|
|
1171
|
+
}
|
|
1172
|
+
/* skipped reasons */
|
|
1173
|
+
function skipReason(t){ const a=t.annotations.find(x=>/^(skip|fixme|slow)$/i.test(x.type)&&x.description); return a? (a.type.toLowerCase()==='fixme'?'fixme: ':'')+a.description : (t.annotations.some(x=>/^fixme$/i.test(x.type))?'fixme':''); }
|
|
1174
|
+
function skippedCard(){
|
|
1175
|
+
const sk=data.tests.filter(t=>t.outcome==='skipped'); if(!sk.length) return null;
|
|
1176
|
+
const withReason=sk.filter(skipReason).length;
|
|
1177
|
+
return h('div',{class:'card'}, h('h2',{},'Skipped', h('span',{class:'hint'},sk.length+' test'+(sk.length>1?'s':'')+(withReason<sk.length?' · '+(sk.length-withReason)+' without a reason':''))),
|
|
1178
|
+
h('ul',{class:'skp'}, sk.slice(0,6).map(t=>h('li',{}, h('button',{onclick:()=>select(t.id)}, h('span',{class:'t'},t.title), h('span',{class:'r'},(data.projects.length>1? t.project+' · ' : '')+(skipReason(t)||'no reason given'))))),
|
|
1179
|
+
sk.length>6? h('li',{}, h('button',{onclick:()=>{state.status='skipped';refresh();showView('tests');}}, h('span',{class:'t',style:'color:var(--accent)'},'+'+(sk.length-6)+' more'))) : null));
|
|
1180
|
+
}
|
|
1181
|
+
/* environment card */
|
|
1182
|
+
function envCard(){
|
|
1183
|
+
const rows=(data.env||[]); const meta=Object.entries(data.metadata||{});
|
|
1184
|
+
if(!rows.length&&!meta.length) return null;
|
|
1185
|
+
return h('div',{class:'card'}, h('h2',{},'Environment'),
|
|
1186
|
+
h('dl',{class:'kv env'}, rows.map(r=>[h('dt',{},r.k), h('dd',{}, r.href? h('a',{href:r.href,target:'_blank',rel:'noopener'},r.v) : r.v)])));
|
|
1187
|
+
}
|
|
1188
|
+
/* feature × project heatmap */
|
|
1189
|
+
function heatmap(){
|
|
1190
|
+
const d=DIMS.includes('feature')?'feature':DIMS[0]; const vals=dimValues(d), ps=data.projects;
|
|
1191
|
+
const cell=(v,p)=>{ const ts=data.tests.filter(t=>t.meta[d]===v&&t.project===p); const f=ts.filter(t=>isFail(t.outcome)).length, k=ts.filter(t=>t.outcome==='flaky').length; return {ts,f,k}; };
|
|
1192
|
+
return h('div',{class:'hm-wrap'}, h('table',{class:'hm'},
|
|
1193
|
+
h('thead',{}, h('tr',{}, h('th',{},d), ps.map(p=>h('th',{},p)))),
|
|
1194
|
+
h('tbody',{}, vals.map(v=>h('tr',{}, h('th',{},v), ps.map(p=>{ const c=cell(v,p); if(!c.ts.length) return h('td',{class:'none'},'–');
|
|
1195
|
+
const cls=c.f?'bad':c.k?'warn':'ok', ratio=c.f/c.ts.length;
|
|
1196
|
+
return h('td',{class:cls,style:c.f?'--a:'+(0.25+ratio*0.75)+';color:'+(ratio>=0.5?'#fff':'var(--fail)'):'',title:c.ts.length+' tests · '+c.f+' failed · '+c.k+' flaky'}, h('button',{onclick:()=>{ state.dims[d]=v; state.project=p; state.status='all'; refresh(); showView('tests'); }}, c.f? h('b',{},c.f+' ✕') : c.k? h('b',{},c.k+' ~') : '✓', h('small',{},'/'+c.ts.length))); }))))),
|
|
1197
|
+
h('div',{class:'legend-inline'}, h('span',{style:'--c:var(--pass-bg)'},'all passed'), h('span',{style:'--c:var(--flaky-bg)'},'flaky'), h('span',{style:'--c:var(--fail)'},'failed, darker = higher share'), h('span',{style:'--c:transparent;margin-left:auto'},'click a cell to filter')));
|
|
1198
|
+
}
|
|
1199
|
+
function vscodeHref(file, line, column){
|
|
1200
|
+
if(data.options.editorLinks===false||!data.rootDir||!file) return null;
|
|
1201
|
+
const root=String(data.rootDir).replace(/\\/g,'/').replace(/\/$/,''); const abs=/^([a-zA-Z]:\/|\/)/.test(file)? file : root+'/'+file;
|
|
1202
|
+
return 'vscode://file'+(abs.startsWith('/')?'':'/')+abs+(line?':'+line+(column?':'+column:''):'');
|
|
1203
|
+
}
|
|
1204
|
+
function editorLink(t){
|
|
1205
|
+
const href=vscodeHref(t.file, t.line, t.column); if(!href) return null;
|
|
1206
|
+
return h('a',{class:'btn',href,title:'Open '+t.file+':'+t.line+' in VS Code'},'Open in VS Code');
|
|
1207
|
+
}
|
|
1208
|
+
function hero(){
|
|
1209
|
+
const s=data.stats, failed=s.failed+s.timedOut+s.interrupted, ran=s.total-s.skipped, total=s.total||1;
|
|
1210
|
+
const rate=ran?Math.round(s.passed/ran*100):0, ok=failed===0;
|
|
1211
|
+
const parts=[['passed',s.passed,'#3DDC8C'],['failed',failed,'#FF7A90'],['flaky',s.flaky,'#FFC65C'],['skipped',s.skipped,'rgba(255,255,255,.4)']].filter(p=>p[1]>0);
|
|
1212
|
+
const R=34, C=2*Math.PI*R; let off=0, arcs='<circle cx="42" cy="42" r="34" fill="none" stroke="rgba(255,255,255,.22)" stroke-width="9"/>';
|
|
1213
|
+
for(const [k,n,c] of parts){ const len=n/total*C; arcs+='<circle cx="42" cy="42" r="34" fill="none" stroke="'+c+'" stroke-width="9" stroke-dasharray="'+Math.max(0,len-2)+' '+(C-Math.max(0,len-2))+'" stroke-dashoffset="'+(-off)+'" transform="rotate(-90 42 42)"><title>'+label[k]+': '+n+'</title></circle>'; off+=len; }
|
|
1214
|
+
const ring=h('div',{class:'ring','aria-hidden':'true',html:'<svg viewBox="0 0 84 84">'+arcs+'<text x="42" y="47" text-anchor="middle">'+rate+'%</text></svg>'});
|
|
1215
|
+
const prev=prevRun(); let delta='';
|
|
1216
|
+
if(prev){ const pr=prev.total-prev.skipped, prate=pr?Math.round(prev.passed/pr*100):0, d=rate-prate; delta=(d===0?'Same as':d>0?'Up '+d+' pts from':'Down '+Math.abs(d)+' pts from')+' '+(prev.label||'last run'); }
|
|
1217
|
+
else delta=ok? 'Nothing to worry about.' : failed+' failed'+(s.flaky?', '+s.flaky+' flaky':'')+(s.skipped?', '+s.skipped+' skipped':'');
|
|
1218
|
+
return h('button',{class:'pill kpi hero','aria-pressed':state.status==='all','data-k':'all',title:'Show all tests',onclick:()=>{state.status='all';refresh();showView('tests');}},
|
|
1219
|
+
spark(hseries(e=>{ const rn=e.total-e.skipped; return rn?Math.round(e.passed/rn*100):0; }),'#fff'),
|
|
1220
|
+
data.options.widgets.outcome!==false? ring : null,
|
|
1221
|
+
h('div',{class:'body'},
|
|
1222
|
+
h('div',{class:'l'}, ok? 'All passed' : 'Pass rate'),
|
|
1223
|
+
h('div',{class:'v'}, s.passed, h('small',{}, 'of '+ran+' ran')),
|
|
1224
|
+
h('div',{class:'mini'}, parts.map(([k,n,c])=>h('i',{style:'width:'+(n/total*100)+'%;background:'+c}))),
|
|
1225
|
+
h('div',{class:'d'}, delta)));
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
function donut(){
|
|
1229
|
+
const s=data.stats, failed=s.failed+s.timedOut+s.interrupted, total=s.total||1;
|
|
1230
|
+
const parts=[['passed',s.passed],['failed',failed],['flaky',s.flaky],['skipped',s.skipped]].filter(p=>p[1]>0);
|
|
1231
|
+
const R=54, C=2*Math.PI*R; let off=0, arcs='';
|
|
1232
|
+
const gap=parts.length>1?3:0;
|
|
1233
|
+
for(const [k,n] of parts){ const len=n/total*C; arcs+='<circle r="'+R+'" cx="66" cy="66" fill="none" stroke="'+colorOf(k)+'" stroke-width="18" stroke-dasharray="'+Math.max(0,len-gap)+' '+(C-Math.max(0,len-gap))+'" stroke-dashoffset="'+(-off)+'" transform="rotate(-90 66 66)"><title>'+label[k]+': '+n+'</title></circle>'; off+=len; }
|
|
1234
|
+
const ran=s.total-s.skipped, rate=ran?Math.round(s.passed/ran*100):0;
|
|
1235
|
+
const svg=h('div',{html:'<svg viewBox="0 0 132 132">'+arcs+'<text class="c" x="66" y="64" text-anchor="middle">'+rate+'%</text><text class="cl" x="66" y="80" text-anchor="middle">pass rate</text></svg>'}).firstChild;
|
|
1236
|
+
return h('div',{class:'donut'}, svg, h('div',{class:'legend'}, parts.map(([k,n])=>h('button',{onclick:()=>{state.status=k;refresh();showView('tests');}}, h('span',{class:'dot',style:'background:'+colorOf(k)}), h('span',{},label[k]), h('span',{class:'n'},n)))));
|
|
1237
|
+
}
|
|
1238
|
+
function attention(limit){
|
|
1239
|
+
const bad=data.tests.filter(t=>isFail(t.outcome)||t.outcome==='flaky').sort((a,b)=>rank(a)-rank(b)||(isFail(b.outcome)-isFail(a.outcome))||b.duration-a.duration);
|
|
1240
|
+
if(!bad.length) return h('div',{class:'ok'},'No failures. Ship it.');
|
|
1241
|
+
const groups=new Map(); for(const t of bad){ const k=t.file+'::'+t.path.join('/')+'::'+t.title; const g=groups.get(k)||{t,projects:[]}; g.projects.push(t.project); groups.set(k,g); }
|
|
1242
|
+
const all=[...groups.values()], rows=limit?all.slice(0,limit):all;
|
|
1243
|
+
const sub=(t,projects)=>{ const parts=[t.file.split('/').pop()];
|
|
1244
|
+
if(data.projects.length>1) parts.push(projects.length>1? projects.length+' projects' : projects[0]);
|
|
1245
|
+
const si=sinceInfo(t); if(si) parts.push(si.kind==='new'? h('b',{class:'new'},'new this run') : 'failing since '+runLabel(si.since));
|
|
1246
|
+
const le=t.results[t.results.length-1]&&t.results[t.results.length-1].errors[0]; if(le&&le.explain) parts.push(h('span',{class:'rsn',title:le.explain.summary},le.explain.label));
|
|
1247
|
+
else if(t.outcome==='flaky') parts.push('passed on retry '+t.results.length);
|
|
1248
|
+
const out=[]; parts.forEach((x,k)=>{ if(k) out.push(' · '); out.push(x); }); return out; };
|
|
1249
|
+
const tbl=h('table',{class:'attn2'}, h('tbody',{}, rows.map(({t,projects})=>h('tr',{tabindex:'0',onclick:()=>select(t.id),onkeydown:e=>{ if(e.key==='Enter') select(t.id); }},
|
|
1250
|
+
h('td',{class:'pr'}, h('i',{class:'dot',style:'background:'+colorOf(bucket(t))}), h('span',{},t.meta.priority||label[t.outcome]), t.meta.severity? h('small',{},t.meta.severity) : null),
|
|
1251
|
+
h('td',{class:'tt'}, h('div',{class:'n'},t.title), h('div',{class:'s'}, sub(t,projects))),
|
|
1252
|
+
h('td',{class:'ow'}, t.meta.owner||'')))));
|
|
1253
|
+
const more=all.length-rows.length;
|
|
1254
|
+
return h('div',{class:'attn-wrap'}, tbl, more>0? h('div',{class:'attn-foot'}, h('button',{onclick:()=>showView('failures')}, 'View all '+all.length+' in Failures →')) : null);
|
|
1255
|
+
}
|
|
1256
|
+
function dimension(d){
|
|
1257
|
+
const vals=dimValues(d), keys=['passed','flaky','failed','skipped'];
|
|
1258
|
+
const rows=vals.map(v=>{ const ts=data.tests.filter(t=>t.meta[d]===v), n=ts.length||1, cnt={}; for(const k of keys) cnt[k]=ts.filter(t=>bucket(t)===k).length;
|
|
1259
|
+
return h('button',{class:'row','aria-pressed':state.dims[d]===v,title:ts.length+' tests',onclick:()=>{state.dims[d]=state.dims[d]===v?null:v;refresh();showView('tests');}},
|
|
1260
|
+
h('span',{class:'k'},v), h('span',{class:'bar'}, keys.map(k=>h('i',{style:'width:'+(cnt[k]/n*100)+'%;background:'+colorOf(k),title:label[k]+' '+cnt[k]}))),
|
|
1261
|
+
h('span',{class:'n'}, cnt.failed? h('b',{},cnt.failed+' ✕ ') : null, ts.length)); });
|
|
1262
|
+
const untagged=data.tests.filter(t=>!t.meta[d]).length;
|
|
1263
|
+
return h('div',{}, h('div',{class:'dim'}, rows), h('div',{class:'legend-inline'}, keys.map(k=>h('span',{style:'--c:'+colorOf(k)},label[k])), untagged?h('span',{style:'--c:transparent;margin-left:auto'},untagged+' without '+d):null));
|
|
1264
|
+
}
|
|
1265
|
+
function histogram(){
|
|
1266
|
+
const ds=data.tests.filter(t=>t.outcome!=='skipped').map(t=>t.duration); if(!ds.length) return h('div',{class:'empty'},'No timings');
|
|
1267
|
+
const edges=[0,250,500,1000,2000,5000,10000,30000,Infinity], lbl=['<250ms','250–500ms','0.5–1s','1–2s','2–5s','5–10s','10–30s','>30s'];
|
|
1268
|
+
const counts=edges.slice(0,-1).map((e,i)=>ds.filter(x=>x>=e&&x<edges[i+1]).length), max=Math.max(...counts,1);
|
|
1269
|
+
const last=counts.map((c,i)=>c?i:-1).filter(i=>i>-1).pop();
|
|
1270
|
+
return h('div',{class:'hist'}, counts.slice(0,last+1).map((c,i)=>h('div',{class:'b',title:c+' tests '+lbl[i]}, h('span',{class:'v'},c||''), h('i',{class:i>=4?'slow':'',style:'height:'+Math.max(2,c/max*70)+'px'}), h('span',{class:'l'},lbl[i]))));
|
|
1271
|
+
}
|
|
1272
|
+
function tagsChart(){
|
|
1273
|
+
const m=new Map(); for(const t of data.tests) for(const g of t.tags){ if(/[:=]/.test(g)||/^@P[0-4]$/i.test(g)) continue; const e=m.get(g)||{n:0,f:0}; e.n++; if(isFail(t.outcome)) e.f++; m.set(g,e); }
|
|
1274
|
+
const list=[...m.entries()].sort((a,b)=>b[1].f-a[1].f||b[1].n-a[1].n).slice(0,24);
|
|
1275
|
+
return h('div',{class:'tags'}, list.map(([g,e])=>h('button',{onclick:()=>{ const inp=document.querySelector('.tools input'); inp.value=g; state.q=g.toLowerCase(); refresh(); showView('tests'); }}, g, h('span',{class:'bar'}, h('i',{style:'width:'+((e.n-e.f)/e.n*100)+'%;background:var(--pass)'}), h('i',{style:'width:'+(e.f/e.n*100)+'%;background:var(--fail)'})), h('span',{style:'color:var(--ink-3)'},e.n))));
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
function tabbed(tabs){
|
|
1279
|
+
let cur=tabs[0][0]; const bar=h('div',{class:'bk-tabs'}), body=h('div',{});
|
|
1280
|
+
const render=()=>{ body.innerHTML=''; body.append(tabs.find(t=>t[0]===cur)[2]()); bar.querySelectorAll('button').forEach(b=>b.setAttribute('aria-selected',b.dataset.k===cur)); };
|
|
1281
|
+
for(const [k,l] of tabs) bar.append(h('button',{'data-k':k,onclick:()=>{cur=k;render();}},l));
|
|
1282
|
+
render(); return h('div',{}, bar, body);
|
|
1283
|
+
}
|
|
1284
|
+
function breakdown(){
|
|
1285
|
+
const tabs=[...DIMS.map(d=>[d,d[0].toUpperCase()+d.slice(1),()=>dimension(d)])];
|
|
1286
|
+
if(data.tests.length>1) tabs.push(['file','Spec file',byFile]);
|
|
1287
|
+
if(data.projects.length>1&&data.options.widgets.projects) tabs.push(['project','Project',projects]);
|
|
1288
|
+
if(data.options.widgets.tags&&data.tests.some(t=>t.tags.length)) tabs.push(['tags','Tags',tagsChart]);
|
|
1289
|
+
if(data.projects.length>1&&DIMS.length) tabs.push(['heat','Heatmap',heatmap]);
|
|
1290
|
+
if(!tabs.length) return h('div',{class:'empty'},'Add meta({ priority, severity, owner, feature }) to your tests to see breakdowns here.');
|
|
1291
|
+
const nudge=!DIMS.length? h('div',{class:'nudge'}, h('b',{},'Tip:'),' add ',h('code',{},"meta({ priority: 'P1', severity: 'major', owner: 'priya', feature: 'checkout' })"),' at the top of a test and this card gains Priority, Severity, Feature and Owner tabs, the failures get ranked, and owners get their own rollup.') : null;
|
|
1292
|
+
let cur=tabs[0][0]; const bar=h('div',{class:'bk-tabs'}), body=h('div',{});
|
|
1293
|
+
const render=()=>{ body.innerHTML=''; body.append(tabs.find(t=>t[0]===cur)[2]()); bar.querySelectorAll('button').forEach(b=>b.setAttribute('aria-selected',b.dataset.k===cur)); };
|
|
1294
|
+
for(const [k,l] of tabs) bar.append(h('button',{'data-k':k,onclick:()=>{cur=k;render();}},l));
|
|
1295
|
+
render(); return h('div',{}, nudge, bar, body);
|
|
1296
|
+
}
|
|
1297
|
+
function errorSignature(msg){
|
|
1298
|
+
return (msg||'').split('\n')[0].replace(/\d+(\.\d+)?(ms|s)\b/g,'N').replace(/\b\d{2,}\b/g,'N').replace(/["'][^"']{0,60}["']/g,'"…"').replace(/\s+/g,' ').trim().slice(0,160);
|
|
1299
|
+
}
|
|
1300
|
+
function failureClusters(){
|
|
1301
|
+
const m=new Map();
|
|
1302
|
+
for(const t of data.tests){ if(!isFail(t.outcome)) continue; const r=t.results[t.results.length-1]; const e=r&&r.errors[0]; const x=e&&e.explain; const sig=x&&!/^(thrown|script)$/.test(x.kind)? x.kind+'|'+(x.locator||x.url||'')+'|'+(x.matcher||x.action||'') : errorSignature(e?e.message:'(no error message)'); const c=m.get(sig)||{sig,sample:e?e.message.split('\n').slice(0,2).join('\n'):'(no error message)',why:e&&e.explain?e.explain:null,tests:[]}; c.tests.push(t); m.set(sig,c); }
|
|
1303
|
+
return [...m.values()].sort((a,b)=>b.tests.length-a.tests.length);
|
|
1304
|
+
}
|
|
1305
|
+
function clustersView(cl){
|
|
1306
|
+
return h('ol',{class:'clu2'}, cl.map(c=>{
|
|
1307
|
+
const byTitle=new Map(); for(const t of c.tests){ const g=byTitle.get(t.title)||[]; g.push(t); byTitle.set(t.title,g); }
|
|
1308
|
+
const names=[...byTitle.entries()].slice(0,6), extra=byTitle.size-names.length;
|
|
1309
|
+
const who=[]; names.forEach(([title,ts],k)=>{ if(k) who.push(h('span',{class:'sep'},'·')); who.push(h('button',{onclick:()=>select(ts[0].id),title:ts.map(t=>t.project).join(', ')}, title, data.projects.length>1&&ts.length>1? h('small',{},' ×'+ts.length) : null)); });
|
|
1310
|
+
if(extra>0) who.push(h('span',{class:'sep'},'·'), h('span',{class:'ex'},'+'+extra+' more'));
|
|
1311
|
+
return h('li',{}, h('span',{class:'n'}, c.tests.length, h('small',{},c.tests.length===1?'test':'tests')),
|
|
1312
|
+
h('div',{class:'b'}, c.why? h('div',{class:'why-c'}, h('span',{class:'why-k'},c.why.label), ' ', c.why.summary) : null, h('div',{class:'msg',title:c.sample}, c.sample.split('\n')[0]), h('div',{class:'who'}, who)));
|
|
1313
|
+
}));
|
|
1314
|
+
}
|
|
1315
|
+
function trend(){
|
|
1316
|
+
const H=data.history, W=760, HT=170, padL=34, padR=12, padT=12, padB=26, n=H.length;
|
|
1317
|
+
const x=i=>padL+(n===1?0:i/(n-1))*(W-padL-padR), y=v=>padT+(1-v/100)*(HT-padT-padB);
|
|
1318
|
+
const rate=e=>{ const ran=e.total-e.skipped; return ran?Math.round(e.passed/ran*100):0; };
|
|
1319
|
+
const failPct=e=>{ const ran=e.total-e.skipped; return ran?Math.round(e.failed/ran*100):0; };
|
|
1320
|
+
const maxD=Math.max(...H.map(e=>e.duration),1);
|
|
1321
|
+
let svg='<g class="grid">'; for(const v of [0,25,50,75,100]) svg+='<line x1="'+padL+'" x2="'+(W-padR)+'" y1="'+y(v)+'" y2="'+y(v)+'"/><text x="'+(padL-6)+'" y="'+(y(v)+3)+'" text-anchor="end">'+v+'%</text>'; svg+='</g>';
|
|
1322
|
+
svg+=H.map((e,i)=>'<rect class="dur" x="'+(x(i)-6)+'" y="'+(y(0)-(e.duration/maxD)*(HT-padT-padB)*0.5)+'" width="12" height="'+((e.duration/maxD)*(HT-padT-padB)*0.5)+'" rx="2"><title>'+ms(e.duration)+'</title></rect>').join('');
|
|
1323
|
+
svg+='<path class="area" d="M'+x(0)+','+y(0)+' '+H.map((e,i)=>'L'+x(i)+','+y(rate(e))).join(' ')+' L'+x(n-1)+','+y(0)+' Z"/>';
|
|
1324
|
+
svg+='<polyline class="fail" points="'+H.map((e,i)=>x(i)+','+y(failPct(e))).join(' ')+'"/>';
|
|
1325
|
+
svg+='<polyline class="pass" points="'+H.map((e,i)=>x(i)+','+y(rate(e))).join(' ')+'"/>';
|
|
1326
|
+
svg+=H.map((e,i)=>'<circle class="pt'+(i===n-1?' now':'')+'" cx="'+x(i)+'" cy="'+y(rate(e))+'" r="3.5"><title>'+new Date(e.time).toLocaleString()+(e.label?' · '+e.label:'')+' · '+rate(e)+'% pass · '+e.failed+' failed · '+ms(e.duration)+'</title></circle>').join('');
|
|
1327
|
+
const step=Math.max(1,Math.ceil(n/8));
|
|
1328
|
+
svg+=H.map((e,i)=>(i===n-1||(i%step===0&&n-1-i>=step))?'<text x="'+x(i)+'" y="'+(HT-6)+'" text-anchor="'+(i===n-1&&n>1?'end':'middle')+'">'+(e.label||new Date(e.time).toLocaleDateString(undefined,{month:'short',day:'numeric'}))+'</text>':'').join('');
|
|
1329
|
+
const colW=n>1?(x(1)-x(0)):(W-padL-padR);
|
|
1330
|
+
svg+='<line class="guide" x1="0" x2="0" y1="'+padT+'" y2="'+y(0)+'" style="display:none"/>';
|
|
1331
|
+
svg+=H.map((e,i)=>'<rect class="hit" data-i="'+i+'" x="'+(x(i)-colW/2)+'" y="0" width="'+colW+'" height="'+HT+'" fill="transparent"/>').join('');
|
|
1332
|
+
const svgEl=h('div',{html:'<svg viewBox="0 0 '+W+' '+HT+'">'+svg+'</svg>'}).firstChild;
|
|
1333
|
+
const tip=h('div',{class:'ttip'}); tip.hidden=true;
|
|
1334
|
+
const wrap=h('div',{class:'trend'}, svgEl, tip);
|
|
1335
|
+
const guide=svgEl.querySelector('.guide');
|
|
1336
|
+
const show=(i,ev)=>{ const e=H[i], ran=e.total-e.skipped, prev=H[i-1];
|
|
1337
|
+
const d=prev? rate(e)-rate(prev) : null;
|
|
1338
|
+
tip.innerHTML='<div class="tt-h">'+escape(e.label||'Run '+(i+1))+'<span>'+escape(new Date(e.time).toLocaleString())+'</span></div>'
|
|
1339
|
+
+'<div class="tt-big">'+rate(e)+'% <small>pass rate'+(d==null?'':d===0?' · same as previous':' · '+(d>0?'+':'')+d+' pts vs previous')+'</small></div>'
|
|
1340
|
+
+'<div class="tt-row"><i style="background:var(--pass)"></i>Passed<b>'+e.passed+'</b></div>'
|
|
1341
|
+
+'<div class="tt-row"><i style="background:var(--fail)"></i>Failed<b>'+e.failed+'</b></div>'
|
|
1342
|
+
+(e.flaky?'<div class="tt-row"><i style="background:var(--flaky)"></i>Flaky<b>'+e.flaky+'</b></div>':'')
|
|
1343
|
+
+(e.skipped?'<div class="tt-row"><i style="background:var(--skip)"></i>Skipped<b>'+e.skipped+'</b></div>':'')
|
|
1344
|
+
+'<div class="tt-row"><i style="background:var(--accent)"></i>Duration<b>'+ms(e.duration)+'</b></div>'
|
|
1345
|
+
+'<div class="tt-row"><i style="background:transparent"></i>Total<b>'+e.total+'</b></div>';
|
|
1346
|
+
tip.hidden=false; guide.style.display=''; guide.setAttribute('x1',x(i)); guide.setAttribute('x2',x(i));
|
|
1347
|
+
const box=wrap.getBoundingClientRect(); let lx=ev.clientX-box.left+14, ly=ev.clientY-box.top+14;
|
|
1348
|
+
if(lx+240>box.width) lx=Math.max(0,ev.clientX-box.left-254); if(ly+170>box.height) ly=Math.max(0,ly-190);
|
|
1349
|
+
tip.style.left=lx+'px'; tip.style.top=ly+'px'; };
|
|
1350
|
+
svgEl.addEventListener('mousemove',ev=>{ const r=ev.target.closest&&ev.target.closest('.hit'); if(!r){ tip.hidden=true; guide.style.display='none'; return; } show(+r.dataset.i,ev); });
|
|
1351
|
+
svgEl.addEventListener('mouseleave',()=>{ tip.hidden=true; guide.style.display='none'; });
|
|
1352
|
+
wrap.append(
|
|
1353
|
+
h('div',{class:'trend-cap'}, h('span',{style:'color:var(--pass)'},'— pass rate'), h('span',{style:'color:var(--fail)'},'- - fail rate'), h('span',{style:'color:var(--accent)'},'▮ duration'), h('span',{style:'margin-left:auto'}, 'this run: '+rate(H[n-1])+'% · '+ms(H[n-1].duration))));
|
|
1354
|
+
return wrap;
|
|
1355
|
+
}
|
|
1356
|
+
function workers(){
|
|
1357
|
+
const lanes=[]; for(let i=0;i<data.workers;i++) lanes.push({i,tests:0,fail:0,ms:0});
|
|
1358
|
+
for(const t of data.tests) for(const r of t.results){ const l=lanes[r.workerIndex]; if(!l) continue; l.tests++; l.ms+=r.duration; if(isFail(r.status)) l.fail++; }
|
|
1359
|
+
const max=Math.max(...lanes.map(l=>l.ms),1), busy=lanes.reduce((a,l)=>a+l.ms,0);
|
|
1360
|
+
const util=data.duration? Math.round(busy/(data.duration*data.workers)*100):0;
|
|
1361
|
+
return h('div',{}, h('div',{class:'wk-sum'}, data.workers+' parallel worker'+(data.workers===1?'':'s')+' · '+util+'% busy · wall clock '+ms(data.duration)+' vs '+ms(busy)+' of test time'),
|
|
1362
|
+
h('div',{class:'wk'}, lanes.map(l=>h('div',{class:'row'}, h('span',{class:'k'},'w'+l.i), h('span',{class:'bar'}, h('i',{style:'width:'+((l.ms-0)/max*100)+'%;background:'+(l.fail?'var(--fail)':'var(--pass)'),title:ms(l.ms)})), h('span',{class:'n'}, l.tests+' runs'+(l.fail?' · '+l.fail+' ✕':'')+' · '+ms(l.ms))))));
|
|
1363
|
+
}
|
|
1364
|
+
function byFile(){
|
|
1365
|
+
const m=new Map(); for(const t of data.tests){ const e=m.get(t.file)||{n:0,f:0,fl:0,ms:0}; e.n++; e.ms+=t.duration; if(isFail(t.outcome)) e.f++; if(t.outcome==='flaky') e.fl++; m.set(t.file,e); }
|
|
1366
|
+
const list=[...m.entries()].sort((a,b)=>b[1].f-a[1].f||b[1].n-a[1].n);
|
|
1367
|
+
return h('div',{class:'dim'}, list.map(([f,e])=>h('button',{class:'row',title:f+' · '+ms(e.ms),onclick:()=>{ const inp=document.querySelector('.tools input'); inp.value=f; state.q=f.toLowerCase(); refresh(); showView('tests'); }},
|
|
1368
|
+
h('span',{class:'k',style:'font:12px var(--mono)'},f.split('/').pop()), h('span',{class:'bar'}, h('i',{style:'width:'+((e.n-e.f-e.fl)/e.n*100)+'%;background:var(--pass)'}), h('i',{style:'width:'+(e.fl/e.n*100)+'%;background:var(--flaky)'}), h('i',{style:'width:'+(e.f/e.n*100)+'%;background:var(--fail)'})),
|
|
1369
|
+
h('span',{class:'n'}, e.f?h('b',{},e.f+' ✕ '):null, e.n))));
|
|
1370
|
+
}
|
|
1371
|
+
function timeline(){
|
|
1372
|
+
const W=900, laneH=18, pad=44, gap=6;
|
|
1373
|
+
const t0=data.startTime, t1=Math.max(...data.tests.flatMap(t=>t.results.map(r=>r.startTime+r.duration)), t0+1);
|
|
1374
|
+
const span=t1-t0, H=data.workers*(laneH+gap)+24;
|
|
1375
|
+
const x = t => pad+ (t-t0)/span*(W-pad-8);
|
|
1376
|
+
let s='';
|
|
1377
|
+
for(let i=0;i<data.workers;i++){ const y=i*(laneH+gap)+2; s+='<rect class="lane" x="'+pad+'" y="'+y+'" width="'+(W-pad-8)+'" height="'+laneH+'" rx="2"/><text x="0" y="'+(y+13)+'">w'+i+'</text>'; }
|
|
1378
|
+
for(const t of data.tests) for(const r of t.results){
|
|
1379
|
+
const y=r.workerIndex*(laneH+gap)+2, x0=x(r.startTime), w=Math.max(2,x(r.startTime+r.duration)-x0);
|
|
1380
|
+
const c = isFail(r.status)?'var(--fail)': r.status==='skipped'?'var(--skip)': (t.outcome==='flaky'?'var(--flaky)':'var(--pass)');
|
|
1381
|
+
s+='<rect class="r" data-id="'+t.id+'" x="'+x0+'" y="'+(y+3)+'" width="'+w+'" height="'+(laneH-6)+'" fill="'+c+'" style="cursor:pointer"><title>'+escape(t.title)+' (retry '+r.retry+') · '+ms(r.duration)+'</title></rect>';
|
|
1382
|
+
}
|
|
1383
|
+
const ticks=4; for(let i=0;i<=ticks;i++){ const t=t0+span*i/ticks; s+='<text x="'+x(t)+'" y="'+(H-4)+'" text-anchor="'+(i===ticks?'end':i===0?'start':'middle')+'">'+ms(t-t0)+'</text>'; }
|
|
1384
|
+
const svg=h('div',{html:'<svg class="tl" viewBox="0 0 '+W+' '+H+'" xmlns="http://www.w3.org/2000/svg">'+s+'</svg>'});
|
|
1385
|
+
svg.addEventListener('click',e=>{const id=e.target.getAttribute('data-id'); if(id) select(id);});
|
|
1386
|
+
return svg;
|
|
1387
|
+
}
|
|
1388
|
+
function slowest(){
|
|
1389
|
+
const top=[...data.tests].filter(t=>t.outcome!=='skipped').sort((a,b)=>b.duration-a.duration).slice(0,5);
|
|
1390
|
+
const max=top[0]?top[0].duration:1;
|
|
1391
|
+
return h('ul',{class:'slow'}, top.map(t=>h('li',{}, h('button',{onclick:()=>select(t.id)},
|
|
1392
|
+
h('span',{}, h('span',{class:'t'},t.title), h('span',{class:'bar',style:'--w:'+Math.max(4,Math.round(t.duration/max*100))+'%'}, h('i',{}))), h('span',{class:'d'},ms(t.duration))))));
|
|
1393
|
+
}
|
|
1394
|
+
function projects(){
|
|
1395
|
+
return h('div',{class:'proj'}, data.projects.map(p=>{
|
|
1396
|
+
const ts=data.tests.filter(t=>t.project===p), n=ts.length||1;
|
|
1397
|
+
const cnt=k=>ts.filter(t=>k==='failed'?isFail(t.outcome):t.outcome===k).length;
|
|
1398
|
+
return h('div',{class:'row'}, h('span',{class:'name',title:p},p),
|
|
1399
|
+
h('span',{class:'bar'}, ['passed','flaky','failed'].map(k=>h('i',{style:'width:'+(cnt(k)/n*100)+'%;background:var(--'+(k==='failed'?'fail':k==='passed'?'pass':'flaky')+')'}))),
|
|
1400
|
+
h('span',{class:'d',style:'font:11px var(--mono);color:var(--ink-3)'}, cnt('passed')+'/'+ts.length));
|
|
1401
|
+
}));
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
/* ---------- main ---------- */
|
|
1405
|
+
function main(){
|
|
1406
|
+
const projSel = h('select',{id:'projsel',onchange:e=>{state.project=e.target.value;refresh();}}, h('option',{value:'all'},'All projects'), data.projects.map(p=>h('option',{value:p},p)));
|
|
1407
|
+
return h('div',{class:'main'},
|
|
1408
|
+
h('aside',{class:'list'},
|
|
1409
|
+
h('div',{class:'tools'}, h('input',{type:'search',placeholder:'Search tests, tags, files…',oninput:e=>{state.q=e.target.value.toLowerCase();refresh();}}), data.projects.length>1?projSel:null,
|
|
1410
|
+
h('div',{class:'seg'}, [['file','Spec files'],['folder','Folders'],['flat','Flat']].map(([k,l])=>h('button',{'data-g':k,'aria-pressed':state.group===k,onclick:()=>{state.group=k;refresh();}},l))),
|
|
1411
|
+
DIMS.length? h('div',{class:'dims'}, DIMS.map(d=>h('select',{'data-dim':d,onchange:e=>{state.dims[d]=e.target.value||null;refresh();}}, h('option',{value:''},'Any '+d), dimValues(d).map(v=>h('option',{value:v},v))))) : null),
|
|
1412
|
+
h('div',{class:'items',id:'items'}),
|
|
1413
|
+
h('div',{class:'hint-kbd'}, h('span',{class:'kbd'},'j'),' / ',h('span',{class:'kbd'},'k'),' next / prev · ',h('span',{class:'kbd'},'f'),' failed only · ',h('span',{class:'kbd'},'/'),' search · ',h('span',{class:'kbd'},'1'),'–',h('span',{class:'kbd'},'5'),' switch view')),
|
|
1414
|
+
h('section',{class:'detail',id:'detail'}));
|
|
1415
|
+
}
|
|
1416
|
+
function visible(){
|
|
1417
|
+
return data.tests.filter(t=>{
|
|
1418
|
+
if(state.project!=='all'&&t.project!==state.project) return false;
|
|
1419
|
+
for(const d of DIMS) if(state.dims[d]&&t.meta[d]!==state.dims[d]) return false;
|
|
1420
|
+
if(state.status==='failed'? !isFail(t.outcome) : state.status!=='all'&&t.outcome!==state.status) return false;
|
|
1421
|
+
if(state.q){ const hay=(t.path.join(' ')+' '+t.title+' '+t.file+' '+t.tags.join(' ')+' '+t.project+' '+Object.values(t.meta).join(' ')).toLowerCase(); if(!hay.includes(state.q)) return false; }
|
|
1422
|
+
return true;
|
|
1423
|
+
});
|
|
1424
|
+
}
|
|
1425
|
+
function refresh(){
|
|
1426
|
+
document.querySelectorAll('.pill').forEach(p=>p.setAttribute('aria-pressed',p.dataset.k===state.status));
|
|
1427
|
+
document.querySelectorAll('.dim .row').forEach(r=>{ const card=r.closest('.card'); const d=card.querySelector('h2').textContent.replace(/^By /,''); r.setAttribute('aria-pressed', state.dims[d]===r.querySelector('.k').textContent); });
|
|
1428
|
+
document.querySelectorAll('select[data-dim]').forEach(sel=>{ sel.value=state.dims[sel.dataset.dim]||''; });
|
|
1429
|
+
const ps=$('#projsel'); if(ps) ps.value=state.project;
|
|
1430
|
+
const vis=visible(), ids=new Set(vis.map(t=>t.id));
|
|
1431
|
+
document.querySelectorAll('.cell').forEach(c=>c.classList.toggle('dim',!ids.has(c.dataset.id)));
|
|
1432
|
+
const box=$('#items'); box.innerHTML='';
|
|
1433
|
+
if(!vis.length){ box.append(h('div',{class:'empty'},'No tests match. Clear the search or pick another filter.')); return; }
|
|
1434
|
+
document.querySelectorAll('.seg button').forEach(b=>b.setAttribute('aria-pressed',b.dataset.g===state.group));
|
|
1435
|
+
const item=(t,inGroup)=>h('button',{class:'item','data-id':t.id,'aria-current':state.selected===t.id,onclick:()=>select(t.id)},
|
|
1436
|
+
h('span',{class:'st '+t.outcome}),
|
|
1437
|
+
h('span',{class:'tt'}, t.path.length&&!inGroup?h('div',{class:'p'},t.path.join(' › ')):null, h('div',{class:'n'},t.title), h('div',{class:'d'}, ms(t.duration)+(t.results.length>1?' · '+t.results.length+' attempts':'')+(data.projects.length>1?' · '+t.project:'')+(t.outcome==='skipped'&&skipReason(t)?' · '+skipReason(t):'')+(t.expectedFailure?' · expected failure':''))));
|
|
1438
|
+
const counts=ts=>{ const f=ts.filter(t=>isFail(t.outcome)).length; return h('span',{class:'cnt'}, f?h('b',{},f+' ✕'):null, h('span',{},ts.length)); };
|
|
1439
|
+
// describe blocks: a header per level, tests indented under it
|
|
1440
|
+
const grouped=(ts,indent)=>{
|
|
1441
|
+
const out=[]; let last=[];
|
|
1442
|
+
for(const t of ts){
|
|
1443
|
+
const p=t.path; let i=0; while(i<p.length && i<last.length && p[i]===last[i]) i++;
|
|
1444
|
+
for(let d=i; d<p.length; d++){
|
|
1445
|
+
const inSuite=ts.filter(x=>x.path.length>d && p.slice(0,d+1).every((seg,k)=>x.path[k]===seg));
|
|
1446
|
+
out.push(h('div',{class:'suite',style:'padding-left:'+(indent+d*14)+'px'}, h('span',{class:'tw'},'▾'), h('span',{class:'sn'},p[d]), counts(inSuite)));
|
|
1447
|
+
}
|
|
1448
|
+
const el=item(t,true); el.style.paddingLeft=(indent+p.length*14)+'px'; out.push(el); last=p;
|
|
1449
|
+
}
|
|
1450
|
+
return out;
|
|
1451
|
+
};
|
|
1452
|
+
if(state.group==='flat'){ for(const t of vis) box.append(item(t)); }
|
|
1453
|
+
else if(state.group==='file'){
|
|
1454
|
+
const byF=new Map(); for(const t of vis){ if(!byF.has(t.file)) byF.set(t.file,[]); byF.get(t.file).push(t); }
|
|
1455
|
+
for(const [f,ts] of byF){ box.append(h('div',{class:'file'},f)); for(const el of grouped(ts,12)) box.append(el); }
|
|
1456
|
+
} else {
|
|
1457
|
+
// folder tree
|
|
1458
|
+
const root={dirs:new Map(),files:new Map()};
|
|
1459
|
+
for(const t of vis){ const parts=t.file.split('/'); const fname=parts.pop(); let node=root; for(const p of parts){ if(!node.dirs.has(p)) node.dirs.set(p,{dirs:new Map(),files:new Map()}); node=node.dirs.get(p); } if(!node.files.has(fname)) node.files.set(fname,[]); node.files.get(fname).push(t); }
|
|
1460
|
+
const allTests=n=>[...n.files.values()].flat().concat([...n.dirs.values()].flatMap(allTests));
|
|
1461
|
+
const render=(node,path,depth)=>{
|
|
1462
|
+
const out=[];
|
|
1463
|
+
for(const [name,child] of [...node.dirs.entries()].sort()){ const key=path+name+'/'; const open=state.open[key]!==false; const ts=allTests(child);
|
|
1464
|
+
out.push(h('button',{class:'folder',style:'padding-left:'+(12+depth*14)+'px',onclick:()=>{state.open[key]=!open;refresh();}}, h('span',{class:'tw'},open?'▾':'▸'), '📁 '+name, counts(ts)));
|
|
1465
|
+
if(open) out.push(...render(child,key,depth+1)); }
|
|
1466
|
+
for(const [name,ts] of [...node.files.entries()].sort()){ const key=path+name; const open=state.open[key]!==false;
|
|
1467
|
+
out.push(h('button',{class:'file-row',style:'padding-left:'+(12+depth*14)+'px',onclick:()=>{state.open[key]=!open;refresh();}}, h('span',{class:'tw'},open?'▾':'▸'), name, h('span',{class:'mini'}, ts.map(t=>h('i',{style:'background:'+colorOf(bucket(t))})))));
|
|
1468
|
+
if(open) out.push(...grouped(ts,24+depth*14)); }
|
|
1469
|
+
return out;
|
|
1470
|
+
};
|
|
1471
|
+
for(const el of render(root,'',0)) box.append(el);
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
function firstInteresting(){ const f=data.tests.find(t=>isFail(t.outcome))||data.tests.find(t=>t.outcome==='flaky')||data.tests[0]; return f&&f.id; }
|
|
1475
|
+
|
|
1476
|
+
/* ---------- detail ---------- */
|
|
1477
|
+
function select(id, quiet){
|
|
1478
|
+
const t=data.tests.find(x=>x.id===id); if(!t) return;
|
|
1479
|
+
state.selected=id; state.retry=t.results.length-1; if(!quiet){ if(state.view!=='tests') showView('tests'); else setHash(); } refresh(); renderDetail(t);
|
|
1480
|
+
const it=document.querySelector('.item[data-id="'+id+'"]'); if(it&&it.scrollIntoView) it.scrollIntoView({block:'nearest'});
|
|
1481
|
+
}
|
|
1482
|
+
function renderDetail(t){
|
|
1483
|
+
const d=$('#detail'); d.innerHTML='';
|
|
1484
|
+
d.append(h('div',{class:'crumb'}, [t.file, ...t.path.map(p=>data.bdd&&!/^Feature:/i.test(p)?'Feature: '+p:p)].map(p=>h('span',{},p))),
|
|
1485
|
+
h('div',{class:'titlebar'}, h('h3',{},t.title), h('div',{class:'actions'},
|
|
1486
|
+
h('button',{class:'btn',onclick:e=>copyText(location.href.split('#')[0]+'#t='+t.id,e.currentTarget,'Link copied')},'Copy link'),
|
|
1487
|
+
(()=>{ const r=t.results[t.results.length-1]; const e=r&&r.errors[0]; return e? [h('button',{class:'btn',onclick:ev=>copyText(t.title+'\n'+t.file+':'+t.line+'\n\n'+e.message,ev.currentTarget,'Error copied')},'Copy error'), h('button',{class:'btn primary',onclick:()=>openBugReport(t)},'Bug report')] : null; })(),
|
|
1488
|
+
editorLink(t))),
|
|
1489
|
+
h('div',{class:'badges'}, h('span',{class:'badge '+t.outcome},label[t.outcome]), t.expectedFailure? h('span',{class:'badge xfail',title:'Marked test.fail(): failing is the expected result'},'Expected failure') : null, sinceBadge(t), dots(t,10), data.bdd?h('span',{class:'badge scenario'},'Scenario'):null, t.tags.map(g=>h('span',{class:'badge tag'},g)), data.projects.length>1?h('span',{class:'badge tag'},t.project):null, h('span',{class:'loc'}, t.file+':'+t.line+' · '+ms(t.duration)+(t.outcome==='timedOut'&&t.timeout?' · timeout '+ms(t.timeout):'')+(t.retries?' · retries '+t.retries:''))));
|
|
1490
|
+
const metaKeys=Object.keys(t.meta);
|
|
1491
|
+
const linkFor=(k,v)=>{ const tpl=data.options.links[k]||data.options.links['*']; if(tpl) return tpl.replace('{id}',encodeURIComponent(v)); if(/^https?:\/\//.test(v)) return v; return null; };
|
|
1492
|
+
if(metaKeys.length) d.append(h('div',{class:'metas'}, metaKeys.map(k=>{ const v=t.meta[k], low=/^(P[3-4]|low|minor|trivial|normal|medium)$/i.test(v), href=linkFor(k,v); return h('span',{class:'meta '+k+(low?' low':'')}, h('span',{class:'k'},k), href? h('a',{href,target:'_blank',rel:'noopener'},v) : h('span',{class:'v'},v)); })));
|
|
1493
|
+
const otherAnn=t.annotations.filter(a=>!DIMS.includes(a.type.toLowerCase()) && !(a.type.toLowerCase() in t.meta));
|
|
1494
|
+
if(otherAnn.length) d.append(h('h4',{},'Annotations'), h('dl',{class:'kv'}, otherAnn.map(a=>[h('dt',{},a.type),h('dd',{},a.description||'')])));
|
|
1495
|
+
if(t.results.length>1){
|
|
1496
|
+
d.append(h('div',{class:'tabs'}, t.results.map((r,i)=>h('button',{class:'tab','aria-selected':state.retry===i,onclick:()=>{state.retry=i;renderDetail(t);}}, (i===0?'Attempt 1':'Retry '+i)+' · '+(label[r.status]||r.status)))));
|
|
1497
|
+
}
|
|
1498
|
+
const r=t.results[state.retry]; if(!r){ d.append(h('p',{class:'empty'},'This test did not run.')); return; }
|
|
1499
|
+
const body=h('div',{});
|
|
1500
|
+
if(t.note&&state.retry===t.results.length-1) body.append(h('div',{class:'note '+(t.outcome==='passed'?'ok':'warn')}, t.note));
|
|
1501
|
+
if(r.errors.length){ body.append(h('h4',{},r.errors.length>1?'Errors':'Error'), ...r.errors.map(errorView)); }
|
|
1502
|
+
if(r.steps.length){ const stepTotal=Math.max(1, r.duration||0, r.steps.reduce((a,x)=>a+x.duration,0)); body.append(h('h4',{},data.bdd?'Scenario steps':'Steps', h('span',{class:'hint'},'bar = share of '+ms(stepTotal))), stepTree(r.steps, stepTotal)); }
|
|
1503
|
+
if(r.logs.length){ const t0=r.startTime; body.append(h('h4',{},'Log'), h('div',{class:'logs'}, r.logs.map(l=>h('div',{class:'ln'+(/\b(error|fail|exception)\b/i.test(l.msg)?' err':/\bwarn/i.test(l.msg)?' warn':'')}, h('span',{class:'ts'},'+'+ms(Math.max(0,l.t-t0))), h('span',{class:'lm'},l.msg))))); }
|
|
1504
|
+
for(const b of r.data){ body.append(h('h4',{},b.name), dataBlock(b)); }
|
|
1505
|
+
if(r.api.length){ body.append(h('h4',{},r.api.length+' API call'+(r.api.length>1?'s':'')), ...r.api.map(apiPanel)); body.append(h('div',{class:'mask-note'},'Secrets and auth headers are masked as ****')); }
|
|
1506
|
+
const imgs=r.attachments.filter(a=>a.src&&a.contentType.startsWith('image/'));
|
|
1507
|
+
const vids=r.attachments.filter(a=>a.src&&a.contentType.startsWith('video/'));
|
|
1508
|
+
const traces=r.attachments.filter(a=>a.src&&(a.name==='trace'||/\.zip$/.test(a.src)));
|
|
1509
|
+
const files=r.attachments.filter(a=>a.src&&!imgs.includes(a)&&!vids.includes(a)&&!traces.includes(a));
|
|
1510
|
+
const texts=r.attachments.filter(a=>a.text!=null);
|
|
1511
|
+
// visual comparison sets: <name>-expected / -actual / -diff
|
|
1512
|
+
const cmp=new Map();
|
|
1513
|
+
for(const a of imgs){ const m=a.name.match(/^(.*)-(expected|actual|diff)(\.\w+)?$/); if(m){ const set=cmp.get(m[1])||{}; set[m[2]]=a; cmp.set(m[1],set); } }
|
|
1514
|
+
const plainImgs=imgs.filter(a=>!/-(expected|actual|diff)(\.\w+)?$/.test(a.name));
|
|
1515
|
+
for(const [name,set] of cmp) if(set.expected&&set.actual) body.append(h('h4',{},'Visual comparison · '+name), compare(set)); else for(const k of Object.keys(set)) plainImgs.push(set[k]);
|
|
1516
|
+
if(vids.length){ body.append(h('h4',{},vids.length>1?'Videos':'Video'), h('div',{class:'vids'}, vids.map(a=>{ const fig=h('figure',{}); const v=h('video',{src:a.src,controls:'',preload:'metadata',playsinline:''});
|
|
1517
|
+
v.addEventListener('error',()=>{ const code=v.error&&v.error.code; const why=code===4?'The file is missing, or it is not a format this browser can play.':code===2?'The file could not be read.':'The file could not be decoded.'; v.replaceWith(h('div',{class:'att-err'}, h('b',{},'Video could not be loaded.'), ' '+why+' Expected at ', h('code',{},a.src), '. Common causes: on macOS, Chrome cannot read files next to a report opened from Downloads, Desktop or Documents until you allow it under System Settings → Privacy & Security → Files and Folders (or move the project elsewhere); or the assets folder was replaced by a newer run. Setting embedVideos: true in the reporter options puts videos inside the HTML and avoids both.')); });
|
|
1518
|
+
fig.append(v, h('figcaption',{}, a.name, a.size?h('span',{},' · '+kb(a.size)):null, ' · ', h('a',{href:a.src,download:'',target:'_blank',rel:'noopener',title:'Downloads when the report is served over http; opens in a new tab when opened as a file'},'download'))); return fig; }))); }
|
|
1519
|
+
if(plainImgs.length){ body.append(h('h4',{},plainImgs.length>1?'Screenshots':'Screenshot'), h('div',{class:'att'}, plainImgs.map(a=>h('figure',{}, h('img',{src:a.src,alt:a.name,loading:'lazy',onclick:()=>lightbox(a.src)}), h('figcaption',{},a.name))))); }
|
|
1520
|
+
if(traces.length){ body.append(h('h4',{},'Trace'), h('div',{class:'trace'}, traces.map(a=>h('div',{class:'trace-card'},
|
|
1521
|
+
h('div',{}, h('b',{},a.name), a.size?h('span',{style:'color:var(--ink-3)'},' · '+kb(a.size)):null),
|
|
1522
|
+
h('div',{class:'trace-how'}, 'Open with ', h('code',{},'npx playwright show-trace '+a.src), ' or drop the file on ', h('a',{href:'https://trace.playwright.dev',target:'_blank',rel:'noopener'},'trace.playwright.dev')),
|
|
1523
|
+
h('a',{class:'dl',href:a.src,download:''},'Download trace'))))); }
|
|
1524
|
+
if(files.length){ body.append(h('h4',{},'Files'), h('div',{class:'att'}, files.map(a=>h('figure',{}, h('div',{class:'file'}, h('a',{href:a.src,download:''},a.name), h('div',{style:'font-size:11px;color:var(--ink-3)'},a.contentType+(a.size?' · '+kb(a.size):''))))))); }
|
|
1525
|
+
for(const a of texts){ if(/^error-context/i.test(a.name)) body.append(h('details',{class:'errfull'}, h('summary',{},'Error context (written by Playwright for AI tools)'), h('pre',{class:'txt'},a.text))); else body.append(h('h4',{},a.name), h('pre',{class:'txt'},a.text)); }
|
|
1526
|
+
const conLines=(arr,forceErr)=>arr.join('').split('\n').filter(x=>x.trim()).map(x=>h('div',{class:'ln'+(forceErr||/\b(error|fail|exception)\b/i.test(x)?' err':/\bwarn/i.test(x)?' warn':'')}, h('span',{class:'lm'},x)));
|
|
1527
|
+
if(r.stdout.length) body.append(h('h4',{},'Console output', h('span',{class:'hint'},'console.log in this test')), h('div',{class:'logs plain'}, conLines(r.stdout,false)));
|
|
1528
|
+
if(r.stderr.length) body.append(h('h4',{},'Console errors', h('span',{class:'hint'},'console.error in this test')), h('div',{class:'logs plain'}, conLines(r.stderr,true)));
|
|
1529
|
+
if(!body.children.length) body.append(h('p',{style:'color:var(--ink-3)'}, r.status==='skipped'?'Skipped — nothing was executed.'+(skipReason(t)?' Reason: '+skipReason(t):''):'Passed with no steps or attachments recorded.'));
|
|
1530
|
+
d.append(body);
|
|
1531
|
+
}
|
|
1532
|
+
function stepTree(steps, total){
|
|
1533
|
+
return h('ul',{class:'steps'}, steps.map(s=>{
|
|
1534
|
+
const bad=!!s.error, kids=s.steps.length>0, pct=total?Math.min(100,s.duration/total*100):0;
|
|
1535
|
+
const li=h('li',{class:kids&&!hasError(s)?'collapsed':''});
|
|
1536
|
+
const row=h('div',{class:'step'+(bad?' bad':'')},
|
|
1537
|
+
h('span',{class:'tw'}, kids? '▸' : ''), data.bdd?null:h('span',{class:'cat'},s.category), gherkin(s.title), total? h('span',{class:'tb',title:Math.round(pct)+'% of the test'}, h('i',{class:pct>=30?'slow':'',style:'width:'+Math.max(pct,s.duration>0?1.5:0)+'%'})) : null, h('span',{class:'d'},ms(s.duration)));
|
|
1538
|
+
if(kids){ row.style.cursor='pointer'; row.addEventListener('click',()=>{li.classList.toggle('collapsed'); row.querySelector('.tw').textContent=li.classList.contains('collapsed')?'▸':'▾';}); if(!li.classList.contains('collapsed')) row.querySelector('.tw').textContent='▾'; }
|
|
1539
|
+
li.append(row); if(bad) li.append(h('div',{class:'e'},s.error)); if(kids) li.append(stepTree(s.steps, total));
|
|
1540
|
+
return li;
|
|
1541
|
+
}));
|
|
1542
|
+
}
|
|
1543
|
+
function gherkin(title){ const m=data.bdd&&title.match(/^(Given|When|Then|And|But)\b\s*(.*)$/); if(!m) return h('span',{class:'t',title},title); return h('span',{class:'t',title}, h('span',{class:'kw'+(/^(And|But)$/.test(m[1])?' and':'')},m[1]), m[2]); }
|
|
1544
|
+
function hasError(s){ return !!s.error || s.steps.some(hasError); }
|
|
1545
|
+
function dataBlock(b){
|
|
1546
|
+
if(b.kind==='table') return h('div',{}, h('div',{class:'tbl-wrap'}, h('table',{class:'tbl'}, h('thead',{}, h('tr',{}, b.columns.map(c=>h('th',{},c)))), h('tbody',{}, b.rows.map(r=>h('tr',{}, r.map(c=>h('td',{class:c==='****'?'mask':'',title:c},c))))))), h('div',{class:'mask-note'}, b.rows.length+' rows · sensitive columns masked'));
|
|
1547
|
+
if(b.kind==='kv') return h('dl',{class:'kv2'}, b.kv.map(([k,v])=>[h('dt',{},k),h('dd',{class:v==='****'?'mask':''},v)]));
|
|
1548
|
+
return h('pre',{class:'txt'},b.text);
|
|
1549
|
+
}
|
|
1550
|
+
function apiPanel(c){
|
|
1551
|
+
const st=c.status||0, cls=st>=500||st>=400?'bad':st>=300?'warn':'ok';
|
|
1552
|
+
const wrap=h('div',{class:'api collapsed'});
|
|
1553
|
+
const head=h('button',{class:'api-head',onclick:()=>wrap.classList.toggle('collapsed')}, h('span',{class:'m '+c.method.toUpperCase()},c.method.toUpperCase()), h('span',{class:'u',title:c.url},c.url), st?h('span',{class:'sc '+cls},st):null, c.duration!=null?h('span',{class:'d'},ms(c.duration)):null);
|
|
1554
|
+
const pre=v=>v==null?null:h('pre',{}, typeof v==='string'?v:JSON.stringify(v,null,2));
|
|
1555
|
+
const col=(title,headers,bodyv)=>h('div',{class:'api-col'}, h('h5',{},title), headers&&Object.keys(headers).length? [h('h5',{},'Headers'), pre(headers)] : null, bodyv!=null? [h('h5',{},'Body'), pre(bodyv)] : h('div',{style:'font-size:12px;color:var(--ink-3)'},'no body'));
|
|
1556
|
+
const tools=h('div',{class:'api-tools'}, h('button',{class:'btn',onclick:e=>copyText(curlOf(c),e.currentTarget,'Copied')},'Copy as cURL'), h('button',{class:'btn',onclick:e=>copyText(c.url,e.currentTarget,'Copied')},'Copy URL'));
|
|
1557
|
+
wrap.append(head, h('div',{class:'api-body'}, col('Request',c.requestHeaders,c.requestBody), col('Response',c.responseHeaders,c.responseBody)), tools);
|
|
1558
|
+
if(cls==='bad') wrap.classList.remove('collapsed');
|
|
1559
|
+
return wrap;
|
|
1560
|
+
}
|
|
1561
|
+
function curlOf(c){
|
|
1562
|
+
const q=v=>"'"+String(v).replace(/'/g,"'\\''")+"'";
|
|
1563
|
+
const hdr=c.requestHeaders||{}, type=Object.keys(hdr).filter(k=>k.toLowerCase()==='content-type').map(k=>hdr[k])[0]||'';
|
|
1564
|
+
const parts=['curl -X '+c.method.toUpperCase()+' '+q(c.url)];
|
|
1565
|
+
for(const k of Object.keys(hdr)) parts.push('-H '+q(k+': '+hdr[k]));
|
|
1566
|
+
if(c.requestBody!=null){
|
|
1567
|
+
let b=c.requestBody;
|
|
1568
|
+
if(typeof b==='object' && /x-www-form-urlencoded/i.test(type)) b=Object.keys(b).map(k=>encodeURIComponent(k)+'='+encodeURIComponent(String(b[k]))).join('&');
|
|
1569
|
+
else if(typeof b!=='string') b=JSON.stringify(b);
|
|
1570
|
+
if(!/^<(binary|file|multipart)/.test(b)) parts.push('--data-raw '+q(b));
|
|
1571
|
+
}
|
|
1572
|
+
return parts.join(' \\\n ');
|
|
1573
|
+
}
|
|
1574
|
+
function kb(n){ return n<1024?n+' B':n<1048576?(n/1024).toFixed(0)+' KB':(n/1048576).toFixed(1)+' MB'; }
|
|
1575
|
+
function compare(set){
|
|
1576
|
+
const wrap=h('div',{class:'cmp'});
|
|
1577
|
+
const tabs=h('div',{class:'cmp-tabs'});
|
|
1578
|
+
const stage=h('div',{class:'cmp-stage'});
|
|
1579
|
+
const views={
|
|
1580
|
+
slider:()=>{ const s=h('div',{class:'cmp-slider'}, h('img',{src:set.expected.src,alt:'expected'}), h('div',{class:'cmp-top'}, h('img',{src:set.actual.src,alt:'actual'})), h('div',{class:'cmp-handle'}));
|
|
1581
|
+
const rng=h('input',{type:'range',min:0,max:100,value:50,'aria-label':'Compare'}); const upd=()=>{ s.querySelector('.cmp-top').style.width=rng.value+'%'; s.querySelector('.cmp-handle').style.left=rng.value+'%'; }; rng.addEventListener('input',upd); upd();
|
|
1582
|
+
return h('div',{}, s, rng, h('div',{class:'cmp-cap'}, h('span',{},'expected'), h('span',{},'actual'))); },
|
|
1583
|
+
side:()=>h('div',{class:'cmp-side'}, ['expected','actual','diff'].filter(k=>set[k]).map(k=>h('figure',{}, h('img',{src:set[k].src,alt:k,onclick:()=>lightbox(set[k].src)}), h('figcaption',{},k)))),
|
|
1584
|
+
diff:()=>set.diff? h('figure',{class:'cmp-one'}, h('img',{src:set.diff.src,alt:'diff',onclick:()=>lightbox(set.diff.src)})) : h('p',{style:'color:var(--ink-3)'},'No diff image attached.'),
|
|
1585
|
+
};
|
|
1586
|
+
let cur='slider';
|
|
1587
|
+
const render=()=>{ stage.innerHTML=''; stage.append(views[cur]()); tabs.querySelectorAll('button').forEach(b=>b.setAttribute('aria-selected',b.dataset.v===cur)); };
|
|
1588
|
+
for(const [v,l] of [['slider','Slider'],['side','Side by side'],['diff','Diff']]) tabs.append(h('button',{class:'tab','data-v':v,onclick:()=>{cur=v;render();}},l));
|
|
1589
|
+
wrap.append(tabs,stage); render(); return wrap;
|
|
1590
|
+
}
|
|
1591
|
+
/* ---- bug report: a ready-to-paste ticket built from the failure ---- */
|
|
1592
|
+
function bugModel(t){
|
|
1593
|
+
const r=t.results[t.results.length-1], e=r&&r.errors[0], x=e&&e.explain, msg=e?e.message:'';
|
|
1594
|
+
const ex=msg.match(/^(Expected[^:\n]{0,40}):[ \t]*(.+)$/m), rc=msg.match(/^(Received[^:\n]{0,40}):[ \t]*(.+)$/m);
|
|
1595
|
+
const si=sinceInfo(t);
|
|
1596
|
+
const steps=[]; const walk=(list,depth)=>{ for(const st of list){ if(st.category==='hook'||/^Attach "/.test(st.title)||/^Worker Cleanup/.test(st.title)) continue; const user=st.category==='test.step'; if(user||depth===0) steps.push({title:st.title.replace(/^(Given|When|Then|And|But)\s+/,m=>m), failed:!!st.error, user}); if(user&&st.steps.length&&!st.steps.some(c=>c.category==='test.step')) continue; if(st.steps.length) walk(st.steps,depth+1); } };
|
|
1597
|
+
if(r) walk(r.steps,0);
|
|
1598
|
+
const userSteps=steps.filter(s=>s.user); const repro=(userSteps.length?userSteps:steps).filter(s=>!/^Expect "/.test(s.title)||s.failed);
|
|
1599
|
+
const env=[]; if(data.options.project&&data.options.project.name) env.push(['Application', data.options.project.name+(data.options.project.version?' v'+data.options.project.version:'')]);
|
|
1600
|
+
for(const [k,v] of Object.entries(data.metadata||{})) env.push([k,v]);
|
|
1601
|
+
if(data.projects.length>1||t.project) env.push(['Playwright project', t.project]);
|
|
1602
|
+
for(const row of (data.env||[])) if(!/^(Workers|Shard)$/.test(row.k)) env.push([row.k, row.href&&row.href!==row.v? row.v+' ('+row.href+')' : row.v]);
|
|
1603
|
+
const dataBlocks=(r?r.data:[]).map(b=>{ if(b.kind==='kv') return {name:b.name, lines:b.kv.map(([k,v])=>k+': '+v)}; if(b.kind==='table') return {name:b.name, lines:b.rows.slice(0,5).map(row=>row.map((c,i)=>(b.columns[i]||'')+'='+c).join(', ')).concat(b.rows.length>5?['… '+(b.rows.length-5)+' more rows']:[])}; return {name:b.name, lines:[String(b.text||'').slice(0,300)]}; });
|
|
1604
|
+
const api=(r?r.api:[]).map(c=>c.method.toUpperCase()+' '+c.url+' → '+(c.status||'no response')+(c.duration!=null?' ('+ms(c.duration)+')':''));
|
|
1605
|
+
const logs=(r?r.logs:[]).slice(-8).map(l=>l.msg);
|
|
1606
|
+
const att=(r?r.attachments:[]).filter(a=>a.contentType.startsWith('image/')||a.contentType.startsWith('video/')||/zip/.test(a.contentType)).map(a=>{ const kind=a.contentType.startsWith('video/')?'video':/zip/.test(a.contentType)?'trace':'screenshot'; return a.name.toLowerCase()===kind? kind : a.name+' ('+kind+')'; });
|
|
1607
|
+
const expected= ex? ex[2].trim() : (x&&x.kind==='not-found'? 'The element is present and the step completes.' : x&&x.kind==='not-visible'? 'The element is visible.' : x&&/^(network|navigation)$/.test(x.kind)? 'The page loads.' : x&&x.kind==='api'? 'The API responds successfully.' : 'The step completes and the test passes.');
|
|
1608
|
+
const actual= rc? rc[2].trim() : (x? x.summary : msg.split('\n')[0]);
|
|
1609
|
+
return { t, r, e, x, si, repro, env, dataBlocks, api, logs, att, expected, actual,
|
|
1610
|
+
title: t.title+(x? ' – '+x.label.toLowerCase() : ''),
|
|
1611
|
+
where: t.file+':'+t.line+(data.projects.length>1?' ['+t.project+']':''),
|
|
1612
|
+
history: si? (si.kind==='new'? 'New failure in this run' : 'Failing since '+runLabel(si.since)) : (t.outcome==='flaky'? 'Flaky: passed on retry' : ''),
|
|
1613
|
+
attempts: t.results.length, when: new Date(data.startTime).toLocaleString() };
|
|
1614
|
+
}
|
|
1615
|
+
function bugReport(t, fmt){
|
|
1616
|
+
const m=bugModel(t), L=[];
|
|
1617
|
+
const H=(txt)=> fmt==='jira'? 'h3. '+txt : fmt==='md'? '### '+txt : txt.toUpperCase();
|
|
1618
|
+
const B=(txt)=> fmt==='text'? txt : '*'+txt+'*';
|
|
1619
|
+
const FENCE=String.fromCharCode(96,96,96);
|
|
1620
|
+
const code=(txt)=> fmt==='jira'? ['{code}',txt,'{code}'] : fmt==='md'? [FENCE,txt,FENCE] : [txt];
|
|
1621
|
+
const li=(i,txt)=> (fmt==='jira'? '# ' : (i+1)+'. ')+txt;
|
|
1622
|
+
const bullet=(txt)=> (fmt==='jira'? '* ' : '- ')+txt;
|
|
1623
|
+
const kv=(k,v)=> fmt==='text'? k+': '+v : (fmt==='jira'? '*'+k+':* ' : '**'+k+':** ')+v;
|
|
1624
|
+
L.push(fmt==='jira'? 'h2. '+m.title : fmt==='md'? '## '+m.title : m.title, '');
|
|
1625
|
+
const pr=[m.t.meta.priority, m.t.meta.severity].filter(Boolean).join(' / ');
|
|
1626
|
+
if(pr) L.push(kv('Priority', pr)); if(m.t.meta.owner) L.push(kv('Owner', m.t.meta.owner)); if(m.t.meta.feature) L.push(kv('Feature', m.t.meta.feature));
|
|
1627
|
+
for(const k of ['story','epic','issue']) if(m.t.meta[k]) L.push(kv(k[0].toUpperCase()+k.slice(1), m.t.meta[k]));
|
|
1628
|
+
L.push(kv('Test', m.where), kv('Run', m.when+(m.attempts>1?' · failed '+m.attempts+' attempts':'')+(m.history?' · '+m.history:'')), '');
|
|
1629
|
+
if(m.x){ L.push(H('Summary'), m.x.summary, ''); }
|
|
1630
|
+
if(m.env.length){ L.push(H('Environment')); for(const [k,v] of m.env) L.push(bullet(k+': '+v)); L.push(''); }
|
|
1631
|
+
if(m.dataBlocks.length){ L.push(H('Test data')); for(const b of m.dataBlocks){ L.push(B(b.name)); for(const ln of b.lines) L.push(bullet(ln)); } L.push(''); }
|
|
1632
|
+
L.push(H('Steps to reproduce'));
|
|
1633
|
+
if(m.repro.length) m.repro.forEach((s,i)=>L.push(li(i, s.title+(s.failed?' ← fails here':'')))); else L.push(li(0,'Run the test: '+m.where));
|
|
1634
|
+
L.push('', H('Expected result'), m.expected, '', H('Actual result'), m.actual, '');
|
|
1635
|
+
if(m.e){ L.push(H('Error')); L.push(...code(m.e.message.split('\n').slice(0,12).join('\n').trim())); L.push(''); }
|
|
1636
|
+
if(m.api.length){ L.push(H('API calls')); for(const a of m.api) L.push(bullet(a)); L.push(''); }
|
|
1637
|
+
if(m.logs.length){ L.push(H('Test log')); L.push(...code(m.logs.join('\n'))); L.push(''); }
|
|
1638
|
+
if(m.att.length){ L.push(H('Attachments')); L.push('In the report next to this test: '+m.att.join(', ')); L.push(''); }
|
|
1639
|
+
L.push(fmt==='text'? 'Generated by reportingLabs' : '_Generated by reportingLabs_');
|
|
1640
|
+
return L.join('\n').replace(/\n{3,}/g,'\n\n');
|
|
1641
|
+
}
|
|
1642
|
+
function openBugReport(t){
|
|
1643
|
+
let fmt=localStorage.getItem('rl-bug-fmt')||'md';
|
|
1644
|
+
const ta=h('textarea',{class:'bug-ta',spellcheck:'false'});
|
|
1645
|
+
const render=()=>{ ta.value=bugReport(t,fmt); ta.scrollTop=0; seg.querySelectorAll('button').forEach(b=>b.setAttribute('aria-pressed',b.dataset.f===fmt)); };
|
|
1646
|
+
const seg=h('div',{class:'seg'}, [['md','Markdown'],['jira','Jira'],['text','Plain text']].map(([f,l])=>h('button',{'data-f':f,onclick:()=>{fmt=f; try{localStorage.setItem('rl-bug-fmt',f);}catch(e){} render();}},l)));
|
|
1647
|
+
const dlg=h('div',{class:'bugdlg',onclick:e=>{ if(e.target===dlg) dlg.remove(); }},
|
|
1648
|
+
h('div',{class:'bug-box',role:'dialog','aria-label':'Bug report'},
|
|
1649
|
+
h('div',{class:'bug-head'}, h('h3',{},'Bug report'), h('span',{class:'hint'},'Edit the text if you like, then copy it into Jira, GitHub, Azure DevOps or an email.'), h('button',{class:'btn',onclick:()=>dlg.remove()},'Close')),
|
|
1650
|
+
h('div',{class:'bug-tools'}, seg, h('div',{class:'grow'}), h('button',{class:'btn',onclick:()=>download((fileStem()+'-'+t.title.replace(/[^a-z0-9]+/gi,'-').toLowerCase()).slice(0,80)+(fmt==='md'?'.md':'.txt'), ta.value, 'text/plain')},'Download'), h('button',{class:'btn primary',onclick:e=>copyText(ta.value,e.currentTarget,'Copied')},'Copy')),
|
|
1651
|
+
ta));
|
|
1652
|
+
render(); document.body.append(dlg); ta.scrollTop=0; try{ ta.focus({preventScroll:true}); ta.setSelectionRange(0,0); }catch(e){}
|
|
1653
|
+
}
|
|
1654
|
+
function lightbox(src){ const lb=h('div',{class:'lb',onclick:()=>lb.remove()}, h('img',{src})); document.body.append(lb); }
|
|
1655
|
+
function escape(s){ return s.replace(/[&<>"]/g,c=>({'&':'&','<':'<','>':'>','"':'"'}[c])); }
|
|
1656
|
+
})();
|
|
1657
|
+
</script>
|
|
1658
|
+
</body>
|
|
1659
|
+
</html>
|