mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
* fix: extend SSE result retention from 2 to 10 minutes for mobile recovery * fix: check server health on tab visibility change for mobile recovery * fix: recover feature install SSE on tab visibility change * fix: reconnect SSE on tab visibility change in tool processor * fix: reconnect SSE on tab visibility change in pipeline processor * test: add visibility recovery tests for connection monitor
102 lines
2.8 KiB
TypeScript
102 lines
2.8 KiB
TypeScript
// @vitest-environment jsdom
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
const fetchMock = vi.fn();
|
|
vi.stubGlobal("fetch", fetchMock);
|
|
|
|
vi.stubGlobal("localStorage", {
|
|
getItem: vi.fn(() => null),
|
|
setItem: vi.fn(),
|
|
removeItem: vi.fn(),
|
|
clear: vi.fn(),
|
|
get length() {
|
|
return 0;
|
|
},
|
|
key: vi.fn(() => null),
|
|
});
|
|
|
|
function okHealth() {
|
|
return Promise.resolve(new Response(JSON.stringify({ status: "healthy" }), { status: 200 }));
|
|
}
|
|
|
|
function simulateVisible() {
|
|
Object.defineProperty(document, "visibilityState", {
|
|
value: "visible",
|
|
writable: true,
|
|
configurable: true,
|
|
});
|
|
document.dispatchEvent(new Event("visibilitychange"));
|
|
}
|
|
|
|
function simulateHidden() {
|
|
Object.defineProperty(document, "visibilityState", {
|
|
value: "hidden",
|
|
writable: true,
|
|
configurable: true,
|
|
});
|
|
document.dispatchEvent(new Event("visibilitychange"));
|
|
}
|
|
|
|
describe("visibility recovery", () => {
|
|
beforeEach(() => {
|
|
vi.useFakeTimers();
|
|
fetchMock.mockReset();
|
|
fetchMock.mockImplementation(() => okHealth());
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.useRealTimers();
|
|
});
|
|
|
|
describe("connection monitor", () => {
|
|
it("calls checkHealth when tab becomes visible", async () => {
|
|
const { useConnectionStore } = await import("@/stores/connection-store");
|
|
const { useConnectionMonitor } = await import("@/hooks/use-connection-monitor");
|
|
const { renderHook } = await import("@testing-library/react");
|
|
|
|
useConnectionStore.setState({
|
|
status: "connected",
|
|
failedSince: null,
|
|
lastHealthCheck: null,
|
|
});
|
|
fetchMock.mockReset();
|
|
fetchMock.mockImplementation(() => okHealth());
|
|
|
|
const { unmount } = renderHook(() => useConnectionMonitor());
|
|
|
|
await vi.advanceTimersByTimeAsync(0);
|
|
const initialCalls = fetchMock.mock.calls.length;
|
|
|
|
simulateVisible();
|
|
await vi.advanceTimersByTimeAsync(0);
|
|
|
|
expect(fetchMock.mock.calls.length).toBeGreaterThan(initialCalls);
|
|
unmount();
|
|
});
|
|
|
|
it("does not call checkHealth when tab becomes hidden", async () => {
|
|
const { useConnectionStore } = await import("@/stores/connection-store");
|
|
const { useConnectionMonitor } = await import("@/hooks/use-connection-monitor");
|
|
const { renderHook } = await import("@testing-library/react");
|
|
|
|
useConnectionStore.setState({
|
|
status: "connected",
|
|
failedSince: null,
|
|
lastHealthCheck: null,
|
|
});
|
|
fetchMock.mockReset();
|
|
fetchMock.mockImplementation(() => okHealth());
|
|
|
|
const { unmount } = renderHook(() => useConnectionMonitor());
|
|
await vi.advanceTimersByTimeAsync(0);
|
|
const callsAfterMount = fetchMock.mock.calls.length;
|
|
|
|
simulateHidden();
|
|
await vi.advanceTimersByTimeAsync(0);
|
|
|
|
expect(fetchMock.mock.calls.length).toBe(callsAfterMount);
|
|
unmount();
|
|
});
|
|
});
|
|
});
|