Files
meshcore-analyzer/test-all.sh
T
efitenandClaude Opus 5.5 fbeb9e4d71 ci: frontend coverage from every E2E suite, merged across the shards (#2204)
Fixes #2203.

## Problem

The frontend coverage badge (35.16% on run 38413268001) came from two
sources on shard 2: one dump part-way through `test-e2e-playwright.js`
and the `collect-frontend-coverage.js` tour. The other E2E suites run
against the instrumented build but never save `window.__coverage__`,
including the suites written for single pages (`path-inspector.js`
4.72%, `touch-gestures.js` 14% on that run).

## Change

1. `9d3bfad5` `test(e2e): red:` `tests/unit/test-e2e-coverage.js`, with
fake pages, contexts and browsers (no Chromium needed). On the
placeholder module the first assertion fails.
2. `c00bbb12` `feat(e2e):` the collector.
- `scripts/e2e-coverage-hook.js` is a preload (`node --require`) that
wraps `chromium.launch` from `playwright`. `playwright` re-exports
`playwright-core`, so a suite's own `const { chromium } =
require('playwright')` gets the same, wrapped object.
- `scripts/e2e-coverage.js` reads `window.__coverage__` before every
call that replaces or ends a page's document: `goto`, `reload`,
`setContent`, `goBack`, `goForward`, `close`, and context and browser
`close`. Pages from `newPage`, `newContext` and the context `page` event
are all tracked.
- Each read zeroes the page's counters, so a document read twice is not
counted twice. Maps travel once per file; later reads carry counts only.
- The page returns a JSON string. Returning the object cost about 10 s
per suite, because Playwright serialises it node by node.
- A read is given up after 5 s, so a busy page cannot hold up a suite's
cleanup.
- On exit the hook writes one file per suite to `.nyc_output/`, or
nothing without coverage. A failed write is logged and never changes the
exit code.
3. `64487c4c` `ci:` the workflow.
- On master pushes the E2E run step sets `NODE_OPTIONS=--require
./scripts/e2e-coverage-hook.js`. On PRs it is empty, so PR runs are
unchanged.
- Each shard runs `nyc merge` (one file per suite is about 6 MB, mostly
the same maps) and uploads `coverage-shard.json` with its results
instead of `.badges/`.
- The `e2e-test` job merges the three shards and makes the frontend
badge (it used to come from shard 2 alone).
- The merge, setup-node and badge steps are `continue-on-error`. When
`nyc report` gives no statement percentage the step warns and writes no
badge, so a registry hiccup cannot publish 0%.
- `test-e2e-playwright.js` no longer writes its own `e2e-coverage.json`:
the hook covers that suite completely, including the tests after the old
dump. `collect-frontend-coverage.js` stays as an extra source.

## Performance

Measured locally against an instrumented server (Windows, Chrome):

| Suite | Without hook | With hook |
|---|---|---|
| `test-path-inspector-coverage-e2e.js` | 1.9 s | 2.2 s |
| `test-touch-gestures-coverage-e2e.js` | 17 s | 16 s |
| `test-e2e-playwright.js` (stops at the same local-fixture failure in
both runs) | 52 s | 52 s |
| `browser.close()` on a page in a 30 s busy loop | 153 ms | 5.2 s |

The hook only loads on master pushes.

## Testing

- `tests/unit/test-e2e-coverage.js` covers:
  - reads before each document-replacing call and before close;
  - pages opened by the page itself;
  - context and browser close;
  - summing without double counts;
  - a failed read, and a read that never answers;
  - the file writer, including a failing write.
- Nine deliberate breaks of the library each turn it red:
  - dropping the counter reset;
- dropping the `page` event, the `goto` read, the `goForward` read, the
`close` read or the browser `close` read;
  - removing the timeout or the write guard, or writing an empty store.
- The test also fails if it stops before its end. Without that check, a
read that never returns would let node exit 0 half-way.
- Real suites with the hook, measured on their own (the badge run had
all suites):

| File | Badge run 38413268001 | Own suite with the hook |
|---|---|---|
| `path-inspector.js` | 4.72% | 52.75% |
| `touch-gestures.js` | 14% | 72.96% |

- Exit codes and pass counts were unchanged with the hook for these
suites (the first three were run before the 5 s read timeout was added):
  - `test-slideover-1056-e2e.js` (6 contexts);
  - `test-a11y-axe-1668.js` (`@axe-core/playwright`);
  - `test-issue-1150-404-state-e2e.js`;
  - the three above.
- The badge step, run locally against two merged shard files:
  - It gives the same per-file numbers as `nyc report` on the inputs.
- With no shard coverage, or with `nyc report` failing, it warns and
writes no badge.
- `sh test-all.sh` passes locally, apart from
`test-issue-1956-release-routing.js`, which needs the workflow's
`GITHUB_REF_NAME` and was skipped. The test inventory classifies 321
suites. `actionlint` 1.7.7 reports only the self-hosted runner label, as
on master.

**Not tested:** the shard and badge steps in CI. They only run on a
master push, so the first master run after merge is the real test. I do
not know what the merged number will be. I will compare the badge with
the merged report in that run's `e2e-test` log.

**Not counted:** a full page load the suite does not start through one
of the wrapped calls, such as a link that leaves the SPA or
`location.reload()` from page code.

## Not in this PR

- The `tests/unit/` suites, which load frontend files through
`vm.createContext` without instrumentation (noted in #2203).
- Coverage on PR runs. The overhead above is small, so this could follow
if wanted.

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 22:04:03 +02:00

210 lines
9.5 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-admin-dashboard-ui.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-proposals-ui.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-approved-ui.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-e2e-coverage.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-packet-detail-channel-escape.js
node tests/unit/test-packet-detail-hash-size.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-2042-recent-adverts-label.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-issue-2095-channels-client-state.js
node tests/unit/test-issue-2097-hop-ambiguity-badge.js
node tests/unit/test-issue-2098-last-hop-region.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-nav-stats-throttle.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-notifications-ui.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-live-channel-filter.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-region-filter-setselected.js
node tests/unit/test-repeater-metric-scatter.js
node tests/unit/test-rx-coverage-config-race.js
node tests/unit/test-rx-coverage-mine.js
node tests/unit/test-rx-coverage-escape.js
node tests/unit/test-rx-coverage-noise.js
node tests/unit/test-rx-coverage-viewport.js
node tests/unit/test-scope-audit-styles-linked.js
node tests/unit/test-settings-sync.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-user-management-ui.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"