@ploaness/config 1.11.0 → 1.13.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 (78) 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-immutability.d.ts.map +1 -1
  10. package/dist/eslint-immutability.js +37 -4
  11. package/dist/eslint-immutability.js.map +1 -1
  12. package/dist/eslint-library.d.ts.map +1 -1
  13. package/dist/eslint-library.js +6 -1
  14. package/dist/eslint-library.js.map +1 -1
  15. package/dist/eslint-runtime.d.ts +11 -0
  16. package/dist/eslint-runtime.d.ts.map +1 -0
  17. package/dist/eslint-runtime.js +68 -0
  18. package/dist/eslint-runtime.js.map +1 -0
  19. package/dist/eslint.d.ts.map +1 -1
  20. package/dist/eslint.js +6 -1
  21. package/dist/eslint.js.map +1 -1
  22. package/dist/layout.d.ts +34 -16
  23. package/dist/layout.d.ts.map +1 -1
  24. package/dist/layout.js +228 -56
  25. package/dist/layout.js.map +1 -1
  26. package/dist/payload-view.d.ts +16 -0
  27. package/dist/payload-view.d.ts.map +1 -0
  28. package/dist/payload-view.js +35 -0
  29. package/dist/payload-view.js.map +1 -0
  30. package/dist/playwright.d.ts.map +1 -1
  31. package/dist/playwright.js +115 -12
  32. package/dist/playwright.js.map +1 -1
  33. package/dist/scanner.d.ts +99 -0
  34. package/dist/scanner.d.ts.map +1 -0
  35. package/dist/scanner.js +278 -0
  36. package/dist/scanner.js.map +1 -0
  37. package/dist/settle.d.ts +8 -6
  38. package/dist/settle.d.ts.map +1 -1
  39. package/dist/settle.js +55 -42
  40. package/dist/settle.js.map +1 -1
  41. package/dist/sweep-disclosures.d.ts +10 -0
  42. package/dist/sweep-disclosures.d.ts.map +1 -0
  43. package/dist/sweep-disclosures.js +179 -0
  44. package/dist/sweep-disclosures.js.map +1 -0
  45. package/dist/sweep-discovery.d.ts +15 -0
  46. package/dist/sweep-discovery.d.ts.map +1 -0
  47. package/dist/sweep-discovery.js +336 -0
  48. package/dist/sweep-discovery.js.map +1 -0
  49. package/dist/sweep-interaction.d.ts +19 -0
  50. package/dist/sweep-interaction.d.ts.map +1 -0
  51. package/dist/sweep-interaction.js +351 -0
  52. package/dist/sweep-interaction.js.map +1 -0
  53. package/dist/sweep-queue.d.ts +24 -0
  54. package/dist/sweep-queue.d.ts.map +1 -0
  55. package/dist/sweep-queue.js +56 -0
  56. package/dist/sweep-queue.js.map +1 -0
  57. package/dist/sweep-reflow.d.ts +17 -0
  58. package/dist/sweep-reflow.d.ts.map +1 -0
  59. package/dist/sweep-reflow.js +210 -0
  60. package/dist/sweep-reflow.js.map +1 -0
  61. package/dist/sweep-resting.d.ts +25 -0
  62. package/dist/sweep-resting.d.ts.map +1 -0
  63. package/dist/sweep-resting.js +98 -0
  64. package/dist/sweep-resting.js.map +1 -0
  65. package/dist/sweep-shared.d.ts +353 -0
  66. package/dist/sweep-shared.d.ts.map +1 -0
  67. package/dist/sweep-shared.js +434 -0
  68. package/dist/sweep-shared.js.map +1 -0
  69. package/dist/sweep.d.ts +14 -0
  70. package/dist/sweep.d.ts.map +1 -0
  71. package/dist/sweep.js +157 -0
  72. package/dist/sweep.js.map +1 -0
  73. package/dist/vitest-core.d.ts +1 -1
  74. package/dist/vitest-core.js +1 -1
  75. package/dist/vitest-library.d.ts.map +1 -1
  76. package/dist/vitest-library.js +2 -1
  77. package/dist/vitest-library.js.map +1 -1
  78. package/package.json +10 -2
