@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,26 @@
1
+ /**
2
+ * Trends across a URL's run history (RIG-13).
3
+ *
4
+ * The point is catching slow decay. A single run that renders in 2.4s looks
5
+ * fine; the same page at 2.0s nine runs ago is a regression nobody filed a
6
+ * bug for, because no individual run ever crossed the budget. So every series
7
+ * reports two deltas — against the previous run (what just changed) and
8
+ * against the oldest run in the window (what has been happening) — and the
9
+ * second one is what produces a headline.
10
+ *
11
+ * Pure: the tests feed arrays of history records.
12
+ */
13
+ import type { HistoryRun } from './history.js';
14
+ import type { Report, TrendReport } from './types.js';
15
+ type Unit = 'ms' | 'score' | 'count';
16
+ export declare function formatTrendValue(unit: Unit, value: number | null): string;
17
+ export declare function formatTrendDelta(unit: Unit, delta: number | null): string;
18
+ /**
19
+ * Compare `current` against prior runs for the same URL.
20
+ *
21
+ * `history` is oldest-first and must NOT include the current run; callers
22
+ * save the run after building the trend so a run never trends against itself.
23
+ */
24
+ export declare function buildTrend(current: Report, history: HistoryRun[]): TrendReport;
25
+ export {};
26
+ //# sourceMappingURL=trend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trend.d.ts","sourceRoot":"","sources":["../../../src/report/trend.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EAAE,MAAM,EAA8B,WAAW,EAAe,MAAM,YAAY,CAAC;AAE/F,KAAK,IAAI,GAAG,IAAI,GAAG,OAAO,GAAG,OAAO,CAAC;AAkDrC,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAOzE;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAIzE;AA2FD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,WAAW,CAY9E"}
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Trends across a URL's run history (RIG-13).
3
+ *
4
+ * The point is catching slow decay. A single run that renders in 2.4s looks
5
+ * fine; the same page at 2.0s nine runs ago is a regression nobody filed a
6
+ * bug for, because no individual run ever crossed the budget. So every series
7
+ * reports two deltas — against the previous run (what just changed) and
8
+ * against the oldest run in the window (what has been happening) — and the
9
+ * second one is what produces a headline.
10
+ *
11
+ * Pure: the tests feed arrays of history records.
12
+ */
13
+ const SERIES = [
14
+ { key: 'lcp', label: 'LCP', unit: 'ms', read: (r) => r.vitals.lcp },
15
+ { key: 'fcp', label: 'FCP', unit: 'ms', read: (r) => r.vitals.fcp },
16
+ { key: 'cls', label: 'CLS', unit: 'score', read: (r) => r.vitals.cls },
17
+ { key: 'inp', label: 'INP', unit: 'ms', read: (r) => r.vitals.inp },
18
+ { key: 'ttfb', label: 'TTFB', unit: 'ms', read: (r) => r.vitals.ttfb },
19
+ {
20
+ key: 'consoleErrors',
21
+ label: 'Console errors',
22
+ unit: 'count',
23
+ read: (r) => r.counts.consoleErrors,
24
+ },
25
+ { key: 'pageErrors', label: 'Page errors', unit: 'count', read: (r) => r.counts.pageErrors },
26
+ {
27
+ key: 'failedRequests',
28
+ label: 'Failed requests',
29
+ unit: 'count',
30
+ read: (r) => r.counts.failedRequests,
31
+ },
32
+ {
33
+ key: 'a11yErrors',
34
+ label: 'Accessibility errors',
35
+ unit: 'count',
36
+ read: (r) => r.counts.a11yErrors,
37
+ },
38
+ ];
39
+ /**
40
+ * Smallest change worth calling a change. Chrome's own run-to-run variance on
41
+ * a paint metric is tens of milliseconds, so without a floor every series
42
+ * would report a direction every single run and the word would stop meaning
43
+ * anything.
44
+ */
45
+ function significant(unit, delta, base) {
46
+ const magnitude = Math.abs(delta);
47
+ if (unit === 'count')
48
+ return magnitude >= 1;
49
+ if (unit === 'score')
50
+ return magnitude >= 0.01;
51
+ const relative = base !== null && base > 0 ? base * 0.05 : 0;
52
+ return magnitude >= Math.max(25, relative);
53
+ }
54
+ export function formatTrendValue(unit, value) {
55
+ if (value === null || !Number.isFinite(value))
56
+ return '—';
57
+ if (unit === 'ms') {
58
+ return value >= 1000 ? `${(value / 1000).toFixed(2)}s` : `${Math.round(value)}ms`;
59
+ }
60
+ if (unit === 'score')
61
+ return value.toFixed(3);
62
+ return String(Math.round(value));
63
+ }
64
+ export function formatTrendDelta(unit, delta) {
65
+ if (delta === null || !Number.isFinite(delta) || delta === 0)
66
+ return 'no change';
67
+ const sign = delta > 0 ? '+' : '−';
68
+ return `${sign}${formatTrendValue(unit, Math.abs(delta))}`;
69
+ }
70
+ function clean(value) {
71
+ return typeof value === 'number' && Number.isFinite(value) ? value : null;
72
+ }
73
+ function buildSeries(def, history, current) {
74
+ const points = history.map((run) => ({
75
+ capturedAt: run.capturedAt,
76
+ value: clean(def.read(run)),
77
+ }));
78
+ const currentValue = clean(def.read({ vitals: current.vitals, counts: current.counts }));
79
+ points.push({ capturedAt: current.capturedAt, value: currentValue });
80
+ const priorWithValues = points.slice(0, -1).filter((p) => p.value !== null);
81
+ const previous = priorWithValues.length
82
+ ? priorWithValues[priorWithValues.length - 1].value
83
+ : null;
84
+ const oldest = priorWithValues.length ? priorWithValues[0].value : null;
85
+ const deltaFromPrevious = currentValue !== null && previous !== null ? currentValue - previous : null;
86
+ const deltaFromOldest = currentValue !== null && oldest !== null ? currentValue - oldest : null;
87
+ let direction = 'flat';
88
+ if (currentValue === null || previous === null) {
89
+ direction = 'new';
90
+ }
91
+ else if (deltaFromPrevious !== null && significant(def.unit, deltaFromPrevious, previous)) {
92
+ // Every metric here is lower-is-better, so the sign maps straight across.
93
+ direction = deltaFromPrevious > 0 ? 'regressed' : 'improved';
94
+ }
95
+ const series = {
96
+ key: def.key,
97
+ label: def.label,
98
+ unit: def.unit,
99
+ points,
100
+ current: currentValue,
101
+ previous,
102
+ oldest,
103
+ deltaFromPrevious,
104
+ deltaFromOldest,
105
+ direction,
106
+ };
107
+ // The creep sentence: drift across the whole window, which is invisible run
108
+ // to run. Needs at least three prior points to be worth asserting.
109
+ if (priorWithValues.length >= 3 &&
110
+ deltaFromOldest !== null &&
111
+ oldest !== null &&
112
+ significant(def.unit, deltaFromOldest, oldest)) {
113
+ const verb = deltaFromOldest > 0 ? 'crept up' : 'come down';
114
+ series.creep =
115
+ `${def.label} has ${verb} ${formatTrendValue(def.unit, Math.abs(deltaFromOldest))} ` +
116
+ `over ${points.length} runs (${formatTrendValue(def.unit, oldest)} → ${formatTrendValue(def.unit, currentValue)}).`;
117
+ }
118
+ return series;
119
+ }
120
+ /**
121
+ * Rank the creep sentences so the report leads with the worst. Regressions
122
+ * first, then by how far the metric moved relative to where it started.
123
+ */
124
+ function headlinesFor(series, history, current) {
125
+ const regressions = series
126
+ .filter((s) => s.creep && (s.deltaFromOldest ?? 0) > 0)
127
+ .sort((a, b) => {
128
+ const ratio = (s) => s.oldest && s.oldest > 0 ? Math.abs(s.deltaFromOldest ?? 0) / s.oldest : Infinity;
129
+ return ratio(b) - ratio(a);
130
+ })
131
+ .map((s) => s.creep);
132
+ const headlines = [...regressions];
133
+ // A verdict flip is the loudest thing that can happen, so it goes first.
134
+ const priorVerdicts = history.map((r) => r.verdict);
135
+ const allPassed = priorVerdicts.length > 0 && priorVerdicts.every((v) => v === 'pass');
136
+ const allFailed = priorVerdicts.length > 0 && priorVerdicts.every((v) => v === 'fail');
137
+ if (current.verdict === 'fail' && allPassed) {
138
+ headlines.unshift(`First failure in this window — the previous ${priorVerdicts.length} run(s) all passed.`);
139
+ }
140
+ else if (current.verdict === 'pass' && allFailed) {
141
+ headlines.unshift(`Back to passing — the previous ${priorVerdicts.length} run(s) all failed.`);
142
+ }
143
+ return headlines;
144
+ }
145
+ /**
146
+ * Compare `current` against prior runs for the same URL.
147
+ *
148
+ * `history` is oldest-first and must NOT include the current run; callers
149
+ * save the run after building the trend so a run never trends against itself.
150
+ */
151
+ export function buildTrend(current, history) {
152
+ const series = SERIES.map((def) => buildSeries(def, history, current));
153
+ return {
154
+ runs: history.length,
155
+ windowFrom: history.length ? history[0].capturedAt : null,
156
+ series,
157
+ verdictHistory: [
158
+ ...history.map((r) => ({ capturedAt: r.capturedAt, verdict: r.verdict })),
159
+ { capturedAt: current.capturedAt, verdict: current.verdict },
160
+ ],
161
+ headlines: headlinesFor(series, history, current),
162
+ };
163
+ }
164
+ //# sourceMappingURL=trend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trend.js","sourceRoot":"","sources":["../../../src/report/trend.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,320 @@
1
+ /**
2
+ * Shared shapes for `monobrowse report` — the one-command page test rig.
3
+ *
4
+ * The pipeline is collect (drive the browser) -> analyze (a11y rules +
5
+ * budget evaluation) -> render (self-contained HTML). Only `collect` talks
6
+ * to Chrome; everything downstream is a pure function over these types,
7
+ * which is what makes the analyzer and the renderer unit-testable without
8
+ * launching a browser.
9
+ */
10
+ export type A11yRuleId = 'unlabelled-control' | 'image-missing-alt' | 'form-field-no-label' | 'heading-order-jump' | 'negative-tabindex';
11
+ export type A11yImpact = 'error' | 'warning';
12
+ export interface A11yFinding {
13
+ rule: A11yRuleId;
14
+ impact: A11yImpact;
15
+ /** ARIA role as the AX tree reports it, lowercased. */
16
+ role: string;
17
+ /** Accessible name, or null when the finding IS the missing name. */
18
+ name: string | null;
19
+ /** CSS selector when we could resolve one, else `ax-node:<id>`. */
20
+ locator: string;
21
+ detail: string;
22
+ }
23
+ /**
24
+ * The subset of CDP's `Accessibility.AXNode` these rules read. Declared here
25
+ * rather than imported because snapshot.ts keeps its own copy private, and
26
+ * because tests feed in hand-written fixture trees.
27
+ *
28
+ * Note `nodeId` is a string on the wire (`AXNodeId`); number is accepted so
29
+ * fixtures can stay terse.
30
+ */
31
+ export interface AxNode {
32
+ nodeId: string | number;
33
+ ignored?: boolean;
34
+ role?: {
35
+ value?: unknown;
36
+ };
37
+ name?: {
38
+ value?: unknown;
39
+ };
40
+ properties?: Array<{
41
+ name: string;
42
+ value?: {
43
+ value?: unknown;
44
+ };
45
+ }>;
46
+ backendDOMNodeId?: number;
47
+ parentId?: string | number;
48
+ childIds?: Array<string | number>;
49
+ }
50
+ /**
51
+ * An element the DOM says has a negative tabindex. The AX tree cannot
52
+ * report tabindex at all, so this comes from a separate DOM sweep.
53
+ */
54
+ export interface FocusCandidate {
55
+ tag: string;
56
+ role: string;
57
+ name: string | null;
58
+ tabindex: number;
59
+ locator: string;
60
+ }
61
+ export interface ConsoleEntry {
62
+ type: string;
63
+ text: string;
64
+ url?: string;
65
+ lineNumber?: number;
66
+ timestamp: number;
67
+ }
68
+ export interface PageErrorEntry {
69
+ text: string;
70
+ url?: string;
71
+ lineNumber?: number;
72
+ columnNumber?: number;
73
+ timestamp: number;
74
+ }
75
+ export interface RequestEntry {
76
+ url: string;
77
+ method: string;
78
+ /**
79
+ * Wall-clock ms the request started, when the CDP monotonic clock could be
80
+ * aligned to Date.now(). Absent otherwise — the evidence timeline (RIG-11)
81
+ * is the only consumer and it degrades to omitting the request.
82
+ */
83
+ startedAtMs?: number;
84
+ status?: number;
85
+ mimeType?: string;
86
+ durationMs?: number;
87
+ encodedSize?: number;
88
+ /** True for a 4xx/5xx response or a request that never got one. */
89
+ failed: boolean;
90
+ /** CDP `Network.loadingFailed` errorText / blockedReason, when we saw one. */
91
+ errorText?: string;
92
+ }
93
+ export interface VitalsData {
94
+ lcp?: number;
95
+ fcp?: number;
96
+ cls?: number;
97
+ ttfb?: number;
98
+ inp?: number;
99
+ domInteractive?: number;
100
+ domContentLoaded?: number;
101
+ loadTime?: number;
102
+ resources?: number;
103
+ }
104
+ export interface Screenshot {
105
+ /** Device name, or 'page' for the default viewport shot. */
106
+ label: string;
107
+ width: number;
108
+ height: number;
109
+ /** `data:image/png;base64,...` — inlined so the HTML stays self-contained. */
110
+ dataUrl: string;
111
+ /** Where captureScreenshot also dropped the PNG, for callers that want it. */
112
+ path?: string;
113
+ }
114
+ export interface CaptureData {
115
+ /** URL as requested on the command line. */
116
+ url: string;
117
+ /** URL after redirects / client-side navigation. */
118
+ finalUrl: string;
119
+ title: string;
120
+ capturedAt: string;
121
+ durationMs: number;
122
+ console: ConsoleEntry[];
123
+ pageErrors: PageErrorEntry[];
124
+ requests: RequestEntry[];
125
+ vitals: VitalsData;
126
+ a11y: A11yFinding[];
127
+ screenshots: Screenshot[];
128
+ /**
129
+ * Flat AX-tree signature used for the structural diff. Optional because a
130
+ * page whose AX tree we could not read still produces a valid report.
131
+ */
132
+ structure?: StructureNode[];
133
+ /** Screencast frames + timeline, present only when evidence was recorded. */
134
+ evidence?: Evidence;
135
+ /** Raw recorder output, consumed by runReport and never serialized. */
136
+ recording?: Recording;
137
+ /** Anything that degraded — a timeout, a collector that came back empty. */
138
+ notes: string[];
139
+ }
140
+ /** `null` means "do not enforce this one". */
141
+ export interface Budget {
142
+ maxConsoleErrors: number | null;
143
+ maxPageErrors: number | null;
144
+ maxFailedRequests: number | null;
145
+ maxA11yErrors: number | null;
146
+ lcpMs: number | null;
147
+ clsScore: number | null;
148
+ inpMs: number | null;
149
+ fcpMs: number | null;
150
+ ttfbMs: number | null;
151
+ }
152
+ export interface BudgetFailure {
153
+ /** The budget key that was breached, e.g. `lcpMs`. */
154
+ budget: keyof Budget;
155
+ /** Human-readable threshold, e.g. `<= 2500ms`. */
156
+ expected: string;
157
+ /** Human-readable measurement, e.g. `3120ms`. */
158
+ actual: string;
159
+ /** Concrete evidence — which errors, which requests. */
160
+ detail?: string;
161
+ }
162
+ export type VerdictValue = 'pass' | 'fail';
163
+ export interface Report extends CaptureData {
164
+ budget: Budget;
165
+ verdict: VerdictValue;
166
+ failures: BudgetFailure[];
167
+ /** Budgets we could not evaluate (e.g. the page reported no LCP). */
168
+ unmeasured: string[];
169
+ counts: {
170
+ consoleErrors: number;
171
+ consoleWarnings: number;
172
+ pageErrors: number;
173
+ requests: number;
174
+ failedRequests: number;
175
+ a11yErrors: number;
176
+ a11yWarnings: number;
177
+ };
178
+ /** This run against the previous N for the same URL (RIG-13). */
179
+ trend?: TrendReport;
180
+ /** This run against the immediately previous one (RIG-10). */
181
+ diff?: RunDiff;
182
+ }
183
+ /** One AX-tree element, addressed by a path of `role[n]` segments. */
184
+ export interface StructureNode {
185
+ path: string;
186
+ role: string;
187
+ name: string | null;
188
+ depth: number;
189
+ }
190
+ export interface StructureDiff {
191
+ gained: StructureNode[];
192
+ lost: StructureNode[];
193
+ /** Same slot, same role, different accessible name. */
194
+ renamed: Array<{
195
+ path: string;
196
+ role: string;
197
+ from: string | null;
198
+ to: string | null;
199
+ }>;
200
+ /** Same role and name, different path — reordered, not added or removed. */
201
+ moved: Array<{
202
+ role: string;
203
+ name: string | null;
204
+ from: string;
205
+ to: string;
206
+ }>;
207
+ unchanged: number;
208
+ /** gained + lost + renamed. `moved` is excluded: moving is rarely a defect. */
209
+ changed: number;
210
+ }
211
+ export interface ImageSize {
212
+ width: number;
213
+ height: number;
214
+ }
215
+ export interface PixelDiff {
216
+ /** False when a screenshot could not be decoded; see `note`. */
217
+ comparable: boolean;
218
+ changedPixels: number;
219
+ totalPixels: number;
220
+ changedPercent: number;
221
+ previousSize: ImageSize | null;
222
+ currentSize: ImageSize | null;
223
+ sizeChanged: boolean;
224
+ /** Highlight image, `data:image/png;base64,...`. Absent when nothing changed. */
225
+ diffDataUrl?: string;
226
+ /** Integer downscale factor applied to the highlight image, when > 1. */
227
+ scale?: number;
228
+ note?: string;
229
+ }
230
+ export interface RunDiff {
231
+ previousRunId: string;
232
+ previousCapturedAt: string;
233
+ structure?: StructureDiff;
234
+ pixels?: PixelDiff;
235
+ notes: string[];
236
+ }
237
+ export type TrendDirection = 'improved' | 'regressed' | 'flat' | 'new';
238
+ export interface TrendPoint {
239
+ capturedAt: string;
240
+ value: number | null;
241
+ }
242
+ export interface TrendSeries {
243
+ /** Metric key, e.g. `lcp` or `consoleErrors`. */
244
+ key: string;
245
+ label: string;
246
+ unit: 'ms' | 'score' | 'count';
247
+ /** Oldest to newest; the last point is this run. */
248
+ points: TrendPoint[];
249
+ current: number | null;
250
+ previous: number | null;
251
+ oldest: number | null;
252
+ deltaFromPrevious: number | null;
253
+ deltaFromOldest: number | null;
254
+ direction: TrendDirection;
255
+ /** Set when drift across the whole window is big enough to name out loud. */
256
+ creep?: string;
257
+ }
258
+ export interface TrendReport {
259
+ /** How many prior runs this run was compared against. */
260
+ runs: number;
261
+ windowFrom: string | null;
262
+ series: TrendSeries[];
263
+ verdictHistory: Array<{
264
+ capturedAt: string;
265
+ verdict: VerdictValue;
266
+ }>;
267
+ /** The sentences worth reading first, e.g. slow LCP decay. */
268
+ headlines: string[];
269
+ }
270
+ /** One screencast frame as the recorder buffers it, before selection. */
271
+ export interface RawFrame {
272
+ /** Milliseconds since the run started. */
273
+ offsetMs: number;
274
+ /** Base64 JPEG, as CDP hands it over. */
275
+ data: string;
276
+ bytes: number;
277
+ }
278
+ /**
279
+ * The recorder's raw output, carried on CaptureData so `runReport` can turn
280
+ * it into an Evidence block once the verdict is known. Stripped from the JSON
281
+ * sibling — it is working material, not part of the report.
282
+ */
283
+ export interface Recording {
284
+ /** `Date.now()` at the start of the run: the zero of every frame offset. */
285
+ startedAtMs: number;
286
+ frames: RawFrame[];
287
+ /** Frames already dropped to keep the in-memory buffer bounded. */
288
+ droppedFrames: number;
289
+ /** True when the caller asked for a recording regardless of the verdict. */
290
+ requested: boolean;
291
+ }
292
+ export interface EvidenceFrame {
293
+ /** Milliseconds since the run started. */
294
+ offsetMs: number;
295
+ /** `data:image/jpeg;base64,...` */
296
+ dataUrl: string;
297
+ bytes: number;
298
+ }
299
+ export type TimelineKind = 'frame' | 'console' | 'pageerror' | 'request' | 'marker';
300
+ export interface TimelineEntry {
301
+ offsetMs: number;
302
+ kind: TimelineKind;
303
+ label: string;
304
+ detail?: string;
305
+ severity: 'info' | 'warning' | 'error';
306
+ /** Index into `Evidence.frames` for a `frame` entry. */
307
+ frameIndex?: number;
308
+ }
309
+ export interface Evidence {
310
+ reason: 'budget-failure' | 'requested';
311
+ /** Offset the timeline is centred on — the first failure we could locate. */
312
+ focusOffsetMs: number | null;
313
+ frames: EvidenceFrame[];
314
+ timeline: TimelineEntry[];
315
+ /** Frames captured but dropped to stay inside the count/byte budget. */
316
+ droppedFrames: number;
317
+ totalBytes: number;
318
+ notes: string[];
319
+ }
320
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/report/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Shared shapes for `monobrowse report` — the one-command page test rig.
3
+ *
4
+ * The pipeline is collect (drive the browser) -> analyze (a11y rules +
5
+ * budget evaluation) -> render (self-contained HTML). Only `collect` talks
6
+ * to Chrome; everything downstream is a pure function over these types,
7
+ * which is what makes the analyzer and the renderer unit-testable without
8
+ * launching a browser.
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/report/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
@@ -0,0 +1,17 @@
1
+ /** Small shared helpers for the report collectors. */
2
+ /** Budget for one non-navigation collector (AX tree, screenshot, eval). */
3
+ export declare const STEP_TIMEOUT_MS = 15000;
4
+ export declare function sleep(ms: number): Promise<void>;
5
+ export declare function message(err: unknown): string;
6
+ /**
7
+ * Races a promise against a timer. Used everywhere in collect.ts so a wedged
8
+ * page degrades into a note instead of hanging the command forever.
9
+ */
10
+ export declare function withTimeout<T>(promise: Promise<T>, ms: number, label: string): Promise<T>;
11
+ /**
12
+ * HTML-escape a value for interpolation into the report. Lives here rather
13
+ * than in render.ts so the renderer and its section modules can share it
14
+ * without importing each other.
15
+ */
16
+ export declare function escapeHtml(value: unknown): string;
17
+ //# sourceMappingURL=util.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../../src/report/util.ts"],"names":[],"mappings":"AAAA,sDAAsD;AAEtD,2EAA2E;AAC3E,eAAO,MAAM,eAAe,QAAS,CAAC;AAEtC,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAK/C;AAED,wBAAgB,OAAO,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAE5C;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAa/F;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAOjD"}
@@ -0,0 +1,45 @@
1
+ /** Small shared helpers for the report collectors. */
2
+ /** Budget for one non-navigation collector (AX tree, screenshot, eval). */
3
+ export const STEP_TIMEOUT_MS = 15_000;
4
+ export function sleep(ms) {
5
+ return new Promise((r) => {
6
+ const t = setTimeout(r, ms);
7
+ t.unref?.();
8
+ });
9
+ }
10
+ export function message(err) {
11
+ return err instanceof Error ? err.message : String(err);
12
+ }
13
+ /**
14
+ * Races a promise against a timer. Used everywhere in collect.ts so a wedged
15
+ * page degrades into a note instead of hanging the command forever.
16
+ */
17
+ export async function withTimeout(promise, ms, label) {
18
+ let timer;
19
+ try {
20
+ return await Promise.race([
21
+ promise,
22
+ new Promise((_, reject) => {
23
+ timer = setTimeout(() => reject(new Error(`${label} timed out after ${ms}ms`)), ms);
24
+ timer.unref?.();
25
+ }),
26
+ ]);
27
+ }
28
+ finally {
29
+ clearTimeout(timer);
30
+ }
31
+ }
32
+ /**
33
+ * HTML-escape a value for interpolation into the report. Lives here rather
34
+ * than in render.ts so the renderer and its section modules can share it
35
+ * without importing each other.
36
+ */
37
+ export function escapeHtml(value) {
38
+ return String(value ?? '')
39
+ .replace(/&/g, '&amp;')
40
+ .replace(/</g, '&lt;')
41
+ .replace(/>/g, '&gt;')
42
+ .replace(/"/g, '&quot;')
43
+ .replace(/'/g, '&#39;');
44
+ }
45
+ //# sourceMappingURL=util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"util.js","sourceRoot":"","sources":["../../../src/report/util.ts"],"names":[],"mappings":"AAAA,sDAAsD;AAEtD,2EAA2E;AAC3E,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAC;AAEtC,MAAM,UAAU,KAAK,CAAC,EAAU;IAC9B,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;QACvB,MAAM,CAAC,GAAG,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC5B,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC;IACd,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,GAAY;IAClC,OAAO,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AAC1D,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAI,OAAmB,EAAE,EAAU,EAAE,KAAa;IACjF,IAAI,KAAgD,CAAC;IACrD,IAAI,CAAC;QACH,OAAO,MAAM,OAAO,CAAC,IAAI,CAAC;YACxB,OAAO;YACP,IAAI,OAAO,CAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE;gBAC/B,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,GAAG,KAAK,oBAAoB,EAAE,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACpF,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;YAClB,CAAC,CAAC;SACH,CAAC,CAAC;IACL,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,KAAc;IACvC,OAAO,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAC5B,CAAC"}