Ratatoskr/src/client/watchdog.test.ts
Void 69d752ff0b watchdog: send stall only, own-page entries, online only; resume sync nudges and never restarts
Soul pass on 77edebff: the watchdog no longer counts interrupted entries from
a previous page (reload loop at startup), no longer reloads on sync ERROR/STOPPED
(js-sdk recovers offline by itself) or while offline, refuses instead of
throwing when sessionStorage is unusable, startClient is idempotent, and the
slow-send label says Resend may duplicate. resumeSync drops its health check
and recover hook: nudge only.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-12 21:34:21 +00:00

60 lines
1.7 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { SEND_STALL_MS, WATCHDOG_INTERVAL_MS, startWatchdog } from './watchdog';
const setup = (over: Partial<Parameters<typeof startWatchdog>[0]> = {}) => {
const recover = vi.fn();
const stop = startWatchdog({
pendingAges: () => [],
isVisible: () => true,
isOnline: () => true,
recover,
...over,
});
return { recover, stop };
};
const tick = (n: number) => vi.advanceTimersByTime(WATCHDOG_INTERVAL_MS * n);
describe('watchdog', () => {
beforeEach(() => {
vi.useFakeTimers();
});
afterEach(() => {
vi.useRealTimers();
});
it('stays quiet while nothing is pending', () => {
const t = setup();
tick(100);
expect(t.recover).not.toHaveBeenCalled();
t.stop();
});
it('recovers when a send has been pending past the stall threshold, not before', () => {
let age = 0;
const t = setup({ pendingAges: () => [age] });
age = SEND_STALL_MS - 1;
tick(1);
expect(t.recover).not.toHaveBeenCalled();
age = SEND_STALL_MS;
tick(1);
expect(t.recover).toHaveBeenCalledTimes(1);
t.stop();
});
it('does nothing while the page is hidden or offline', () => {
const hidden = setup({ isVisible: () => false, pendingAges: () => [1e9] });
const offline = setup({ isOnline: () => false, pendingAges: () => [1e9] });
tick(50);
expect(hidden.recover).not.toHaveBeenCalled();
expect(offline.recover).not.toHaveBeenCalled();
hidden.stop();
offline.stop();
});
it('stop() ends it', () => {
const t = setup({ pendingAges: () => [1e9] });
t.stop();
tick(10);
expect(t.recover).not.toHaveBeenCalled();
});
});