@ploaness/config 1.12.0 → 1.14.0

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 (75) hide show
  1. package/dist/a11y.d.ts +13 -5
  2. package/dist/a11y.d.ts.map +1 -1
  3. package/dist/a11y.js +20 -11
  4. package/dist/a11y.js.map +1 -1
  5. package/dist/clock-preload.d.ts +2 -0
  6. package/dist/clock-preload.d.ts.map +1 -0
  7. package/dist/clock-preload.js +37 -0
  8. package/dist/clock-preload.js.map +1 -0
  9. package/dist/eslint-library.d.ts.map +1 -1
  10. package/dist/eslint-library.js +6 -1
  11. package/dist/eslint-library.js.map +1 -1
  12. package/dist/eslint-runtime.d.ts +11 -0
  13. package/dist/eslint-runtime.d.ts.map +1 -0
  14. package/dist/eslint-runtime.js +68 -0
  15. package/dist/eslint-runtime.js.map +1 -0
  16. package/dist/eslint.d.ts.map +1 -1
  17. package/dist/eslint.js +6 -1
  18. package/dist/eslint.js.map +1 -1
  19. package/dist/layout.d.ts +34 -16
  20. package/dist/layout.d.ts.map +1 -1
  21. package/dist/layout.js +228 -56
  22. package/dist/layout.js.map +1 -1
  23. package/dist/payload-view.d.ts +16 -0
  24. package/dist/payload-view.d.ts.map +1 -0
  25. package/dist/payload-view.js +35 -0
  26. package/dist/payload-view.js.map +1 -0
  27. package/dist/playwright.d.ts.map +1 -1
  28. package/dist/playwright.js +115 -12
  29. package/dist/playwright.js.map +1 -1
  30. package/dist/scanner.d.ts +99 -0
  31. package/dist/scanner.d.ts.map +1 -0
  32. package/dist/scanner.js +278 -0
  33. package/dist/scanner.js.map +1 -0
  34. package/dist/settle.d.ts +8 -6
  35. package/dist/settle.d.ts.map +1 -1
  36. package/dist/settle.js +55 -42
  37. package/dist/settle.js.map +1 -1
  38. package/dist/sweep-disclosures.d.ts +10 -0
  39. package/dist/sweep-disclosures.d.ts.map +1 -0
  40. package/dist/sweep-disclosures.js +179 -0
  41. package/dist/sweep-disclosures.js.map +1 -0
  42. package/dist/sweep-discovery.d.ts +15 -0
  43. package/dist/sweep-discovery.d.ts.map +1 -0
  44. package/dist/sweep-discovery.js +336 -0
  45. package/dist/sweep-discovery.js.map +1 -0
  46. package/dist/sweep-interaction.d.ts +19 -0
  47. package/dist/sweep-interaction.d.ts.map +1 -0
  48. package/dist/sweep-interaction.js +351 -0
  49. package/dist/sweep-interaction.js.map +1 -0
  50. package/dist/sweep-queue.d.ts +24 -0
  51. package/dist/sweep-queue.d.ts.map +1 -0
  52. package/dist/sweep-queue.js +56 -0
  53. package/dist/sweep-queue.js.map +1 -0
  54. package/dist/sweep-reflow.d.ts +17 -0
  55. package/dist/sweep-reflow.d.ts.map +1 -0
  56. package/dist/sweep-reflow.js +210 -0
  57. package/dist/sweep-reflow.js.map +1 -0
  58. package/dist/sweep-resting.d.ts +25 -0
  59. package/dist/sweep-resting.d.ts.map +1 -0
  60. package/dist/sweep-resting.js +98 -0
  61. package/dist/sweep-resting.js.map +1 -0
  62. package/dist/sweep-shared.d.ts +353 -0
  63. package/dist/sweep-shared.d.ts.map +1 -0
  64. package/dist/sweep-shared.js +434 -0
  65. package/dist/sweep-shared.js.map +1 -0
  66. package/dist/sweep.d.ts +14 -0
  67. package/dist/sweep.d.ts.map +1 -0
  68. package/dist/sweep.js +157 -0
  69. package/dist/sweep.js.map +1 -0
  70. package/dist/vitest-core.d.ts +1 -1
  71. package/dist/vitest-core.js +1 -1
  72. package/dist/vitest-library.d.ts.map +1 -1
  73. package/dist/vitest-library.js +2 -1
  74. package/dist/vitest-library.js.map +1 -1
  75. package/package.json +10 -2
