test(api): assert the export body's brand, not which realm built its Blob

`expect(x).toBeInstanceOf(Blob)` asks which realm constructed the body, not
whether there is one. Under jsdom the ambient `Blob` is jsdom's class, while
`Response.blob()` hands back node's own on Node 22 and jsdom's on Node 24 — so
both assertions passed locally and failed on the server gate, for a reason that
says nothing about the code under test. `.text()` is the mirror image: jsdom's
Blob does not implement it, so reading the bytes back is green on 22 and red on
24.

Both now assert the brand (`[object Blob]`, agreed by both realms) plus size and
type. Mutation-checked in node:22-bookworm: dropping `{ raw: true }` from
`debugExport` still turns the test red, so the repaired assertion still catches
the defect it was written for.

core.test.ts also stops building its Response from a jsdom `Blob`: on Node 22
undici does not recognise it as a body and stringifies it, so the fixture's body
was the 13 bytes of "[object Blob]" rather than the zip header. A string body is
what the sibling test already used.
This commit is contained in:
2026-09-20 16:33:26 +02:00
parent 09becb3d00
commit ec63056bd7
2 changed files with 15 additions and 3 deletions
+11 -2
View File
@@ -221,7 +221,7 @@ describe("req — a file, not a parsed answer", () => {
// A zip. Without the `raw` branch this falls into `r.json()`, throws on the first byte, and the // A zip. Without the `raw` branch this falls into `r.json()`, throws on the first byte, and the
// download dies as an opaque failure — which no lane would see, because the only consumer test // download dies as an opaque failure — which no lane would see, because the only consumer test
// mocks the api method wholesale. // mocks the api method wholesale.
const zip = new Response(new Blob(["PK"]), { const zip = new Response("PK", {
status: 200, status: 200,
headers: { headers: {
"content-type": "application/zip", "content-type": "application/zip",
@@ -234,7 +234,16 @@ describe("req — a file, not a parsed answer", () => {
expect(r).toBe(zip); expect(r).toBe(zip);
expect(r.headers.get("content-disposition")).toContain("siftlode-debug-260919.zip"); expect(r.headers.get("content-disposition")).toContain("siftlode-debug-260919.zip");
expect(await r.blob()).toBeInstanceOf(Blob); // the body is still there to be read // NOT `toBeInstanceOf(Blob)`: that asserts which realm built the body, not that there is one.
// Under jsdom the ambient `Blob` is jsdom's class, while `Response.blob()` hands back node's own
// on Node 22 and jsdom's on Node 24 — so the same assertion passed here and failed on the server
// gate (measured 2026-09-20). Nor `.text()`, for the mirror-image reason: jsdom's Blob has no
// such method, so reading the bytes back is green on 22 and red on 24. The brand and the size
// are the two things both realms agree on, and they are what this test means.
const body = await r.blob();
expect(Object.prototype.toString.call(body)).toBe("[object Blob]");
expect(body.size).toBe(4); // the body is still there to be read, all four of its bytes
expect(body.type).toBe("application/zip");
}); });
it("still refuses before the body is touched, so a refusal is shown and not saved", async () => { it("still refuses before the body is touched, so a refusal is shown and not saved", async () => {
+4 -1
View File
@@ -42,7 +42,10 @@ describe("debugExport", () => {
expect(out.name).toBe("siftlode-debug-20260919-1402-abc123.zip"); expect(out.name).toBe("siftlode-debug-20260919-1402-abc123.zip");
// The body is read as bytes, not parsed: `r.json()` on a zip would throw on its first one. // The body is read as bytes, not parsed: `r.json()` on a zip would throw on its first one.
expect(out.blob).toBeInstanceOf(Blob); // Brand, not `toBeInstanceOf(Blob)` — that asks which realm built the body: under jsdom the
// ambient `Blob` is jsdom's class, while `Response.blob()` returns node's own on Node 22 and
// jsdom's on Node 24, so the instance check passed locally and failed on the server gate.
expect(Object.prototype.toString.call(out.blob)).toBe("[object Blob]");
expect(out.blob.size).toBe(4); expect(out.blob.size).toBe(4);
}); });