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