@@ -0,0 +1,434 @@
1
+ // What every pass of the managed browser sweep shares: the browser surface its page functions touch,
2
+ // the files the passes hand each other, loading a location, and the budget each pass runs under.
3
+ import { appendFileSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
4
+ import path from 'node:path';
5
+ import { expect, test } from '@playwright/test';
6
+ import { allowedOrigins, distinctFindings, FONT_LOAD_RULE, failingPlaces, findingAt, findingLine, isAllowedRequest, isArray, isRecord, LAYOUT_RULES, PAGE_ERROR_RULE, PASS_BUDGET_RULE, partBudgetMs, REAL_CLOCK, RESTING_ELEMENT_RULES, SETTLED_STORY_PHASES, storyLocation, storySamples, } from '@ploaness/governance';
7
+ import { outlineElements } from './layout.js';
8
+ import { projectSettings } from './project-settings.js';
9
+ import { engineOf, healthFindings } from './scanner.js';
10
+ import { firstUntaken, takeNext, untakenCount } from './sweep-queue.js';
11
+ export const EMPTY_VISIT = { findings: [], used: [], declared: [], notes: [] };
12
+ const SWEEP_DIRECTORY = 'ploaness-sweep';
13
+ // Every element a person can operate, wherever it sits on the page.
14
+ export const CONTROLS = [
15
+ 'a[href]',
16
+ 'button',
17
+ 'input:not([type="hidden"])',
18
+ 'select',
19
+ 'textarea',
20
+ 'summary',
21
+ '[role="button"]',
22
+ '[role="link"]',
23
+ '[role="checkbox"]',
24
+ '[role="radio"]',
25
+ '[role="switch"]',
26
+ '[role="tab"]',
27
+ '[role="menuitem"]',
28
+ '[role="option"]',
29
+ '[role="combobox"]',
30
+ '[role="slider"]',
31
+ '[tabindex]:not([tabindex="-1"])',
32
+ ].join(', ');
33
+ // The site chrome renders identically on every page, so its controls are driven once per viewport, on
34
+ // the first location, rather than once per page.
35
+ export const CHROME = 'header, footer';
36
+ export const PROBE_ATTRIBUTE = 'data-ploaness-probe';
37
+ export const DISCLOSURE_ATTRIBUTE = 'data-ploaness-disclosure';
38
+ // Motion is disabled so every run measures the same frame: what a reader is left looking at.
39
+ export const STILL_STYLE = '*, *::before, *::after { animation-duration: 0s !important; animation-delay: 0s !important; ' +
40
+ 'transition-duration: 0s !important; transition-delay: 0s !important; caret-color: transparent !important; ' +
41
+ 'scroll-behavior: auto !important; }';
42
+ // Enough to show what each failing place looked like without turning a broken site into gigabytes.
43
+ const MAX_SCREENSHOTS = 60;
44
+ // Grace beyond the pass budget, so the pass reports its own budget finding before Playwright's timeout.
45
+ const TIMEOUT_GRACE_MS = 120_000;
46
+ const STORY_RENDER_MS = 30_000;
47
+ export const DESKTOP = { width: 1280, height: 800 };
48
+ // ---------------------------------------------------------------------------------------------------
49
+ // Files
50
+ /**
51
+ * The directory every engine's passes hand their files through. Every project shares the config's
52
+ * output directory, so discovery, run once, is read from here by every engine.
53
+ * @param info the running test.
54
+ * @returns the directory.
55
+ */
56
+ export const sweepRoot = (info) => path.join(info.project.outputDir, SWEEP_DIRECTORY);
57
+ /**
58
+ * The directory the passes of one engine write their reports and progress to.
59
+ * @param info the running test.
60
+ * @param engine the engine.
61
+ * @returns the directory.
62
+ */
63
+ export const engineDirectory = (info, engine) => path.join(sweepRoot(info), engine);
64
+ const JSON_INDENT = 2;
65
+ /**
66
+ * Write a value as indented JSON, creating its directory.
67
+ * @param file the file to write.
68
+ * @param value the value.
69
+ */
70
+ export const writeJson = (file, value) => {
71
+ mkdirSync(path.dirname(file), { recursive: true });
72
+ writeFileSync(file, `${JSON.stringify(value, null, JSON_INDENT)}\n`);
73
+ };
74
+ const parsedJson = (file) => {
75
+ try {
76
+ return JSON.parse(readFileSync(file, 'utf8'));
77
+ }
78
+ catch {
79
+ return undefined;
80
+ }
81
+ };
82
+ /**
83
+ * Read a JSON file another pass wrote, as the shape that pass writes.
84
+ * @param file the file to read.
85
+ * @param isShape whether a parsed value has the shape.
86
+ * @returns the parsed value, or undefined when it is absent, unreadable or of another shape.
87
+ */
88
+ export const readJson = (file, isShape) => {
89
+ const value = parsedJson(file);
90
+ return isShape(value) ? value : undefined;
91
+ };
92
+ const hasArrays = (value, keys) => keys.every((key) => isArray(value[key]));
93
+ const hasNumbers = (value, keys) => keys.every((key) => typeof value[key] === 'number');
94
+ /**
95
+ * Whether a parsed value is what discovery writes for the later passes.
96
+ * @param value the parsed value.
97
+ * @returns whether it carries every list a discovery has.
98
+ */
99
+ export const isDiscovery = (value) => isRecord(value) && hasArrays(value, ['routes', 'stories', 'locations', 'samples']);
100
+ /**
101
+ * Whether a parsed value is what discovery writes for the summary.
102
+ * @param value the parsed value.
103
+ * @returns whether it carries every field a discovery report has.
104
+ */
105
+ export const isDiscoveryReport = (value) => isRecord(value) &&
106
+ hasArrays(value, ['findings', 'problems', 'locations']) &&
107
+ hasNumbers(value, ['places', 'elapsedMs']) &&
108
+ isRecord(value['scope']) &&
109
+ typeof value['scope']['isScoped'] === 'boolean' &&
110
+ hasArrays(value['scope'], ['lines']);
111
+ /**
112
+ * Whether a parsed value is what a shard of a pass writes for the summary.
113
+ * @param value the parsed value.
114
+ * @returns whether it carries every field a pass report has.
115
+ */
116
+ export const isPassReport = (value) => isRecord(value) &&
117
+ typeof value['pass'] === 'string' &&
118
+ typeof value['engine'] === 'string' &&
119
+ isRecord(value['shard']) &&
120
+ hasArrays(value, ['findings', 'used', 'declared', 'judgedRules', 'locations', 'notes']) &&
121
+ hasNumbers(value, ['places', 'elapsedMs']);
122
+ /**
123
+ * The file discovery writes for every later pass, in every engine.
124
+ * @param info the running test.
125
+ * @returns the file.
126
+ */
127
+ export const discoveryFile = (info) => path.join(sweepRoot(info), 'discovered.json');
128
+ /**
129
+ * The file discovery writes its findings and problems to, for the summary.
130
+ * @param info the running test.
131
+ * @returns the file.
132
+ */
133
+ export const discoveryReportFile = (info) => path.join(sweepRoot(info), 'discovery.json');
134
+ /**
135
+ * How a report file names one shard of a pass.
136
+ * @param pass the pass.
137
+ * @param shard the shard.
138
+ * @returns the file's name.
139
+ */
140
+ export const reportName = (pass, shard) => `${pass}-${String(shard.index + 1)}-of-${String(shard.count)}.json`;
141
+ /**
142
+ * The file one shard of a pass writes its report to.
143
+ * @param info the running test.
144
+ * @param engine the engine it ran in.
145
+ * @param pass the pass.
146
+ * @param shard the shard.
147
+ * @returns the file.
148
+ */
149
+ export const reportFile = (info, engine, pass, shard) => path.join(engineDirectory(info, engine), reportName(pass, shard));
150
+ /**
151
+ * What discovery recorded, failing the test when it recorded nothing.
152
+ * @param info the running test.
153
+ * @returns the discovery.
154
+ */
155
+ export const readDiscovery = (info) => {
156
+ const discovery = readJson(discoveryFile(info), isDiscovery);
157
+ expect(discovery, 'discovery did not record what to scan; its own test names the reason').toBeDefined();
158
+ return discovery ?? { routes: [], stories: [], locations: [], samples: [] };
159
+ };
160
+ // ---------------------------------------------------------------------------------------------------
161
+ // Pages
162
+ const ORIGINS = allowedOrigins([
163
+ projectSettings.serverUrl,
164
+ ...projectSettings.auxiliaryServers.map((server) => server.url),
165
+ ]);
166
+ export const origin = new URL(projectSettings.serverUrl).origin;
167
+ // Only `Date` is fixed. Playwright's clock fakes `performance.now()` too and keeps counting it across
168
+ // navigations, while each new document's animation timeline starts again at zero, so a library that
169
+ // starts its Web Animations at `performance.now()` would schedule them further ahead on every page the
170
+ // sweep loads. Timers, frames and animations therefore stay on the browser's own clock.
171
+ const fixDateInPage = (instant) => {
172
+ const RealDate = Date;
173
+ const FixedDate = new Proxy(RealDate, {
174
+ construct: (target, values, newTarget) => {
175
+ const made = Reflect.construct(target, values.length === 0 ? [instant] : values, newTarget);
176
+ return typeof made === 'object' && made !== null ? made : new RealDate(instant);
177
+ },
178
+ apply: () => new RealDate(instant).toString(),
179
+ get: (target, key) => {
180
+ const value = Reflect.get(target, key);
181
+ return key === 'now' ? () => instant : value;
182
+ },
183
+ });
184
+ Reflect.set(globalThis, 'Date', FixedDate);
185
+ };
186
+ /** Block every request outside the application and its auxiliary servers, and fix the browser's `Date`. */
187
+ export const preparePage = async (page) => {
188
+ await page.route((url) => !isAllowedRequest(url.href, ORIGINS), async (route) => {
189
+ await route.abort('blockedbyclient');
190
+ });
191
+ if (projectSettings.clock !== REAL_CLOCK) {
192
+ await page.addInitScript(fixDateInPage, Date.parse(projectSettings.clock));
193
+ }
194
+ };
195
+ // Storybook defines `__STORYBOOK_PREVIEW__` on the preview window only once its preview has started,
196
+ // so it is read as a property of the global rather than declared as a name that may not exist yet.
197
+ const isStoryInPhaseInPage = (phases) => {
198
+ const preview = Reflect.get(globalThis, '__STORYBOOK_PREVIEW__');
199
+ const render = typeof preview === 'object' && preview !== null ? Reflect.get(preview, 'currentRender') : undefined;
200
+ const phase = typeof render === 'object' && render !== null ? Reflect.get(render, 'phase') : undefined;
201
+ return phases.includes(typeof phase === 'string' ? phase : '');
202
+ };
203
+ const hasStoryFailedInPage = () => document.querySelector('body.sb-show-errordisplay') !== null;
204
+ /**
205
+ * Load a location fresh at a viewport, still, with a story rendered and played.
206
+ * @param page the test's page.
207
+ * @param location the location.
208
+ * @param viewport the viewport.
209
+ * @param place where findings about the load are made.
210
+ * @returns findings about the load itself.
211
+ */
212
+ export const loadLocation = async (page, location, viewport, place) => {
213
+ await page.setViewportSize(viewport);
214
+ await page.goto(location.url);
215
+ await page.addStyleTag({ content: STILL_STYLE });
216
+ if (!location.isStory) {
217
+ return [];
218
+ }
219
+ try {
220
+ await page.waitForFunction(isStoryInPhaseInPage, SETTLED_STORY_PHASES, { timeout: STORY_RENDER_MS });
221
+ }
222
+ catch {
223
+ return [findingAt({ ...place, viewport: undefined }, PAGE_ERROR_RULE, 'the story did not finish rendering')];
224
+ }
225
+ return (await page.evaluate(hasStoryFailedInPage))
226
+ ? [findingAt({ ...place, viewport: undefined }, PAGE_ERROR_RULE, 'the story rendered its error display')]
227
+ : [];
228
+ };
229
+ /**
230
+ * Where a finding at a location was made.
231
+ * @param page the test's page.
232
+ * @param location the location.
233
+ * @param viewport the viewport, or undefined for a finding about the whole location.
234
+ * @param state the state the location was in.
235
+ * @returns the place.
236
+ */
237
+ export const placeAt = (page, location, viewport, state) => ({
238
+ location: location.location,
239
+ state,
240
+ engine: engineOf(page),
241
+ viewport,
242
+ });
243
+ /**
244
+ * The page errors and failed requests of a location since its last navigation.
245
+ * @param page the test's page.
246
+ * @param place where the page is.
247
+ * @returns the visit carrying them.
248
+ */
249
+ export const healthOf = async (page, place) => {
250
+ const reading = await healthFindings(page, { ...place, viewport: undefined }, ORIGINS);
251
+ return {
252
+ ...EMPTY_VISIT,
253
+ findings: reading.findings,
254
+ notes: reading.isRequestLogFull
255
+ ? [`${place.location}: the request log was full, so earlier requests went unread`]
256
+ : [],
257
+ };
258
+ };
259
+ /**
260
+ * Several visits as one.
261
+ * @param visits the visits.
262
+ * @returns their findings, exemptions and notes together.
263
+ */
264
+ export const merged = (visits) => ({
265
+ findings: visits.flatMap((visit) => visit.findings),
266
+ used: visits.flatMap((visit) => visit.used),
267
+ declared: visits.flatMap((visit) => visit.declared),
268
+ notes: visits.flatMap((visit) => visit.notes),
269
+ });
270
+ /**
271
+ * Attach a screenshot of a failing place with its failing elements outlined, up to a cap per pass.
272
+ * @param page the test's page.
273
+ * @param scan what was found there.
274
+ * @param place where it was found.
275
+ * @param number how many places the pass visited before this one.
276
+ */
277
+ export const screenshotOf = async (page, scan, place, number) => {
278
+ const elements = failingPlaces(scan.findings).flatMap((failing) => failing.elements);
279
+ if (scan.findings.length === 0 || number >= MAX_SCREENSHOTS) {
280
+ return;
281
+ }
282
+ await outlineElements(page, elements);
283
+ await test.info().attach(`${place.state} ${place.location} ${String(place.viewport?.width ?? '')}`, {
284
+ body: await page.screenshot({ fullPage: true }),
285
+ contentType: 'image/png',
286
+ });
287
+ };
288
+ // ---------------------------------------------------------------------------------------------------
289
+ // Budgets
290
+ const MS_PER_SECOND = 1000;
291
+ /** The whole of a pass that is not split, which is discovery. */
292
+ export const WHOLE_PASS = { index: 0, count: 1 };
293
+ /**
294
+ * Start a shard's budget and set its test's timeout beyond it.
295
+ * @param page the test's page, whose engine names the progress log.
296
+ * @param pass the pass.
297
+ * @param shard the shard.
298
+ * @param units how many units of work the whole pass has.
299
+ * @returns the budget.
300
+ */
301
+ export const armBudget = (page, pass, shard, units) => {
302
+ const budgetMs = partBudgetMs(pass, units, shard);
303
+ test.info().setTimeout(budgetMs + TIMEOUT_GRACE_MS);
304
+ const directory = engineDirectory(test.info(), engineOf(page));
305
+ const queue = path.join(directory, 'queue', pass);
306
+ mkdirSync(queue, { recursive: true });
307
+ const startedAt = performance.now();
308
+ return {
309
+ pass,
310
+ shard,
311
+ progressFile: path.join(directory, 'progress.log'),
312
+ queue,
313
+ startedAt,
314
+ deadline: startedAt + budgetMs,
315
+ };
316
+ };
317
+ /**
318
+ * How many units of work a pass's items carry, for its budget.
319
+ * @param items the pass's items.
320
+ * @param unitsOf the units one item carries.
321
+ * @returns their sum.
322
+ */
323
+ export const passUnits = (items, unitsOf) => items.reduce((total, item) => total + unitsOf(item), 0);
324
+ // A pass of thousands of loads otherwise says nothing until it ends, and the e2e gate shows its output
325
+ // only then too. One line per item, written as it finishes, lets anyone see how far a pass has got and
326
+ // how fast it goes. Seconds since the shard started, because the runner's own clock is the shifted one.
327
+ // The shards of every pass in one engine append to one log, a line at a time.
328
+ const recordProgress = (budget, item) => {
329
+ const seconds = ((performance.now() - budget.startedAt) / MS_PER_SECOND).toFixed(1);
330
+ const part = `${String(budget.shard.index + 1)}/${String(budget.shard.count)}`;
331
+ appendFileSync(budget.progressFile, `${budget.pass} part ${part} ${seconds}s ${item}\n`);
332
+ };
333
+ const NOTHING_VISITED = { visits: [], taken: [] };
334
+ const budgetFinding = (items, visitor, item) => {
335
+ const { budget, labelOf } = visitor;
336
+ return {
337
+ ...EMPTY_VISIT,
338
+ findings: [
339
+ findingAt({ location: labelOf(item), state: budget.pass, engine: '', viewport: undefined }, PASS_BUDGET_RULE, `part ${String(budget.shard.index + 1)} of the ${budget.pass} pass ran out of its budget at this item, ` +
340
+ `with ${String(untakenCount(budget.queue, items.length))} of the pass's ${String(items.length)} items ` +
341
+ 'not yet taken by any part'),
342
+ ],
343
+ };
344
+ };
345
+ /**
346
+ * Take items of a pass from the queue its shards share and visit each, until none is left or the shard
347
+ * runs out of budget, which it reports at the first item it left untaken.
348
+ * @param items every item of the pass, in order.
349
+ * @param visitor the budget, and how to name and visit an item.
350
+ * @param from the index to look for the next untaken item at.
351
+ * @returns the visits, a budget finding among them when the shard stopped early, and the items it took.
352
+ */
353
+ export const visitAll = async (items, visitor, from = 0) => {
354
+ const { budget, labelOf, visit } = visitor;
355
+ if (performance.now() > budget.deadline) {
356
+ const left = items[firstUntaken(budget.queue, items.length, from) ?? items.length];
357
+ return left === undefined ? NOTHING_VISITED : { visits: [budgetFinding(items, visitor, left)], taken: [] };
358
+ }
359
+ const index = takeNext(budget.queue, items.length, from) ?? items.length;
360
+ const item = items[index];
361
+ if (item === undefined) {
362
+ return NOTHING_VISITED;
363
+ }
364
+ const visited = await visit(item, index);
365
+ recordProgress(budget, `${String(index + 1)}/${String(items.length)} ${labelOf(item)}`);
366
+ const rest = await visitAll(items, visitor, index + 1);
367
+ return { visits: [visited, ...rest.visits], taken: [{ item, index }, ...rest.taken] };
368
+ };
369
+ /**
370
+ * Write a shard's report for the summary, and fail the shard's test on any finding.
371
+ * @param page the test's page.
372
+ * @param finished the pass, its visits, the rules it judged and the locations it covered.
373
+ */
374
+ export const finishPass = (page, finished) => {
375
+ const { budget, pass, visits, judgedRules, locations } = finished;
376
+ const all = merged(visits);
377
+ const findings = distinctFindings(all.findings);
378
+ const engine = engineOf(page);
379
+ const report = {
380
+ pass,
381
+ engine,
382
+ shard: budget.shard,
383
+ findings,
384
+ used: all.used,
385
+ declared: all.declared,
386
+ judgedRules,
387
+ places: visits.length,
388
+ locations,
389
+ notes: [...new Set(all.notes)],
390
+ elapsedMs: Math.round(performance.now() - budget.startedAt),
391
+ };
392
+ writeJson(reportFile(test.info(), engine, pass, budget.shard), report);
393
+ expect(findings.map((finding) => findingLine(finding)), `${pass} pass findings`).toEqual([]);
394
+ };
395
+ /**
396
+ * Whether the test runs in Chromium.
397
+ * @param page the test's page.
398
+ * @returns true in Chromium.
399
+ */
400
+ export const isChromium = (page) => engineOf(page) === 'chromium';
401
+ /**
402
+ * How a budget finding names a location at a viewport.
403
+ * @param item the location and viewport.
404
+ * @returns its label.
405
+ */
406
+ export const itemLabel = (item) => `${item.location.location} @${String(item.viewport.width)}x${String(item.viewport.height)}`;
407
+ /**
408
+ * The locations a shard's items cover, each once.
409
+ * @param items the shard's items.
410
+ * @param locationOf the location an item visits.
411
+ * @returns the locations' names.
412
+ */
413
+ export const shardLocations = (items, locationOf) => [
414
+ ...new Set(items.map((shardItem) => locationOf(shardItem.item).location)),
415
+ ];
416
+ /**
417
+ * The location of a place item.
418
+ * @param item the location and viewport.
419
+ * @returns the location.
420
+ */
421
+ export const locationOfItem = (item) => item.location;
422
+ /** The rules a resting scan judges. */
423
+ export const RESTING_JUDGED = [...LAYOUT_RULES, ...RESTING_ELEMENT_RULES, FONT_LOAD_RULE];
424
+ /**
425
+ * One route per template and every story, for the passes that sample instead of covering all.
426
+ * @param discovery what discovery recorded.
427
+ * @returns the sampled locations.
428
+ */
429
+ export const sampledLocations = (discovery) => {
430
+ const sampled = new Set(discovery.samples.map((sample) => sample.route));
431
+ const stories = new Set(storySamples(discovery.stories).map((story) => storyLocation(story)));
432
+ return discovery.locations.filter((location) => (location.isStory ? stories : sampled).has(location.location));
433
+ };
434
+ //# sourceMappingURL=sweep-shared.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sweep-shared.js","sourceRoot":"","sources":["../src/sweep-shared.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ export { SWEEP_SHARDS } from '@ploaness/governance';
2
+ export { expectDisclosureStates } from './sweep-disclosures.js';
3
+ export { expectDiscoveredSite } from './sweep-discovery.js';
4
+ export { expectInteractionStates } from './sweep-interaction.js';
5
+ export { expectTextStress, expectWidthSweep } from './sweep-reflow.js';
6
+ export { expectDarkScheme, expectEngineRules, expectRestingRules } from './sweep-resting.js';
7
+ export type { Shard } from './sweep-shared.js';
8
+ /**
9
+ * Judge discovery's problems and findings and the exemptions no part of a pass used, write the report
10
+ * and the coverage summary, and fail when a part of a pass did not finish. It runs as the sweep's
11
+ * teardown, after every part of every engine, whatever their outcome.
12
+ */
13
+ export declare const expectSweepSummary: () => Promise<void>;
14
+ //# sourceMappingURL=sweep.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sweep.d.ts","sourceRoot":"","sources":["../src/sweep.ts"],"names":[],"mappings":"AAgDA,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AACnD,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAA;AAC/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAA;AAC3D,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAA;AAChE,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACtE,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AAC5F,YAAY,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAkK9C;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,QAAa,OAAO,CAAC,IAAI,CA8CvD,CAAA"}
package/dist/sweep.js ADDED
@@ -0,0 +1,157 @@
1
+ // The passes of the managed browser sweep. The pinned spec calls one of these per test, so each part of
2
+ // a pass has its own budget and one failing part hides nothing another would have reported.
3
+ //
4
+ // Discovery runs once, in Chromium, as the setup project every pass depends on, and writes what it
5
+ // found - routes, stories, breakpoints, colour schemes, control counts - to the ignored output
6
+ // directory. Every pass is split into shards that run as separate tests on parallel workers; each
7
+ // reads that file instead of crawling again, and writes its own findings and coverage under its
8
+ // engine's directory. The summary is the teardown: it runs after every part of every engine has
9
+ // finished, whatever their outcome, judges discovery's problems and the exemptions no part used, and
10
+ // prints the coverage. A part that did not finish is reported there too, so reduced coverage never
11
+ // reads as a full pass.
12
+ //
13
+ // Nothing here decides what a defect is. Each verdict is a `@ploaness/governance` function over what the
14
+ // browser measured; the `sweep-*` modules drive the browser into each state and hand over the
15
+ // measurements. This module is the entry point: it holds the summary and re-exports every pass.
16
+ import { readdirSync, writeFileSync } from 'node:fs';
17
+ import path from 'node:path';
18
+ import { expect, test } from '@playwright/test';
19
+ import { BROWSER_ENGINES, coversEveryEngine, distinctFindings, findingLine, SWEEP_SHARDS, staleExemptions, } from '@ploaness/governance';
20
+ import { discoveryFile, discoveryReportFile, isDiscovery, isDiscoveryReport, isPassReport, readJson, reportFile, reportName, sweepRoot, writeJson, } from './sweep-shared.js';
21
+ export { SWEEP_SHARDS } from '@ploaness/governance';
22
+ export { expectDisclosureStates } from './sweep-disclosures.js';
23
+ export { expectDiscoveredSite } from './sweep-discovery.js';
24
+ export { expectInteractionStates } from './sweep-interaction.js';
25
+ export { expectTextStress, expectWidthSweep } from './sweep-reflow.js';
26
+ export { expectDarkScheme, expectEngineRules, expectRestingRules } from './sweep-resting.js';
27
+ const CHROMIUM = 'chromium';
28
+ const CHROMIUM_PASSES = [
29
+ 'resting',
30
+ 'interaction',
31
+ 'disclosures',
32
+ 'text-stress',
33
+ 'width-sweep',
34
+ 'dark-scheme',
35
+ ];
36
+ const ENGINE_PASSES = ['engine'];
37
+ const SHARDS = Array.from({ length: SWEEP_SHARDS }, (_unused, index) => ({
38
+ index,
39
+ count: SWEEP_SHARDS,
40
+ }));
41
+ const presentEngines = (info) => {
42
+ try {
43
+ return readdirSync(sweepRoot(info), { withFileTypes: true }).flatMap((entry) => entry.isDirectory() && BROWSER_ENGINES.includes(entry.name) ? [entry.name] : []);
44
+ }
45
+ catch {
46
+ return [];
47
+ }
48
+ };
49
+ // Chromium always runs; the other engines run when the pinned browsers do outside a `delta` run's
50
+ // change scope, and whatever ran in them is judged even when the endpoint is no longer named.
51
+ const expectedEngines = (info) => {
52
+ const isEveryEngine = coversEveryEngine(process.env);
53
+ const present = new Set(presentEngines(info));
54
+ return BROWSER_ENGINES.filter((engine) => engine === CHROMIUM || isEveryEngine || present.has(engine));
55
+ };
56
+ const expectedReports = (engines) => engines.flatMap((engine) => (engine === CHROMIUM ? CHROMIUM_PASSES : ENGINE_PASSES).flatMap((pass) => SHARDS.map((shard) => ({ engine, pass, shard }))));
57
+ const missingLine = (expected) => `${expected.engine} ${expected.pass} part ${String(expected.shard.index + 1)} of ${String(expected.shard.count)}: ` +
58
+ `did not record ${reportName(expected.pass, expected.shard)}`;
59
+ const MS_PER_SECOND = 1000;
60
+ const NOTHING_DISCOVERED = { routes: [], stories: [], locations: [], samples: [] };
61
+ const NO_DISCOVERY_REPORT = {
62
+ findings: [],
63
+ problems: [],
64
+ places: 0,
65
+ locations: [],
66
+ elapsedMs: 0,
67
+ scope: { isScoped: false, lines: [] },
68
+ };
69
+ const discoveryText = (discovery, report) => `discovery (${CHROMIUM}): ${String(discovery.routes.length)} routes, ${String(discovery.stories.length)} stories, ` +
70
+ `${String(discovery.samples.length)} templates, ${String(report.findings.length)} findings, ` +
71
+ `${String(Math.round(report.elapsedMs / MS_PER_SECOND))}s`;
72
+ // One line per pass in each engine: the places and findings of its parts summed, the locations they
73
+ // covered, and the slowest part, which is how long the pass held the run. A pass a change scope narrowed
74
+ // says so, because its coverage is not complete.
75
+ const passLine = (engine, pass, reports, isScoped) => {
76
+ const parts = reports.filter((report) => report.engine === engine && report.pass === pass);
77
+ const places = parts.reduce((total, report) => total + report.places, 0);
78
+ const findings = parts.reduce((total, report) => total + report.findings.length, 0);
79
+ const locations = new Set(parts.flatMap((report) => report.locations))
80
+ .size;
81
+ const slowestMs = Math.max(0, ...parts.map((report) => report.elapsedMs));
82
+ return (`${pass} (${engine}${isScoped ? ', scoped to the change' : ''}): ${String(places)} places over ` +
83
+ `${String(locations)} locations, ${String(findings)} ` +
84
+ `findings, ${String(parts.length)} of ${String(SWEEP_SHARDS)} parts, slowest part ` +
85
+ `${String(Math.round(slowestMs / MS_PER_SECOND))}s`);
86
+ };
87
+ const coverageText = (record) => [
88
+ ...(record.discoveryReport ?? NO_DISCOVERY_REPORT).scope.lines.map((line) => `scope: ${line}`),
89
+ discoveryText(record.discovery ?? NOTHING_DISCOVERED, record.discoveryReport ?? NO_DISCOVERY_REPORT),
90
+ ...(record.discovery?.samples ?? []).map((sample) => ` template ${sample.template}: sampled by ${sample.route} (${String(sample.routes)} routes)`),
91
+ ...record.engines.flatMap((engine) => (engine === CHROMIUM ? CHROMIUM_PASSES : ENGINE_PASSES).map((pass) => passLine(engine, pass, record.reports, record.discoveryReport?.scope.isScoped ?? false))),
92
+ ...[...new Set(record.reports.flatMap((report) => report.notes))].map((note) => ` note: ${note}`),
93
+ ...record.missing,
94
+ ].join('\n');
95
+ // An exemption is stale in an engine when no part of any pass in that engine used it.
96
+ const staleIn = (engine, reports) => {
97
+ const own = reports.filter((report) => report.engine === engine);
98
+ return own.length === 0
99
+ ? []
100
+ : staleExemptions(own.flatMap((report) => report.declared), own.flatMap((report) => report.used), [...new Set(own.flatMap((report) => report.judgedRules))], engine);
101
+ };
102
+ const readRecord = (info) => {
103
+ const engines = expectedEngines(info);
104
+ const expected = expectedReports(engines);
105
+ const read = expected.map((part) => readJson(reportFile(info, part.engine, part.pass, part.shard), isPassReport));
106
+ return {
107
+ discovery: readJson(discoveryFile(info), isDiscovery),
108
+ discoveryReport: readJson(discoveryReportFile(info), isDiscoveryReport),
109
+ engines,
110
+ reports: read.flatMap((report) => report === undefined ? [] : [report]),
111
+ missing: expected.flatMap((part, index) => read[index] === undefined ? [missingLine(part)] : []),
112
+ };
113
+ };
114
+ /**
115
+ * Judge discovery's problems and findings and the exemptions no part of a pass used, write the report
116
+ * and the coverage summary, and fail when a part of a pass did not finish. It runs as the sweep's
117
+ * teardown, after every part of every engine, whatever their outcome.
118
+ */
119
+ export const expectSweepSummary = async () => {
120
+ const info = test.info();
121
+ const record = readRecord(info);
122
+ const problems = record.discovery === undefined || record.discoveryReport === undefined
123
+ ? ['discovery did not record what to scan; its own test names the reason']
124
+ : record.discoveryReport.problems;
125
+ const discoveryFindings = distinctFindings(record.discoveryReport?.findings ?? []);
126
+ const stale = record.engines.flatMap((engine) => staleIn(engine, record.reports));
127
+ const coverage = coverageText(record);
128
+ writeJson(path.join(sweepRoot(info), 'report.json'), {
129
+ findings: distinctFindings([
130
+ ...discoveryFindings,
131
+ ...record.reports.flatMap((report) => report.findings),
132
+ ...stale,
133
+ ]),
134
+ problems,
135
+ scope: record.discoveryReport?.scope,
136
+ passes: record.reports.map((report) => ({
137
+ pass: report.pass,
138
+ engine: report.engine,
139
+ shard: report.shard,
140
+ places: report.places,
141
+ locations: report.locations,
142
+ notes: report.notes,
143
+ elapsedMs: report.elapsedMs,
144
+ })),
145
+ missing: record.missing,
146
+ });
147
+ writeFileSync(path.join(sweepRoot(info), 'coverage.txt'), `${coverage}\n`);
148
+ await info.attach('coverage', { body: coverage, contentType: 'text/plain' });
149
+ process.stdout.write(`\nploaness sweep coverage:\n${coverage}\n`);
150
+ expect.soft(problems, 'discovery is incomplete').toEqual([]);
151
+ expect
152
+ .soft(discoveryFindings.map((finding) => findingLine(finding)), 'discovery findings')
153
+ .toEqual([]);
154
+ expect.soft(record.missing, 'sweep parts that did not finish; their own tests name the reason').toEqual([]);
155
+ expect(stale.map((finding) => findingLine(finding)), 'exemptions no pass used').toEqual([]);
156
+ };
157
+ //# sourceMappingURL=sweep.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sweep.js","sourceRoot":"","sources":["../src/sweep.ts"],"names":[],"mappings":"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"}