Tap-target check expects a pin button per WAN host row (closes #46) #96
@@ -23,6 +23,11 @@ latest run passes.
|
|||||||
|
|
||||||
# Completed Steps
|
# Completed Steps
|
||||||
|
|
||||||
|
- 2026-10-03: the tap-target check in `make frontend-viewport-test` expects one
|
||||||
|
visible pin button per WAN host row (issue #46), where it expected at least 10
|
||||||
|
of the 26, so pin buttons missing from only some rows now fail it. The host
|
||||||
|
row count the harness gathers, which the `app-rendered` check also reads, now
|
||||||
|
counts only the WAN host rows: the local host rows have no pin button
|
||||||
- 2026-10-03: each target's row shows its result as soon as its check ends
|
- 2026-10-03: each target's row shows its result as soon as its check ends
|
||||||
(issue #91), where every row waited for the round's slowest check, up to 24
|
(issue #91), where every row waited for the round's slowest check, up to 24
|
||||||
seconds at a 30-second interval. Every row is still redrawn, and sorting, the
|
seconds at a 30-second interval. Every row is still redrawn, and sorting, the
|
||||||
@@ -237,9 +242,11 @@ latest run passes.
|
|||||||
- 2026-08-09: automated responsive-layout harness
|
- 2026-08-09: automated responsive-layout harness
|
||||||
(`make frontend-viewport-test`): digest-pinned headless Chrome driven over CDP
|
(`make frontend-viewport-test`): digest-pinned headless Chrome driven over CDP
|
||||||
against the built `dist/`, viewport widths derived from the breakpoints in
|
against the built `dist/`, viewport widths derived from the breakpoints in
|
||||||
`src/styles.css` ([#13](https://git.eeqj.de/sneak/netwatch/issues/13)). Every
|
`src/styles.css` ([#13](https://git.eeqj.de/sneak/netwatch/issues/13)). The
|
||||||
check carries a presence guard so none of them can pass against a page it is
|
tap-target and host-row checks each fail when they measured nothing; the
|
||||||
not actually measuring. Found two real layout defects, filed as
|
overflow, viewport-edge and clipped-text checks have no such guard of their
|
||||||
|
own and rely on the `app-rendered` check, which fails the run when the app did
|
||||||
|
not render. Found two real layout defects, filed as
|
||||||
[#42](https://git.eeqj.de/sneak/netwatch/issues/42) and
|
[#42](https://git.eeqj.de/sneak/netwatch/issues/42) and
|
||||||
[#43](https://git.eeqj.de/sneak/netwatch/issues/43)
|
[#43](https://git.eeqj.de/sneak/netwatch/issues/43)
|
||||||
- 2026-07-07 Adopted scripts-to-rule-them-all: `script/` entrypoints, Makefile
|
- 2026-07-07 Adopted scripts-to-rule-them-all: `script/` entrypoints, Makefile
|
||||||
|
|||||||
@@ -49,10 +49,11 @@ sizes straddling the breakpoint for the rotation case.
|
|||||||
excluded: it is a design choice, not breakage.
|
excluded: it is a design choice, not breakage.
|
||||||
- **tap-targets-44px** — every interactive control is at least 44x44 CSS px on
|
- **tap-targets-44px** — every interactive control is at least 44x44 CSS px on
|
||||||
touch viewports, _and_ each selector in the control list matched at least the
|
touch viewports, _and_ each selector in the control list matched at least the
|
||||||
number of visible elements it declares. The second half is what stops the
|
number of visible elements it declares: one of each single control, and one
|
||||||
check passing vacuously: with size alone, a renamed class would take its
|
pin button per WAN host row. The second half is what stops the check passing
|
||||||
controls out of the measured set and the check would report "all 0 controls
|
vacuously: with size alone, a renamed class would take its controls out of the
|
||||||
are at least 44x44" and pass. See below.
|
measured set and the check would report "all 0 controls are at least 44x44"
|
||||||
|
and pass. See below.
|
||||||
- **host-rows-stacked / host-rows-side-by-side** — the rows genuinely reflow.
|
- **host-rows-stacked / host-rows-side-by-side** — the rows genuinely reflow.
|
||||||
Computed `flex-direction` _and_ the actual geometry are checked, and in the
|
Computed `flex-direction` _and_ the actual geometry are checked, and in the
|
||||||
narrow layout the info block and the sparkline must each occupy essentially
|
narrow layout the info block and the sparkline must each occupy essentially
|
||||||
|
|||||||
+14
-13
@@ -15,7 +15,8 @@ export const MIN_TAP_TARGET_PX = 44;
|
|||||||
|
|
||||||
// The controls named in the definition of done, plus the pause button.
|
// The controls named in the definition of done, plus the pause button.
|
||||||
// Each carries the smallest number of *visible* instances the page has to
|
// Each carries the smallest number of *visible* instances the page has to
|
||||||
// contain for the tap-target oracle to be measuring anything at all.
|
// contain, worked out from the facts gathered from that page, for the
|
||||||
|
// tap-target oracle to be measuring every control it should.
|
||||||
//
|
//
|
||||||
// Without those floors the check is inert: `undersized` is empty both when
|
// Without those floors the check is inert: `undersized` is empty both when
|
||||||
// every control is large enough and when the selectors have gone stale and
|
// every control is large enough and when the selectors have gone stale and
|
||||||
@@ -24,13 +25,12 @@ export const MIN_TAP_TARGET_PX = 44;
|
|||||||
// for all three singleton controls vanishing at once — so the floor is per
|
// for all three singleton controls vanishing at once — so the floor is per
|
||||||
// selector, and one stale selector out of four fails the check.
|
// selector, and one stale selector out of four fails the check.
|
||||||
export const INTERACTIVE_CONTROLS = [
|
export const INTERACTIVE_CONTROLS = [
|
||||||
{ selector: "#pause-btn", minCount: 1 },
|
{ selector: "#pause-btn", minCount: () => 1 },
|
||||||
{ selector: "#interval-select", minCount: 1 },
|
{ selector: "#interval-select", minCount: () => 1 },
|
||||||
// One per pinnable host row. `app-rendered` already requires at least
|
// One per WAN host row, so pin buttons missing from even one row fail
|
||||||
// 10 host rows, so a count below that means the pin buttons stopped
|
// the check rather than only a drop below some fixed number.
|
||||||
// being rendered per row rather than that there were fewer hosts.
|
{ selector: ".pin-btn", minCount: (facts) => facts.wanRowCount },
|
||||||
{ selector: ".pin-btn", minCount: 10 },
|
{ selector: "#debug-toggle", minCount: () => 1 },
|
||||||
{ selector: "#debug-toggle", minCount: 1 },
|
|
||||||
];
|
];
|
||||||
|
|
||||||
export const INTERACTIVE_SELECTORS = INTERACTIVE_CONTROLS.map(
|
export const INTERACTIVE_SELECTORS = INTERACTIVE_CONTROLS.map(
|
||||||
@@ -105,8 +105,8 @@ export function evaluateChecks(facts, viewport, probes) {
|
|||||||
// never rendered. Everything below is only meaningful if this holds.
|
// never rendered. Everything below is only meaningful if this holds.
|
||||||
check(
|
check(
|
||||||
"app-rendered",
|
"app-rendered",
|
||||||
facts.rowCount >= 10 && facts.numericLatencies >= 5,
|
facts.wanRowCount >= 10 && facts.numericLatencies >= 5,
|
||||||
`${facts.rowCount} host rows, ${facts.numericLatencies} showing a numeric latency`,
|
`${facts.wanRowCount} WAN host rows, ${facts.numericLatencies} showing a numeric latency`,
|
||||||
);
|
);
|
||||||
|
|
||||||
const viewportWidth = Math.min(facts.innerWidth, facts.documentClientWidth);
|
const viewportWidth = Math.min(facts.innerWidth, facts.documentClientWidth);
|
||||||
@@ -162,7 +162,8 @@ export function evaluateChecks(facts, viewport, probes) {
|
|||||||
seen.set(target.selector, (seen.get(target.selector) ?? 0) + 1);
|
seen.set(target.selector, (seen.get(target.selector) ?? 0) + 1);
|
||||||
}
|
}
|
||||||
const missing = INTERACTIVE_CONTROLS.filter(
|
const missing = INTERACTIVE_CONTROLS.filter(
|
||||||
(control) => (seen.get(control.selector) ?? 0) < control.minCount,
|
(control) =>
|
||||||
|
(seen.get(control.selector) ?? 0) < control.minCount(facts),
|
||||||
);
|
);
|
||||||
|
|
||||||
const undersized = facts.tapTargets.filter(
|
const undersized = facts.tapTargets.filter(
|
||||||
@@ -184,11 +185,11 @@ export function evaluateChecks(facts, viewport, probes) {
|
|||||||
const detail = [];
|
const detail = [];
|
||||||
if (missing.length > 0) {
|
if (missing.length > 0) {
|
||||||
detail.push(
|
detail.push(
|
||||||
"oracle is not measuring the page: " +
|
"oracle is not measuring every control: " +
|
||||||
summarise(
|
summarise(
|
||||||
missing,
|
missing,
|
||||||
(c) =>
|
(c) =>
|
||||||
`${c.selector} matched ${seen.get(c.selector) ?? 0} visible element(s), expected at least ${c.minCount}`,
|
`${c.selector} matched ${seen.get(c.selector) ?? 0} visible element(s), expected at least ${c.minCount(facts)}`,
|
||||||
4,
|
4,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -173,7 +173,9 @@ export function collectLayoutFacts(options) {
|
|||||||
clipped,
|
clipped,
|
||||||
tapTargets,
|
tapTargets,
|
||||||
rows,
|
rows,
|
||||||
rowCount: document.querySelectorAll(".host-row").length,
|
// WAN host rows only: each has a pin button, and the tap-target
|
||||||
|
// check expects one per row. The local host rows have none.
|
||||||
|
wanRowCount: document.querySelectorAll("#wan-hosts .host-row").length,
|
||||||
numericLatencies: Array.from(
|
numericLatencies: Array.from(
|
||||||
document.querySelectorAll(".latency-value"),
|
document.querySelectorAll(".latency-value"),
|
||||||
).filter((el) => /\d/.test(el.textContent)).length,
|
).filter((el) => /\d/.test(el.textContent)).length,
|
||||||
|
|||||||
Reference in New Issue
Block a user