Files
meshcore-analyzer/test-all.sh
T
efitenandClaude Opus 5 2cfe9cbbc5 fix(a11y): raise the Scope Audit observed-chip contrast above 4.5:1 (#2070)
Closes #1996.

## Reproduced first

The chips tint their own background — `color-mix(in srgb,
var(--status-green) 16%, transparent)` — which darkens whatever surface
sits behind them. With `--status-green-text` (green-700, `#15803d`) on
top:

| surface | composited chip | ratio |
|---|---|---|
| `--surface-0` `#f4f5f7` | `#d2eddf` | **4.04:1** |
| `--card-bg` `#ffffff` | `#dcf6e5` | **4.38:1** |

Both under the 4.5:1 the #1719 gate requires for normal text. The first
row is the same ratio **and the same hex** @n30nex measured in the
browser, which is how I know the model in the test agrees with what a
visitor actually sees.

## Fixed on the text, not by thinning the tint

Dropping the tint to 12% reaches 4.52:1. That is two hundredths above
the line, and a margin that thin fails again the next time a surface
value moves — the same trap #2039 hit with a threshold sitting inside
the healthy band. One palette step darker gives **6.23:1** on white and
**5.74:1** on `--surface-0`, and keeps the tint that makes a chip read
as a chip rather than as plain text.

- `--palette-green-800: #166534` added. The greens ran 300–700 while the
blues already reach 900, so this fills the scale rather than inventing a
colour.
- `--sa-chip-observed-fg` defined per theme: green-800 in light, and the
bright `#22c55e` **kept** in dark, where the chip already passed at
6.48:1 / 5.73:1. Dark is deliberately untouched.
- The chip reads the variable, so the customizer still governs it and no
literal enters a component.

`.sa-chip-verified` needed no change: `scope-audit.js:106` only ever
adds it alongside `sa-chip-observed` or `sa-chip-unobserved`, and it
contributes an underline. So the fix covers both classes the issue names
— worth stating, since the title mentions both.

## Tests

`tests/unit/test-a11y-1996-scope-audit-chips.js`, 7 cases: both themes ×
both surfaces, that the chip still tints (so the suite cannot pass by
testing nothing), that its colour comes from a variable rather than a
literal, and a guard asserting green-700 **would** still fail — so a
quiet revert to `--status-green-text` turns this red instead of passing.

**Red-run confirmed:** with the old colour restored it fails at exactly
4.04:1 and 4.38:1, naming the composited `rgb(210,237,223)`.

Two deliberate choices in the test:

- **A separate suite, not a case in `test-a11y-1719`.** That suite's
`parseColor` handles hex and `rgb()` only; teaching it `color-mix()` is
a larger change than this fix. These chips are the only
contrast-critical user of the function today. If a second appears, the
two should merge, and the file says so.
- **Derived from the stylesheets, not a rendered page.** The default
Scope Audit fixture renders no chips at all, which is precisely why the
existing browser coverage missed this. A stylesheet-derived check cannot
be defeated by a fixture that shows nothing.

`check-css-vars` passes (180 definitions, 0 undefined) and
`test-test-inventory` passes with the new file classified.

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-25 00:07:57 +02:00

192 lines
8.7 KiB
Bash
Executable File

#!/bin/sh
# Authoritative standalone frontend test list for local runs and CI.
# Every suite in tests/unit is listed here; every suite in tests/e2e is classified
# in scripts/non-unit-tests.json.
set -e
cd "$(dirname "$0")"
node tests/unit/test-test-inventory.js
node tests/unit/test-1108-region-hide-nodes.js
node tests/unit/test-1659-analytics-warmup.js
node tests/unit/test-a11y-1705-subpath-hop-prefix-e2e.js
node tests/unit/test-a11y-1715-dark-role-swatches.js
node tests/unit/test-a11y-1716-rf-range-btn-active.js
node tests/unit/test-a11y-1719-contrast-root-causes-e2e.js
node tests/unit/test-a11y-1996-scope-audit-chips.js
node tests/unit/test-a11y-axe-1668-selftest.js
node tests/unit/test-a11y-axe-routes-coverage.js
node tests/unit/test-aging.js
node tests/unit/test-analytics-channels-integration.js
node tests/unit/test-anl1-tooltip-render.js
node tests/unit/test-area-filter.js
node tests/unit/test-channel-color-picker.js
node tests/unit/test-channel-colors.js
node tests/unit/test-channel-decrypt-ecb.js
node tests/unit/test-channel-decrypt-insecure-context.js
node tests/unit/test-channel-decrypt-m345.js
node tests/unit/test-channel-fluid-layout.js
node tests/unit/test-channel-issue-1087.js
node tests/unit/test-channel-issue-1101.js
node tests/unit/test-channel-live-decrypt-userprefix.js
node tests/unit/test-channel-live-decrypt.js
node tests/unit/test-channel-modal-ux.js
node tests/unit/test-channel-psk-ux.js
node tests/unit/test-channel-qr-wiring.js
node tests/unit/test-channel-qr.js
node tests/unit/test-channel-sidebar-layout.js
node tests/unit/test-channel-ux-followup.js
node tests/unit/test-channel-ux-round2.js
node tests/unit/test-channels-merge-1498-unit.js
node tests/unit/test-clear-filters.js
node tests/unit/test-color-picker-ux.js
node tests/unit/test-compare-flood-filter.js
node tests/unit/test-compare-overlap.js
node tests/unit/test-confidence-indicator.js
node tests/unit/test-coverage-gate.js
node tests/unit/test-customizer-v2.js
node tests/unit/test-drag-manager.js
node tests/unit/test-direct-rf-heard-by.js
node tests/unit/test-embed-mode-1369.js
node tests/unit/test-fetch-all-nodes-pagination.js
node tests/unit/test-fluid-scaffolding.js
node tests/unit/test-frontend-helpers.js
node tests/unit/test-geofilter-draft.js
node tests/unit/test-hash-color.js
node tests/unit/test-hop-resolver-affinity.js
node tests/unit/test-issue-1065-gesture-hints-gates.js
node tests/unit/test-issue-1107-live-layout.js
node tests/unit/test-issue-1136-observer-iata-map.js
node tests/unit/test-issue-1166-first-seen-column.js
node tests/unit/test-issue-1189-composed-cell.js
node tests/unit/test-issue-1189-live-iata-badge.js
node tests/unit/test-issue-1279-p2-code-filter.js
node tests/unit/test-issue-1293-marker-shapes.js
node tests/unit/test-issue-1356-map-a11y.js
node tests/unit/test-issue-1360-pill-letter-count.js
node tests/unit/test-issue-1361-cb-presets.js
node tests/unit/test-issue-1364-pill-no-clamp.js
node tests/unit/test-issue-1375-scope-stats-fetch.js
node tests/unit/test-issue-1380-cb-reset-button.js
node tests/unit/test-issue-1380-cb-sim-overlay.js
node tests/unit/test-issue-1407-cb-preset-propagation.js
node tests/unit/test-issue-1409-no-encrypted-flood.js
node tests/unit/test-issue-1412-customizer-no-override.js
node tests/unit/test-issue-1415-packets-layout.js
node tests/unit/test-issue-1418-cb-preset-ramp.js
node tests/unit/test-issue-1418-deeplink-hops-channels.js
node tests/unit/test-issue-1418-edge-weights.js
node tests/unit/test-issue-1418-polish-review.js
node tests/unit/test-issue-1418-raw-hex-extraction.js
node tests/unit/test-issue-1418-spider-fan.js
node tests/unit/test-issue-1420-tile-providers.js
node tests/unit/test-issue-1438-customizer-mcrole.js
node tests/unit/test-issue-1438-marker-css-vars.js
node tests/unit/test-issue-1446-cb-preset-cascade.js
node tests/unit/test-issue-1450-logo-aspect.js
node tests/unit/test-issue-1454-channels-toggle.js
node tests/unit/test-issue-1456-score-labels.js
node tests/unit/test-issue-1461-mobile-page-actions.js
node tests/unit/test-issue-1470-card-bg-contrast.js
node tests/unit/test-issue-1470-node-tile-helper.js
node tests/unit/test-issue-1473-prefix-generator.js
node tests/unit/test-issue-1473-reserved-prefixes.js
node tests/unit/test-issue-1485-live-anim-z.js
node tests/unit/test-issue-1488-marker-stroke-vars.js
node tests/unit/test-issue-1496-reset-all-complete.js
node tests/unit/test-issue-1509-detect-preset.js
node tests/unit/test-issue-1509-nav-active-bg.js
node tests/unit/test-issue-1518-home-url.js
node tests/unit/test-issue-1532-live-fullscreen.js
node tests/unit/test-issue-1562-observers-summary.js
node tests/unit/test-issue-1563-aggregate-and-inflight.js
node tests/unit/test-issue-1574-live-map-max-nodes.js
node tests/unit/test-issue-1606-pagination.js
node tests/unit/test-issue-1614-tile-url-function.js
node tests/unit/test-issue-1619-feed-detail-card-draggable.js
node tests/unit/test-issue-1633-hide-1byte-hops.js
node tests/unit/test-issue-1644-redesign.js
node tests/unit/test-issue-1646-compare-polish.js
node tests/unit/test-issue-1648-followup-phosphor-leaks.js
node tests/unit/test-issue-1648-m1-emoji-scan.js
node tests/unit/test-issue-1648-m2-emoji-scan.js
node tests/unit/test-issue-1648-m3-emoji-scan.js
node tests/unit/test-issue-1648-m4-emoji-scan.js
node tests/unit/test-issue-1648-m5-emoji-scan.js
node tests/unit/test-issue-1648-m6-final-sweep.js
node tests/unit/test-issue-1648-m6-lint-self.js
node tests/unit/test-issue-1668-m2-contrast.js
node tests/unit/test-issue-1668-m3-typography.js
node tests/unit/test-issue-1668-m4-per-route.js
node tests/unit/test-issue-1697-mqtt-mobile-e2e.js
node tests/unit/test-issue-1699-retransmission-chart.js
node tests/unit/test-issue-1705-subpath-contrast.js
node tests/unit/test-issue-1753-copy-url-slash.js
node tests/unit/test-issue-1770-mobile-row-clamp.js
node tests/unit/test-issue-1789-observer-firmware-cols.js
node tests/unit/test-issue-1825-observer-node-cross-links.js
node tests/unit/test-issue-1833-legend-toggle-vcr-offset.js
node tests/unit/test-issue-1836-crossnav-case-normalization.js
node tests/unit/test-issue-1843-node-qr-quiet-zone.js
node tests/unit/test-issue-1846-observers-width.js
node tests/unit/test-issue-1849-trace-hashbytes.js
node tests/unit/test-issue-1851-channel-message-scope.js
node tests/unit/test-issue-1862-map-region-filter.js
node tests/unit/test-issue-1868-control-decode.js
node tests/unit/test-issue-1890-og-url.js
node tests/unit/test-issue-1956-release-routing.js
node tests/unit/test-issue-1979-scope-adverts-by-role.js
node tests/unit/test-issue-1997-distance-building.js
node tests/unit/test-issue-2001-map-scope-state.js
node tests/unit/test-issue-2012-clear-filters-selection.js
node tests/unit/test-live-anims.js
node tests/unit/test-live-dt-cap-1524.js
node tests/unit/test-live-legend-helper.js
node tests/unit/test-live-multibyte-filter.js
node tests/unit/test-live-region-filter.js
node tests/unit/test-live.js
node tests/unit/test-map-clustering.js
node tests/unit/test-mqtt-status-panel.js
node tests/unit/test-my-repeaters-dashboard.js
node tests/unit/test-naive-banner-tone.js
node tests/unit/test-node-hop-analytics.js
node tests/unit/test-node-reach-coverage-debounce.js
node tests/unit/test-node-reach-coverage.js
node tests/unit/test-nodes-export-wiring.js
node tests/unit/test-nav-drawer-version-footer.js
node tests/unit/test-nodes-export.js
node tests/unit/test-observer-iata-1188.js
node tests/unit/test-observer-menu-interactions.js
node tests/unit/test-observer-naive-clock-1478.js
node tests/unit/test-observer-search-filter.js
node tests/unit/test-observers-headings.js
node tests/unit/test-packet-filter-time.js
node tests/unit/test-packet-filter-ux.js
node tests/unit/test-packet-filter.js
node tests/unit/test-packets-local-channels.js
node tests/unit/test-packets.js
node tests/unit/test-panel-corner.js
node tests/unit/test-path-inspector.js
node tests/unit/test-payload-labels-content.js
node tests/unit/test-payload-labels-namespace.js
node tests/unit/test-perf-anomaly.js
node tests/unit/test-perf-disk-io-1120.js
node tests/unit/test-perf-go-runtime.js
node tests/unit/test-perf-render-1258.js
node tests/unit/test-preflight-xss-gate.js
node tests/unit/test-pull-to-reconnect-1091.js
node tests/unit/test-pull-to-reconnect.js
node tests/unit/test-repeater-metric-scatter.js
node tests/unit/test-rx-coverage-config-race.js
node tests/unit/test-rx-coverage-escape.js
node tests/unit/test-rx-coverage-viewport.js
node tests/unit/test-scope-audit-styles-linked.js
node tests/unit/test-slideover-1056-rowsel-strict.js
node tests/unit/test-top-routes-overlay.js
node tests/unit/test-traces.js
node tests/unit/test-url-state.js
node tests/unit/test-warmup-banner.js
node tests/unit/test-ws-stale-watchdog-1074.js
node tests/unit/test-xss-escape-sinks.js
echo "All standalone frontend suites passed"