# Tests This deployment repo would normally carry no tests — upstream has them, and a copy-and-push pipeline has little to verify. These exist because of one thing: `overlay/sdr-api-core.js` is a hand-written JavaScript port of upstream's 1,200-line Python server, and a port that drifts from the server it mirrors makes the Space lie about what the tool does. Nothing else in the build would notice that drift. These two suites do. ```powershell node tests\parity\run-parity.mjs # the port vs. the real app.py node tests\browser\run-browser-check.mjs # the built site in a real browser ``` Both run automatically in `scripts\deploy.ps1` before anything is pushed, since a Static Space goes live the instant the push lands. ## parity/ — is the port the same program? `run-parity.mjs` replays one 67-request workflow twice and diffs the results: - **The reference.** `reference.py` imports the vendored `app.py` from `app/`, points its storage at a temporary directory, replaces `utc_now` and `uuid4` with counters, and serves it over real HTTP on a single-threaded server. - **The port.** `run-parity.mjs` loads `overlay/sdr-api-core.js` in Node with an in-memory store and the same counters. Then it compares every response status, every response body, the SHA-256 of the downloaded bytes, the final record store, and the list of stored uploads. Two details do most of the work: - **Sequential timestamps and ids.** Because the clock advances one second per call and ids count up from 1, the port has to *call* them the same number of times in the same order. A missing `utc_now()` or an extra `uuid4()` — easy to introduce, since Python builds its migration `defaults` dict eagerly and consumes an id whether it uses one or not — becomes a visible mismatch instead of a value nobody compares. - **A JSON round-trip on every load and save.** `app.py` re-reads its file per request, so a handler that mutates a record and then fails without saving throws the change away. The in-memory store copies on load and save for the same reason; handing out a live object would let those changes stick and hide the difference. ### The corpus `corpus/` is committed and covers the rubric and the text pipeline: | File | What it is for | | --- | --- | | `clean-policy.md` | All six required sections, long enough, no findings | | `messy-draft.md` | Every placeholder form, two vague phrases, an overlong sentence, missing sections | | `tiny.txt` | Short-document and every missing-section finding at once | | `unicode.md` | Word counting across scripts, apostrophes, hyphens, and combining marks — where Python's Unicode-aware `\w` and JavaScript's ASCII `\w` would otherwise disagree | | `whitespace.txt` | Rejected: no readable text | | `notes.rtf` | Rejected: unsupported type | `.corpus/` is generated by `reference.py` on each run and gitignored, because the fixtures are binary or encoding-specific: a deflated DOCX, a stored DOCX, a ZIP with no `word/document.xml`, a file that is not a ZIP at all, UTF-16 with a BOM, cp1252 with bytes that are not valid UTF-8, and an empty file. `corpus/**` is marked `-text` in `.gitattributes`. One rubric rule counts characters between sentence terminators, so a CRLF checkout would change a finding. ### Accepted divergences `ACCEPTED_DIVERGENCES` in `run-parity.mjs` lists differences that are correct, each with its reason, and prints them on every run rather than dropping them. There is currently one: `mimetypes.guess_type` returns `application/octet-stream` for `.docx` on a Windows machine with no Office mapping, where the port always sends the real OOXML type. Add to that list only for a difference you can justify in a sentence. Anything not on it fails the run. ## browser/ — does it work as a page? The parity suite runs the port in Node, so it says nothing about the parts between the port and the browser. `run-browser-check.mjs` serves the repository root over HTTP — plainly, with no SPA fallback, the way a Static Space does — opens it in headless Chromium through the DevTools protocol, and drives the real UI: upload, review, add a reviewer, assign, approve, download, reload. It checks the things only a browser can prove: - both overlay scripts loaded, in order, before `app.js` ran - upstream's `XMLHttpRequest` calls are answered locally - IndexedDB keeps the workspace across a reload - the Download button produces a file instead of navigating to a path that does not exist on a static host - no console errors anywhere in the run It talks the DevTools protocol directly instead of adding a browser-automation dependency this repo otherwise has no use for. It finds Edge or Chrome from the usual Windows install paths; set `BROWSER` to override, and pass `--headed` to watch it happen. One quirk worth knowing: approving a document that still has findings goes through `window.confirm`, and an unanswered dialog blocks the renderer — including the evaluation waiting on it. The client accepts the dialog over CDP rather than stubbing `confirm` in the page, so the real code path runs. ## When a test fails after an upstream change That is the intended outcome, not a broken test. `build-static.ps1` will already have refused to build for the same reason. Read the upstream diff, carry the behavior into `overlay/sdr-api-core.js`, re-run both suites, then acknowledge the change with `.\scripts\build-static.ps1 -AcceptUpstreamChanges`.