SimpleDocReview / tests /README.md
Eric Putnam
feat: deploy simpledocreview as a browser-only static space
3d968d9
|
Raw History Blame Contribute Delete
5.48 kB
# 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`.