@setsquare/review-sdk 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/NOTICE +57 -0
- package/README.md +338 -0
- package/THIRD-PARTY-NOTICES.md +61 -0
- package/dist/autoscan.d.ts +25 -0
- package/dist/autoscan.d.ts.map +1 -0
- package/dist/autoscan.js +332 -0
- package/dist/autoscan.js.map +1 -0
- package/dist/axe.d.ts +96 -0
- package/dist/axe.d.ts.map +1 -0
- package/dist/axe.js +210 -0
- package/dist/axe.js.map +1 -0
- package/dist/bin/setsquare.d.ts +3 -0
- package/dist/bin/setsquare.d.ts.map +1 -0
- package/dist/bin/setsquare.js +21 -0
- package/dist/bin/setsquare.js.map +1 -0
- package/dist/brand.d.ts +84 -0
- package/dist/brand.d.ts.map +1 -0
- package/dist/brand.js +335 -0
- package/dist/brand.js.map +1 -0
- package/dist/checks/dynamic.d.ts +57 -0
- package/dist/checks/dynamic.d.ts.map +1 -0
- package/dist/checks/dynamic.js +184 -0
- package/dist/checks/dynamic.js.map +1 -0
- package/dist/checks/rule-pack.d.ts +34 -0
- package/dist/checks/rule-pack.d.ts.map +1 -0
- package/dist/checks/rule-pack.js +270 -0
- package/dist/checks/rule-pack.js.map +1 -0
- package/dist/checks/versions.d.ts +28 -0
- package/dist/checks/versions.d.ts.map +1 -0
- package/dist/checks/versions.js +45 -0
- package/dist/checks/versions.js.map +1 -0
- package/dist/ci.d.ts +37 -0
- package/dist/ci.d.ts.map +1 -0
- package/dist/ci.js +199 -0
- package/dist/ci.js.map +1 -0
- package/dist/contract.d.ts +334 -0
- package/dist/contract.d.ts.map +1 -0
- package/dist/contract.js +35 -0
- package/dist/contract.js.map +1 -0
- package/dist/dedupe.d.ts +79 -0
- package/dist/dedupe.d.ts.map +1 -0
- package/dist/dedupe.js +102 -0
- package/dist/dedupe.js.map +1 -0
- package/dist/document.d.ts +29 -0
- package/dist/document.d.ts.map +1 -0
- package/dist/document.js +94 -0
- package/dist/document.js.map +1 -0
- package/dist/envelope.d.ts +124 -0
- package/dist/envelope.d.ts.map +1 -0
- package/dist/envelope.js +337 -0
- package/dist/envelope.js.map +1 -0
- package/dist/escape.d.ts +14 -0
- package/dist/escape.d.ts.map +1 -0
- package/dist/escape.js +20 -0
- package/dist/escape.js.map +1 -0
- package/dist/findings.d.ts +47 -0
- package/dist/findings.d.ts.map +1 -0
- package/dist/findings.js +229 -0
- package/dist/findings.js.map +1 -0
- package/dist/fixture.d.ts +7 -0
- package/dist/fixture.d.ts.map +1 -0
- package/dist/fixture.js +237 -0
- package/dist/fixture.js.map +1 -0
- package/dist/group.d.ts +214 -0
- package/dist/group.d.ts.map +1 -0
- package/dist/group.js +709 -0
- package/dist/group.js.map +1 -0
- package/dist/html-report.d.ts +68 -0
- package/dist/html-report.d.ts.map +1 -0
- package/dist/html-report.js +649 -0
- package/dist/html-report.js.map +1 -0
- package/dist/human.d.ts +65 -0
- package/dist/human.d.ts.map +1 -0
- package/dist/human.js +111 -0
- package/dist/human.js.map +1 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/infer.d.ts +65 -0
- package/dist/infer.d.ts.map +1 -0
- package/dist/infer.js +67 -0
- package/dist/infer.js.map +1 -0
- package/dist/insights.d.ts +140 -0
- package/dist/insights.d.ts.map +1 -0
- package/dist/insights.js +483 -0
- package/dist/insights.js.map +1 -0
- package/dist/install.d.ts +8 -0
- package/dist/install.d.ts.map +1 -0
- package/dist/install.js +114 -0
- package/dist/install.js.map +1 -0
- package/dist/links.d.ts +45 -0
- package/dist/links.d.ts.map +1 -0
- package/dist/links.js +45 -0
- package/dist/links.js.map +1 -0
- package/dist/mask.d.ts +85 -0
- package/dist/mask.d.ts.map +1 -0
- package/dist/mask.js +98 -0
- package/dist/mask.js.map +1 -0
- package/dist/observe.d.ts +51 -0
- package/dist/observe.d.ts.map +1 -0
- package/dist/observe.js +233 -0
- package/dist/observe.js.map +1 -0
- package/dist/options.d.ts +249 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +185 -0
- package/dist/options.js.map +1 -0
- package/dist/output.d.ts +113 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +231 -0
- package/dist/output.js.map +1 -0
- package/dist/perf.d.ts +11 -0
- package/dist/perf.d.ts.map +1 -0
- package/dist/perf.js +150 -0
- package/dist/perf.js.map +1 -0
- package/dist/reading-level.d.ts +73 -0
- package/dist/reading-level.d.ts.map +1 -0
- package/dist/reading-level.js +189 -0
- package/dist/reading-level.js.map +1 -0
- package/dist/reporter.d.ts +94 -0
- package/dist/reporter.d.ts.map +1 -0
- package/dist/reporter.js +709 -0
- package/dist/reporter.js.map +1 -0
- package/dist/rules.d.ts +55 -0
- package/dist/rules.d.ts.map +1 -0
- package/dist/rules.js +77 -0
- package/dist/rules.js.map +1 -0
- package/dist/runtime.d.ts +32 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +67 -0
- package/dist/runtime.js.map +1 -0
- package/dist/sanitise.d.ts +116 -0
- package/dist/sanitise.d.ts.map +1 -0
- package/dist/sanitise.js +247 -0
- package/dist/sanitise.js.map +1 -0
- package/dist/scan.d.ts +60 -0
- package/dist/scan.d.ts.map +1 -0
- package/dist/scan.js +246 -0
- package/dist/scan.js.map +1 -0
- package/dist/screens.d.ts +98 -0
- package/dist/screens.d.ts.map +1 -0
- package/dist/screens.js +301 -0
- package/dist/screens.js.map +1 -0
- package/dist/settle.d.ts +65 -0
- package/dist/settle.d.ts.map +1 -0
- package/dist/settle.js +162 -0
- package/dist/settle.js.map +1 -0
- package/dist/shots.d.ts +109 -0
- package/dist/shots.d.ts.map +1 -0
- package/dist/shots.js +113 -0
- package/dist/shots.js.map +1 -0
- package/dist/style.d.ts +47 -0
- package/dist/style.d.ts.map +1 -0
- package/dist/style.js +154 -0
- package/dist/style.js.map +1 -0
- package/dist/suite.d.ts +218 -0
- package/dist/suite.d.ts.map +1 -0
- package/dist/suite.js +219 -0
- package/dist/suite.js.map +1 -0
- package/dist/summary.d.ts +268 -0
- package/dist/summary.d.ts.map +1 -0
- package/dist/summary.js +1308 -0
- package/dist/summary.js.map +1 -0
- package/dist/unscannable.d.ts +75 -0
- package/dist/unscannable.d.ts.map +1 -0
- package/dist/unscannable.js +111 -0
- package/dist/unscannable.js.map +1 -0
- package/dist/versions.d.ts +13 -0
- package/dist/versions.d.ts.map +1 -0
- package/dist/versions.js +39 -0
- package/dist/versions.js.map +1 -0
- package/dist/wcag-map.d.ts +19 -0
- package/dist/wcag-map.d.ts.map +1 -0
- package/dist/wcag-map.js +52 -0
- package/dist/wcag-map.js.map +1 -0
- package/dist/with-setsquare.d.ts +26 -0
- package/dist/with-setsquare.d.ts.map +1 -0
- package/dist/with-setsquare.js +70 -0
- package/dist/with-setsquare.js.map +1 -0
- package/package.json +81 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"suite.d.ts","sourceRoot":"","sources":["../src/suite.ts"],"names":[],"mappings":"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"}
|
package/dist/suite.js
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { MAX_FAILURE_MESSAGE_LENGTH, MAX_SLOWEST_ROWS, MAX_STEP_TITLE_LENGTH, } from '@setsquare/schema/limits';
|
|
2
|
+
import { capLength, sanitiseTestText } from './sanitise.js';
|
|
3
|
+
/**
|
|
4
|
+
* A class name parsed out of an error message, or nothing.
|
|
5
|
+
*
|
|
6
|
+
* Deliberately strict: only a leading token that actually looks like an error
|
|
7
|
+
* class (`TimeoutError:`, `AssertionError:`). Anything else yields `undefined`
|
|
8
|
+
* rather than a guess, because a taxonomy inferred from arbitrary prose looks
|
|
9
|
+
* computed while being invented — and a field like this gets grouped by, charted,
|
|
10
|
+
* and eventually trusted.
|
|
11
|
+
*/
|
|
12
|
+
const ERROR_CLASS = /^([A-Z][A-Za-z0-9_]*Error):/;
|
|
13
|
+
export function errorClassOf(message) {
|
|
14
|
+
const match = ERROR_CLASS.exec(message.trimStart());
|
|
15
|
+
return match?.[1];
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Collapse a message to one line and cap it.
|
|
19
|
+
*
|
|
20
|
+
* A Playwright error message is natively multi-line — assertion diff, call log,
|
|
21
|
+
* code frame — and a newline is a C0 control, which the contract's character
|
|
22
|
+
* constraint bans. Collapsing rather than permitting newlines is a deliberate
|
|
23
|
+
* contract decision recorded in `ingest.ts`: one sanitisation rule, not two that
|
|
24
|
+
* can drift. The repro command is how someone gets the readable original.
|
|
25
|
+
*/
|
|
26
|
+
export function collapseMessage(value) {
|
|
27
|
+
const flat = value.replace(/\s+/g, ' ').trim();
|
|
28
|
+
return capLength(flat, MAX_FAILURE_MESSAGE_LENGTH);
|
|
29
|
+
}
|
|
30
|
+
/** Depth-first walk, parents before children. */
|
|
31
|
+
function walk(steps, visit, depth = 0) {
|
|
32
|
+
for (const step of steps ?? []) {
|
|
33
|
+
visit(step, depth);
|
|
34
|
+
walk(step.steps, visit, depth + 1);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* The deepest failing step's title.
|
|
39
|
+
*
|
|
40
|
+
* Deepest, not first: Playwright marks every ancestor of a failure as failed too,
|
|
41
|
+
* so the outermost failing step is usually `Before Hooks` or the test body — true,
|
|
42
|
+
* and useless. The innermost one is the actual operation that broke.
|
|
43
|
+
*/
|
|
44
|
+
export function deepestFailingStep(steps) {
|
|
45
|
+
let best;
|
|
46
|
+
walk(steps, (step, depth) => {
|
|
47
|
+
if (step.error === undefined || step.error === null)
|
|
48
|
+
return;
|
|
49
|
+
if (best === undefined || depth > best.depth)
|
|
50
|
+
best = { title: step.title, depth };
|
|
51
|
+
});
|
|
52
|
+
return best === undefined ? undefined : sanitiseTestText(best.title, MAX_STEP_TITLE_LENGTH);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Why this test failed, from the error list and the step tree.
|
|
56
|
+
*
|
|
57
|
+
* Returns `undefined` for a test that did not fail, and for a failed test whose
|
|
58
|
+
* result carried neither an error nor an identifiable failing step — because
|
|
59
|
+
* `{}` would imply we looked and found a failure with no properties, which is not
|
|
60
|
+
* what happened.
|
|
61
|
+
*/
|
|
62
|
+
export function failureFacts(errors, steps) {
|
|
63
|
+
const facts = {};
|
|
64
|
+
const raw = errors?.find((error) => typeof error.message === 'string' && error.message.length > 0)?.message;
|
|
65
|
+
if (raw !== undefined) {
|
|
66
|
+
const message = collapseMessage(raw);
|
|
67
|
+
if (message.length > 0)
|
|
68
|
+
facts.message = message;
|
|
69
|
+
// Parsed from the RAW message, before collapsing, because the class is at the
|
|
70
|
+
// very start and collapsing cannot move it — but trimming might.
|
|
71
|
+
const errorClass = errorClassOf(raw);
|
|
72
|
+
if (errorClass)
|
|
73
|
+
facts.errorClass = errorClass;
|
|
74
|
+
}
|
|
75
|
+
const step = deepestFailingStep(steps);
|
|
76
|
+
if (step)
|
|
77
|
+
facts.step = step;
|
|
78
|
+
return Object.keys(facts).length > 0 ? facts : undefined;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The slowest LEAF steps.
|
|
82
|
+
*
|
|
83
|
+
* Leaves only, and that is the load-bearing decision. Playwright's step tree
|
|
84
|
+
* nests, and a parent's duration CONTAINS its children's — so a list mixing the
|
|
85
|
+
* two double-counts, and "the slowest step took 8s" would be answered by a
|
|
86
|
+
* wrapper whose children did all the work. Leaves are the actual operations.
|
|
87
|
+
*
|
|
88
|
+
* The cost of that choice, stated: a slow custom step that wraps many fast ones
|
|
89
|
+
* will not appear, even though it is arguably the interesting row. Reporting both
|
|
90
|
+
* would need a tree in the output, and the useful artefact here is a short list.
|
|
91
|
+
*/
|
|
92
|
+
export function slowestSteps(steps, limit = MAX_SLOWEST_ROWS) {
|
|
93
|
+
const leaves = [];
|
|
94
|
+
walk(steps, (step) => {
|
|
95
|
+
if (step.steps !== undefined && step.steps.length > 0)
|
|
96
|
+
return;
|
|
97
|
+
if (!Number.isFinite(step.duration) || step.duration < 0)
|
|
98
|
+
return;
|
|
99
|
+
leaves.push({
|
|
100
|
+
title: sanitiseTestText(step.title, MAX_STEP_TITLE_LENGTH),
|
|
101
|
+
category: sanitiseTestText(step.category, 64),
|
|
102
|
+
durationMs: Math.round(step.duration),
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
return leaves.sort((a, b) => b.durationMs - a.durationMs).slice(0, limit);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Per-worker busy time.
|
|
109
|
+
*
|
|
110
|
+
* **Busy time, never wall clock.** These are summed test durations, so the total
|
|
111
|
+
* across workers exceeds the run's elapsed time by roughly the parallelism factor.
|
|
112
|
+
* Nothing may present these as "the run took X" or subtract them from anything —
|
|
113
|
+
* the same discipline scan overhead follows, and for the same reason: we can
|
|
114
|
+
* measure what we spent, not what the run would have cost without it.
|
|
115
|
+
*
|
|
116
|
+
* `undefined` when no outcome carried a worker index, which is the honest answer
|
|
117
|
+
* for a run where Playwright never told us (and for envelopes written before the
|
|
118
|
+
* field existed). Renderers must then say nothing rather than reporting one
|
|
119
|
+
* worker.
|
|
120
|
+
*/
|
|
121
|
+
export function workerLoad(outcomes, configured) {
|
|
122
|
+
const busy = new Map();
|
|
123
|
+
for (const outcome of outcomes) {
|
|
124
|
+
if (outcome.workerIndex === undefined)
|
|
125
|
+
continue;
|
|
126
|
+
const duration = Number.isFinite(outcome.durationMs) ? Math.max(0, outcome.durationMs) : 0;
|
|
127
|
+
busy.set(outcome.workerIndex, (busy.get(outcome.workerIndex) ?? 0) + duration);
|
|
128
|
+
}
|
|
129
|
+
if (busy.size === 0)
|
|
130
|
+
return undefined;
|
|
131
|
+
const totals = [...busy.values()].sort((a, b) => a - b);
|
|
132
|
+
const median = totals[Math.floor(totals.length / 2)] ?? 0;
|
|
133
|
+
const busiest = totals[totals.length - 1] ?? 0;
|
|
134
|
+
return {
|
|
135
|
+
workers: busy.size,
|
|
136
|
+
...(configured !== undefined && configured > 0 ? { configured } : {}),
|
|
137
|
+
busiestMs: Math.round(busiest),
|
|
138
|
+
idlestMs: Math.round(totals[0] ?? 0),
|
|
139
|
+
tailMs: Math.round(Math.max(0, busiest - median)),
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
export function flakyTests(outcomes) {
|
|
143
|
+
const attempts = new Map();
|
|
144
|
+
for (const outcome of outcomes) {
|
|
145
|
+
const existing = attempts.get(outcome.testId);
|
|
146
|
+
if (existing)
|
|
147
|
+
existing.push(outcome);
|
|
148
|
+
else
|
|
149
|
+
attempts.set(outcome.testId, [outcome]);
|
|
150
|
+
}
|
|
151
|
+
const flaky = [];
|
|
152
|
+
for (const [testId, tries] of attempts) {
|
|
153
|
+
const passed = tries.find((attempt) => attempt.status === 'passed' && attempt.retry > 0);
|
|
154
|
+
if (!passed)
|
|
155
|
+
continue;
|
|
156
|
+
// The earliest failing attempt is the one worth reporting: it is the failure
|
|
157
|
+
// the retry hid.
|
|
158
|
+
const failed = [...tries]
|
|
159
|
+
.filter((attempt) => attempt.status !== 'passed' && attempt.status !== 'skipped')
|
|
160
|
+
.sort((a, b) => a.retry - b.retry)[0];
|
|
161
|
+
flaky.push({
|
|
162
|
+
testId,
|
|
163
|
+
passedOnRetry: passed.retry,
|
|
164
|
+
...(failed?.failure ? { failure: failed.failure } : {}),
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
return flaky.sort((a, b) => a.testId.localeCompare(b.testId));
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* The local-only suite/overhead/coverage blocks for `meta.json`.
|
|
171
|
+
*
|
|
172
|
+
* Assembled in one place because all three are reductions over the same
|
|
173
|
+
* `outcomes` array, and because a renderer recomputing any of them is how the
|
|
174
|
+
* terminal, the HTML report and the markdown output come to disagree.
|
|
175
|
+
*/
|
|
176
|
+
export function localFacts(outcomes, runDurationMs, configuredWorkers) {
|
|
177
|
+
const slowestTests = [...outcomes]
|
|
178
|
+
.sort((a, b) => b.durationMs - a.durationMs)
|
|
179
|
+
.slice(0, MAX_SLOWEST_ROWS)
|
|
180
|
+
.map((outcome) => ({ testId: outcome.testId, durationMs: Math.round(outcome.durationMs) }));
|
|
181
|
+
const steps = outcomes
|
|
182
|
+
.flatMap((outcome) => (outcome.slowestSteps ?? []).map((step) => ({ testId: outcome.testId, ...step })))
|
|
183
|
+
.sort((a, b) => b.durationMs - a.durationMs)
|
|
184
|
+
.slice(0, MAX_SLOWEST_ROWS);
|
|
185
|
+
let scans = 0;
|
|
186
|
+
let scanMs = 0;
|
|
187
|
+
let axeMs = 0;
|
|
188
|
+
for (const outcome of outcomes) {
|
|
189
|
+
for (const record of outcome.records) {
|
|
190
|
+
if (record.kind !== 'scan' || !record.cost)
|
|
191
|
+
continue;
|
|
192
|
+
scans += 1;
|
|
193
|
+
scanMs += record.cost.totalMs;
|
|
194
|
+
axeMs += record.cost.axeMs;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
const workers = workerLoad(outcomes, configuredWorkers);
|
|
198
|
+
return {
|
|
199
|
+
// Absent when no scan reported a cost, rather than a run claiming it spent
|
|
200
|
+
// nothing inside us.
|
|
201
|
+
...(scans > 0
|
|
202
|
+
? {
|
|
203
|
+
overhead: {
|
|
204
|
+
scans,
|
|
205
|
+
scanMs: Math.round(scanMs),
|
|
206
|
+
axeMs: Math.round(axeMs),
|
|
207
|
+
runDurationMs: Math.round(runDurationMs),
|
|
208
|
+
},
|
|
209
|
+
}
|
|
210
|
+
: {}),
|
|
211
|
+
suite: {
|
|
212
|
+
slowestTests,
|
|
213
|
+
slowestSteps: steps,
|
|
214
|
+
...(workers ? { workers } : {}),
|
|
215
|
+
flaky: flakyTests(outcomes),
|
|
216
|
+
},
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
//# sourceMappingURL=suite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"suite.js","sourceRoot":"","sources":["../src/suite.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import type { AxeFinding, RunIngestRequest } from '@setsquare/schema';
|
|
2
|
+
import { type DeclaredAxes } from './insights.js';
|
|
3
|
+
import type { OverheadFacts, SuiteFacts } from './suite.js';
|
|
4
|
+
/**
|
|
5
|
+
* What a run says when it finishes.
|
|
6
|
+
*
|
|
7
|
+
* This is read on every run by every user, forever, which makes it the highest-
|
|
8
|
+
* leverage piece of writing in the free layer. It has to be legible to someone
|
|
9
|
+
* who has never heard of Setsquare — that is the acceptance criterion, judged by
|
|
10
|
+
* a founder who did not write the SDK — and it has to stay legible when a suite
|
|
11
|
+
* produces four findings or four hundred.
|
|
12
|
+
*
|
|
13
|
+
* Three rules govern the rendering, and each exists because the obvious
|
|
14
|
+
* alternative fails:
|
|
15
|
+
*
|
|
16
|
+
* 1. **Colour is decoration, never information.** Every status is legible in a
|
|
17
|
+
* plain-text log. Non-negotiable for an accessibility company, and it also
|
|
18
|
+
* means CI logs lose nothing.
|
|
19
|
+
* 2. **No box-drawing.** A bordered table becomes garbage the moment it is
|
|
20
|
+
* pasted into a narrow Slack window or soft-wrapped by a terminal, and being
|
|
21
|
+
* pasted somewhere is the main thing that happens to this output.
|
|
22
|
+
* 3. **Every line stands alone.** Greppable, and meaningful without the header
|
|
23
|
+
* above it.
|
|
24
|
+
*
|
|
25
|
+
* Grouped by rule rather than listed by node (decision 2, 2026-08-17): the SDK
|
|
26
|
+
* suppresses nothing, so legibility is earned by presentation. One contrast rule
|
|
27
|
+
* across 214 nodes is one line, not 214.
|
|
28
|
+
*/
|
|
29
|
+
export interface SummaryInput {
|
|
30
|
+
envelope: RunIngestRequest;
|
|
31
|
+
envelopePath: string;
|
|
32
|
+
/** Surfaces the suite visited that nothing scanned. Reported, never hidden. */
|
|
33
|
+
warnings: string[];
|
|
34
|
+
promo: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Playwright's own HTML report, when one was generated.
|
|
37
|
+
*
|
|
38
|
+
* This runs inside a Playwright suite, and the summary should behave like it
|
|
39
|
+
* knows that. A developer whose run just failed wants the trace and the
|
|
40
|
+
* screenshots, not only our findings — pointing at the report they already have
|
|
41
|
+
* costs one line and stops us behaving like the only thing that happened.
|
|
42
|
+
*/
|
|
43
|
+
reportPath?: string;
|
|
44
|
+
/** Setsquare's own HTML report, when writing it succeeded. */
|
|
45
|
+
htmlReportPath?: string;
|
|
46
|
+
/**
|
|
47
|
+
* The visual contact sheet, when the run had screenshots to index.
|
|
48
|
+
*
|
|
49
|
+
* Named in the terminal because a report nobody knows exists is a report
|
|
50
|
+
* nobody opens — and this one exists for the person who is about to approve a
|
|
51
|
+
* change by reading a green tick.
|
|
52
|
+
*/
|
|
53
|
+
screensPath?: string;
|
|
54
|
+
/**
|
|
55
|
+
* How many tests this run intended to execute.
|
|
56
|
+
*
|
|
57
|
+
* Read from Playwright's own suite tree rather than counted from results, which
|
|
58
|
+
* is the only way to see the tests that never ran at all — the ones a failed
|
|
59
|
+
* setup project took down with it, and the ones that make a partial run look
|
|
60
|
+
* like a complete one.
|
|
61
|
+
*/
|
|
62
|
+
plannedTests?: number;
|
|
63
|
+
/**
|
|
64
|
+
* How the conformance grid renders: aligned glyph matrix (default) or
|
|
65
|
+
* criterion rows only. The matrix also steps aside by itself when the run
|
|
66
|
+
* has more surfaces than the width budget fits.
|
|
67
|
+
*/
|
|
68
|
+
grid?: 'matrix' | 'rows';
|
|
69
|
+
/**
|
|
70
|
+
* The engine's criterion → rules map, from `criterionRuleMap()`. What lets
|
|
71
|
+
* the conformance section split "no automated check exists" from "checks
|
|
72
|
+
* exist but were not run". Optional: without it the wording is combined,
|
|
73
|
+
* never wrong.
|
|
74
|
+
*/
|
|
75
|
+
criterionRules?: ReadonlyMap<string, readonly string[]>;
|
|
76
|
+
/**
|
|
77
|
+
* Local-only facts from `meta.json`, for the P1b insight blocks.
|
|
78
|
+
*
|
|
79
|
+
* Optional throughout: a caller that has no sidecar (the HTML report rendered
|
|
80
|
+
* from an envelope alone, a fixture test) renders the envelope-derived blocks
|
|
81
|
+
* and silently omits the rest. Absence must never become a zero — the blocks in
|
|
82
|
+
* `insights.ts` return `undefined` rather than an empty section for exactly that
|
|
83
|
+
* reason.
|
|
84
|
+
*/
|
|
85
|
+
suite?: SuiteFacts;
|
|
86
|
+
overhead?: OverheadFacts;
|
|
87
|
+
declaredAxes?: DeclaredAxes;
|
|
88
|
+
unmeasuredAxes?: readonly string[];
|
|
89
|
+
/**
|
|
90
|
+
* Present when this invocation is one part of a run group (SETSQUARE_RUN_ID).
|
|
91
|
+
*
|
|
92
|
+
* The summary above the block describes THIS invocation only; the block says
|
|
93
|
+
* so, names the merged artifact, and states what is known about the group's
|
|
94
|
+
* coverage — including, out loud, when completeness is not knowable.
|
|
95
|
+
*/
|
|
96
|
+
group?: GroupSummary;
|
|
97
|
+
}
|
|
98
|
+
export interface GroupSummary {
|
|
99
|
+
id: string;
|
|
100
|
+
lane?: string;
|
|
101
|
+
partId: string;
|
|
102
|
+
/** Invocations whose evidence is in the merged artifact right now. */
|
|
103
|
+
mergedParts: number;
|
|
104
|
+
/** The labels namespacing each merged part's testIds, in merge order. */
|
|
105
|
+
labels: string[];
|
|
106
|
+
/** The declared census, or null when none was declared. */
|
|
107
|
+
expectedParts: number | null;
|
|
108
|
+
/** Invocations that began but were never merged. */
|
|
109
|
+
missing: number;
|
|
110
|
+
coverage: 'complete' | 'partial' | 'unknown';
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* One wording for every renderer, because the three formats must never say
|
|
114
|
+
* different things about the same coverage.
|
|
115
|
+
*/
|
|
116
|
+
export declare function groupLines(group: GroupSummary): string[];
|
|
117
|
+
interface RuleGroup {
|
|
118
|
+
ruleId: string;
|
|
119
|
+
impact: string;
|
|
120
|
+
status: AxeFinding['status'];
|
|
121
|
+
nodes: number;
|
|
122
|
+
contexts: string[];
|
|
123
|
+
/** The same contexts with their element counts, for ranking worst-first. */
|
|
124
|
+
contextNodes: {
|
|
125
|
+
label: string;
|
|
126
|
+
nodes: number;
|
|
127
|
+
}[];
|
|
128
|
+
/**
|
|
129
|
+
* A representative sample of failing selectors (bounded), and axe's own
|
|
130
|
+
* fix text from a representative node. These are the actionable halves of a
|
|
131
|
+
* finding — a rule entry without them says how big a problem is while
|
|
132
|
+
* refusing to say what to change or where.
|
|
133
|
+
*/
|
|
134
|
+
selectors: string[];
|
|
135
|
+
selectorsTruncated: boolean;
|
|
136
|
+
failureSummary?: string;
|
|
137
|
+
helpUrl?: string;
|
|
138
|
+
criteria: string[];
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Collapse findings to one row per (rule, status).
|
|
142
|
+
*
|
|
143
|
+
* Deliberately not per rule alone: a rule that fails on one surface and is
|
|
144
|
+
* *unresolvable* on another is telling you two different things, and merging them
|
|
145
|
+
* would report "we could not check this" as "this is broken".
|
|
146
|
+
*/
|
|
147
|
+
export declare function groupFindings(envelope: RunIngestRequest): RuleGroup[];
|
|
148
|
+
export interface SurfaceRow {
|
|
149
|
+
label: string;
|
|
150
|
+
violations: number;
|
|
151
|
+
/**
|
|
152
|
+
* Elements axe could not decide about.
|
|
153
|
+
*
|
|
154
|
+
* Kept separate from `violations` because the difference is the whole point: a
|
|
155
|
+
* surface with unresolved checks has not been verified, and calling it a pass
|
|
156
|
+
* would be the confident false pass this product exists to avoid.
|
|
157
|
+
*/
|
|
158
|
+
incomplete: number;
|
|
159
|
+
rules: string[];
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* One row per scanned context, worst first.
|
|
163
|
+
*
|
|
164
|
+
* The summary used to report only totals and rules, which answered "what is
|
|
165
|
+
* broken" without answering "where". Both matter, and the second is the one a
|
|
166
|
+
* person acts on: they open a surface, not a rule.
|
|
167
|
+
*/
|
|
168
|
+
export declare function surfaceRows(envelope: RunIngestRequest): SurfaceRow[];
|
|
169
|
+
export interface EvidenceQuality {
|
|
170
|
+
/** Distinct axe rules that actually ran, across the whole run. */
|
|
171
|
+
rulesAssessed: number;
|
|
172
|
+
/** Scans that fired on a page that had gone still — the best case. */
|
|
173
|
+
quiet: number;
|
|
174
|
+
/** Scans taken as the test ended. Common, and not a lesser result. */
|
|
175
|
+
teardown: number;
|
|
176
|
+
/** Scans the settle ceiling cut short. Weaker evidence, and named as such. */
|
|
177
|
+
ceiling: number;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* How much the findings are worth, as distinct from what they say.
|
|
181
|
+
*
|
|
182
|
+
* The worst failure available to an accessibility scanner is not a crash but a
|
|
183
|
+
* CONFIDENT FALSE PASS — audit a page before its content arrives, find nothing,
|
|
184
|
+
* report conformance nobody verified. That failure is invisible in the findings
|
|
185
|
+
* themselves, which is why the schema carries the conditions each scan fired
|
|
186
|
+
* under. Until now nothing read them back: every scan in a run looked equally
|
|
187
|
+
* trustworthy in the summary, including the ones we already knew were not.
|
|
188
|
+
*
|
|
189
|
+
* `rulesAssessed` is the other half of the same idea. "2,518 checks passed" is an
|
|
190
|
+
* impressive number with no denominator — 2,518 out of what? Naming how many
|
|
191
|
+
* distinct rules ran turns it into a statement someone could audit.
|
|
192
|
+
*/
|
|
193
|
+
export declare function evidenceQuality(envelope: RunIngestRequest): EvidenceQuality;
|
|
194
|
+
export interface PerfRow {
|
|
195
|
+
label: string;
|
|
196
|
+
lcpMs?: number;
|
|
197
|
+
cls?: number;
|
|
198
|
+
loadMs?: number;
|
|
199
|
+
ttfbMs?: number;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* One row per page LOAD, not per scan.
|
|
203
|
+
*
|
|
204
|
+
* `setsquare.scan()` can run several times against one navigation — modal closed, then
|
|
205
|
+
* modal open — and every one of those scans carries the same `perf` numbers,
|
|
206
|
+
* because there was only ever one load. Averaging or ranking without collapsing
|
|
207
|
+
* them would weight a surface by how many states it happens to have, which is a
|
|
208
|
+
* property of how somebody wrote their test rather than of the page. `visitRef`
|
|
209
|
+
* exists in the schema precisely to make this collapse possible.
|
|
210
|
+
*/
|
|
211
|
+
export declare function perfRows(envelope: RunIngestRequest): PerfRow[];
|
|
212
|
+
export interface RunTotals {
|
|
213
|
+
surfaces: number;
|
|
214
|
+
themes: number;
|
|
215
|
+
scans: number;
|
|
216
|
+
violations: number;
|
|
217
|
+
incomplete: number;
|
|
218
|
+
passes: number;
|
|
219
|
+
clean: number;
|
|
220
|
+
}
|
|
221
|
+
export interface TestOutcomes {
|
|
222
|
+
passed: number;
|
|
223
|
+
failed: number;
|
|
224
|
+
/** Failed at least once, then passed. Playwright's own word for it. */
|
|
225
|
+
flaky: number;
|
|
226
|
+
skipped: number;
|
|
227
|
+
/** In the suite, but never reported an outcome. Absent when unknown. */
|
|
228
|
+
notRun?: number;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* What Playwright itself reported — counted the way Playwright counts it.
|
|
232
|
+
*
|
|
233
|
+
* The first version of this disagreed with the run it was printed underneath. On
|
|
234
|
+
* Eos, Playwright said *26 passed, 2 failed, 2 flaky, 82 did not run* and we said
|
|
235
|
+
* *28 passed, 6 failed*. Both of our numbers were defensible and both were wrong
|
|
236
|
+
* to print: the 6 counted every failed ATTEMPT including retries, and the 28
|
|
237
|
+
* quietly folded the two flaky tests in with the healthy ones.
|
|
238
|
+
*
|
|
239
|
+
* A tool that runs inside somebody's suite and then contradicts that suite's own
|
|
240
|
+
* summary, on the same screen, a few lines further down, has undermined itself
|
|
241
|
+
* before it says anything about accessibility. So: one row per TEST, the last
|
|
242
|
+
* attempt decides, and a test that needed a retry is named as flaky rather than
|
|
243
|
+
* absorbed.
|
|
244
|
+
*
|
|
245
|
+
* `notRun` is the one that changes what the rest of the report means. Eos's run
|
|
246
|
+
* scanned 10 surfaces — which reads as coverage of the application until you know
|
|
247
|
+
* that 82 of its 112 tests never executed, because a failing setup project took
|
|
248
|
+
* their dependents down with it. Evidence from a quarter of a suite must not look
|
|
249
|
+
* like evidence from a suite.
|
|
250
|
+
*/
|
|
251
|
+
export declare function testOutcomes(envelope: RunIngestRequest, plannedTests?: number): TestOutcomes;
|
|
252
|
+
export declare function totals(envelope: RunIngestRequest): RunTotals;
|
|
253
|
+
/** Never wider than the terminal, never narrower than legible. */
|
|
254
|
+
export declare function terminalWidth(columns: number | undefined): number;
|
|
255
|
+
/**
|
|
256
|
+
* The plain-text summary.
|
|
257
|
+
*
|
|
258
|
+
* Two spaces of indent throughout rather than aligned columns: alignment breaks
|
|
259
|
+
* the moment a surface name is long, and a broken column looks like a bug in the
|
|
260
|
+
* tool rather than a long name.
|
|
261
|
+
*/
|
|
262
|
+
export declare function renderText(input: SummaryInput, columns?: number): string;
|
|
263
|
+
/** Markdown, for pasting into Slack, an issue, or an LLM prompt. */
|
|
264
|
+
export declare function renderMarkdown(input: SummaryInput): string;
|
|
265
|
+
export type SummaryFormat = 'text' | 'markdown' | 'json';
|
|
266
|
+
export declare function render(input: SummaryInput, format: SummaryFormat, columns?: number): string;
|
|
267
|
+
export {};
|
|
268
|
+
//# sourceMappingURL=summary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"summary.d.ts","sourceRoot":"","sources":["../src/summary.ts"],"names":[],"mappings":"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"}
|