@krizaka/page-audit 0.8.0 → 0.8.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/README.md +3 -3
- package/package.json +2 -2
- package/src/fixtures.mjs +5 -5
- package/src/page-audit.mjs +4 -4
- package/src/settle.mjs +1 -1
package/README.md
CHANGED
|
@@ -17,15 +17,15 @@ const problems = await auditRoutes({ base, routes: ["/en", "/fr"], checks: { h1:
|
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
`auditContext` / `loadSettled` / `resizeSettled` open a context with reduced motion and no View Transition, and wait for none to run
|
|
20
|
-
before anything is measured (
|
|
20
|
+
before anything is measured (verikora#354). `prepare(page, route)` signs in or seeds; `launch` gives your own browser.
|
|
21
21
|
|
|
22
22
|
## The dev-preview crawls, in one audit (0.3)
|
|
23
23
|
|
|
24
24
|
Opt-in through `checks` (nothing changes for a repo that does not ask): `status` (HTTP 4xx/5xx or no response), `emptyMain`, `frame`
|
|
25
25
|
(the signed-in frame, `[data-app-frame-slot]`, forces a scroll), `minAction` (a button-styled action under N px), `boxes` (a landmark
|
|
26
26
|
wider than its box), `landmarks` (`"public"` one footer naming Krizaka and a nav, `"app"`, `"auth"`), `pictures`, `emptyControls`,
|
|
27
|
-
`hardColors`, `maps` (an empty map,
|
|
28
|
-
a Leaflet map with no loaded tile; `maps: { required: true }` also fails a page that should draw one but has none), `smallTargets` (a control under 44 px on a side — an inline link in a sentence is exempt), `controlOverlaps` (two interactive elements that share pixels on screen, one not inside the other —
|
|
27
|
+
`hardColors`, `maps` (an empty map, folioviv#488: a GL / Leaflet / `[data-kz-map]` box under 120 px on a side, a GL map with no canvas,
|
|
28
|
+
a Leaflet map with no loaded tile; `maps: { required: true }` also fails a page that should draw one but has none), `smallTargets` (a control under 44 px on a side — an inline link in a sentence is exempt), `controlOverlaps` (two interactive elements that share pixels on screen, one not inside the other — folioviv#214: the composer's title over a row). Console noise the app tolerates: `ignoreConsole: [/…/]` (`[]` counts every error); `attempts` retries a route.
|
|
29
29
|
|
|
30
30
|
```js
|
|
31
31
|
const routes = await routesFromSitemap(base, { first: ["/", "/docs"], limit: 14 }); // a crawl as the route source (null: nothing answers)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@krizaka/page-audit",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"description": "The page audit of every Krizaka app, in one place: HTTP status, empty main, horizontal overflow, a card out of its panel, sections covering each other, a column cut off, top chrome overlaps, unnamed buttons, empty headings. Runs in a real browser (Playwright) over a route list, viewports and themes, with View Transitions neutralised and a self-test on its own fixtures.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"krizaka",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"eslint": "^9.39.0",
|
|
66
66
|
"playwright-core": "^1.55.0",
|
|
67
67
|
"vitest": "^4.1.11",
|
|
68
|
-
"@krizaka/config": "^0.
|
|
68
|
+
"@krizaka/config": "^0.21.0"
|
|
69
69
|
},
|
|
70
70
|
"engines": {
|
|
71
71
|
"node": ">=22"
|
package/src/fixtures.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Small pages that reproduce what the layout audit must catch (
|
|
1
|
+
// Small pages that reproduce what the layout audit must catch (verikora#435) and one that is fine, for `check-page-audit.mjs`:
|
|
2
2
|
// the guard is proven on its own fixtures before it is trusted on the app.
|
|
3
3
|
|
|
4
4
|
const page = (body, css = "") =>
|
|
@@ -33,7 +33,7 @@ export const FOLDED_SECTION = page(
|
|
|
33
33
|
|
|
34
34
|
/** A page whose `<main>` draws nothing. */
|
|
35
35
|
export const EMPTY_MAIN = page("");
|
|
36
|
-
/** The signed-in frame asks 1000 px of a 700 px screen under a 60 px notice (
|
|
36
|
+
/** The signed-in frame asks 1000 px of a 700 px screen under a 60 px notice (folioviv#444). */
|
|
37
37
|
export const FRAME_FORCES_SCROLL = page(
|
|
38
38
|
`<div style="height:60px">notice</div><div data-app-frame-slot><div style="min-height:1000px">shell</div></div>`,
|
|
39
39
|
);
|
|
@@ -63,14 +63,14 @@ export const CHROME_BAD = `<!doctype html><html><body><main><p>Hello</p></main><
|
|
|
63
63
|
|
|
64
64
|
/** A short token in a table row stretched by a tall neighbour: the cell is tall, its text is one line. */
|
|
65
65
|
export const TOKEN_IN_STRETCHED_ROW = page(
|
|
66
|
-
`<table style="width:600px"><tbody><tr><td>
|
|
66
|
+
`<table style="width:600px"><tbody><tr><td>sovkora-media-pack</td><td>${"A long description. ".repeat(30)}</td></tr></tbody></table>`,
|
|
67
67
|
);
|
|
68
68
|
/** An identifier in a narrow cell that breaks every few characters. */
|
|
69
69
|
export const TOKEN_WRAPPED = page(
|
|
70
70
|
`<table style="width:100px;table-layout:fixed"><tbody><tr><td style="word-break:break-all;font-size:20px">abcdefghijklmnopqrstuvwxyz0123456789</td></tr></tbody></table>`,
|
|
71
71
|
);
|
|
72
72
|
|
|
73
|
-
/** A map that laid out at 0 px: `absolute inset-0` in a frame with no height of its own (
|
|
73
|
+
/** A map that laid out at 0 px: `absolute inset-0` in a frame with no height of its own (folioviv#488). */
|
|
74
74
|
export const MAP_COLLAPSED = page(
|
|
75
75
|
`<section><div style="position:relative"><div class="maplibregl-map" style="position:absolute;inset:0"><canvas width="0" height="0"></canvas></div></div></section>`,
|
|
76
76
|
);
|
|
@@ -85,7 +85,7 @@ export const MAP_NO_CANVAS = page(
|
|
|
85
85
|
/** A map that is not drawn (display none: a closed tab, a small screen): nothing to measure. */
|
|
86
86
|
export const MAP_HIDDEN = page(`<section><div class="maplibregl-map" style="display:none"></div></section>`);
|
|
87
87
|
|
|
88
|
-
/** Two controls on top of each other: a title button over a row's button (
|
|
88
|
+
/** Two controls on top of each other: a title button over a row's button (folioviv#214, the composer's « Style » over « Réservation »). */
|
|
89
89
|
export const CONTROLS_OVERLAP = page(
|
|
90
90
|
`<button style="display:block;width:200px;height:40px">Réservation</button><button style="display:block;width:200px;height:40px;margin-top:-20px;position:relative">Style</button>`,
|
|
91
91
|
);
|
package/src/page-audit.mjs
CHANGED
|
@@ -207,7 +207,7 @@ function cutColumnsOf() {
|
|
|
207
207
|
return [...new Set(cut)].slice(0, 3);
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
-
/** The top chrome never overlaps (
|
|
210
|
+
/** The top chrome never overlaps (verikora#449): the in-flow blocks above the page (`[data-top-chrome]`, e.g. the development-version notice) and a bar that is fixed or sticky at the top of the viewport. Two of them that share pixels hide one another. */
|
|
211
211
|
function topBoxOf(el) {
|
|
212
212
|
return el.getBoundingClientRect().height === 0 && el.firstElementChild ? el.firstElementChild : el;
|
|
213
213
|
}
|
|
@@ -279,7 +279,7 @@ function wrappedOf() {
|
|
|
279
279
|
.map((el) => (el.textContent || "").trim().slice(0, 24));
|
|
280
280
|
}
|
|
281
281
|
|
|
282
|
-
/** The whole measure of a page. Decorative layers (aria-hidden), fixed elements and anything inside a scroller are left out of the layout probes (
|
|
282
|
+
/** The whole measure of a page. Decorative layers (aria-hidden), fixed elements and anything inside a scroller are left out of the layout probes (verikora#435). */
|
|
283
283
|
/** A heading with no text (and no image or labelled icon) says nothing to a screen reader. */
|
|
284
284
|
function emptyHeadingsOf() {
|
|
285
285
|
return [...document.querySelectorAll("h1, h2, h3")].filter(
|
|
@@ -307,7 +307,7 @@ function actionsOf() {
|
|
|
307
307
|
}
|
|
308
308
|
|
|
309
309
|
/**
|
|
310
|
-
* The signed-in frame's own screen (
|
|
310
|
+
* The signed-in frame's own screen (folioviv#444): its shell (`min-height`) and its sticky rail must fit in what is left of the viewport
|
|
311
311
|
* under the notice, or every page, an empty one included, scrolls by the notice's height. `null` when the page has no `[data-app-frame-slot]`.
|
|
312
312
|
*/
|
|
313
313
|
function frameOf(doc) {
|
|
@@ -579,7 +579,7 @@ export function problemsOf(
|
|
|
579
579
|
export const MIN_MAP_SIDE = 120;
|
|
580
580
|
|
|
581
581
|
/**
|
|
582
|
-
* An empty map (
|
|
582
|
+
* An empty map (folioviv#488): a box under `min` px on a side, a GL map with no canvas, a Leaflet map with no loaded tile.
|
|
583
583
|
* `maps` is `true` (the default minimum) or `{ min, required }`; with `required`, a page that was expected to draw a map and has none is a problem too.
|
|
584
584
|
*/
|
|
585
585
|
function mapProblems(where, found, option) {
|
package/src/settle.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// One way for every browser audit to measure (
|
|
1
|
+
// One way for every browser audit to measure (verikora#354): never while a View Transition is swapping the page.
|
|
2
2
|
//
|
|
3
3
|
// The flake: the page was read while a transition was running (« Viewport size changed », 0 of 2 h1). The cure is the
|
|
4
4
|
// same everywhere, so it lives here and nowhere else: the context emulates reduced motion (the app honours it, the page
|