@@ -0,0 +1,351 @@
1
+ // The sweep's interaction pass: hover and keyboard focus on every control.
2
+ import { test } from '@playwright/test';
3
+ import { classifyHitTarget, drivenViewports, FOCUS_CONTRAST_RATIO, FOCUS_RING_WIDTH, findingAt, hasContrastingFocus, hasVisibleFocus, isFocusBackwards, judgeCarried, obscuringContent, STRESS_VIEWPORTS, } from '@ploaness/governance';
4
+ import { targetFacts } from './layout.js';
5
+ import { axeFindings, settleFindings } from './scanner.js';
6
+ import { settleForScan } from './settle.js';
7
+ import { armBudget, CHROME, CONTROLS, DESKTOP, EMPTY_VISIT, finishPass, healthOf, isChromium, itemLabel, loadLocation, locationOfItem, merged, PROBE_ATTRIBUTE, passUnits, placeAt, preparePage, readDiscovery, STILL_STYLE, shardLocations, visitAll, } from './sweep-shared.js';
8
+ const PROBE_SELECTOR = `[${PROBE_ATTRIBUTE}]`;
9
+ // What the browser has to say before a control can be classified. Scrolled and hit-tested in one
10
+ // evaluate, so reading the box and hit-testing it cannot straddle a scroll.
11
+ const probeHitTarget = async (control) => await control.evaluate((element) => {
12
+ const halves = 2;
13
+ element.scrollIntoView({ block: 'center', inline: 'center' });
14
+ const box = element.getBoundingClientRect();
15
+ const style = getComputedStyle(element);
16
+ const atCentre = element.ownerDocument.elementFromPoint(box.left + box.width / halves, box.top + box.height / halves);
17
+ return {
18
+ width: box.width,
19
+ height: box.height,
20
+ clipPath: style.clipPath,
21
+ clip: style.getPropertyValue('clip'),
22
+ ownsCentrePoint: atCentre !== null && element.contains(atCentre),
23
+ pointerEvents: style.getPropertyValue('pointer-events'),
24
+ visibility: style.getPropertyValue('visibility'),
25
+ isInert: element.closest('[inert]') !== null,
26
+ };
27
+ });
28
+ const markProbe = async (control, isMarked) => {
29
+ await control.evaluate((element, [name, marked]) => {
30
+ if (marked) {
31
+ element.setAttribute(name, '');
32
+ }
33
+ else {
34
+ element.removeAttribute(name);
35
+ }
36
+ }, [PROBE_ATTRIBUTE, isMarked]);
37
+ };
38
+ /**
39
+ * A finding on a driven element, judged against the exemptions above it.
40
+ * @param finding the finding.
41
+ * @param facts the element and the exemptions above it.
42
+ * @returns the visit carrying the finding, or the exemption that excused it.
43
+ */
44
+ export const carried = (finding, facts) => {
45
+ const judged = judgeCarried(finding, facts?.exemptions ?? []);
46
+ return {
47
+ findings: judged.finding === undefined ? [] : [judged.finding],
48
+ used: judged.used,
49
+ declared: judged.declared,
50
+ notes: [],
51
+ };
52
+ };
53
+ const hoverControl = async (page, control, place) => {
54
+ const reach = classifyHitTarget(await probeHitTarget(control));
55
+ await markProbe(control, true);
56
+ const facts = await targetFacts(page, PROBE_SELECTOR);
57
+ if (reach.verdict === 'obscured') {
58
+ await markProbe(control, false);
59
+ return carried(findingAt(place, 'obscured', `${facts?.label ?? 'a control'} cannot be reached by a pointer: ${reach.reason}`), facts);
60
+ }
61
+ if (reach.verdict !== 'hoverable') {
62
+ await markProbe(control, false);
63
+ return EMPTY_VISIT;
64
+ }
65
+ await control.hover();
66
+ await settleForScan(page);
67
+ const contrast = await axeFindings(page, { ...place, state: 'hover' }, (builder) => builder.include(PROBE_SELECTOR).withRules(['color-contrast']));
68
+ await markProbe(control, false);
69
+ return { ...EMPTY_VISIT, findings: contrast };
70
+ };
71
+ // The page's own controls. Locators pierce shadow roots, which reach a framework's development overlay
72
+ // as well as a component's internals; a control the document cannot name is one no finding could
73
+ // point a reader to, so the sweep drives the document's own controls. A control the browser does not render -
74
+ // inside a closed `<details>`, or under `display: none` - cannot be operated, and Chromium still reports
75
+ // a box for some of them; a visually hidden skip link is rendered and is still driven.
76
+ const controlsToDrive = async (page, shouldIncludeChrome) => {
77
+ const all = await page.locator(CONTROLS).all();
78
+ const kept = await Promise.all(all.map(async (control) => await control.evaluate((element, [chrome, keep]) => element.getRootNode() === element.ownerDocument &&
79
+ element.checkVisibility() &&
80
+ (keep || element.closest(chrome) === null), [CHROME, shouldIncludeChrome])));
81
+ return all.filter((_control, index) => kept[index] === true);
82
+ };
83
+ // Where the focused element is, and whether fixed or sticky content covers it at five points.
84
+ const focusStateInPage = (ring) => {
85
+ const active = document.activeElement;
86
+ if (active === null || active === document.body) {
87
+ return { samples: [], clip: undefined, extent: 0 };
88
+ }
89
+ const box = active.getBoundingClientRect();
90
+ const width = document.documentElement.clientWidth;
91
+ const height = document.documentElement.clientHeight;
92
+ const left = Math.max(0, box.left);
93
+ const top = Math.max(0, box.top);
94
+ const right = Math.min(width, box.right);
95
+ const bottom = Math.min(height, box.bottom);
96
+ if (right - left < 1 || bottom - top < 1) {
97
+ return { samples: [], clip: undefined, extent: 0 };
98
+ }
99
+ const halves = 2;
100
+ const quarters = 4;
101
+ const maximumInset = 2;
102
+ const inset = Math.min(maximumInset, (right - left) / quarters, (bottom - top) / quarters);
103
+ const points = [
104
+ [(left + right) / halves, (top + bottom) / halves],
105
+ [left + inset, top + inset],
106
+ [right - inset, top + inset],
107
+ [left + inset, bottom - inset],
108
+ [right - inset, bottom - inset],
109
+ ];
110
+ const pinned = (element) => element === null || ['fixed', 'sticky'].includes(getComputedStyle(element).position)
111
+ ? element
112
+ : pinned(element.parentElement);
113
+ const describe = (element) => [element.tagName.toLowerCase(), ...(element.id.length > 0 ? [element.id] : [])].join('#');
114
+ const samples = points.map(([pointX, pointY]) => {
115
+ const hit = document.elementFromPoint(pointX, pointY);
116
+ const cover = hit === null || active.contains(hit) || hit.contains(active) ? null : pinned(hit);
117
+ return { isCovered: cover !== null && !cover.contains(active), coveredBy: cover === null ? '' : describe(cover) };
118
+ });
119
+ const clipLeft = Math.max(0, box.left - ring);
120
+ const clipTop = Math.max(0, box.top - ring);
121
+ return {
122
+ samples,
123
+ extent: Math.max(right - left, bottom - top),
124
+ clip: {
125
+ x: Math.floor(clipLeft),
126
+ y: Math.floor(clipTop),
127
+ width: Math.ceil(Math.min(width, box.right + ring) - clipLeft),
128
+ height: Math.ceil(Math.min(height, box.bottom + ring) - clipTop),
129
+ },
130
+ };
131
+ };
132
+ // The elements whose extent a focus position is compared within, and those whose order is their own.
133
+ const LANDMARKS = [
134
+ 'header',
135
+ 'nav',
136
+ 'main',
137
+ 'aside',
138
+ 'footer',
139
+ 'search',
140
+ '[role="banner"]',
141
+ '[role="navigation"]',
142
+ '[role="main"]',
143
+ '[role="complementary"]',
144
+ '[role="contentinfo"]',
145
+ '[role="region"]',
146
+ '[role="search"]',
147
+ 'section[aria-label]',
148
+ 'section[aria-labelledby]',
149
+ 'form[aria-label]',
150
+ 'form[aria-labelledby]',
151
+ ].join(', ');
152
+ const DIALOGS = 'dialog, [role="dialog"], [role="alertdialog"]';
153
+ // Where the focused element sits in the document, and the landmark it sits in, named by its path of
154
+ // child indices so two stops in one landmark name it alike.
155
+ const focusPositionInPage = ([landmarks, dialogs]) => {
156
+ const active = document.activeElement;
157
+ if (active === null || active === document.body) {
158
+ return undefined;
159
+ }
160
+ const box = active.getBoundingClientRect();
161
+ const isPinned = (element) => element !== null &&
162
+ (['fixed', 'sticky'].includes(getComputedStyle(element).position) || isPinned(element.parentElement));
163
+ const pathOf = (element) => {
164
+ const parent = element?.parentElement ?? null;
165
+ if (element === null || parent === null) {
166
+ return '';
167
+ }
168
+ const index = Array.from(parent.querySelectorAll(':scope > *')).indexOf(element);
169
+ return `${pathOf(parent)}/${String(index)}`;
170
+ };
171
+ return {
172
+ top: box.top + scrollY,
173
+ bottom: box.bottom + scrollY,
174
+ left: box.left + scrollX,
175
+ right: box.right + scrollX,
176
+ landmark: pathOf(active.closest(landmarks)),
177
+ isUnplaced: active.closest(dialogs) !== null || isPinned(active) || box.width <= 1 || box.height <= 1,
178
+ isRightToLeft: getComputedStyle(active).getPropertyValue('direction') === 'rtl',
179
+ };
180
+ };
181
+ // The browser decodes the screenshots it took: PNG is its own format, and Node has no decoder for it.
182
+ const decodeInPage = async (images) => await Promise.all(images.map(async (image) => {
183
+ const bytes = Uint8Array.from(atob(image), (character) => character.codePointAt(0) ?? 0);
184
+ const bitmap = await createImageBitmap(new Blob([bytes], { type: 'image/png' }));
185
+ const context = new OffscreenCanvas(bitmap.width, bitmap.height).getContext('2d');
186
+ if (context === null) {
187
+ return { width: 0, pixels: [] };
188
+ }
189
+ context.drawImage(bitmap, 0, 0);
190
+ return { width: bitmap.width, pixels: Array.from(context.getImageData(0, 0, bitmap.width, bitmap.height).data) };
191
+ }));
192
+ const BASE64 = 'base64';
193
+ // Judged only where a focus indicator shows at all; one that does not is the `focus-visible` finding.
194
+ const hasFocusContrast = async (page, shots, measure) => {
195
+ const [focused, unfocused] = await page.evaluate(decodeInPage, [
196
+ Buffer.from(shots.focused).toString(BASE64),
197
+ Buffer.from(shots.unfocused).toString(BASE64),
198
+ ]);
199
+ if (focused === undefined || unfocused === undefined || focused.width === 0) {
200
+ throw new Error('the browser could not decode the focus screenshots');
201
+ }
202
+ return hasContrastingFocus({
203
+ focused: focused.pixels,
204
+ unfocused: unfocused.pixels,
205
+ scale: focused.width / measure.clip.width,
206
+ extent: measure.extent,
207
+ });
208
+ };
209
+ const focusIndicator = async (page, place, facts, { shots, measure }) => {
210
+ if (!hasVisibleFocus(shots.unfocused, shots.focused)) {
211
+ return carried(findingAt(place, 'focus-visible', `${facts.label} shows no visible change when focused by keyboard`), facts);
212
+ }
213
+ if (await hasFocusContrast(page, shots, measure)) {
214
+ return EMPTY_VISIT;
215
+ }
216
+ return carried(findingAt(place, 'focus-contrast', `${facts.label} changes when focused by keyboard, but too little of the change contrasts ` +
217
+ `${String(FOCUS_CONTRAST_RATIO)}:1 with its unfocused rendering`), facts);
218
+ };
219
+ const blurInPage = () => {
220
+ document.activeElement?.blur?.();
221
+ };
222
+ const markFocusedInPage = (name) => {
223
+ document.activeElement?.setAttribute(name, '');
224
+ };
225
+ const unmarkInPage = ([selector, name]) => {
226
+ document.querySelector(selector)?.removeAttribute(name);
227
+ };
228
+ const focusOrder = (place, facts, previous, position) => previous === undefined || position === undefined || !isFocusBackwards(previous.position, position)
229
+ ? EMPTY_VISIT
230
+ : carried(findingAt(place, 'focus-order', `${facts.label} takes focus after ${previous.label}, but sits entirely above it in the same landmark`), facts);
231
+ const focusStop = async (page, place, previous) => {
232
+ const facts = await targetFacts(page, null);
233
+ if (facts === undefined) {
234
+ return { visit: EMPTY_VISIT, order: EMPTY_VISIT, key: undefined, previous: undefined };
235
+ }
236
+ const state = await page.evaluate(focusStateInPage, FOCUS_RING_WIDTH);
237
+ const focusPlace = { ...place, state: 'focus' };
238
+ const position = await page.evaluate(focusPositionInPage, [LANDMARKS, DIALOGS]);
239
+ const order = focusOrder(focusPlace, facts, previous, position);
240
+ const here = position === undefined ? undefined : { position, label: facts.label };
241
+ const covering = obscuringContent(state.samples);
242
+ const obscured = covering === undefined
243
+ ? EMPTY_VISIT
244
+ : carried(findingAt(focusPlace, 'focus-obscured', `${facts.label} is focused and entirely hidden by ${covering}`), facts);
245
+ await page.evaluate(markFocusedInPage, PROBE_ATTRIBUTE);
246
+ const contrast = await axeFindings(page, focusPlace, (builder) => builder.include(PROBE_SELECTOR).withRules(['color-contrast']));
247
+ await page.evaluate(unmarkInPage, [PROBE_SELECTOR, PROBE_ATTRIBUTE]);
248
+ const clip = state.clip;
249
+ if (clip === undefined) {
250
+ return { visit: merged([obscured, { ...EMPTY_VISIT, findings: contrast }]), order, key: facts.key, previous: here };
251
+ }
252
+ const focused = await page.screenshot({ clip, animations: 'disabled', caret: 'hide' });
253
+ await page.evaluate(blurInPage);
254
+ const unfocused = await page.screenshot({ clip, animations: 'disabled', caret: 'hide' });
255
+ const indicator = await focusIndicator(page, focusPlace, facts, {
256
+ shots: { focused, unfocused },
257
+ measure: { clip, extent: state.extent },
258
+ });
259
+ return {
260
+ visit: merged([obscured, indicator, { ...EMPTY_VISIT, findings: contrast }]),
261
+ order,
262
+ key: facts.key,
263
+ previous: here,
264
+ };
265
+ };
266
+ // Tab through the page once from its start: each stop is judged, and the walk ends when focus leaves
267
+ // the document or comes back to an element already visited.
268
+ const tabThrough = async (page, place, remaining, walked) => {
269
+ if (remaining <= 0) {
270
+ return [];
271
+ }
272
+ await page.keyboard.press('Tab');
273
+ const stop = await focusStop(page, place, walked.previous);
274
+ if (stop.key === undefined || walked.seen.has(stop.key)) {
275
+ return [stop.visit];
276
+ }
277
+ return [
278
+ stop.visit,
279
+ stop.order,
280
+ ...(await tabThrough(page, place, remaining - 1, {
281
+ seen: new Set([...walked.seen, stop.key]),
282
+ previous: stop.previous,
283
+ })),
284
+ ];
285
+ };
286
+ // The tab walk may take this many stops beyond the controls discovery counted.
287
+ const EXTRA_TAB_STOPS = 2;
288
+ const interactionVisit = async (page, item, isFirst) => {
289
+ const place = placeAt(page, item.location, item.viewport, 'resting');
290
+ const loaded = await loadLocation(page, item.location, item.viewport, place);
291
+ const unsettled = await settleFindings(page, place);
292
+ const controls = await controlsToDrive(page, isFirst);
293
+ // Hover is a pointer state, and a phone has no pointer to hover with.
294
+ const hovered = item.viewport.width === DESKTOP.width
295
+ ? await controls.reduce(async (earlier, control) => [
296
+ ...(await earlier),
297
+ await hoverControl(page, control, place),
298
+ ], Promise.resolve([]))
299
+ : [];
300
+ await page.goto(item.location.url);
301
+ await page.addStyleTag({ content: STILL_STYLE });
302
+ await settleForScan(page);
303
+ const focused = await tabThrough(page, place, item.location.controls + EXTRA_TAB_STOPS, {
304
+ seen: new Set(),
305
+ previous: undefined,
306
+ });
307
+ return merged([
308
+ { ...EMPTY_VISIT, findings: [...loaded, ...unsettled] },
309
+ ...hovered,
310
+ ...focused,
311
+ await healthOf(page, place),
312
+ ]);
313
+ };
314
+ const INTERACTION_RULES = [
315
+ 'obscured',
316
+ 'focus-obscured',
317
+ 'focus-visible',
318
+ 'focus-contrast',
319
+ 'focus-order',
320
+ ];
321
+ /**
322
+ * Drive every control of one shard of the locations into hover and keyboard focus, and judge contrast,
323
+ * reach and focus visibility.
324
+ * @param page the test's page.
325
+ * @param shard the part of the pass this test visits.
326
+ */
327
+ export const expectInteractionStates = async (page, shard) => {
328
+ test.info().skip(!isChromium(page), 'the interaction pass runs in Chromium');
329
+ const discovery = readDiscovery(test.info());
330
+ const places = discovery.locations.flatMap((location) => drivenViewports(location.isStory).map((viewport) => ({ location, viewport })));
331
+ // The chrome is driven once per viewport across every shard, at the first place the whole pass has at
332
+ // that viewport, by whichever shard takes it.
333
+ const chromePlaces = new Set(STRESS_VIEWPORTS.map((viewport) => places.findIndex((place) => place.viewport.width === viewport.width)));
334
+ const units = passUnits(places, (place) => place.location.controls + 1);
335
+ const budget = armBudget(page, 'interaction', shard, units);
336
+ await preparePage(page);
337
+ const { visits, taken } = await visitAll(places, {
338
+ budget,
339
+ labelOf: itemLabel,
340
+ // The index is the item's place in the whole pass.
341
+ visit: async (item, index) => await interactionVisit(page, item, chromePlaces.has(index)),
342
+ });
343
+ finishPass(page, {
344
+ budget,
345
+ pass: 'interaction',
346
+ visits,
347
+ judgedRules: INTERACTION_RULES,
348
+ locations: shardLocations(taken, locationOfItem),
349
+ });
350
+ };
351
+ //# sourceMappingURL=sweep-interaction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sweep-interaction.js","sourceRoot":"","sources":["../src/sweep-interaction.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Take the first item at or after `from` that no part has taken.
3
+ * @param directory the pass's queue directory, which must exist.
4
+ * @param count how many items the pass has.
5
+ * @param from the index to start looking at.
6
+ * @returns the index taken, or undefined when every item from there on is taken.
7
+ */
8
+ export declare const takeNext: (directory: string, count: number, from: number) => number | undefined;
9
+ /**
10
+ * The first item at or after `from` that no part has taken, without taking it.
11
+ * @param directory the pass's queue directory.
12
+ * @param count how many items the pass has.
13
+ * @param from the index to start looking at.
14
+ * @returns its index, or undefined when every item from there on is taken.
15
+ */
16
+ export declare const firstUntaken: (directory: string, count: number, from: number) => number | undefined;
17
+ /**
18
+ * How many items of a pass no part has taken.
19
+ * @param directory the pass's queue directory.
20
+ * @param count how many items the pass has.
21
+ * @returns the number not taken.
22
+ */
23
+ export declare const untakenCount: (directory: string, count: number) => number;
24
+ //# sourceMappingURL=sweep-queue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sweep-queue.d.ts","sourceRoot":"","sources":["../src/sweep-queue.ts"],"names":[],"mappings":"AAyBA;;;;;;GAMG;AACH,eAAO,MAAM,QAAQ,GAAI,WAAW,MAAM,EAAE,OAAO,MAAM,EAAE,MAAM,MAAM,KAAG,MAAM,GAAG,SAKlF,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,GAAI,WAAW,MAAM,EAAE,OAAO,MAAM,EAAE,MAAM,MAAM,KAAG,MAAM,GAAG,SAKtF,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,YAAY,GAAI,WAAW,MAAM,EAAE,OAAO,MAAM,KAAG,MAA+C,CAAA"}
@@ -0,0 +1,56 @@
1
+ // The queue the parts of a sweep pass share. Each part takes the next item no part has taken, so a part
2
+ // that meets slow items does not hold the pass while the others wait idle. An item is taken by creating
3
+ // a directory named by its index, which succeeds for exactly one part. The directory lives in the run's
4
+ // output directory, which every run starts empty.
5
+ import { existsSync, mkdirSync, readdirSync } from 'node:fs';
6
+ import path from 'node:path';
7
+ const isTakenAlready = (error) => typeof error === 'object' &&
8
+ error !== null &&
9
+ 'code' in error &&
10
+ error.code === 'EEXIST';
11
+ const isTakenNow = (directory, index) => {
12
+ try {
13
+ mkdirSync(path.join(directory, String(index)));
14
+ return true;
15
+ }
16
+ catch (error) {
17
+ if (isTakenAlready(error)) {
18
+ return false;
19
+ }
20
+ throw error;
21
+ }
22
+ };
23
+ /**
24
+ * Take the first item at or after `from` that no part has taken.
25
+ * @param directory the pass's queue directory, which must exist.
26
+ * @param count how many items the pass has.
27
+ * @param from the index to start looking at.
28
+ * @returns the index taken, or undefined when every item from there on is taken.
29
+ */
30
+ export const takeNext = (directory, count, from) => {
31
+ if (from >= count) {
32
+ return undefined;
33
+ }
34
+ return isTakenNow(directory, from) ? from : takeNext(directory, count, from + 1);
35
+ };
36
+ /**
37
+ * The first item at or after `from` that no part has taken, without taking it.
38
+ * @param directory the pass's queue directory.
39
+ * @param count how many items the pass has.
40
+ * @param from the index to start looking at.
41
+ * @returns its index, or undefined when every item from there on is taken.
42
+ */
43
+ export const firstUntaken = (directory, count, from) => {
44
+ if (from >= count) {
45
+ return undefined;
46
+ }
47
+ return existsSync(path.join(directory, String(from))) ? firstUntaken(directory, count, from + 1) : from;
48
+ };
49
+ /**
50
+ * How many items of a pass no part has taken.
51
+ * @param directory the pass's queue directory.
52
+ * @param count how many items the pass has.
53
+ * @returns the number not taken.
54
+ */
55
+ export const untakenCount = (directory, count) => count - readdirSync(directory).length;
56
+ //# sourceMappingURL=sweep-queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sweep-queue.js","sourceRoot":"","sources":["../src/sweep-queue.ts"],"names":[],"mappings":"AAAA,wGAAwG;AACxG,wGAAwG;AACxG,wGAAwG;AACxG,kDAAkD;AAClD,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAC5D,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,MAAM,cAAc,GAAG,CAAC,KAAc,EAAW,EAAE,CACjD,OAAO,KAAK,KAAK,QAAQ;IACzB,KAAK,KAAK,IAAI;IACd,MAAM,IAAI,KAAK;IACd,KAAqC,CAAC,IAAI,KAAK,QAAQ,CAAA;AAE1D,MAAM,UAAU,GAAG,CAAC,SAAiB,EAAE,KAAa,EAAW,EAAE;IAC/D,IAAI,CAAC;QACH,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;QAC9C,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO,KAAK,CAAA;QACd,CAAC;QACD,MAAM,KAAK,CAAA;IACb,CAAC;AACH,CAAC,CAAA;AAED;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,SAAiB,EAAE,KAAa,EAAE,IAAY,EAAsB,EAAE;IAC7F,IAAI,IAAI,IAAI,KAAK,EAAE,CAAC;QAClB,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,OAAO,UAAU,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,EAAE,KAAK,EAAE,IAAI,GAAG,CAAC,CAAC,CAAA;AAClF,CAAC,CAAA;AAED;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,SAAiB,EAAE,KAAa,EAAE,IAAY,EAAsB,EAAE;IACjG,IAAI,IAAI,IAAI,KAAK,EAAE,CAAC;QAClB,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,OAAO,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,SAAS,EAAE,KAAK,EAAE,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;AACzG,CAAC,CAAA;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,SAAiB,EAAE,KAAa,EAAU,EAAE,CAAC,KAAK,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC,MAAM,CAAA"}
@@ -0,0 +1,17 @@
1
+ import { type Page } from '@playwright/test';
2
+ import { type Shard } from './sweep-shared.js';
3
+ /**
4
+ * Apply the WCAG text-spacing overrides, then double every text size, and judge the reflow each time,
5
+ * on one shard of the sampled locations.
6
+ * @param page the test's page.
7
+ * @param shard the part of the pass this test visits.
8
+ */
9
+ export declare const expectTextStress: (page: Page, shard: Shard) => Promise<void>;
10
+ /**
11
+ * Resize one shard of one route per template and every story across the whole width range, and report
12
+ * each reflow defect with the exact widths it holds at.
13
+ * @param page the test's page.
14
+ * @param shard the part of the pass this test visits.
15
+ */
16
+ export declare const expectWidthSweep: (page: Page, shard: Shard) => Promise<void>;
17
+ //# sourceMappingURL=sweep-reflow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sweep-reflow.d.ts","sourceRoot":"","sources":["../src/sweep-reflow.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,IAAI,EAAQ,MAAM,kBAAkB,CAAA;AAsBlD,OAAO,EAqBL,KAAK,KAAK,EAOX,MAAM,mBAAmB,CAAA;AA6G1B;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GAAU,MAAM,IAAI,EAAE,OAAO,KAAK,KAAG,OAAO,CAAC,IAAI,CA2B7E,CAAA;AAyID;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GAAU,MAAM,IAAI,EAAE,OAAO,KAAK,KAAG,OAAO,CAAC,IAAI,CAkB7E,CAAA"}