- scripts/smoke/helpers.mjs — spawn-pi (via python3 pty.spawn), wait-for-port,
fetch, WebSocket helpers; createSmokeHome/removeSmokeHome for isolated HOME
- scripts/smoke/smoke.mjs — 6 node:test assertions:
GET /manifest.json → 200 + JSON shape
GET /icon.svg → 200 + <svg body
GET / (with token) → 302→200 + HTML marker
GET / (no token) → 403
WS /ws (with token) → 101 upgrade
pi process alive check
- scripts/smoke/README.md — usage, design notes, extension guide
- package.json: add 'smoke' script
- docs/SYNC.md: add scripts/smoke/** ownership row + History entry
All 6 tests pass in ~1.4 s locally.
Key finding: pi requires a PTY to enter interactive mode and fire
session_start. Spawning without a TTY causes immediate exit. Workaround:
python3 pty.spawn() — allocates a PTY with no additional deps.
|
||
|---|---|---|
| .. | ||
| README.md | ||
| helpers.mjs | ||
| smoke.mjs | ||
README.md
Smoke Test Harness
End-to-end smoke tests for the remote-control extension. These tests spawn
a real pi subprocess with the extension loaded and hit the HTTP/WebSocket
endpoints to verify they respond correctly.
Running
npm run smoke
Or directly:
node --test scripts/smoke/smoke.mjs
What is tested (MVP — T-1.0a)
| # | Test | Description |
|---|---|---|
| 1 | Server starts | pi spawns with --remote-control; TCP port opens within 12 s |
| 2 | GET /manifest.json |
200, application/manifest+json, parses, has name/short_name/start_url |
| 3 | GET /icon.svg |
200, image/svg+xml, body starts with <svg |
| 4 | GET / (with token) |
302→200, text/html, contains HTML marker |
| 5 | GET / (no token) |
403 Forbidden |
| 6 | WS /ws (with token) |
101 upgrade, WebSocket enters OPEN state |
| 7 | Process alive | pi hasn't crashed during the test run |
| T | Teardown | SIGTERM pi, wait for exit, remove temp HOME |
Port
Default port: 19876. Override with the SMOKE_PORT environment variable:
SMOKE_PORT=20000 npm run smoke
How it works
The harness creates a temporary HOME directory containing:
$HOME/.pi/remote-control/config.json—publicBaseUrl+bindAddresspointing atSMOKE_PORT$HOME/.pi/remote-control/token— a known deterministic token for auth
pi is spawned with HOME=<tmpdir> so no real ~/.pi files are read or
written. The temp directory is deleted in the after() teardown hook even
if tests fail.
Authentication
The server requires either a valid session cookie or ?token=<value> query
parameter. The smoke tests pre-seed a known token (smoke-test-token-deterministic-1234)
and pass it in the ?token= parameter. No production auth logic is modified.
Adding new tests
- Create a new file
scripts/smoke/<feature>.test.mjs - Import helpers from
./helpers.mjs - Import your test file from
smoke.mjs(or run it standalone withnode --test)
Example:
// scripts/smoke/stream.test.mjs
import { describe, it } from "node:test";
import { openWebSocket, closeWebSocket } from "./helpers.mjs";
export function registerStreamTests(port, token) {
describe("stream tests", () => {
it("WS /sessions/:id/stream → 101", async () => {
// ...
});
});
}
Flags used
Same flags as make dev:
pi -nt -ne -ns -np -nc --no-session --offline -e extensions/remote-control --remote-control
Troubleshooting
Port busy: if SMOKE_PORT is already in use, the test will fail at the
waitForPort step. Change the port: SMOKE_PORT=20001 npm run smoke.
pi not found: ensure pi is on your PATH. Check with which pi.
Server not starting: run with verbose output to see what pi logs:
node --test --reporter spec scripts/smoke/smoke.mjs
The port-wait error will include captured stdout/stderr from pi.