48 lines
1.8 KiB
TypeScript
48 lines
1.8 KiB
TypeScript
// @vitest-environment node
|
|
import { describe, expect, it, vi } from "vitest";
|
|
import { eventStream } from "./event-stream";
|
|
|
|
describe("eventStream", () => {
|
|
it("disposes once and ignores late sends after reader cancellation", async () => {
|
|
const abortController = new AbortController();
|
|
const cleanup = vi.fn();
|
|
let sendAfterCancel: ((args: { event?: string; data: string }) => void) | undefined;
|
|
const response = eventStream(abortController.signal, (send) => {
|
|
sendAfterCancel = send;
|
|
send({ event: "ready", data: "initial" });
|
|
return cleanup;
|
|
});
|
|
const reader = response.body!.getReader();
|
|
|
|
await expect(reader.read()).resolves.toMatchObject({ done: false });
|
|
await reader.cancel(new Error("client disconnected"));
|
|
|
|
expect(cleanup).toHaveBeenCalledTimes(1);
|
|
expect(() => sendAfterCancel?.({ event: "heartbeat", data: "late" })).not.toThrow();
|
|
abortController.abort();
|
|
expect(cleanup).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it("closes and disposes once when the request aborts", async () => {
|
|
const abortController = new AbortController();
|
|
const cleanup = vi.fn();
|
|
let sendAfterAbort: ((args: { event?: string; data: string }) => void) | undefined;
|
|
const response = eventStream(abortController.signal, (send) => {
|
|
sendAfterAbort = send;
|
|
send({ data: "initial" });
|
|
return cleanup;
|
|
});
|
|
const reader = response.body!.getReader();
|
|
|
|
await expect(reader.read()).resolves.toMatchObject({ done: false });
|
|
await expect(reader.read()).resolves.toMatchObject({ done: false });
|
|
abortController.abort();
|
|
|
|
await expect(reader.read()).resolves.toEqual({ done: true, value: undefined });
|
|
expect(cleanup).toHaveBeenCalledTimes(1);
|
|
expect(() => sendAfterAbort?.({ data: "late" })).not.toThrow();
|
|
await reader.cancel();
|
|
expect(cleanup).toHaveBeenCalledTimes(1);
|
|
});
|
|
});
|