import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import { renderSidebarShell, wireSidebar } from '../vault-sidebar'; import type { VaultController } from '../vault-context'; const STATUS = { ahead: 0, behind: 0, lastSyncAt: 1700000000, pendingItems: 4 }; function makeCtx() { return { state: { searchQuery: '' }, sendMessage: vi.fn(async (req: { type: string }) => req.type === 'get_vault_status' ? { ok: true, data: STATUS } : { ok: true }), render: vi.fn(), renderPane: vi.fn(), renderListPane: vi.fn(), closeDrawer: vi.fn(), openTypePanel: vi.fn(), setHash: vi.fn(), applyShellViewClass: vi.fn(), } as unknown as VaultController; } function statusCalls(ctx: VaultController): number { return (ctx.sendMessage as ReturnType).mock.calls .filter((c) => (c[0] as { type: string }).type === 'get_vault_status').length; } describe('vault-sidebar status wiring', () => { beforeEach(() => { document.body.innerHTML = renderSidebarShell(); }); afterEach(() => { document.body.innerHTML = ''; }); it('fetches + renders the indicator on mount', async () => { const ctx = makeCtx(); wireSidebar(ctx); await vi.waitFor(() => { expect(document.getElementById('vault-status-slot')?.textContent).toMatch(/4 pending/i); }); expect(statusCalls(ctx)).toBe(1); }); it('re-fetches on the manual refresh button', async () => { const ctx = makeCtx(); wireSidebar(ctx); await vi.waitFor(() => expect(statusCalls(ctx)).toBe(1)); document.getElementById('status-refresh-btn')?.dispatchEvent(new Event('click')); await vi.waitFor(() => expect(statusCalls(ctx)).toBe(2)); }); it('does NOT poll on a timer', async () => { vi.useFakeTimers(); try { const ctx = makeCtx(); wireSidebar(ctx); await vi.advanceTimersByTimeAsync(60_000); // Only the single mount fetch — no interval re-fetches. expect(statusCalls(ctx)).toBe(1); } finally { vi.useRealTimers(); } }); });