fix(timeline): pause sse while hidden
This commit is contained in:
@@ -52,13 +52,43 @@ class MockEventSource {
|
||||
}
|
||||
}
|
||||
|
||||
type VisibilityHandler = () => void;
|
||||
|
||||
class MockVisibilityDocument {
|
||||
visibilityState: "visible" | "hidden" = "visible";
|
||||
private readonly listeners = new Set<VisibilityHandler>();
|
||||
|
||||
addEventListener(type: string, listener: VisibilityHandler) {
|
||||
if (type === "visibilitychange") {
|
||||
this.listeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
removeEventListener(type: string, listener: VisibilityHandler) {
|
||||
if (type === "visibilitychange") {
|
||||
this.listeners.delete(listener);
|
||||
}
|
||||
}
|
||||
|
||||
setVisibility(state: "visible" | "hidden") {
|
||||
this.visibilityState = state;
|
||||
for (const listener of this.listeners) {
|
||||
listener();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
describe("useTimelineSSE", () => {
|
||||
let mockDocument: MockVisibilityDocument;
|
||||
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers();
|
||||
vi.clearAllMocks();
|
||||
effectCleanups.length = 0;
|
||||
MockEventSource.instances.length = 0;
|
||||
mockDocument = new MockVisibilityDocument();
|
||||
vi.stubGlobal("EventSource", MockEventSource);
|
||||
vi.stubGlobal("document", mockDocument);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -109,7 +139,7 @@ describe("useTimelineSSE", () => {
|
||||
|
||||
firstConnection?.emitError();
|
||||
firstConnection?.emitError();
|
||||
expect(firstConnection?.close).toHaveBeenCalledTimes(2);
|
||||
expect(firstConnection?.close).toHaveBeenCalledTimes(1);
|
||||
|
||||
vi.advanceTimersByTime(1999);
|
||||
expect(MockEventSource.instances).toHaveLength(1);
|
||||
@@ -172,4 +202,42 @@ describe("useTimelineSSE", () => {
|
||||
expect(MockEventSource.instances).toHaveLength(1);
|
||||
expect(firstConnection?.close).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not connect while the page is hidden on mount, then connects when visible", () => {
|
||||
mockDocument.visibilityState = "hidden";
|
||||
|
||||
useTimelineSSE();
|
||||
|
||||
expect(MockEventSource.instances).toHaveLength(0);
|
||||
|
||||
mockDocument.setVisibility("visible");
|
||||
|
||||
expect(MockEventSource.instances).toHaveLength(1);
|
||||
expect(invalidateQueries).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("closes the active connection while hidden and resyncs once when visible again", () => {
|
||||
useTimelineSSE();
|
||||
|
||||
const firstConnection = MockEventSource.instances[0];
|
||||
expect(firstConnection).toBeDefined();
|
||||
|
||||
firstConnection?.emitOpen();
|
||||
mockDocument.setVisibility("hidden");
|
||||
|
||||
expect(firstConnection?.close).toHaveBeenCalledTimes(1);
|
||||
expect(MockEventSource.instances).toHaveLength(1);
|
||||
|
||||
mockDocument.setVisibility("visible");
|
||||
|
||||
expect(MockEventSource.instances).toHaveLength(2);
|
||||
|
||||
const secondConnection = MockEventSource.instances[1];
|
||||
secondConnection?.emitOpen();
|
||||
|
||||
expect(invalidateQueries).toHaveBeenCalledTimes(getTimelineSseResyncKeys().length);
|
||||
expect(invalidateQueries.mock.calls).toEqual(
|
||||
getTimelineSseResyncKeys().map((queryKey) => [{ queryKey }]),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user