UI QA script¶
The manual pass for the three pages after any UI change. The automated part runs first:
node --test "tests/web/*.test.mjs" # pure page logic (labels, validation, HTML builders escape <x>)
.venv\Scripts\pytest tests\test_web_pages.py tests\test_web_assets.py tests\test_faxes_static.py tests\test_review_ui_api.py tests\test_faxes_api.py tests\test_settings_api.py tests\test_jobs_file_hold.py -q
Then start the app on a sandbox data directory so nothing touches production files:
$env:FAX_DATA_DIR = ".local-qa"; $env:APP_AUTH_ENABLED = "false"
.venv\Scripts\uvicorn faxautomation.main:app --reload
Use synthetic documents only. Never type a patient name, MRN or date of birth into any field.
1. Shell (every page)¶
- [ ]
/,/loinc-review,/faxes,/settingsshare the header; the current page is highlighted; the status strip shows the mapper state (and "N setting override(s)" when the Settings page overrides env). - [ ] Widths 375, 768 and 1280 px: no horizontal scroll; the review page shows 1, 2 and 3 columns; Tab reaches every control with a visible focus ring.
- [ ] Browser console: no errors on load; the report-only CSP may list violations, note them for 17.11's enforced policy.
- [ ] With
APP_AUTH_ENABLED=true: delete the session cookie, click Refresh on the review page → the app goes to/login?next=/loinc-reviewand returns after sign-in.
2. LOINC review¶
- [ ] Chips show counts; Open is pressed by default; the count matches the list.
- [ ] Type in the search box → the list narrows server-side (test name, printed name, code, status, job or case id); Clear restores it.
- [ ] Open
/loinc-review?case=<id>→ the case is selected with the list scrolled to it. - [ ] A case with a Gemini-renamed row shows Printed on the fax and Gemini read this as in "What the fax showed".
- [ ] "What the mapper made of it" reads as sentences (reason, closest candidate, What to do).
- [ ] Candidates: the mapper's best is marked, none is pre-selected; clicking one fills Selected LOINC and marks the row.
- [ ] Search LOINC: type two letters → results; arrow keys move, Enter picks, Escape closes.
- [ ] Submit with nothing chosen → the decision field is outlined and focused, "Fix the highlighted field" beside the button, no scroll.
- [ ] Approve with a short rationale → the rationale field is outlined.
- [ ] Valid approval → the green line under Submit names the decision and the code and says to publish; the case stays open with a Decided badge; the form locks.
- [ ] Select the next case → an empty form (reviewer id and name remembered).
- [ ] Reopen a decided case → Withdraw approval and reopen asks first; afterwards the form is unlocked and prefilled from the withdrawn decision with the banner.
- [ ] Publish… with nothing eligible → the modal says nothing to publish and Confirm is disabled. With one approval → the modal lists the code; Confirm → toast with the version; the strip's registry version updates.
- [ ] New correction → modal with human specimen labels; a short "why" is refused inline; success opens the disputed case.
- [ ] Export CSV downloads a file; with the mapper package missing the toast says so.
3. Extraction harness¶
- [ ] Ticking Simulate inbox greys the parser boxes and shows the Path B note; unticking restores them.
- [ ] Run a synthetic PDF: the status line sits beside the Run button; the stages progress; Cancel mid-run leaves "Cancelled — the server may still finish this job."
- [ ] Force a stage error (e.g. an unreadable file): only that stage is red, later stages grey, the bar keeps its width.
- [ ] Results: the scan-quality line, the funnel line with drops, the job expiry line; the labs table sorts on Test/Value/Unit/LOINC/Mapper/Page and filters by text; Details opens the drawer with the LabObservation; Escape closes it.
- [ ] Wrong code on a coded row lands on
/loinc-review?case=…. - [ ] File to Elation (sandbox): the filing card persists with the report id, Copy report id works, Open in Fax explorer shows the job; a second click asks "File again?".
- [ ] After the job TTL the export buttons and File to Elation are disabled with the expiry note.
- [ ] Verdict (plan Part A): set Max pages to 2 on the Settings page → a 3-page upload is refused with "413 … too_many_pages" beside Run. Set Hold only with at least N lab rows to 1 and Hold when the unfiled share reaches to 0.5, run a synthetic lab where the mapper abstains on most rows → the red "Held — not filed" line, the button reads File anyway…, clicking it asks first, filing then succeeds and the card shows. Clear the overrides afterwards.
4. Fax explorer¶
- [ ]
/faxeslists the run above (source "Harness upload"); search by the job-id prefix, byoutcome=parsed, by date. - [ ] Each tab renders: Timeline (deltas), Funnel (chain and drops), Filing (segments, note, Read back from Elation after a sandbox filing), Rows (Wrong code), Review cases (links), Logs ("Set GCP_PROJECT_ID…" until set), Retries.
- [ ] Retry a sandbox inbox item twice (
POST /internal/inbox/poll?submit=trueagainst the sandbox,skip_if_processed=falsefrom a script) → Retries shows attempts 1 and 2 and the journey of each. - [ ] With auth on:
/faxesredirects to login;/api/v1/faxesreturns 401. - [ ] The Held outcome chip and the Needs communication chip narrow the list; the run held above shows a "Held by verdict" badge and the Filing tab opens with the verdict card (numbers, thresholds, "Hold overridden by …" after File anyway).
5. Settings¶
- [ ]
/settingslists every key with its three columns (in effect, .env, override); the summary line says "No overrides" on a fresh data directory. - [ ] Type a page cap and pick On for Gemini classify → Save overrides → the toast names what changed, the summary says who saved and when, the status strip shows "2 setting overrides",
/health→runtime_settings.override_count= 2. - [ ] A hold share below the warn share → "The hold share must be at or above the warn share." beside the buttons; nothing saved. "ten" in a number field → the field is named and focused.
- [ ] Blank a field and save → its row shows the .env badge again. Clear all overrides asks first, then the summary says "No overrides".
- [ ] With auth on:
/settingsredirects to login;/api/v1/settingsreturns 401.
6. Closed page¶
- [ ] With
FAX_EDGE_MODE=trueoutside clinic hours/shows the closed page with the force-load form; no status strip; the header colours match the app.