@monoes/monobrowse 1.0.12 → 1.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/dist/src/__tests__/profiler-heap.test.d.ts +2 -0
  2. package/dist/src/__tests__/profiler-heap.test.d.ts.map +1 -0
  3. package/dist/src/__tests__/profiler-heap.test.js +154 -0
  4. package/dist/src/__tests__/profiler-heap.test.js.map +1 -0
  5. package/dist/src/__tests__/report-a11y.test.d.ts +2 -0
  6. package/dist/src/__tests__/report-a11y.test.d.ts.map +1 -0
  7. package/dist/src/__tests__/report-a11y.test.js +147 -0
  8. package/dist/src/__tests__/report-a11y.test.js.map +1 -0
  9. package/dist/src/__tests__/report-analyze.test.d.ts +2 -0
  10. package/dist/src/__tests__/report-analyze.test.d.ts.map +1 -0
  11. package/dist/src/__tests__/report-analyze.test.js +157 -0
  12. package/dist/src/__tests__/report-analyze.test.js.map +1 -0
  13. package/dist/src/__tests__/report-budget.test.d.ts +2 -0
  14. package/dist/src/__tests__/report-budget.test.d.ts.map +1 -0
  15. package/dist/src/__tests__/report-budget.test.js +80 -0
  16. package/dist/src/__tests__/report-budget.test.js.map +1 -0
  17. package/dist/src/__tests__/report-diff.test.d.ts +2 -0
  18. package/dist/src/__tests__/report-diff.test.d.ts.map +1 -0
  19. package/dist/src/__tests__/report-diff.test.js +231 -0
  20. package/dist/src/__tests__/report-diff.test.js.map +1 -0
  21. package/dist/src/__tests__/report-evidence.test.d.ts +2 -0
  22. package/dist/src/__tests__/report-evidence.test.d.ts.map +1 -0
  23. package/dist/src/__tests__/report-evidence.test.js +214 -0
  24. package/dist/src/__tests__/report-evidence.test.js.map +1 -0
  25. package/dist/src/__tests__/report-flake.test.d.ts +2 -0
  26. package/dist/src/__tests__/report-flake.test.d.ts.map +1 -0
  27. package/dist/src/__tests__/report-flake.test.js +182 -0
  28. package/dist/src/__tests__/report-flake.test.js.map +1 -0
  29. package/dist/src/__tests__/report-history.test.d.ts +2 -0
  30. package/dist/src/__tests__/report-history.test.d.ts.map +1 -0
  31. package/dist/src/__tests__/report-history.test.js +229 -0
  32. package/dist/src/__tests__/report-history.test.js.map +1 -0
  33. package/dist/src/__tests__/report-output.test.d.ts +2 -0
  34. package/dist/src/__tests__/report-output.test.d.ts.map +1 -0
  35. package/dist/src/__tests__/report-output.test.js +169 -0
  36. package/dist/src/__tests__/report-output.test.js.map +1 -0
  37. package/dist/src/__tests__/report-png.test.d.ts +2 -0
  38. package/dist/src/__tests__/report-png.test.d.ts.map +1 -0
  39. package/dist/src/__tests__/report-png.test.js +84 -0
  40. package/dist/src/__tests__/report-png.test.js.map +1 -0
  41. package/dist/src/__tests__/report-render-extras.test.d.ts +2 -0
  42. package/dist/src/__tests__/report-render-extras.test.d.ts.map +1 -0
  43. package/dist/src/__tests__/report-render-extras.test.js +285 -0
  44. package/dist/src/__tests__/report-render-extras.test.js.map +1 -0
  45. package/dist/src/__tests__/report-render.test.d.ts +2 -0
  46. package/dist/src/__tests__/report-render.test.d.ts.map +1 -0
  47. package/dist/src/__tests__/report-render.test.js +143 -0
  48. package/dist/src/__tests__/report-render.test.js.map +1 -0
  49. package/dist/src/__tests__/report-run.test.d.ts +2 -0
  50. package/dist/src/__tests__/report-run.test.d.ts.map +1 -0
  51. package/dist/src/__tests__/report-run.test.js +234 -0
  52. package/dist/src/__tests__/report-run.test.js.map +1 -0
  53. package/dist/src/browser/index.d.ts +1 -0
  54. package/dist/src/browser/index.d.ts.map +1 -1
  55. package/dist/src/browser/index.js +1 -0
  56. package/dist/src/browser/index.js.map +1 -1
  57. package/dist/src/browser/profiler.d.ts.map +1 -1
  58. package/dist/src/browser/profiler.js +19 -22
  59. package/dist/src/browser/profiler.js.map +1 -1
  60. package/dist/src/cli/commands.d.ts.map +1 -1
  61. package/dist/src/cli/commands.js +254 -0
  62. package/dist/src/cli/commands.js.map +1 -1
  63. package/dist/src/report/a11y.d.ts +52 -0
  64. package/dist/src/report/a11y.d.ts.map +1 -0
  65. package/dist/src/report/a11y.js +231 -0
  66. package/dist/src/report/a11y.js.map +1 -0
  67. package/dist/src/report/analyze.d.ts +20 -0
  68. package/dist/src/report/analyze.d.ts.map +1 -0
  69. package/dist/src/report/analyze.js +136 -0
  70. package/dist/src/report/analyze.js.map +1 -0
  71. package/dist/src/report/budget.d.ts +27 -0
  72. package/dist/src/report/budget.d.ts.map +1 -0
  73. package/dist/src/report/budget.js +143 -0
  74. package/dist/src/report/budget.js.map +1 -0
  75. package/dist/src/report/collect-a11y.d.ts +25 -0
  76. package/dist/src/report/collect-a11y.d.ts.map +1 -0
  77. package/dist/src/report/collect-a11y.js +154 -0
  78. package/dist/src/report/collect-a11y.js.map +1 -0
  79. package/dist/src/report/collect.d.ts +45 -0
  80. package/dist/src/report/collect.d.ts.map +1 -0
  81. package/dist/src/report/collect.js +275 -0
  82. package/dist/src/report/collect.js.map +1 -0
  83. package/dist/src/report/evidence.d.ts +80 -0
  84. package/dist/src/report/evidence.d.ts.map +1 -0
  85. package/dist/src/report/evidence.js +279 -0
  86. package/dist/src/report/evidence.js.map +1 -0
  87. package/dist/src/report/flake.d.ts +88 -0
  88. package/dist/src/report/flake.d.ts.map +1 -0
  89. package/dist/src/report/flake.js +232 -0
  90. package/dist/src/report/flake.js.map +1 -0
  91. package/dist/src/report/history.d.ts +85 -0
  92. package/dist/src/report/history.d.ts.map +1 -0
  93. package/dist/src/report/history.js +176 -0
  94. package/dist/src/report/history.js.map +1 -0
  95. package/dist/src/report/index.d.ts +102 -0
  96. package/dist/src/report/index.d.ts.map +1 -0
  97. package/dist/src/report/index.js +216 -0
  98. package/dist/src/report/index.js.map +1 -0
  99. package/dist/src/report/pixel-diff.d.ts +30 -0
  100. package/dist/src/report/pixel-diff.d.ts.map +1 -0
  101. package/dist/src/report/pixel-diff.js +175 -0
  102. package/dist/src/report/pixel-diff.js.map +1 -0
  103. package/dist/src/report/png.d.ts +28 -0
  104. package/dist/src/report/png.d.ts.map +1 -0
  105. package/dist/src/report/png.js +259 -0
  106. package/dist/src/report/png.js.map +1 -0
  107. package/dist/src/report/render-evidence.d.ts +16 -0
  108. package/dist/src/report/render-evidence.d.ts.map +1 -0
  109. package/dist/src/report/render-evidence.js +174 -0
  110. package/dist/src/report/render-evidence.js.map +1 -0
  111. package/dist/src/report/render-trend.d.ts +16 -0
  112. package/dist/src/report/render-trend.d.ts.map +1 -0
  113. package/dist/src/report/render-trend.js +194 -0
  114. package/dist/src/report/render-trend.js.map +1 -0
  115. package/dist/src/report/render.d.ts +21 -0
  116. package/dist/src/report/render.d.ts.map +1 -0
  117. package/dist/src/report/render.js +286 -0
  118. package/dist/src/report/render.js.map +1 -0
  119. package/dist/src/report/run-diff.d.ts +18 -0
  120. package/dist/src/report/run-diff.d.ts.map +1 -0
  121. package/dist/src/report/run-diff.js +51 -0
  122. package/dist/src/report/run-diff.js.map +1 -0
  123. package/dist/src/report/structure.d.ts +41 -0
  124. package/dist/src/report/structure.d.ts.map +1 -0
  125. package/dist/src/report/structure.js +210 -0
  126. package/dist/src/report/structure.js.map +1 -0
  127. package/dist/src/report/trend.d.ts +26 -0
  128. package/dist/src/report/trend.d.ts.map +1 -0
  129. package/dist/src/report/trend.js +164 -0
  130. package/dist/src/report/trend.js.map +1 -0
  131. package/dist/src/report/types.d.ts +320 -0
  132. package/dist/src/report/types.d.ts.map +1 -0
  133. package/dist/src/report/types.js +11 -0
  134. package/dist/src/report/types.js.map +1 -0
  135. package/dist/src/report/util.d.ts +17 -0
  136. package/dist/src/report/util.d.ts.map +1 -0
  137. package/dist/src/report/util.js +45 -0
  138. package/dist/src/report/util.js.map +1 -0
  139. package/dist/tsconfig.tsbuildinfo +1 -1
  140. package/package.json +1 -1
  141. package/src/__tests__/profiler-heap.test.ts +191 -0
  142. package/src/__tests__/report-a11y.test.ts +180 -0
  143. package/src/__tests__/report-analyze.test.ts +202 -0
  144. package/src/__tests__/report-budget.test.ts +92 -0
  145. package/src/__tests__/report-diff.test.ts +272 -0
  146. package/src/__tests__/report-evidence.test.ts +276 -0
  147. package/src/__tests__/report-flake.test.ts +214 -0
  148. package/src/__tests__/report-history.test.ts +293 -0
  149. package/src/__tests__/report-output.test.ts +210 -0
  150. package/src/__tests__/report-png.test.ts +95 -0
  151. package/src/__tests__/report-render-extras.test.ts +315 -0
  152. package/src/__tests__/report-render.test.ts +175 -0
  153. package/src/__tests__/report-run.test.ts +264 -0
  154. package/src/browser/index.ts +1 -0
  155. package/src/browser/profiler.ts +28 -21
  156. package/src/cli/commands.ts +272 -0
  157. package/src/report/a11y.ts +242 -0
  158. package/src/report/analyze.ts +181 -0
  159. package/src/report/budget.ts +155 -0
  160. package/src/report/collect-a11y.ts +200 -0
  161. package/src/report/collect.ts +408 -0
  162. package/src/report/evidence.ts +379 -0
  163. package/src/report/flake.ts +303 -0
  164. package/src/report/history.ts +219 -0
  165. package/src/report/index.ts +307 -0
  166. package/src/report/pixel-diff.ts +197 -0
  167. package/src/report/png.ts +290 -0
  168. package/src/report/render-evidence.ts +194 -0
  169. package/src/report/render-trend.ts +225 -0
  170. package/src/report/render.ts +314 -0
  171. package/src/report/run-diff.ts +63 -0
  172. package/src/report/structure.ts +212 -0
  173. package/src/report/trend.ts +189 -0
  174. package/src/report/types.ts +356 -0
  175. package/src/report/util.ts +48 -0
