@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.
- package/dist/src/__tests__/profiler-heap.test.d.ts +2 -0
- package/dist/src/__tests__/profiler-heap.test.d.ts.map +1 -0
- package/dist/src/__tests__/profiler-heap.test.js +154 -0
- package/dist/src/__tests__/profiler-heap.test.js.map +1 -0
- package/dist/src/__tests__/report-a11y.test.d.ts +2 -0
- package/dist/src/__tests__/report-a11y.test.d.ts.map +1 -0
- package/dist/src/__tests__/report-a11y.test.js +147 -0
- package/dist/src/__tests__/report-a11y.test.js.map +1 -0
- package/dist/src/__tests__/report-analyze.test.d.ts +2 -0
- package/dist/src/__tests__/report-analyze.test.d.ts.map +1 -0
- package/dist/src/__tests__/report-analyze.test.js +157 -0
- package/dist/src/__tests__/report-analyze.test.js.map +1 -0
- package/dist/src/__tests__/report-budget.test.d.ts +2 -0
- package/dist/src/__tests__/report-budget.test.d.ts.map +1 -0
- package/dist/src/__tests__/report-budget.test.js +80 -0
- package/dist/src/__tests__/report-budget.test.js.map +1 -0
- package/dist/src/__tests__/report-diff.test.d.ts +2 -0
- package/dist/src/__tests__/report-diff.test.d.ts.map +1 -0
- package/dist/src/__tests__/report-diff.test.js +231 -0
- package/dist/src/__tests__/report-diff.test.js.map +1 -0
- package/dist/src/__tests__/report-evidence.test.d.ts +2 -0
- package/dist/src/__tests__/report-evidence.test.d.ts.map +1 -0
- package/dist/src/__tests__/report-evidence.test.js +214 -0
- package/dist/src/__tests__/report-evidence.test.js.map +1 -0
- package/dist/src/__tests__/report-flake.test.d.ts +2 -0
- package/dist/src/__tests__/report-flake.test.d.ts.map +1 -0
- package/dist/src/__tests__/report-flake.test.js +182 -0
- package/dist/src/__tests__/report-flake.test.js.map +1 -0
- package/dist/src/__tests__/report-history.test.d.ts +2 -0
- package/dist/src/__tests__/report-history.test.d.ts.map +1 -0
- package/dist/src/__tests__/report-history.test.js +229 -0
- package/dist/src/__tests__/report-history.test.js.map +1 -0
- package/dist/src/__tests__/report-output.test.d.ts +2 -0
- package/dist/src/__tests__/report-output.test.d.ts.map +1 -0
- package/dist/src/__tests__/report-output.test.js +169 -0
- package/dist/src/__tests__/report-output.test.js.map +1 -0
- package/dist/src/__tests__/report-png.test.d.ts +2 -0
- package/dist/src/__tests__/report-png.test.d.ts.map +1 -0
- package/dist/src/__tests__/report-png.test.js +84 -0
- package/dist/src/__tests__/report-png.test.js.map +1 -0
- package/dist/src/__tests__/report-render-extras.test.d.ts +2 -0
- package/dist/src/__tests__/report-render-extras.test.d.ts.map +1 -0
- package/dist/src/__tests__/report-render-extras.test.js +285 -0
- package/dist/src/__tests__/report-render-extras.test.js.map +1 -0
- package/dist/src/__tests__/report-render.test.d.ts +2 -0
- package/dist/src/__tests__/report-render.test.d.ts.map +1 -0
- package/dist/src/__tests__/report-render.test.js +143 -0
- package/dist/src/__tests__/report-render.test.js.map +1 -0
- package/dist/src/__tests__/report-run.test.d.ts +2 -0
- package/dist/src/__tests__/report-run.test.d.ts.map +1 -0
- package/dist/src/__tests__/report-run.test.js +234 -0
- package/dist/src/__tests__/report-run.test.js.map +1 -0
- package/dist/src/browser/index.d.ts +1 -0
- package/dist/src/browser/index.d.ts.map +1 -1
- package/dist/src/browser/index.js +1 -0
- package/dist/src/browser/index.js.map +1 -1
- package/dist/src/browser/profiler.d.ts.map +1 -1
- package/dist/src/browser/profiler.js +19 -22
- package/dist/src/browser/profiler.js.map +1 -1
- package/dist/src/cli/commands.d.ts.map +1 -1
- package/dist/src/cli/commands.js +254 -0
- package/dist/src/cli/commands.js.map +1 -1
- package/dist/src/report/a11y.d.ts +52 -0
- package/dist/src/report/a11y.d.ts.map +1 -0
- package/dist/src/report/a11y.js +231 -0
- package/dist/src/report/a11y.js.map +1 -0
- package/dist/src/report/analyze.d.ts +20 -0
- package/dist/src/report/analyze.d.ts.map +1 -0
- package/dist/src/report/analyze.js +136 -0
- package/dist/src/report/analyze.js.map +1 -0
- package/dist/src/report/budget.d.ts +27 -0
- package/dist/src/report/budget.d.ts.map +1 -0
- package/dist/src/report/budget.js +143 -0
- package/dist/src/report/budget.js.map +1 -0
- package/dist/src/report/collect-a11y.d.ts +25 -0
- package/dist/src/report/collect-a11y.d.ts.map +1 -0
- package/dist/src/report/collect-a11y.js +154 -0
- package/dist/src/report/collect-a11y.js.map +1 -0
- package/dist/src/report/collect.d.ts +45 -0
- package/dist/src/report/collect.d.ts.map +1 -0
- package/dist/src/report/collect.js +275 -0
- package/dist/src/report/collect.js.map +1 -0
- package/dist/src/report/evidence.d.ts +80 -0
- package/dist/src/report/evidence.d.ts.map +1 -0
- package/dist/src/report/evidence.js +279 -0
- package/dist/src/report/evidence.js.map +1 -0
- package/dist/src/report/flake.d.ts +88 -0
- package/dist/src/report/flake.d.ts.map +1 -0
- package/dist/src/report/flake.js +232 -0
- package/dist/src/report/flake.js.map +1 -0
- package/dist/src/report/history.d.ts +85 -0
- package/dist/src/report/history.d.ts.map +1 -0
- package/dist/src/report/history.js +176 -0
- package/dist/src/report/history.js.map +1 -0
- package/dist/src/report/index.d.ts +102 -0
- package/dist/src/report/index.d.ts.map +1 -0
- package/dist/src/report/index.js +216 -0
- package/dist/src/report/index.js.map +1 -0
- package/dist/src/report/pixel-diff.d.ts +30 -0
- package/dist/src/report/pixel-diff.d.ts.map +1 -0
- package/dist/src/report/pixel-diff.js +175 -0
- package/dist/src/report/pixel-diff.js.map +1 -0
- package/dist/src/report/png.d.ts +28 -0
- package/dist/src/report/png.d.ts.map +1 -0
- package/dist/src/report/png.js +259 -0
- package/dist/src/report/png.js.map +1 -0
- package/dist/src/report/render-evidence.d.ts +16 -0
- package/dist/src/report/render-evidence.d.ts.map +1 -0
- package/dist/src/report/render-evidence.js +174 -0
- package/dist/src/report/render-evidence.js.map +1 -0
- package/dist/src/report/render-trend.d.ts +16 -0
- package/dist/src/report/render-trend.d.ts.map +1 -0
- package/dist/src/report/render-trend.js +194 -0
- package/dist/src/report/render-trend.js.map +1 -0
- package/dist/src/report/render.d.ts +21 -0
- package/dist/src/report/render.d.ts.map +1 -0
- package/dist/src/report/render.js +286 -0
- package/dist/src/report/render.js.map +1 -0
- package/dist/src/report/run-diff.d.ts +18 -0
- package/dist/src/report/run-diff.d.ts.map +1 -0
- package/dist/src/report/run-diff.js +51 -0
- package/dist/src/report/run-diff.js.map +1 -0
- package/dist/src/report/structure.d.ts +41 -0
- package/dist/src/report/structure.d.ts.map +1 -0
- package/dist/src/report/structure.js +210 -0
- package/dist/src/report/structure.js.map +1 -0
- package/dist/src/report/trend.d.ts +26 -0
- package/dist/src/report/trend.d.ts.map +1 -0
- package/dist/src/report/trend.js +164 -0
- package/dist/src/report/trend.js.map +1 -0
- package/dist/src/report/types.d.ts +320 -0
- package/dist/src/report/types.d.ts.map +1 -0
- package/dist/src/report/types.js +11 -0
- package/dist/src/report/types.js.map +1 -0
- package/dist/src/report/util.d.ts +17 -0
- package/dist/src/report/util.d.ts.map +1 -0
- package/dist/src/report/util.js +45 -0
- package/dist/src/report/util.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/__tests__/profiler-heap.test.ts +191 -0
- package/src/__tests__/report-a11y.test.ts +180 -0
- package/src/__tests__/report-analyze.test.ts +202 -0
- package/src/__tests__/report-budget.test.ts +92 -0
- package/src/__tests__/report-diff.test.ts +272 -0
- package/src/__tests__/report-evidence.test.ts +276 -0
- package/src/__tests__/report-flake.test.ts +214 -0
- package/src/__tests__/report-history.test.ts +293 -0
- package/src/__tests__/report-output.test.ts +210 -0
- package/src/__tests__/report-png.test.ts +95 -0
- package/src/__tests__/report-render-extras.test.ts +315 -0
- package/src/__tests__/report-render.test.ts +175 -0
- package/src/__tests__/report-run.test.ts +264 -0
- package/src/browser/index.ts +1 -0
- package/src/browser/profiler.ts +28 -21
- package/src/cli/commands.ts +272 -0
- package/src/report/a11y.ts +242 -0
- package/src/report/analyze.ts +181 -0
- package/src/report/budget.ts +155 -0
- package/src/report/collect-a11y.ts +200 -0
- package/src/report/collect.ts +408 -0
- package/src/report/evidence.ts +379 -0
- package/src/report/flake.ts +303 -0
- package/src/report/history.ts +219 -0
- package/src/report/index.ts +307 -0
- package/src/report/pixel-diff.ts +197 -0
- package/src/report/png.ts +290 -0
- package/src/report/render-evidence.ts +194 -0
- package/src/report/render-trend.ts +225 -0
- package/src/report/render.ts +314 -0
- package/src/report/run-diff.ts +63 -0
- package/src/report/structure.ts +212 -0
- package/src/report/trend.ts +189 -0
- package/src/report/types.ts +356 -0
- package/src/report/util.ts +48 -0
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The orchestration seam in report/index.ts: history is read before the run
|
|
3
|
+
* is saved, evidence is only built when it is warranted, and `--repeat`
|
|
4
|
+
* judges the set rather than the last run.
|
|
5
|
+
*
|
|
6
|
+
* `collect` is mocked, so nothing here launches Chrome. Output and history
|
|
7
|
+
* both go to a scratch directory under the monomind data dir — never the
|
|
8
|
+
* shared /tmp.
|
|
9
|
+
*/
|
|
10
|
+
import { mkdir, mkdtemp, readdir, readFile, rm, writeFile } from 'node:fs/promises';
|
|
11
|
+
import { homedir } from 'node:os';
|
|
12
|
+
import { join } from 'node:path';
|
|
13
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
14
|
+
import { historyKey, listRuns } from '../report/history.js';
|
|
15
|
+
import { encodePng, pngToDataUrl } from '../report/png.js';
|
|
16
|
+
const collect = vi.hoisted(() => vi.fn());
|
|
17
|
+
vi.mock('../report/collect.js', () => ({ collect }));
|
|
18
|
+
const { runReport, runReportRepeated, readHistory } = await import('../report/index.js');
|
|
19
|
+
const URL_UNDER_TEST = 'https://shop.test/checkout';
|
|
20
|
+
const client = {};
|
|
21
|
+
function shot(shade, width = 8, height = 8) {
|
|
22
|
+
const data = new Uint8Array(width * height * 4);
|
|
23
|
+
for (let i = 0; i < width * height; i++)
|
|
24
|
+
data.set([shade, shade, shade, 255], i * 4);
|
|
25
|
+
return {
|
|
26
|
+
label: 'page',
|
|
27
|
+
width,
|
|
28
|
+
height,
|
|
29
|
+
dataUrl: pngToDataUrl(encodePng({ width, height, data })),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function capture(partial = {}) {
|
|
33
|
+
return {
|
|
34
|
+
url: URL_UNDER_TEST,
|
|
35
|
+
finalUrl: URL_UNDER_TEST,
|
|
36
|
+
title: 'Checkout',
|
|
37
|
+
capturedAt: '2026-09-21T10:00:00.000Z',
|
|
38
|
+
durationMs: 1000,
|
|
39
|
+
console: [],
|
|
40
|
+
pageErrors: [],
|
|
41
|
+
requests: [],
|
|
42
|
+
vitals: { lcp: 2000, cls: 0.01, inp: 50 },
|
|
43
|
+
a11y: [],
|
|
44
|
+
structure: [{ path: '/main[1]/button[1]', role: 'button', name: 'Pay now', depth: 1 }],
|
|
45
|
+
screenshots: [shot(200)],
|
|
46
|
+
notes: [],
|
|
47
|
+
...partial,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
let root;
|
|
51
|
+
let outDir;
|
|
52
|
+
beforeEach(async () => {
|
|
53
|
+
await mkdir(join(homedir(), '.monomind'), { recursive: true });
|
|
54
|
+
root = await mkdtemp(join(homedir(), '.monomind', 'monobrowse-run-test-'));
|
|
55
|
+
outDir = join(root, 'out');
|
|
56
|
+
await mkdir(outDir, { recursive: true });
|
|
57
|
+
collect.mockReset();
|
|
58
|
+
});
|
|
59
|
+
afterEach(async () => {
|
|
60
|
+
await rm(root, { recursive: true, force: true });
|
|
61
|
+
});
|
|
62
|
+
const run = (data, extra = {}) => {
|
|
63
|
+
collect.mockResolvedValueOnce(data);
|
|
64
|
+
return runReport(client, 'S1', {
|
|
65
|
+
url: URL_UNDER_TEST,
|
|
66
|
+
out: join(outDir, `${Math.random().toString(36).slice(2)}.html`),
|
|
67
|
+
historyDir: root,
|
|
68
|
+
cwd: outDir,
|
|
69
|
+
...extra,
|
|
70
|
+
});
|
|
71
|
+
};
|
|
72
|
+
describe('runReport and history', () => {
|
|
73
|
+
it('does not let the first run trend or diff against itself', async () => {
|
|
74
|
+
const result = await run(capture());
|
|
75
|
+
expect(result.report.trend?.runs).toBe(0);
|
|
76
|
+
expect(result.report.diff).toBeUndefined();
|
|
77
|
+
// ...but it is on disk for the next run to compare against.
|
|
78
|
+
expect((await listRuns(join(root, historyKey(URL_UNDER_TEST)))).length).toBe(1);
|
|
79
|
+
});
|
|
80
|
+
it('trends and diffs the second run against the first', async () => {
|
|
81
|
+
await run(capture());
|
|
82
|
+
const second = await run(capture({
|
|
83
|
+
capturedAt: '2026-09-21T11:00:00.000Z',
|
|
84
|
+
vitals: { lcp: 2600, cls: 0.01, inp: 50 },
|
|
85
|
+
structure: [{ path: '/main[1]/button[1]', role: 'button', name: 'Place order', depth: 1 }],
|
|
86
|
+
screenshots: [shot(40)],
|
|
87
|
+
}));
|
|
88
|
+
expect(second.report.trend?.runs).toBe(1);
|
|
89
|
+
const lcp = second.report.trend?.series.find((s) => s.key === 'lcp');
|
|
90
|
+
expect(lcp).toMatchObject({ previous: 2000, current: 2600, direction: 'regressed' });
|
|
91
|
+
expect(second.report.diff?.previousCapturedAt).toBe('2026-09-21T10:00:00.000Z');
|
|
92
|
+
expect(second.report.diff?.structure?.renamed).toEqual([
|
|
93
|
+
{ path: '/main[1]/button[1]', role: 'button', from: 'Pay now', to: 'Place order' },
|
|
94
|
+
]);
|
|
95
|
+
// Every pixel went from light grey to dark — a whole-screenshot change.
|
|
96
|
+
expect(second.report.diff?.pixels?.changedPercent).toBe(100);
|
|
97
|
+
});
|
|
98
|
+
it('reports the history directory it wrote to', async () => {
|
|
99
|
+
const result = await run(capture());
|
|
100
|
+
expect(result.historyDir).toBe(join(root, historyKey(URL_UNDER_TEST)));
|
|
101
|
+
});
|
|
102
|
+
it('prunes to the configured maximum across runs', async () => {
|
|
103
|
+
for (let i = 0; i < 4; i++) {
|
|
104
|
+
await run(capture({ capturedAt: `2026-09-2${i + 1}T10:00:00.000Z` }), { historyMax: 2 });
|
|
105
|
+
}
|
|
106
|
+
const runs = await listRuns(join(root, historyKey(URL_UNDER_TEST)));
|
|
107
|
+
expect(runs.map((r) => r.capturedAt)).toEqual([
|
|
108
|
+
'2026-09-23T10:00:00.000Z',
|
|
109
|
+
'2026-09-24T10:00:00.000Z',
|
|
110
|
+
]);
|
|
111
|
+
});
|
|
112
|
+
it('writes nothing to the store when history is off, and says nothing about trends', async () => {
|
|
113
|
+
const result = await run(capture(), { history: false });
|
|
114
|
+
expect(result.report.trend).toBeUndefined();
|
|
115
|
+
expect(result.historyDir).toBeUndefined();
|
|
116
|
+
await expect(readdir(join(root, historyKey(URL_UNDER_TEST)))).rejects.toThrow();
|
|
117
|
+
});
|
|
118
|
+
it('keeps the report when the history store cannot be written', async () => {
|
|
119
|
+
// A regular file where the store's directory needs to be: mkdir fails
|
|
120
|
+
// with ENOTDIR, and the report still has to come out.
|
|
121
|
+
const blocked = join(root, 'blocked-store');
|
|
122
|
+
await writeFile(blocked, 'not a directory', 'utf8');
|
|
123
|
+
const result = await run(capture(), { historyDir: blocked });
|
|
124
|
+
expect(result.report.verdict).toBe('pass');
|
|
125
|
+
expect(result.report.notes.join(' ')).toMatch(/Run history unavailable/);
|
|
126
|
+
expect(result.historyDir).toBeUndefined();
|
|
127
|
+
});
|
|
128
|
+
it('exposes the stored runs through readHistory', async () => {
|
|
129
|
+
await run(capture());
|
|
130
|
+
const { runs } = await readHistory(URL_UNDER_TEST, { historyDir: root });
|
|
131
|
+
expect(runs.length).toBe(1);
|
|
132
|
+
expect(runs[0]).toMatchObject({ url: URL_UNDER_TEST, verdict: 'pass' });
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
describe('runReport and evidence', () => {
|
|
136
|
+
const recording = {
|
|
137
|
+
startedAtMs: 1_000_000,
|
|
138
|
+
frames: [
|
|
139
|
+
{ offsetMs: 0, data: 'AAAA', bytes: 4 },
|
|
140
|
+
{ offsetMs: 900, data: 'BBBB', bytes: 4 },
|
|
141
|
+
],
|
|
142
|
+
droppedFrames: 0,
|
|
143
|
+
requested: false,
|
|
144
|
+
};
|
|
145
|
+
it('attaches evidence when the run breaches its budget', async () => {
|
|
146
|
+
const result = await run(capture({
|
|
147
|
+
recording,
|
|
148
|
+
console: [{ type: 'error', text: 'boom', timestamp: 1_000_800 }],
|
|
149
|
+
}));
|
|
150
|
+
expect(result.report.verdict).toBe('fail');
|
|
151
|
+
expect(result.report.evidence?.reason).toBe('budget-failure');
|
|
152
|
+
expect(result.report.evidence?.focusOffsetMs).toBe(800);
|
|
153
|
+
expect(result.report.evidence?.frames.length).toBe(2);
|
|
154
|
+
});
|
|
155
|
+
it('does not attach evidence to a passing run that did not ask for it', async () => {
|
|
156
|
+
const result = await run(capture({ recording }));
|
|
157
|
+
expect(result.report.verdict).toBe('pass');
|
|
158
|
+
expect(result.report.evidence).toBeUndefined();
|
|
159
|
+
});
|
|
160
|
+
it('attaches evidence to a passing run when --record asked for it', async () => {
|
|
161
|
+
const result = await run(capture({ recording: { ...recording, requested: true } }));
|
|
162
|
+
expect(result.report.evidence?.reason).toBe('requested');
|
|
163
|
+
});
|
|
164
|
+
it('never leaves the raw recording on the report it returns', async () => {
|
|
165
|
+
const result = await run(capture({ recording: { ...recording, requested: true } }));
|
|
166
|
+
expect(result.report.recording).toBeUndefined();
|
|
167
|
+
});
|
|
168
|
+
it('keeps the frame images out of the JSON sibling', async () => {
|
|
169
|
+
const result = await run(capture({ recording: { ...recording, requested: true } }));
|
|
170
|
+
const json = JSON.parse(await readFile(result.jsonPath, 'utf8'));
|
|
171
|
+
expect(json.evidence.frames).toEqual([
|
|
172
|
+
{ offsetMs: 0, bytes: 4 },
|
|
173
|
+
{ offsetMs: 900, bytes: 4 },
|
|
174
|
+
]);
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
describe('runReportRepeated', () => {
|
|
178
|
+
const failing = capture({ console: [{ type: 'error', text: 'boom', timestamp: 0 }] });
|
|
179
|
+
it('runs the URL N times and judges the set', async () => {
|
|
180
|
+
for (const data of [capture(), failing, capture()])
|
|
181
|
+
collect.mockResolvedValueOnce(data);
|
|
182
|
+
const result = await runReportRepeated(client, 'S1', {
|
|
183
|
+
url: URL_UNDER_TEST,
|
|
184
|
+
out: join(outDir, 'repeat.html'),
|
|
185
|
+
historyDir: root,
|
|
186
|
+
cwd: outDir,
|
|
187
|
+
repeat: 3,
|
|
188
|
+
});
|
|
189
|
+
expect(collect).toHaveBeenCalledTimes(3);
|
|
190
|
+
expect(result.reports.length).toBe(3);
|
|
191
|
+
expect(result.flake.verdict).toBe('flaky');
|
|
192
|
+
expect(result.summary).toMatch(/^FLAKY/);
|
|
193
|
+
});
|
|
194
|
+
it('refuses to call a sometimes-failing URL a pass, even when the last run is green', async () => {
|
|
195
|
+
for (const data of [failing, capture()])
|
|
196
|
+
collect.mockResolvedValueOnce(data);
|
|
197
|
+
const result = await runReportRepeated(client, 'S1', {
|
|
198
|
+
url: URL_UNDER_TEST,
|
|
199
|
+
out: join(outDir, 'repeat2.html'),
|
|
200
|
+
historyDir: root,
|
|
201
|
+
cwd: outDir,
|
|
202
|
+
repeat: 2,
|
|
203
|
+
});
|
|
204
|
+
expect(result.report.verdict).toBe('pass'); // the last run alone
|
|
205
|
+
expect(result.flake.verdict).toBe('flaky'); // what the command reports
|
|
206
|
+
});
|
|
207
|
+
it('writes one history entry for the whole command, not one per run', async () => {
|
|
208
|
+
for (const data of [capture(), capture(), capture()])
|
|
209
|
+
collect.mockResolvedValueOnce(data);
|
|
210
|
+
await runReportRepeated(client, 'S1', {
|
|
211
|
+
url: URL_UNDER_TEST,
|
|
212
|
+
out: join(outDir, 'repeat3.html'),
|
|
213
|
+
historyDir: root,
|
|
214
|
+
cwd: outDir,
|
|
215
|
+
repeat: 3,
|
|
216
|
+
});
|
|
217
|
+
expect((await listRuns(join(root, historyKey(URL_UNDER_TEST)))).length).toBe(1);
|
|
218
|
+
});
|
|
219
|
+
it('puts the flake analysis in the JSON sibling', async () => {
|
|
220
|
+
for (const data of [capture(), failing])
|
|
221
|
+
collect.mockResolvedValueOnce(data);
|
|
222
|
+
const result = await runReportRepeated(client, 'S1', {
|
|
223
|
+
url: URL_UNDER_TEST,
|
|
224
|
+
out: join(outDir, 'repeat4.html'),
|
|
225
|
+
historyDir: root,
|
|
226
|
+
cwd: outDir,
|
|
227
|
+
repeat: 2,
|
|
228
|
+
});
|
|
229
|
+
const json = JSON.parse(await readFile(result.jsonPath, 'utf8'));
|
|
230
|
+
expect(json.flake.verdict).toBe('flaky');
|
|
231
|
+
expect(json.flake.runs).toBe(2);
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
//# sourceMappingURL=report-run.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report-run.test.js","sourceRoot":"","sources":["../../../src/__tests__/report-run.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/browser/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/browser/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/browser/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/browser/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profiler.d.ts","sourceRoot":"","sources":["../../../src/browser/profiler.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAE1C,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;
|
|
1
|
+
{"version":3,"file":"profiler.d.ts","sourceRoot":"","sources":["../../../src/browser/profiler.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAE1C,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAQD,wBAAsB,eAAe,CACnC,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAcf;AAED,wBAAsB,cAAc,CAClC,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,CAAC,CAiBjB;AAED,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAE5D;AAED,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,CAAC,CAgDjB"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { writeFile } from 'node:fs/promises';
|
|
2
2
|
import { tmpdir } from 'node:os';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
|
+
/** Heap snapshots on a large page take far longer than the 30s CDP default. */
|
|
5
|
+
const HEAP_SNAPSHOT_TIMEOUT_MS = 120_000;
|
|
4
6
|
const _sessions = new Set();
|
|
5
7
|
const _heapSessions = new Set();
|
|
6
8
|
export async function startCpuProfile(client, sessionId, options = {}) {
|
|
@@ -47,34 +49,29 @@ export async function startHeapSnapshot(client, sessionId, outputPath) {
|
|
|
47
49
|
chunks.push(params.chunk);
|
|
48
50
|
});
|
|
49
51
|
try {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
resolve();
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
client
|
|
65
|
-
.send('HeapProfiler.takeHeapSnapshot', { reportProgress: true }, sessionId)
|
|
66
|
-
.catch((err) => {
|
|
67
|
-
clearTimeout(timeoutHandle);
|
|
68
|
-
off2();
|
|
69
|
-
reject(err);
|
|
70
|
-
});
|
|
71
|
-
});
|
|
52
|
+
// Resolve on takeHeapSnapshot's own RESPONSE, not on
|
|
53
|
+
// `HeapProfiler.reportHeapSnapshotProgress` with finished:true. Chrome
|
|
54
|
+
// emits that progress event once it has finished WALKING the heap, which
|
|
55
|
+
// is before it has streamed a single addHeapSnapshotChunk (verified
|
|
56
|
+
// against Chrome 153) — so resolving there detached the chunk listener in
|
|
57
|
+
// the `finally` below and wrote a 0-byte snapshot every single time. The
|
|
58
|
+
// command response is the only signal that every chunk has been sent.
|
|
59
|
+
//
|
|
60
|
+
// reportProgress is off for the same reason: nothing consumes those
|
|
61
|
+
// events any more, and they are pure noise on the wire.
|
|
62
|
+
await client.send('HeapProfiler.takeHeapSnapshot', { reportProgress: false }, sessionId, HEAP_SNAPSHOT_TIMEOUT_MS);
|
|
72
63
|
}
|
|
73
64
|
finally {
|
|
74
65
|
off();
|
|
75
66
|
_heapSessions.delete(sessionId);
|
|
76
67
|
await client.send('HeapProfiler.disable', {}, sessionId).catch(() => { });
|
|
77
68
|
}
|
|
69
|
+
// A zero-chunk snapshot is not a snapshot. Writing the empty file anyway is
|
|
70
|
+
// how this bug stayed invisible — the caller got a path, and only noticed
|
|
71
|
+
// when DevTools refused to load it.
|
|
72
|
+
if (chunks.length === 0) {
|
|
73
|
+
throw new Error('Heap snapshot produced no data — Chrome accepted HeapProfiler.takeHeapSnapshot but sent no chunks');
|
|
74
|
+
}
|
|
78
75
|
const path = outputPath ?? join(tmpdir(), `monomind-heap-${Date.now()}.heapsnapshot`);
|
|
79
76
|
await writeFile(path, chunks.join(''));
|
|
80
77
|
return path;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profiler.js","sourceRoot":"","sources":["../../../src/browser/profiler.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"profiler.js","sourceRoot":"","sources":["../../../src/browser/profiler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAQjC,+EAA+E;AAC/E,MAAM,wBAAwB,GAAG,OAAO,CAAC;AAEzC,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;AACpC,MAAM,aAAa,GAAG,IAAI,GAAG,EAAU,CAAC;AAExC,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,MAAiB,EACjB,SAAiB,EACjB,OAAO,GAAoB,EAAE;IAE7B,IAAI,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;IACnE,CAAC;IACD,MAAM,MAAM,CAAC,IAAI,CAAC,iBAAiB,EAAE,EAAE,EAAE,SAAS,CAAC,CAAC;IACpD,IAAI,OAAO,CAAC,gBAAgB,KAAK,SAAS,EAAE,CAAC;QAC3C,MAAM,MAAM,CAAC,IAAI,CACf,8BAA8B,EAC9B,EAAE,QAAQ,EAAE,OAAO,CAAC,gBAAgB,EAAE,EACtC,SAAS,CACV,CAAC;IACJ,CAAC;IACD,MAAM,MAAM,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,EAAE,SAAS,CAAC,CAAC;IACnD,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AAC3B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,MAAiB,EACjB,SAAiB,EACjB,UAAmB;IAEnB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;IAC7D,CAAC;IACD,IAAI,MAA4B,CAAC;IACjC,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAuB,eAAe,EAAE,EAAE,EAAE,SAAS,CAAC,CAAC;IACnF,CAAC;YAAS,CAAC;QACT,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAC9B,CAAC;IAED,sFAAsF;IACtF,MAAM,MAAM,CAAC,IAAI,CAAC,kBAAkB,EAAE,EAAE,EAAE,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAErE,MAAM,IAAI,GAAG,UAAU,IAAI,IAAI,CAAC,MAAM,EAAE,EAAE,oBAAoB,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;IACvF,MAAM,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAO,CAAC,OAAO,CAAC,CAAC,CAAC;IACvD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,SAAiB;IACjD,OAAO,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,MAAiB,EACjB,SAAiB,EACjB,UAAmB;IAEnB,IAAI,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IACxE,CAAC;IACD,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAC7B,MAAM,MAAM,CAAC,IAAI,CAAC,qBAAqB,EAAE,EAAE,EAAE,SAAS,CAAC,CAAC;IAExD,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,GAAG,GAAG,MAAM,CAAC,EAAE,CAAC,mCAAmC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE;QACzE,IAAI,GAAG,KAAK,SAAS;YAAE,OAAO;QAC9B,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAe,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,qDAAqD;QACrD,uEAAuE;QACvE,yEAAyE;QACzE,oEAAoE;QACpE,0EAA0E;QAC1E,yEAAyE;QACzE,sEAAsE;QACtE,EAAE;QACF,oEAAoE;QACpE,wDAAwD;QACxD,MAAM,MAAM,CAAC,IAAI,CACf,+BAA+B,EAC/B,EAAE,cAAc,EAAE,KAAK,EAAE,EACzB,SAAS,EACT,wBAAwB,CACzB,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,GAAG,EAAE,CAAC;QACN,aAAa,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAChC,MAAM,MAAM,CAAC,IAAI,CAAC,sBAAsB,EAAE,EAAE,EAAE,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAC3E,CAAC;IAED,4EAA4E;IAC5E,0EAA0E;IAC1E,oCAAoC;IACpC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CACb,mGAAmG,CACpG,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,UAAU,IAAI,IAAI,CAAC,MAAM,EAAE,EAAE,iBAAiB,IAAI,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC;IACtF,MAAM,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IACvC,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../../src/cli/commands.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EAAE,OAAO,EAAiC,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../../src/cli/commands.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EAAE,OAAO,EAAiC,MAAM,YAAY,CAAC;AA+4GzE;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,GACrE;IACD,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG,IAAI,CAUP;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG;IACrD,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC,CA4BA;AA4fD,QAAA,MAAM,aAAa,EAAE,OA+JpB,CAAC;eAEa,aAAa"}
|
package/dist/src/cli/commands.js
CHANGED
|
@@ -1537,6 +1537,254 @@ const evalCommand = {
|
|
|
1537
1537
|
return { success: true, data: { result } };
|
|
1538
1538
|
},
|
|
1539
1539
|
};
|
|
1540
|
+
const reportCommand = {
|
|
1541
|
+
name: 'report',
|
|
1542
|
+
description: 'Test a page and write one self-contained HTML report + sibling JSON. Usage: monomind browse report <url>',
|
|
1543
|
+
options: [
|
|
1544
|
+
{ name: 'out', short: 'o', type: 'string', description: 'Output .html path, or a directory' },
|
|
1545
|
+
{
|
|
1546
|
+
name: 'budget',
|
|
1547
|
+
short: 'b',
|
|
1548
|
+
type: 'string',
|
|
1549
|
+
description: 'Budget JSON file path, or inline JSON',
|
|
1550
|
+
},
|
|
1551
|
+
{
|
|
1552
|
+
name: 'devices',
|
|
1553
|
+
short: 'd',
|
|
1554
|
+
type: 'string',
|
|
1555
|
+
description: 'Comma-separated device names for the screenshot matrix',
|
|
1556
|
+
},
|
|
1557
|
+
{
|
|
1558
|
+
name: 'wait',
|
|
1559
|
+
short: 'w',
|
|
1560
|
+
type: 'string',
|
|
1561
|
+
description: 'Extra settle step: a CSS selector to wait for, or milliseconds',
|
|
1562
|
+
},
|
|
1563
|
+
{ name: 'json', type: 'boolean', description: 'Output as JSON', default: false },
|
|
1564
|
+
{
|
|
1565
|
+
name: 'full-page',
|
|
1566
|
+
type: 'boolean',
|
|
1567
|
+
description: 'Full-page screenshot (--no-full-page for viewport only)',
|
|
1568
|
+
default: true,
|
|
1569
|
+
},
|
|
1570
|
+
{
|
|
1571
|
+
name: 'vitals-wait',
|
|
1572
|
+
type: 'number',
|
|
1573
|
+
description: 'Milliseconds to let the web-vitals observers run',
|
|
1574
|
+
default: 2500,
|
|
1575
|
+
},
|
|
1576
|
+
{
|
|
1577
|
+
name: 'timeout',
|
|
1578
|
+
type: 'number',
|
|
1579
|
+
description: 'Milliseconds to wait for the page to go network-idle',
|
|
1580
|
+
default: 20000,
|
|
1581
|
+
},
|
|
1582
|
+
{
|
|
1583
|
+
name: 'keep-open',
|
|
1584
|
+
type: 'boolean',
|
|
1585
|
+
description: 'Leave the browser running after the report',
|
|
1586
|
+
default: false,
|
|
1587
|
+
},
|
|
1588
|
+
{
|
|
1589
|
+
name: 'repeat',
|
|
1590
|
+
type: 'number',
|
|
1591
|
+
description: 'Run the URL N times and report per-check flake rates (RIG-14)',
|
|
1592
|
+
},
|
|
1593
|
+
{
|
|
1594
|
+
name: 'record',
|
|
1595
|
+
type: 'boolean',
|
|
1596
|
+
description: 'Record frames for the evidence timeline even when the run passes',
|
|
1597
|
+
default: false,
|
|
1598
|
+
},
|
|
1599
|
+
{
|
|
1600
|
+
name: 'history',
|
|
1601
|
+
type: 'boolean',
|
|
1602
|
+
description: 'Print the stored run history for this URL instead of running it',
|
|
1603
|
+
default: false,
|
|
1604
|
+
},
|
|
1605
|
+
{
|
|
1606
|
+
name: 'save',
|
|
1607
|
+
type: 'boolean',
|
|
1608
|
+
description: 'Save this run to the history store (--no-save to skip)',
|
|
1609
|
+
default: true,
|
|
1610
|
+
},
|
|
1611
|
+
{
|
|
1612
|
+
name: 'history-max',
|
|
1613
|
+
type: 'number',
|
|
1614
|
+
description: 'Runs kept per URL before the oldest are pruned (default 20)',
|
|
1615
|
+
},
|
|
1616
|
+
{
|
|
1617
|
+
name: 'trend-window',
|
|
1618
|
+
type: 'number',
|
|
1619
|
+
description: 'Prior runs charted in the trend section (default 10)',
|
|
1620
|
+
},
|
|
1621
|
+
],
|
|
1622
|
+
examples: [
|
|
1623
|
+
{ command: 'monomind browse report https://example.com', description: 'Report with defaults' },
|
|
1624
|
+
{
|
|
1625
|
+
command: 'monomind browse report https://example.com --repeat 5',
|
|
1626
|
+
description: 'Run five times and report flake rates',
|
|
1627
|
+
},
|
|
1628
|
+
{
|
|
1629
|
+
command: 'monomind browse report https://example.com --history',
|
|
1630
|
+
description: 'Show the stored run history for a URL',
|
|
1631
|
+
},
|
|
1632
|
+
{
|
|
1633
|
+
command: 'monomind browse report https://example.com --record',
|
|
1634
|
+
description: 'Attach a frame-by-frame evidence timeline',
|
|
1635
|
+
},
|
|
1636
|
+
{
|
|
1637
|
+
command: 'monomind browse report https://example.com --out ./reports/home.html',
|
|
1638
|
+
description: 'Choose the output path',
|
|
1639
|
+
},
|
|
1640
|
+
{
|
|
1641
|
+
command: 'monomind browse report https://example.com --budget \'{"lcp":4000}\'',
|
|
1642
|
+
description: 'Relax a budget inline',
|
|
1643
|
+
},
|
|
1644
|
+
{
|
|
1645
|
+
command: 'monomind browse report https://example.com --devices "iPhone 14,iPad"',
|
|
1646
|
+
description: 'Add a device screenshot matrix',
|
|
1647
|
+
},
|
|
1648
|
+
],
|
|
1649
|
+
action: async (ctx) => {
|
|
1650
|
+
const url = ctx.args[0];
|
|
1651
|
+
if (!url)
|
|
1652
|
+
throw new Error('URL required. Usage: monomind browse report <url>');
|
|
1653
|
+
// Imported lazily for the same reason getBrowser() is: this module loads
|
|
1654
|
+
// on every CLI invocation, and nothing but `report` needs the renderer.
|
|
1655
|
+
const { runReport, runReportRepeated, readHistory } = await import('../report/index.js');
|
|
1656
|
+
// --history is a read of the store, so it deliberately never launches a
|
|
1657
|
+
// browser — `report --history` must work offline and on a dead site.
|
|
1658
|
+
if (ctx.flags.history) {
|
|
1659
|
+
const { dir, runs } = await readHistory(url);
|
|
1660
|
+
if (ctx.flags.json) {
|
|
1661
|
+
print(JSON.stringify({ data: { dir, runs } }, null, 2));
|
|
1662
|
+
}
|
|
1663
|
+
else if (!runs.length) {
|
|
1664
|
+
output.printWarning(`No stored runs for ${url}`);
|
|
1665
|
+
print(`Looked in: ${dir}`);
|
|
1666
|
+
}
|
|
1667
|
+
else {
|
|
1668
|
+
print(`${runs.length} run(s) for ${url}`);
|
|
1669
|
+
print(`Stored in: ${dir}`);
|
|
1670
|
+
for (const run of runs) {
|
|
1671
|
+
const lcp = run.vitals.lcp === undefined ? '—' : `${Math.round(run.vitals.lcp)}ms`;
|
|
1672
|
+
print(` ${run.capturedAt} ${run.verdict.toUpperCase().padEnd(4)} ` +
|
|
1673
|
+
`LCP ${lcp.padStart(7)} ${run.counts.consoleErrors} console errors ` +
|
|
1674
|
+
`${run.counts.failedRequests} failed requests ${run.counts.a11yErrors} a11y errors`);
|
|
1675
|
+
}
|
|
1676
|
+
}
|
|
1677
|
+
return { success: true, data: { dir, runs } };
|
|
1678
|
+
}
|
|
1679
|
+
const repeatRaw = ctx.flags.repeat;
|
|
1680
|
+
const repeat = typeof repeatRaw === 'number' && Number.isFinite(repeatRaw) && repeatRaw > 1
|
|
1681
|
+
? Math.floor(repeatRaw)
|
|
1682
|
+
: undefined;
|
|
1683
|
+
const { client, sessionId } = await ensureConnected(_port);
|
|
1684
|
+
const browser = await getBrowser();
|
|
1685
|
+
const rawDevices = ctx.flags.devices;
|
|
1686
|
+
const devices = typeof rawDevices === 'string'
|
|
1687
|
+
? rawDevices
|
|
1688
|
+
.split(',')
|
|
1689
|
+
.map((d) => d.trim())
|
|
1690
|
+
.filter(Boolean)
|
|
1691
|
+
: undefined;
|
|
1692
|
+
const runOptions = {
|
|
1693
|
+
url,
|
|
1694
|
+
out: ctx.flags.out,
|
|
1695
|
+
budget: ctx.flags.budget,
|
|
1696
|
+
devices,
|
|
1697
|
+
wait: ctx.flags.wait,
|
|
1698
|
+
vitalsWaitMs: ctx.flags['vitals-wait'],
|
|
1699
|
+
loadTimeoutMs: ctx.flags.timeout,
|
|
1700
|
+
fullPage: ctx.flags['full-page'] !== false,
|
|
1701
|
+
cwd: ctx.cwd,
|
|
1702
|
+
// A failing run records its own evidence without being asked; --record
|
|
1703
|
+
// is for when you want the timeline from a run that passes.
|
|
1704
|
+
record: ctx.flags.record === true,
|
|
1705
|
+
history: ctx.flags.save !== false,
|
|
1706
|
+
historyMax: ctx.flags['history-max'],
|
|
1707
|
+
trendWindow: ctx.flags['trend-window'],
|
|
1708
|
+
};
|
|
1709
|
+
let result;
|
|
1710
|
+
try {
|
|
1711
|
+
result = repeat
|
|
1712
|
+
? await runReportRepeated(client, sessionId, { ...runOptions, repeat })
|
|
1713
|
+
: await runReport(client, sessionId, runOptions);
|
|
1714
|
+
}
|
|
1715
|
+
finally {
|
|
1716
|
+
// A report is a one-shot command — CI should not be left with an
|
|
1717
|
+
// orphan Chrome. Only close a browser THIS process launched: an
|
|
1718
|
+
// attached one belongs to the user's own `open`/`connect` session.
|
|
1719
|
+
if (!ctx.flags['keep-open'] && browser.getLaunchedPid(_port) !== undefined) {
|
|
1720
|
+
browser.stopRequestCapture(sessionId);
|
|
1721
|
+
browser.teardownConsoleCapture(sessionId);
|
|
1722
|
+
try {
|
|
1723
|
+
await browser.closeBrowser(client, _port);
|
|
1724
|
+
}
|
|
1725
|
+
catch {
|
|
1726
|
+
/* best-effort */
|
|
1727
|
+
}
|
|
1728
|
+
_client = null;
|
|
1729
|
+
_sessionId = '';
|
|
1730
|
+
_targetId = '';
|
|
1731
|
+
_refs = new Map();
|
|
1732
|
+
await browser.clearActivePort();
|
|
1733
|
+
await browser.clearRefCache();
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
const { report, htmlPath, jsonPath, summary, historyDir } = result;
|
|
1737
|
+
const { flake } = result;
|
|
1738
|
+
// With --repeat the flake verdict governs: a check that failed 2 of 5
|
|
1739
|
+
// runs must not exit 0 just because the last run happened to be green.
|
|
1740
|
+
const passed = flake ? flake.verdict === 'pass' : report.verdict === 'pass';
|
|
1741
|
+
if (ctx.flags.json) {
|
|
1742
|
+
const { toJsonReport } = await import('../report/index.js');
|
|
1743
|
+
print(JSON.stringify({ data: { ...toJsonReport(report), flake, htmlPath, jsonPath, historyDir } }, null, 2));
|
|
1744
|
+
}
|
|
1745
|
+
else {
|
|
1746
|
+
if (passed)
|
|
1747
|
+
output.printSuccess(summary);
|
|
1748
|
+
else
|
|
1749
|
+
output.printError(summary);
|
|
1750
|
+
if (flake) {
|
|
1751
|
+
print(` ${flake.confidenceNote}`);
|
|
1752
|
+
for (const check of flake.checks.filter((c) => !c.stable)) {
|
|
1753
|
+
print(` ${check.label}: failed ${check.failed} of ${check.runs} runs`);
|
|
1754
|
+
}
|
|
1755
|
+
for (const signal of flake.signals.slice(0, 5)) {
|
|
1756
|
+
print(` ${signal.kind} "${signal.signature}" in ${signal.runs} of ${signal.total} runs`);
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1759
|
+
for (const failure of report.failures) {
|
|
1760
|
+
print(` ${failure.budget}: expected ${failure.expected}, got ${failure.actual}`);
|
|
1761
|
+
if (failure.detail)
|
|
1762
|
+
print(` ${failure.detail}`);
|
|
1763
|
+
}
|
|
1764
|
+
for (const headline of report.trend?.headlines ?? [])
|
|
1765
|
+
output.printWarning(headline);
|
|
1766
|
+
if (report.diff?.structure) {
|
|
1767
|
+
const d = report.diff.structure;
|
|
1768
|
+
print(` vs previous run: ${d.gained.length} gained, ${d.lost.length} lost, ${d.renamed.length} renamed`);
|
|
1769
|
+
}
|
|
1770
|
+
if (report.diff?.pixels?.comparable) {
|
|
1771
|
+
print(` vs previous run: ${report.diff.pixels.changedPercent.toFixed(2)}% of pixels changed`);
|
|
1772
|
+
}
|
|
1773
|
+
for (const note of report.notes)
|
|
1774
|
+
output.printWarning(note);
|
|
1775
|
+
print(`Report: ${htmlPath}`);
|
|
1776
|
+
print(`JSON: ${jsonPath}`);
|
|
1777
|
+
if (historyDir)
|
|
1778
|
+
print(`History: ${historyDir}`);
|
|
1779
|
+
}
|
|
1780
|
+
// Non-zero exit is the point of RIG-06 — CI and agents gate on it.
|
|
1781
|
+
return {
|
|
1782
|
+
success: passed,
|
|
1783
|
+
exitCode: passed ? 0 : 1,
|
|
1784
|
+
data: { htmlPath, jsonPath, report, flake },
|
|
1785
|
+
};
|
|
1786
|
+
},
|
|
1787
|
+
};
|
|
1540
1788
|
const closeCommand = {
|
|
1541
1789
|
name: 'close',
|
|
1542
1790
|
description: 'Close the active browser session',
|
|
@@ -3579,6 +3827,7 @@ const browseCommand = {
|
|
|
3579
3827
|
traceCommand,
|
|
3580
3828
|
profilerCommand,
|
|
3581
3829
|
vitalsCommand,
|
|
3830
|
+
reportCommand,
|
|
3582
3831
|
harCommand,
|
|
3583
3832
|
resizeCommand,
|
|
3584
3833
|
closeCommand,
|
|
@@ -3612,6 +3861,10 @@ const browseCommand = {
|
|
|
3612
3861
|
command: 'monomind browse network route --pattern "https://api.*" --abort',
|
|
3613
3862
|
description: 'Abort API calls',
|
|
3614
3863
|
},
|
|
3864
|
+
{
|
|
3865
|
+
command: 'monomind browse report https://example.com',
|
|
3866
|
+
description: 'One-command page report with a pass/fail verdict',
|
|
3867
|
+
},
|
|
3615
3868
|
{ command: 'monomind browse close', description: 'Close browser session' },
|
|
3616
3869
|
],
|
|
3617
3870
|
action: async (_ctx) => {
|
|
@@ -3668,6 +3921,7 @@ const browseCommand = {
|
|
|
3668
3921
|
output.printInfo(' batch Execute multiple commands');
|
|
3669
3922
|
output.printInfo(' addinitscript Add script to run before page navigation');
|
|
3670
3923
|
output.printInfo(' removeinitscript Remove a previously added init script');
|
|
3924
|
+
output.printInfo(' report Test a page and write an HTML report');
|
|
3671
3925
|
output.printInfo(' close Close the browser session');
|
|
3672
3926
|
return { success: true };
|
|
3673
3927
|
},
|