refactor(shared): extract uploadOutcome from the XHR load closure (RB-27)
UploadAdapter.xhrUpload built new XMLHttpRequest() directly and put the
actual decisions inside its load listener: 2xx-vs-not, JSON.parse of the
body with a fallback, and ProblemDetails mapping via parseError. None of
it was reachable without stubbing the XHR global, so it had no spec
(TE-005; file LH 5/64, BRH 3/57).
Extract uploadOutcome(status, responseText): Result<string, {
documentId }>, a pure function next to genericError/parseError. It holds
the 2xx check, the JSON.parse-with-fallback, and the ProblemDetails
mapping. The load listener is now a two-line dispatch into it.
Abort-vs-error disambiguation stays where it is: it decides whether a
response exists at all, before uploadOutcome would even run, and the
proposed signature has no field for "aborted". It is already a one-line
ternary with no DOM-only logic to extract.
Add upload.adapter.spec.ts: plain describe/it, no DOM, no XHR stub,
covering a 2xx success, a 2xx unparseable body, a non-2xx ProblemDetails
body, a non-2xx non-ProblemDetails body, and the 200/300 boundary.
Verified red by editing uploadOutcome down to one line (an Edit, not
git checkout): 4 of 5 new specs failed. Re-applied with a second Edit.
Coverage for upload.adapter.ts: LH 5/64 -> 12/65, BRH 3/57 -> 7/59.
Skip TE-005's optional half (moving the currentScenario() branch into
KeepaliveTransport.send()): it needs a second file, upload-shell.
service.ts, and this ticket's own scope fences it to upload.adapter.ts
and its spec. The dev simulator's behaviour is unchanged.
Mark RB-27 implemented in 99-backlog.md and add its implementation note,
including a batch 5 close-out.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -20,7 +20,7 @@ tested where._
|
||||
|
||||
Every bullet below is a real test name from the suite — an `it()` title (frontend) or a test
|
||||
method name (backend), read as a sentence. Nothing here is hand-written prose: this page
|
||||
**is** the suite, reshaped for a business reader. 492 frontend behaviours across
|
||||
**is** the suite, reshaped for a business reader. 497 frontend behaviours across
|
||||
9 contexts; 261 backend behaviours across 42 test
|
||||
classes.
|
||||
|
||||
@@ -929,6 +929,14 @@ classes.
|
||||
- failed then retried returns to queued
|
||||
- UploadRemoved drops the upload
|
||||
|
||||
#### uploadOutcome
|
||||
|
||||
- resolves a 2xx response with a valid JSON body to the document id
|
||||
- falls back to the generic error when a 2xx body is not valid JSON
|
||||
- maps a non-2xx ProblemDetails body to its detail
|
||||
- falls back to the generic error for a non-2xx body without a ProblemDetails detail
|
||||
- treats status 200-299 as success and everything else as failure
|
||||
|
||||
#### withIdempotencyKey / currentIdempotencyKey
|
||||
|
||||
- threads the key to every read made inside the wrapped fn
|
||||
|
||||
Reference in New Issue
Block a user