Skip to content

chore: mock-server fleet expansion + docs screenshot refresh pipeline#4624

Open
robertsLando wants to merge 9 commits into
masterfrom
chore/mock-server-fleet
Open

chore: mock-server fleet expansion + docs screenshot refresh pipeline#4624
robertsLando wants to merge 9 commits into
masterfrom
chore/mock-server-fleet

Conversation

@robertsLando

@robertsLando robertsLando commented Apr 29, 2026

Copy link
Copy Markdown
Member

Summary

Two related parts: a richer mock-server fleet, and a Playwright-driven pipeline that uses it to regenerate the docs screenshots.

Mock-server fleet

  • Adds a mock-server/ directory of 10 .cjs files / 31 mock nodes that npx mock-server merges at startup. Coverage: lighting (binary/dimmer/RGB/RGBW/fan), sensors (contact/temp+humidity/multi-sensor), notifications (motion/smoke/water/CO), locks (basic + keypad with full Schedule Entry Lock), thermostats (heat-only + HVAC), covers (shutter/blinds/garage), energy (electric/gas/solar w/ Energy Production CC), multi-channel (4-outlet strip + dual dimmer), misc (siren/indicator/scene controller/configurable parameters).
  • Splits fake-stick into two scripts:
    • npm run fake-stick — single node, loaded straight from mock-server/002-window-covering-pinned.cjs (fast, deterministic; this is what the e2e workflow uses).
    • npm run fake-stick:fleet — the full 31-node fleet (the whole mock-server/ directory; for dev / screenshots).
  • Removes the old single-node server_config.js — its node 2 (a Window Covering blinds device with User Code + Schedule Entry Lock) was duplicated by 002-window-covering-pinned.cjs. That fleet file is now the single source of truth and doubles as the single-node config.
  • The e2e workflow (.github/workflows/test-application.yml) is unchanged: npm run fake-stick still resolves to one node, so CI interviews fast and the MQTT round-trip on node 2's Window Covering CC parameter 3 (zwave/nodeID_2/106/0/targetValue/3) behaves exactly as before.
  • Updates the three .github/ instruction files and the AGENTS.md / CLAUDE.md quick-reference command lists for the two scripts.

Docs screenshot pipeline

  • Adds the refresh-docs-screenshots Claude Code skill: SKILL.md orchestration + capture.mjs (Playwright/Chromium capture script) + manifest.json (per-image recipe: route, theme, viewport, dialog steps) + seed data (fakeNodes.seed.json, a zero-node mock-server stub, scenes.json). Playwright is isolated in the skill's own package.json/package-lock.json so the heavy Chromium download doesn't leak into every contributor's root npm install.
  • Regenerates 14 PNGs under docs/_images/ with this tooling — control_panel, control_panel_dark, settings, settings_dark, debug, mesh_diagram, mesh-selected, route_health_result, nodes_manager, scenes, gateway_values_table, edit_gateway_value, config_updates_dialog, config_updates_icon. control_panel.png is new; the unused unknown-device.png is dropped.

Supporting code changes

  • ZwaveClient.getNodeNeighbors — guard the getNode() result. It can be undefined (node removed mid-request, or a UI-only fake node), which previously threw on .protocol.
  • NodePanel.refreshNodeNeighbors — the passive on-open neighbor refresh now passes infoSnack: false, errorSnack: false to apiRequest instead of wrapping the call in a bare swallow-everything try/catch, so it doesn't flash the per-request toast.
  • ZwaveGraph.vue — exposes the vis-network instance on window.__zwGraph when localStorage.exposeZwaveGraph is set, so the capture script can deterministically select a mesh node (canvas hit-testing is non-deterministic under physics layout). No-op in normal usage.
  • App.vue — listens for a zwave:dismiss-snackbars DOM event and clears all open toasts; capture.mjs fires it before each screenshot so transient snackbars never leak into a shot. No-op when the event is never dispatched.

Verification

  • npm run fake-stick boots a single node from 002-window-covering-pinned.cjs; npm run fake-stick:fleet boots all 31 — both verified listening on tcp://:::5555.
  • Node 2 keeps Window Covering CC parameter 3 (Outbound Right) supported, so the e2e MQTT round-trip is unaffected.
  • npx eslint mock-server/ is clean.
  • The 14 refreshed PNGs were produced by running capture.mjs end-to-end against the local stack.

