Files
selfphoneng/scripts/e2e/README.md
T
iamdoubz ae3a723a3c softphone: SIP.js engine, /api/me/webrtc, minimal dock
GET /api/me/webrtc returns the <ext>-web identity, WebSocket URL
(WEBRTC_WS_URL overrides wss://PUBLIC_HOSTNAME/ws) and STUN/TURN servers.
SoftphoneEngine wraps SIP.js 0.21.2: register with backoff reconnect,
call, answer, decline, hang up, remote audio. A minimal dock on /me
enables it (asks for the microphone on the click) and dials/answers;
M5-T2 grows it into the full panel.

Generator: ice_host_candidates keeps the LAN address
(include_local_address), so LAN browsers don't need hairpin NAT, and -web
endpoints set from_domain = selfphoneng.invalid because SIP.js drops
INVITEs whose From host starts with a digit (Docker/VPS hostnames).

e2e m5-t1 (Docker): browser registers as 170-web and has two-way audio
with a baresip phone both ways. The LAN and hotspot check on the owner's
server is still open (roadmap note).

Task: M5-T1
2026-10-18 09:27:45 -05:00

4.4 KiB
Raw Blame History

Browser checks

Dependency-free scripts that drive a headless Chromium (Edge/Chrome) over the DevTools protocol. They need an api serving the built web UI and a fresh database.

pnpm --filter @selfphoneng/web build && mkdir -p /tmp/sp && cp -r apps/web/dist /tmp/sp/public
# fresh DB, then from /tmp/sp:
DATABASE_URL=postgres://… INITIAL_ADMIN_EMAIL=admin@example.com INITIAL_ADMIN_PASSWORD=initial-admin-pw \
  node --env-file=<repo>/.env --conditions=source <repo>/apps/api/src/index.ts
BROWSER=/usr/bin/chromium node scripts/e2e/m1-t4.mjs http://127.0.0.1:8080 admin@example.com initial-admin-pw /tmp/shots
node scripts/e2e/mobile.mjs http://127.0.0.1:8080 admin@example.com correct-horse-battery-staple /tmp/shots

m1-t4.mjs is the M1-T4 acceptance flow: forced password change, then create/edit/delete a user.

M2 live loop (any Docker host, no host networking)

m2-live.mjs runs the whole chain on a private Docker network: a test Asterisk with AMI published on 127.0.0.1:15038, the api writing config into it, two baresip phones, and the dashboard in a browser. It checks that a new extension is live in Asterisk within 2 s, both phones show online, and the dots turn red during a call.

node scripts/e2e/m2-live.mjs up /tmp/sp-live-conf
# start the api with AMI_PORT=15038 AMI_SECRET=m2-live-secret ASTERISK_CONFIG_DIR=/tmp/sp-live-conf
node scripts/e2e/m1-t4.mjs http://127.0.0.1:8080 admin@example.com initial-admin-pw /tmp/shots
node scripts/e2e/m2-live.mjs check http://127.0.0.1:8080 admin@example.com correct-horse-battery-staple /tmp/shots
node scripts/e2e/m2-live.mjs down

m3-t1.mjs runs on the same setup (after m1-t4.mjs): it starts a fake voip.ms (a second Asterisk that accepts one sub-account) on the m2-live network, creates the trunk in the UI and waits for Registered, then presses Test. m3-t2.mjs (after m3-t1.mjs) adds a phone number routed to a user in the UI and checks sp-inbound in Asterisk, and that the extension can no longer be deleted. m3-t3.mjs (after both) checks the default outbound rules, the test box, a user's calling permission, and that reordering changes the include order in Asterisk. m3-t4.mjs (after all three) runs a tiny SMTP sink on 127.0.0.1:2525 and a baresip phone as 101, then checks the dashboard warnings, Settings → Email and Emergency, and the Test notifications button (email arrives, 101 rings, red banner). Nothing dials 911. The fake provider from m3-t1.mjs stays up until m2-live.mjs down: a container that took over its IP would be identified as the trunk.

pnpm test:asterisk (golden-file load test, call-test.ts with 30 s two-way audio between two baresip phones, and trunk-test.ts with registration against a fake provider) needs no api at all.

m3-t5.mjs is the M3-T5 acceptance and needs its own fresh database: it signs in with the initial password, walks all ten wizard steps against a fake voip.ms, then proves an inbound call to the DID rings the new user's softphone and an outbound call leaves with the DID as caller ID.

m4-t2.mjs is the M4-T2 acceptance (no browser): start m2-live with a voicemail dir (m2-live.mjs up <confDir> <vmDir>) and the api with VOICEMAIL_DIR=<vmDir>. It runs the SMTP sink (smtp-sink.mjs, shared with m3-t4.mjs), adds a user and extension 150 with voicemail, leaves a message from a Local channel, and checks the email arrives within 10 s with a PCM 8 kHz wav attached. The voicemail itself (MWI on a phone, *97) is covered by pnpm test:asterisk.

m4-t3.mjs <baseUrl> <adminEmail> <adminPassword> <vmDir> <shotsDir> is the M4-T3 acceptance on the same setup: it adds a user with extension 160 and a baresip phone with the mwi module, leaves messages, then as that user in the browser plays one (marks it read) and deletes another, each time checking the phone's MWI goes off within 5 s. It records the "no answer" greeting with a fake microphone and checks a caller hears it.

m5-t1.mjs <baseUrl> <adminEmail> <adminPassword> <shotsDir> is the M5-T1 check in Docker: start the api with WEBRTC_WS_URL=ws://127.0.0.1:18088/ws. m2-live.mjs up publishes Asterisk's HTTP server on 127.0.0.1:18088 and RTP 10000–10019/udp. The script sets LAN IP = the container and public IP = 127.0.0.1 (so ICE offers 127.0.0.1), restarts telephony, then signs in as a new user, enables the softphone with a fake microphone, and checks two-way audio to a baresip phone (171) in both directions.