Harden dashboard realtime state and controls
This commit is contained in:
1 parent
4b3f00729f
commit
d108903174
21 files changed
+422
-29
No files matched your search
@@ -57,6 +57,24 @@ describe('dashboard realtime client', () => {
|
||||
expect(client.getSnapshot()).toMatchObject({ status: 'closed', isStale: true });
|
||||
});
|
||||
|
||||
it('requests an authoritative repair on initial connection and every reconnect', () => {
|
||||
const source = new FakeEventSource();
|
||||
const connected = vi.fn();
|
||||
const client = createDashboardRealtimeClient({
|
||||
sourceFactory: () => source,
|
||||
onEvent: vi.fn(),
|
||||
onConnected: connected,
|
||||
});
|
||||
|
||||
client.start();
|
||||
source.emit('open');
|
||||
source.emit('error');
|
||||
source.emit('open');
|
||||
|
||||
expect(connected).toHaveBeenNthCalledWith(1, { isReconnect: false });
|
||||
expect(connected).toHaveBeenNthCalledWith(2, { isReconnect: true });
|
||||
});
|
||||
|
||||
it('maps events to the queries whose authoritative snapshots need refresh', () => {
|
||||
expect(
|
||||
queryKeysForDashboardEvent({
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import { createVisibilityAwarePollingFallback } from '../../apps/dashboard/src/features/operations/realtime-fallback.js';
|
||||
|
||||
describe('visibility-aware realtime fallback', () => {
|
||||
it('polls only while stale and visible, including immediately on returning visible', () => {
|
||||
let visible = false;
|
||||
let interval: (() => void) | undefined;
|
||||
let visibilityListener: (() => void) | undefined;
|
||||
const poll = vi.fn();
|
||||
const fallback = createVisibilityAwarePollingFallback({
|
||||
intervalMs: 5_000,
|
||||
poll,
|
||||
scheduler: {
|
||||
setInterval(callback) { interval = callback; return 'timer'; },
|
||||
clearInterval: vi.fn(),
|
||||
},
|
||||
visibility: {
|
||||
isVisible: () => visible,
|
||||
subscribe(listener) { visibilityListener = listener; return vi.fn(); },
|
||||
},
|
||||
});
|
||||
|
||||
fallback.start();
|
||||
fallback.setStale(true);
|
||||
interval?.();
|
||||
expect(poll).not.toHaveBeenCalled();
|
||||
|
||||
visible = true;
|
||||
visibilityListener?.();
|
||||
expect(poll).toHaveBeenCalledOnce();
|
||||
interval?.();
|
||||
expect(poll).toHaveBeenCalledTimes(2);
|
||||
|
||||
fallback.setStale(false);
|
||||
interval?.();
|
||||
expect(poll).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,13 @@
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import { repairRealtimeSnapshots } from '../../apps/dashboard/src/app/realtime-repair.js';
|
||||
|
||||
describe('authoritative realtime repair', () => {
|
||||
it('marks snapshots stale and explicitly refetches active observers', async () => {
|
||||
const invalidateQueries = vi.fn().mockResolvedValue(undefined);
|
||||
const refetchQueries = vi.fn().mockResolvedValue(undefined);
|
||||
await repairRealtimeSnapshots({ invalidateQueries, refetchQueries });
|
||||
expect(invalidateQueries).toHaveBeenCalled();
|
||||
expect(refetchQueries).toHaveBeenCalled();
|
||||
expect(refetchQueries).toHaveBeenCalledWith(expect.objectContaining({ type: 'active' }));
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
// @vitest-environment jsdom
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { createDashboardRoutes } from '../../apps/dashboard/src/app/router.js';
|
||||
|
||||
describe('dashboard route error boundary', () => {
|
||||
it('protects the application shell from route rendering failures', () => {
|
||||
const root = createDashboardRoutes()[0];
|
||||
expect(root?.errorElement).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { deriveShellStatus } from '../../apps/dashboard/src/app/shell-status.js';
|
||||
|
||||
describe('global shell status', () => {
|
||||
it('derives safety-critical labels from authoritative snapshots', () => {
|
||||
expect(deriveShellStatus({
|
||||
stats: { isRunning: true, dryRunMode: true, invitationCooldown: { reason: 'Reddit cooldown' } },
|
||||
reddit: { ready: true, loggedIn: true, status: 'authenticated' },
|
||||
realtime: { status: 'reconnecting', isStale: true },
|
||||
sync: { syncing: true, syncingKind: 'full' },
|
||||
})).toEqual({
|
||||
bot: 'Running (dry run)', reddit: 'Reddit authenticated', realtime: 'Realtime reconnecting (stale)',
|
||||
cooldown: 'Reddit cooldown', sync: 'Full sync active', controlAction: 'stop', controlDisabled: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('guards bot controls until the authoritative bot state is available', () => {
|
||||
expect(deriveShellStatus({ realtime: { status: 'idle', isStale: true } })).toMatchObject({
|
||||
bot: 'Bot state unavailable', controlDisabled: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user