You were right that Playwright has been catching the easy bugs while
the high-signal bugs (lightbox stranded after the Bedside reorg, PVC
clinically wrong, prod not rebuilt) all had to be caught by you as
the user. Adding a static linter so the class of bug that produced
the lightbox regression fails CI next time instead of the app.
scripts/lint-references.js walks public/js and validates every
getElementById('X') and querySelector('#X') resolves to an id that
is defined SOMEWHERE in the repo — either a static HTML attribute,
a .id = 'X' assignment, or an id="X" substring inside a JS template
string. It also walks HTML for asset references (data-img-src,
<img src>, <audio src>, <link href>) and verifies each root-absolute
path maps to a real file on disk.
Running it on the current tree surfaced two real problems:
1. shadess.js:917 reached for #wv-note-transcript when collecting
refine source context. The actual id is #wv-transcript (no -note-
infix — the transcript element is shared across well-visit sub-
panels). The bug meant a generated well-visit note's Refine call
silently missed the original transcript as source context; the AI
still "worked" but with less signal and no error. Fixed.
2. public/js/adminMilestones.js (221 lines) referenced 17 ids that
were removed a year+ ago in commit 3173ce6 ("Remove milestone
admin UI, add CMS content refresh button"). That commit dropped
the HTML but forgot the JS, which has been dead-loaded on every
page view since. All its addEventListener calls are guarded with
optional chaining, so nothing errored — just silent cruft.
Deleted the file and dropped the <script defer> tag from
index.html.
scripts/e2e.sh runs the linter as a preflight before the Playwright
container starts; a broken reference now fails the suite before any
test even boots.
Allowlist is kept small and prefix-based for the handful of id families
that are built dynamically by JS (bedside em-* sections, BP chart
elements, etc.). When a new component is added, its ids get picked up
automatically by the repo-wide collect() pass; the allowlist rarely
needs to grow.
Suite: 294 passed / 0 failed.
32 lines
1.2 KiB
Bash
Executable file
32 lines
1.2 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# Runs Playwright smoke tests inside the official Playwright container against
|
|
# the running PedScribe app. Usage: npm run e2e (or ./scripts/e2e.sh)
|
|
set -euo pipefail
|
|
|
|
cd "$(dirname "$0")/.."
|
|
|
|
IMAGE="mcr.microsoft.com/playwright:v1.50.0-noble"
|
|
|
|
# --- PREFLIGHT: static reference linter ---
|
|
# Catches the class of bug where a JS file reaches for an id that no
|
|
# HTML element (or dynamic id assignment anywhere in the repo) ever
|
|
# produces — the lightbox + adminMilestones dead-code bugs were both
|
|
# this shape and both went undetected until someone tripped over them
|
|
# in the real app. Fails the build before tests even start.
|
|
echo "==> Static reference lint"
|
|
docker run --rm -v "$PWD:/work" -w /work node:20-alpine \
|
|
node scripts/lint-references.js
|
|
|
|
# Attach the Playwright container to the same Docker network as the app so it
|
|
# can resolve pediatric-ai-scribe by service name. Internal container port is 3000.
|
|
NETWORK="${E2E_NETWORK:-ped-ai_default}"
|
|
BASE_URL="${BASE_URL:-http://pediatric-ai-scribe:3000}"
|
|
|
|
docker run --rm --ipc=host \
|
|
--network="$NETWORK" \
|
|
-v "$PWD/e2e":/work \
|
|
-w /work \
|
|
-e BASE_URL="$BASE_URL" \
|
|
-e CI=true \
|
|
"$IMAGE" \
|
|
sh -c "npm install --no-audit --no-fund --silent && npx playwright test"
|