Test plan

  • CI green on chore: Test Application — the e2e workflow itself is untouched; npm run fake-stick still loads a single node, so this is a no-op for CI behavior.
  • Review the refreshed docs/_images/*.png for visual correctness.
  • Manually run npm run fake-stick:fleet + npm run dev:server + npm run dev and walk the Control Panel to confirm the fleet renders with realistic names/locations.

Out of scope (intentionally deferred)

  • Re-recording the GIF / MP4 docs assets.
  • Cleaning up orphan PNGs (troubleshoot_*.png) — needs a docs-content decision.

…gories

Replaces the single-node `server_config.js` with a `mock-server/` directory
that the upstream `mock-server` CLI merges at startup. The 31 nodes cover
lighting, sensors, notifications, locks, thermostats, covers, energy,
multi-channel, and miscellaneous (siren / indicator / scene controller /
configurable parameters) — broad enough to drive realistic dev workflows
and docs screenshots without hardware.

- Pin node 2 (Window Covering CC, parameter 3) in its own file with a
  CI-contract comment so the e2e MQTT round-trip in
  `test-application.yml` keeps working.
- Bump the workflow's post-`npm start` `sleep` from 25s to 45s to give
  the backend room to interview the larger fleet.
- Update the three `.github/` doc references that pointed at
  `server_config.js`.

Also adds an initial `.claude/skills/refresh-docs-screenshots/` scaffold
(SKILL.md + manifest + seed `scenes.json`) for regenerating the PNGs
under `docs/_images/` against the new fleet via Claude-in-Chrome. The
selectors are best-effort and need an interactive shake-down before
they're trustworthy — see the failure-modes section in SKILL.md.
@coveralls

coveralls commented Apr 29, 2026

Copy link
Copy Markdown

Coverage Report for CI Build 26155599214

Coverage decreased (-1.0%) to 17.619%

Details

  • Coverage decreased (-1.0%) from the base build.
  • Patch coverage: 1349 uncovered changes across 14 files (0 of 1349 lines covered, 0.0%).
  • No coverage regressions found.

Uncovered Changes

Top 10 Files by Coverage Impact Changed Covered %
.claude/skills/refresh-docs-screenshots/capture.mjs 223 0 0.0%
mock-server/010-lighting.cjs 205 0 0.0%
mock-server/090-misc.cjs 149 0 0.0%
mock-server/030-notifications.cjs 117 0 0.0%
mock-server/040-locks.cjs 113 0 0.0%
mock-server/050-thermostats.cjs 103 0 0.0%
mock-server/080-multi-channel.cjs 100 0 0.0%
mock-server/070-energy.cjs 92 0 0.0%
mock-server/060-covers.cjs 90 0 0.0%
mock-server/020-sensors.cjs 86 0 0.0%

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 24967
Covered Lines: 4142
Line Coverage: 16.59%
Relevant Branches: 466
Covered Branches: 339
Branch Coverage: 72.75%
Branches in Coverage %: Yes
Coverage Strength: 1.06 hits per line

💛 - Coveralls

@robertsLando robertsLando changed the title chore: expand fake-stick fleet to 31 mock nodes across 10 device categories chore: mock-server fleet expansion + docs screenshot refresh pipeline May 20, 2026
The 31-node fleet made the backend interview slow enough that node 2's
value was not published over MQTT before the e2e round-trip test hit its
1-minute timeout. Restore the original single-node server_config.js and
keep both mock servers behind two scripts:

- npm run fake-stick       -> server_config.js (single node, used by CI)
- npm run fake-stick:fleet -> mock-server/ (31-node demo fleet)

Revert the workflow post-start sleep 45 -> 25 and update the docs.
server_config.js duplicated node 2 of the demo fleet — both defined a
Window Covering device with User Code and Schedule Entry Lock. Drop
server_config.js and point `npm run fake-stick` straight at
mock-server/002-window-covering-pinned.cjs, which mock-server loads as a
valid single-node config. The window-covering node now lives in exactly
one file, used both standalone (fake-stick) and merged (fake-stick:fleet).
- eslint: ignore .claude/ — the screenshots skill's capture.mjs uses
  top-level await, which the app's flat config (tuned for the Vue 3 app)
  cannot parse. The skill is isolated tooling with its own package.json,
  so the app lint should not cover it (consistent with .github/ already
  being ignored).
- e2e: node 2 in 002-window-covering-pinned.cjs carries a Node Naming CC,
  so with nodeNames:true the gateway published MQTT topics as
  zwave/<location>/<name>/... and the test's hardcoded zwave/nodeID_2/...
  topics never matched. Set the workflow gateway config to
  nodeNames:false + ignoreLoc:true so topics are keyed by node id
  (zwave/2/...) regardless of the node's name, and update the test topics.
  Verified locally end-to-end with a mosquitto round-trip.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants