test(web): drop the double cast from the CRLF SSE stream mocks

Both new #2006 regressions faked the events response with an object cast
`as unknown as Response`, which AGENTS.md rejects — it erases the check
that the mock actually satisfies the API the hook consumes.

Each now builds a real `ReadableStream` inside a real `Response`. `pull`
runs once per chunk the hook's reader consumes, so awaiting a promise
inside it gates delivery exactly the way the hand-rolled reader did,
while the mock stays type-checked against the Response contract. The
chunk counter replaces the read counter as the "the reader has consumed
the previous chunk" signal.

Both still fail against the pre-fix parser, verified.

Raised by Copilot on PR #2036.

Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
cliffhall 2026-08-16 20:47:01 -04:00
commit 7a29a21618

View file

@ -987,7 +987,6 @@ describe("useServers", () => {
const framed = new Promise<void>((r) => { const framed = new Promise<void>((r) => {
releaseFrame = r; releaseFrame = r;
}); });
let reads = 0;
const encoder = new TextEncoder(); const encoder = new TextEncoder();
// Referentially stable: an inline arrow re-subscribes on every render, and // Referentially stable: an inline arrow re-subscribes on every render, and
// the re-subscription's own mount refresh would pick the edit up on its // the re-subscription's own mount refresh would pick the edit up on its
@ -995,22 +994,18 @@ describe("useServers", () => {
const fetchFn: typeof fetch = async (input, init) => { const fetchFn: typeof fetch = async (input, init) => {
const url = input instanceof Request ? input.url : String(input); const url = input instanceof Request ? input.url : String(input);
if (url.endsWith("/api/servers/events")) { if (url.endsWith("/api/servers/events")) {
const body = { // A real ReadableStream in a real Response — `pull` is only invoked
getReader: () => ({ // when the hook's reader asks for a chunk, so awaiting inside it
read: async () => { // gates delivery exactly the way a hand-rolled reader double would,
reads += 1; // while keeping the mock type-checked against the Response API.
if (reads === 1) { const stream = new ReadableStream<Uint8Array>({
await framed; async pull(controller) {
return { await framed;
done: false, controller.enqueue(encoder.encode("event: change\r\n\r\n"));
value: encoder.encode("event: change\r\n\r\n"), controller.close();
}; },
} });
return { done: true, value: undefined }; return new Response(stream, { status: 200 });
},
}),
};
return { ok: true, body } as unknown as Response;
} }
return h.fetchFn(url, init); return h.fetchFn(url, init);
}; };
@ -1057,31 +1052,30 @@ describe("useServers", () => {
releaseSecondHalf = r; releaseSecondHalf = r;
}); });
let listGets = 0; let listGets = 0;
let reads = 0; let chunks = 0;
const encoder = new TextEncoder(); const encoder = new TextEncoder();
const fetchFn: typeof fetch = async (input, init) => { const fetchFn: typeof fetch = async (input, init) => {
const url = input instanceof Request ? input.url : String(input); const url = input instanceof Request ? input.url : String(input);
if (url.endsWith("/api/servers/events")) { if (url.endsWith("/api/servers/events")) {
const body = { // `pull` runs once per chunk the hook's reader consumes, so `chunks`
getReader: () => ({ // reaching 2 proves the half-separator chunk was read and parsed.
read: async () => { const stream = new ReadableStream<Uint8Array>({
reads += 1; async pull(controller) {
if (reads === 1) { chunks += 1;
await firstHalf; if (chunks === 1) {
return { await firstHalf;
done: false, controller.enqueue(encoder.encode("event: change\r\n\r"));
value: encoder.encode("event: change\r\n\r"), return;
}; }
} if (chunks === 2) {
if (reads === 2) { await secondHalf;
await secondHalf; controller.enqueue(encoder.encode("\n"));
return { done: false, value: encoder.encode("\n") }; return;
} }
return { done: true, value: undefined }; controller.close();
}, },
}), });
}; return new Response(stream, { status: 200 });
return { ok: true, body } as unknown as Response;
} }
if (url.endsWith("/api/servers")) listGets += 1; if (url.endsWith("/api/servers")) listGets += 1;
return h.fetchFn(url, init); return h.fetchFn(url, init);
@ -1094,7 +1088,7 @@ describe("useServers", () => {
// Half a separator is not a frame: no refresh yet. // Half a separator is not a frame: no refresh yet.
releaseFirstHalf?.(); releaseFirstHalf?.();
await waitFor(() => expect(reads).toBeGreaterThanOrEqual(2)); await waitFor(() => expect(chunks).toBeGreaterThanOrEqual(2));
await new Promise((r) => setTimeout(r, 100)); await new Promise((r) => setTimeout(r, 100));
expect(listGets).toBe(1); expect(listGets).toBe(1);