@@ -0,0 +1,174 @@
1
+ /**
2
+ * Report sections for the recorded evidence timeline (RIG-11) and the flake
3
+ * analysis (RIG-14).
4
+ *
5
+ * The evidence section is written to be read the way someone triages a bug:
6
+ * a filmstrip of what the page looked like either side of the failure, then
7
+ * one time-ordered list mixing frames, console output and network failures,
8
+ * so "the error fired, then the screen went blank" is visible rather than
9
+ * inferred.
10
+ */
11
+ import { escapeHtml } from './util.js';
12
+ export const EVIDENCE_STYLES = `
13
+ .filmstrip{display:flex;gap:10px;overflow-x:auto;padding:4px 0 10px;margin:0 0 8px}
14
+ .filmstrip figure{flex:0 0 auto;width:180px;margin:0}
15
+ .filmstrip img{width:180px;height:auto;border-radius:6px}
16
+ .filmstrip figcaption{font-variant-numeric:tabular-nums}
17
+ .filmstrip figure.focus img{border-color:var(--fail);border-width:2px}
18
+ .timeline{list-style:none;margin:0;padding:0;border-left:2px solid var(--line);
19
+ margin-left:8px}
20
+ .timeline li{position:relative;padding:6px 0 6px 18px;font-size:13px}
21
+ .timeline li::before{content:"";position:absolute;left:-5px;top:12px;width:8px;height:8px;
22
+ border-radius:50%;background:var(--muted)}
23
+ .timeline li.error::before{background:var(--fail)}
24
+ .timeline li.warning::before{background:var(--warn)}
25
+ .timeline li.marker{font-weight:600;color:var(--fail)}
26
+ .timeline .at{display:inline-block;min-width:66px;color:var(--muted);
27
+ font-variant-numeric:tabular-nums;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}
28
+ .verdict.flaky{background:var(--warn-bg);border-color:var(--warn);color:var(--warn)}
29
+ .rate{display:inline-block;min-width:72px}
30
+ .bar{display:inline-block;width:80px;height:8px;border-radius:4px;background:var(--pass);
31
+ overflow:hidden;vertical-align:middle}
32
+ .bar i{display:block;height:100%;background:var(--fail)}
33
+ `.trim();
34
+ function at(offsetMs) {
35
+ const sign = offsetMs < 0 ? '−' : '+';
36
+ const abs = Math.abs(offsetMs);
37
+ return abs >= 1000 ? `${sign}${(abs / 1000).toFixed(2)}s` : `${sign}${Math.round(abs)}ms`;
38
+ }
39
+ // ---------------------------------------------------------------------------
40
+ // Evidence
41
+ // ---------------------------------------------------------------------------
42
+ function renderFilmstrip(evidence) {
43
+ if (!evidence.frames.length)
44
+ return '';
45
+ // Mark the frame closest to the failure so the eye lands on it first.
46
+ let focusIndex = -1;
47
+ if (evidence.focusOffsetMs !== null) {
48
+ let best = Infinity;
49
+ evidence.frames.forEach((f, i) => {
50
+ const d = Math.abs(f.offsetMs - evidence.focusOffsetMs);
51
+ if (d < best) {
52
+ best = d;
53
+ focusIndex = i;
54
+ }
55
+ });
56
+ }
57
+ const figures = evidence.frames
58
+ .map((f, i) => `<figure class="${i === focusIndex ? 'focus' : ''}">
59
+ <figcaption>${escapeHtml(at(f.offsetMs))}${i === focusIndex ? ' · at failure' : ''}</figcaption>
60
+ <img alt="${escapeHtml(`Frame at ${at(f.offsetMs)}`)}" src="${escapeHtml(f.dataUrl)}">
61
+ </figure>`)
62
+ .join('');
63
+ return `<div class="filmstrip">${figures}</div>`;
64
+ }
65
+ function renderTimelineRows(timeline) {
66
+ if (!timeline.length)
67
+ return '<p class="empty">Nothing was recorded for this run.</p>';
68
+ const rows = timeline
69
+ .map((e) => {
70
+ const detail = e.detail ? ` — ${escapeHtml(e.detail)}` : '';
71
+ const frame = e.kind === 'frame' && e.frameIndex !== undefined
72
+ ? ` <span style="color:var(--muted)">#${e.frameIndex + 1}</span>`
73
+ : '';
74
+ return `<li class="${e.severity}${e.kind === 'marker' ? ' marker' : ''}">
75
+ <span class="at">${escapeHtml(at(e.offsetMs))}</span>${escapeHtml(e.label)}${frame}${detail}
76
+ </li>`;
77
+ })
78
+ .join('');
79
+ return `<ul class="timeline">${rows}</ul>`;
80
+ }
81
+ export function renderEvidence(evidence) {
82
+ if (!evidence)
83
+ return '';
84
+ const why = evidence.reason === 'budget-failure'
85
+ ? 'Recorded because this run breached its budget.'
86
+ : 'Recorded because --record was passed.';
87
+ const focus = evidence.focusOffsetMs !== null
88
+ ? ` The timeline is centred on the first failure, at ${at(evidence.focusOffsetMs)} into the run.`
89
+ : '';
90
+ const notes = evidence.notes.length
91
+ ? `<p class="note">${evidence.notes.map((n) => escapeHtml(n)).join(' ')}</p>`
92
+ : '';
93
+ return `<h2>Evidence</h2>
94
+ <p class="note">${escapeHtml(why)}${escapeHtml(focus)} Offsets are measured from the start of the run.</p>
95
+ ${renderFilmstrip(evidence)}
96
+ ${renderTimelineRows(evidence.timeline)}
97
+ ${notes}`;
98
+ }
99
+ // ---------------------------------------------------------------------------
100
+ // Flake
101
+ // ---------------------------------------------------------------------------
102
+ function rateBar(check) {
103
+ const pct = Math.round(check.flakeRate * 100);
104
+ return `<span class="bar" role="img" aria-label="${escapeHtml(`failed ${pct}% of runs`)}"><i style="width:${pct}%"></i></span>`;
105
+ }
106
+ function renderChecks(flake) {
107
+ const rows = flake.checks
108
+ // Unstable checks first: they are the reason this section exists.
109
+ .sort((a, b) => Number(a.stable) - Number(b.stable) || b.flakeRate - a.flakeRate)
110
+ .map((c) => `<tr>
111
+ <td>${escapeHtml(c.label)}</td>
112
+ <td class="num mono"><span class="rate">${c.passed} of ${c.runs} passed</span></td>
113
+ <td>${rateBar(c)}</td>
114
+ <td>${c.stable ? (c.failed ? '<span class="pill error">always fails</span>' : '<span class="pill good">stable</span>') : '<span class="pill warning">flaky</span>'}</td>
115
+ <td class="wrap mono">${escapeHtml(c.actuals.join(', '))}</td>
116
+ </tr>`)
117
+ .join('');
118
+ return `<table><thead><tr><th>Check</th><th>Outcome</th><th>Failure rate</th><th></th><th>Measured each run</th></tr></thead>
119
+ <tbody>${rows}</tbody></table>`;
120
+ }
121
+ function renderSignals(flake) {
122
+ if (!flake.signals.length) {
123
+ return '<p class="empty">No error or failed request came and went between runs.</p>';
124
+ }
125
+ const rows = flake.signals
126
+ .slice(0, 30)
127
+ .map((s) => `<tr>
128
+ <td>${escapeHtml(s.kind)}</td>
129
+ <td class="wrap">${escapeHtml(s.signature)}</td>
130
+ <td class="num mono">${s.runs} of ${s.total}</td>
131
+ </tr>`)
132
+ .join('');
133
+ return `<table><thead><tr><th>Kind</th><th>Signal</th><th>Appeared in</th></tr></thead><tbody>${rows}</tbody></table>
134
+ <p class="note">Ids, hashes and long numbers are normalised before grouping, so one intermittent error is one row rather than N.</p>`;
135
+ }
136
+ function renderMetricSpread(flake) {
137
+ if (!flake.metrics.length)
138
+ return '';
139
+ const rows = flake.metrics
140
+ .map((m) => {
141
+ const fmt = (v) => m.unit === 'score'
142
+ ? v.toFixed(3)
143
+ : v >= 1000
144
+ ? `${(v / 1000).toFixed(2)}s`
145
+ : `${Math.round(v)}ms`;
146
+ return `<tr>
147
+ <td><b>${escapeHtml(m.label)}</b></td>
148
+ <td class="num mono">${escapeHtml(fmt(m.min))} – ${escapeHtml(fmt(m.max))}</td>
149
+ <td class="num mono">${escapeHtml(fmt(m.median))}</td>
150
+ <td class="num mono">${escapeHtml(fmt(m.spread))}</td>
151
+ <td>${m.unstable ? '<span class="pill warning">varies widely</span>' : '<span class="pill good">consistent</span>'}</td>
152
+ <td class="num mono">${m.measured} of ${m.total}</td>
153
+ </tr>`;
154
+ })
155
+ .join('');
156
+ return `<h3 style="font-size:13px;color:var(--muted);margin:24px 0 8px">Metric spread</h3>
157
+ <table><thead><tr><th>Metric</th><th>Range</th><th>Median</th><th>Spread</th><th></th><th>Measured</th></tr></thead>
158
+ <tbody>${rows}</tbody></table>`;
159
+ }
160
+ export function renderFlake(flake) {
161
+ if (!flake)
162
+ return '';
163
+ return `<h2>Repeatability — ${flake.runs} runs</h2>
164
+ <section class="verdict ${flake.verdict === 'pass' ? 'pass' : flake.verdict === 'fail' ? 'fail' : 'flaky'}">
165
+ <div class="tag">${flake.verdict.toUpperCase()}</div>
166
+ <div class="line">${escapeHtml(flake.headline)}</div>
167
+ </section>
168
+ <p class="note"><b>Confidence: ${escapeHtml(flake.confidence)}.</b> ${escapeHtml(flake.confidenceNote)}</p>
169
+ ${renderChecks(flake)}
170
+ <h3 style="font-size:13px;color:var(--muted);margin:24px 0 8px">Intermittent errors and requests</h3>
171
+ ${renderSignals(flake)}
172
+ ${renderMetricSpread(flake)}`;
173
+ }
174
+ //# sourceMappingURL=render-evidence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-evidence.js","sourceRoot":"","sources":["../../../src/report/render-evidence.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Report sections for the trend (RIG-13) and the run-to-run diff (RIG-10).
3
+ *
4
+ * Kept separate from render.ts purely for size. Same rules apply: no external
5
+ * resources, so the sparklines are hand-written inline SVG rather than a
6
+ * charting library, and the diff image is a `data:` URI.
7
+ *
8
+ * The design goal for the trend is legibility at a glance — the point of the
9
+ * feature is catching decay nobody noticed, which only works if the reader
10
+ * sees it without going looking.
11
+ */
12
+ import type { RunDiff, TrendReport } from './types.js';
13
+ export declare const TREND_STYLES: string;
14
+ export declare function renderTrend(trend: TrendReport | undefined): string;
15
+ export declare function renderDiff(diff: RunDiff | undefined): string;
16
+ //# sourceMappingURL=render-trend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-trend.d.ts","sourceRoot":"","sources":["../../../src/report/render-trend.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAgC,WAAW,EAAe,MAAM,YAAY,CAAC;AAMlG,eAAO,MAAM,YAAY,QAkBjB,CAAC;AAyCT,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,SAAS,GAAG,MAAM,CAyClE;AAsFD,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAmB5D"}
@@ -0,0 +1,194 @@
1
+ /**
2
+ * Report sections for the trend (RIG-13) and the run-to-run diff (RIG-10).
3
+ *
4
+ * Kept separate from render.ts purely for size. Same rules apply: no external
5
+ * resources, so the sparklines are hand-written inline SVG rather than a
6
+ * charting library, and the diff image is a `data:` URI.
7
+ *
8
+ * The design goal for the trend is legibility at a glance — the point of the
9
+ * feature is catching decay nobody noticed, which only works if the reader
10
+ * sees it without going looking.
11
+ */
12
+ import { formatTrendDelta, formatTrendValue } from './trend.js';
13
+ import { escapeHtml } from './util.js';
14
+ /** Rows shown per diff category before the tail is summarised. */
15
+ const MAX_DIFF_ROWS = 20;
16
+ export const TREND_STYLES = `
17
+ .headlines{background:var(--warn-bg);border:1px solid var(--warn);color:var(--warn);
18
+ border-radius:10px;padding:12px 16px;margin:0 0 16px}
19
+ .headlines p{margin:0 0 6px;font-size:14px}
20
+ .headlines p:last-child{margin-bottom:0}
21
+ .spark{display:block}
22
+ .spark .line{fill:none;stroke:var(--muted);stroke-width:1.5}
23
+ .spark .dot{fill:var(--ink)}
24
+ .dir{font-weight:600}
25
+ .dir.regressed{color:var(--fail)}
26
+ .dir.improved{color:var(--pass)}
27
+ .dir.flat,.dir.new{color:var(--muted)}
28
+ .verdictstrip{display:flex;flex-wrap:wrap;gap:4px;margin:0 0 16px;padding:0;list-style:none}
29
+ .verdictstrip li{width:13px;height:13px;border-radius:3px;background:var(--pass)}
30
+ .verdictstrip li.fail{background:var(--fail)}
31
+ .difftag{display:inline-block;margin:0 8px 8px 0;padding:4px 10px;border-radius:999px;
32
+ font-size:12px;background:var(--panel);border:1px solid var(--line)}
33
+ .difftag b{font-variant-numeric:tabular-nums}
34
+ `.trim();
35
+ // ---------------------------------------------------------------------------
36
+ // Trend
37
+ // ---------------------------------------------------------------------------
38
+ /**
39
+ * A sparkline as inline SVG. Flat series are drawn down the middle rather
40
+ * than at y=0, which is what a naive min/max scale does when every value is
41
+ * identical and it reads as a cliff.
42
+ */
43
+ function sparkline(series) {
44
+ const values = series.points.map((p) => p.value).filter((v) => v !== null);
45
+ if (values.length < 2)
46
+ return '<span style="color:var(--muted)">—</span>';
47
+ const width = 120;
48
+ const height = 24;
49
+ const min = Math.min(...values);
50
+ const max = Math.max(...values);
51
+ const span = max - min;
52
+ const x = (i) => (i / (values.length - 1)) * (width - 4) + 2;
53
+ const y = (v) => span === 0 ? height / 2 : height - 2 - ((v - min) / span) * (height - 4);
54
+ const points = values.map((v, i) => `${x(i).toFixed(1)},${y(v).toFixed(1)}`).join(' ');
55
+ const lastX = x(values.length - 1).toFixed(1);
56
+ const lastY = y(values[values.length - 1]).toFixed(1);
57
+ const label = `${series.label} over ${values.length} runs, ${formatTrendValue(series.unit, min)} to ${formatTrendValue(series.unit, max)}`;
58
+ return `<svg class="spark" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}" role="img" aria-label="${escapeHtml(label)}">
59
+ <polyline class="line" points="${points}"/>
60
+ <circle class="dot" cx="${lastX}" cy="${lastY}" r="2.5"/>
61
+ </svg>`;
62
+ }
63
+ const DIRECTION_WORD = {
64
+ regressed: 'worse',
65
+ improved: 'better',
66
+ flat: 'steady',
67
+ new: 'first',
68
+ };
69
+ export function renderTrend(trend) {
70
+ if (!trend)
71
+ return '';
72
+ if (trend.runs === 0) {
73
+ return `<h2>Trend</h2><p class="empty">First recorded run for this URL — from the next run on, this section compares against it.</p>`;
74
+ }
75
+ const headlines = trend.headlines.length
76
+ ? `<div class="headlines">${trend.headlines.map((h) => `<p>${escapeHtml(h)}</p>`).join('')}</div>`
77
+ : '';
78
+ const strip = `<ul class="verdictstrip" aria-label="Verdict per run, oldest first">${trend.verdictHistory
79
+ .map((v) => `<li class="${v.verdict}" title="${escapeHtml(`${v.capturedAt}: ${v.verdict}`)}"></li>`)
80
+ .join('')}</ul>`;
81
+ // A series nobody has ever measured is noise, not an absent trend.
82
+ const rows = trend.series
83
+ .filter((s) => s.points.some((p) => p.value !== null))
84
+ .map((s) => `<tr>
85
+ <td><b>${escapeHtml(s.label)}</b></td>
86
+ <td class="num mono">${escapeHtml(formatTrendValue(s.unit, s.previous))}</td>
87
+ <td class="num mono">${escapeHtml(formatTrendValue(s.unit, s.current))}</td>
88
+ <td class="num mono"><span class="dir ${s.direction}">${escapeHtml(formatTrendDelta(s.unit, s.deltaFromPrevious))}</span></td>
89
+ <td class="num mono">${escapeHtml(formatTrendDelta(s.unit, s.deltaFromOldest))}</td>
90
+ <td><span class="dir ${s.direction}">${DIRECTION_WORD[s.direction]}</span></td>
91
+ <td>${sparkline(s)}</td>
92
+ </tr>`)
93
+ .join('');
94
+ return `<h2>Trend — this run against the previous ${trend.runs}</h2>
95
+ ${headlines}
96
+ ${strip}
97
+ <table><thead><tr>
98
+ <th>Metric</th><th>Last run</th><th>This run</th><th>vs last</th>
99
+ <th>vs ${trend.runs} runs ago</th><th>Direction</th><th>History</th>
100
+ </tr></thead><tbody>${rows}</tbody></table>
101
+ <p class="note">Window starts ${escapeHtml(trend.windowFrom ?? 'unknown')}. Every metric here is lower-is-better, so a positive delta is a regression.</p>`;
102
+ }
103
+ // ---------------------------------------------------------------------------
104
+ // Diff
105
+ // ---------------------------------------------------------------------------
106
+ function nodeRows(nodes, kind) {
107
+ const shown = nodes.slice(0, MAX_DIFF_ROWS);
108
+ const rows = shown
109
+ .map((n) => `<tr>
110
+ <td>${escapeHtml(kind)}</td>
111
+ <td>${escapeHtml(n.role)}</td>
112
+ <td>${n.name ? escapeHtml(n.name) : '<span style="color:var(--muted)">(no accessible name)</span>'}</td>
113
+ <td class="wrap mono">${escapeHtml(n.path)}</td>
114
+ </tr>`)
115
+ .join('');
116
+ const rest = nodes.length - shown.length;
117
+ return rest > 0
118
+ ? `${rows}<tr><td colspan="4" style="color:var(--muted)">…and ${rest} more ${escapeHtml(kind)}</td></tr>`
119
+ : rows;
120
+ }
121
+ function renderStructure(diff) {
122
+ const tags = [
123
+ `<span class="difftag"><b>${diff.gained.length}</b> gained</span>`,
124
+ `<span class="difftag"><b>${diff.lost.length}</b> lost</span>`,
125
+ `<span class="difftag"><b>${diff.renamed.length}</b> renamed</span>`,
126
+ `<span class="difftag"><b>${diff.moved.length}</b> moved</span>`,
127
+ `<span class="difftag"><b>${diff.unchanged}</b> unchanged</span>`,
128
+ ].join('');
129
+ if (diff.changed === 0 && diff.moved.length === 0) {
130
+ return `${tags}<p class="empty">The accessibility tree is identical to the previous run.</p>`;
131
+ }
132
+ const renamedRows = diff.renamed
133
+ .slice(0, MAX_DIFF_ROWS)
134
+ .map((r) => `<tr>
135
+ <td>renamed</td>
136
+ <td>${escapeHtml(r.role)}</td>
137
+ <td>${escapeHtml(r.from ?? '(none)')} → <b>${escapeHtml(r.to ?? '(none)')}</b></td>
138
+ <td class="wrap mono">${escapeHtml(r.path)}</td>
139
+ </tr>`)
140
+ .join('');
141
+ const body = `${nodeRows(diff.gained, 'gained')}${nodeRows(diff.lost, 'lost')}${renamedRows}`;
142
+ return `${tags}
143
+ <table><thead><tr><th>Change</th><th>Role</th><th>Accessible name</th><th>Path</th></tr></thead>
144
+ <tbody>${body}</tbody></table>
145
+ <p class="note">Compared on the accessibility tree, not the DOM: a restyled class name is invisible here, while a control losing its label is not. Elements that only moved are counted but not listed.</p>`;
146
+ }
147
+ function renderPixels(diff) {
148
+ if (!diff.comparable)
149
+ return `<p class="empty">${escapeHtml(diff.note ?? 'Pixel diff unavailable.')}</p>`;
150
+ const pct = diff.changedPercent === 0
151
+ ? '0'
152
+ : diff.changedPercent < 0.01
153
+ ? '<0.01'
154
+ : diff.changedPercent.toFixed(2);
155
+ const size = diff.sizeChanged
156
+ ? `<span class="difftag">size <b>${diff.previousSize?.width}×${diff.previousSize?.height}</b> → <b>${diff.currentSize?.width}×${diff.currentSize?.height}</b></span>`
157
+ : '';
158
+ const tags = `<span class="difftag"><b>${pct}%</b> of pixels changed</span>
159
+ <span class="difftag"><b>${diff.changedPixels.toLocaleString('en-US')}</b> of ${diff.totalPixels.toLocaleString('en-US')} pixels</span>${size}`;
160
+ if (!diff.diffDataUrl) {
161
+ return `${tags}<p class="empty">The screenshots are pixel-identical.</p>`;
162
+ }
163
+ const scaled = diff.scale
164
+ ? ` Shown at 1/${diff.scale} scale; a change smaller than one output pixel is still marked.`
165
+ : '';
166
+ return `${tags}
167
+ <figure>
168
+ <figcaption>Changed pixels in magenta, over this run's screenshot.${escapeHtml(scaled)}</figcaption>
169
+ <img alt="Pixel differences against the previous run" src="${escapeHtml(diff.diffDataUrl)}">
170
+ </figure>
171
+ <p class="note">Per-channel tolerance is applied before counting, so anti-aliasing and font-hinting jitter do not register as change.</p>`;
172
+ }
173
+ export function renderDiff(diff) {
174
+ if (!diff)
175
+ return '';
176
+ const notes = diff.notes.length
177
+ ? `<p class="note">${diff.notes.map((n) => escapeHtml(n)).join(' ')}</p>`
178
+ : '';
179
+ const structure = diff.structure
180
+ ? `<h3 style="font-size:13px;color:var(--muted);margin:20px 0 8px">Structure</h3>${renderStructure(diff.structure)}`
181
+ : '';
182
+ const pixels = diff.pixels
183
+ ? `<h3 style="font-size:13px;color:var(--muted);margin:24px 0 8px">Pixels</h3>${renderPixels(diff.pixels)}`
184
+ : '';
185
+ if (!structure && !pixels) {
186
+ return `<h2>Changes since the previous run</h2>${notes || '<p class="empty">Nothing could be compared against the previous run.</p>'}`;
187
+ }
188
+ return `<h2>Changes since the previous run</h2>
189
+ <p class="note">Compared against the run of ${escapeHtml(diff.previousCapturedAt)}.</p>
190
+ ${structure}
191
+ ${pixels}
192
+ ${notes}`;
193
+ }
194
+ //# sourceMappingURL=render-trend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-trend.js","sourceRoot":"","sources":["../../../src/report/render-trend.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Renders a Report as ONE self-contained HTML file: CSS inline, screenshots
3
+ * as `data:` URIs, no fonts, no CDN, no network access of any kind at view
4
+ * time. That is not a stylistic preference — it is what lets monomind's
5
+ * document pipeline ingest the file as an ordinary document, so test history
6
+ * becomes searchable, and what lets the report be mailed or archived and
7
+ * still render years later.
8
+ *
9
+ * Reading order matches how you triage: verdict, errors, failed requests,
10
+ * vitals, accessibility, screenshots.
11
+ */
12
+ import type { FlakeReport } from './flake.js';
13
+ import type { Report } from './types.js';
14
+ import { escapeHtml } from './util.js';
15
+ export { escapeHtml };
16
+ export interface RenderOptions {
17
+ /** Present when the report came from `--repeat` (RIG-14). */
18
+ flake?: FlakeReport;
19
+ }
20
+ export declare function renderHtml(report: Report, options?: RenderOptions): string;
21
+ //# sourceMappingURL=render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../../src/report/render.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAG9C,OAAO,KAAK,EAAe,MAAM,EAA4B,MAAM,YAAY,CAAC;AAChF,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC,OAAO,EAAE,UAAU,EAAE,CAAC;AA6OtB,MAAM,WAAW,aAAa;IAC5B,6DAA6D;IAC7D,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAoD9E"}