fix: serialize session lifecycle transitions
This commit is contained in:
@@ -21,14 +21,34 @@ test("publish assigns monotonic ids and a subscriber replays only ids newer than
|
||||
]);
|
||||
});
|
||||
|
||||
test("clear drops stale subscribers and buffers but preserves the per-session id sequence", () => {
|
||||
test("clear closes every stale subscriber once and replays post-clear events from the cursor", () => {
|
||||
const hub = new SseHub();
|
||||
const stale: any[] = [];
|
||||
hub.subscribe("s1", (event, data, id) => stale.push({ event, data, id }));
|
||||
const firstStale: any[] = [];
|
||||
const secondStale: any[] = [];
|
||||
const closeCalls = [0, 0];
|
||||
let offFirst: () => void = () => undefined;
|
||||
let offSecond: () => void = () => undefined;
|
||||
offFirst = hub.subscribe(
|
||||
"s1",
|
||||
(event, data, id) => firstStale.push({ event, data, id }),
|
||||
{ close: () => { closeCalls[0] += 1; offFirst(); } },
|
||||
);
|
||||
offSecond = hub.subscribe(
|
||||
"s1",
|
||||
(event, data, id) => secondStale.push({ event, data, id }),
|
||||
{ close: () => { closeCalls[1] += 1; offSecond(); } },
|
||||
);
|
||||
expect(hub.publish("s1", "info", { text: "before" })).toBe(1);
|
||||
|
||||
hub.clear("s1");
|
||||
offFirst();
|
||||
offSecond();
|
||||
expect(closeCalls).toEqual([1, 1]);
|
||||
expect(hub.publish("s1", "info", { text: "after" })).toBe(2);
|
||||
expect(hub.publish("s1", "ui_request", {
|
||||
type: "ui_request",
|
||||
ui_request: { id: "gate-1", widget: "select" },
|
||||
})).toBe(3);
|
||||
const resumed: any[] = [];
|
||||
hub.subscribe(
|
||||
"s1",
|
||||
@@ -36,22 +56,47 @@ test("clear drops stale subscribers and buffers but preserves the per-session id
|
||||
{ afterId: 1 },
|
||||
);
|
||||
|
||||
expect(stale).toEqual([{ event: "info", data: { text: "before" }, id: 1 }]);
|
||||
expect(resumed).toEqual([{ event: "info", data: { text: "after" }, id: 2 }]);
|
||||
const before = [{ event: "info", data: { text: "before" }, id: 1 }];
|
||||
expect(firstStale).toEqual(before);
|
||||
expect(secondStale).toEqual(before);
|
||||
expect(resumed).toEqual([
|
||||
{ event: "info", data: { text: "after" }, id: 2 },
|
||||
{
|
||||
event: "ui_request",
|
||||
data: { type: "ui_request", ui_request: { id: "gate-1", widget: "select" } },
|
||||
id: 3,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test("forget drops subscribers, buffers, and the per-session id sequence", () => {
|
||||
test("forget closes every subscriber once and resets the per-session id sequence", () => {
|
||||
const hub = new SseHub();
|
||||
const stale: any[] = [];
|
||||
hub.subscribe("s1", (event, data, id) => stale.push({ event, data, id }));
|
||||
const firstStale: any[] = [];
|
||||
const secondStale: any[] = [];
|
||||
const closeCalls = [0, 0];
|
||||
let offFirst: () => void = () => undefined;
|
||||
let offSecond: () => void = () => undefined;
|
||||
offFirst = hub.subscribe(
|
||||
"s1",
|
||||
(event, data, id) => firstStale.push({ event, data, id }),
|
||||
{ close: () => { closeCalls[0] += 1; offFirst(); } },
|
||||
);
|
||||
offSecond = hub.subscribe(
|
||||
"s1",
|
||||
(event, data, id) => secondStale.push({ event, data, id }),
|
||||
{ close: () => { closeCalls[1] += 1; offSecond(); } },
|
||||
);
|
||||
expect(hub.publish("s1", "info", { text: "before" })).toBe(1);
|
||||
|
||||
hub.forget("s1");
|
||||
expect(closeCalls).toEqual([1, 1]);
|
||||
expect(hub.publish("s1", "info", { text: "after" })).toBe(1);
|
||||
const fresh: any[] = [];
|
||||
hub.subscribe("s1", (event, data, id) => fresh.push({ event, data, id }));
|
||||
|
||||
expect(stale).toEqual([{ event: "info", data: { text: "before" }, id: 1 }]);
|
||||
const before = [{ event: "info", data: { text: "before" }, id: 1 }];
|
||||
expect(firstStale).toEqual(before);
|
||||
expect(secondStale).toEqual(before);
|
||||
expect(fresh).toEqual([{ event: "info", data: { text: "after" }, id: 1 }]);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user