test(ext/vault): handler→renderer status integration + indicator CSS (Plan C Phase 6)
Pins the 6.1↔6.2 contract: handleGetVaultStatus output feeds straight into renderStatusIndicator. Adds minimal self-contained .vault-status CSS. Stays out of vault-sidebar.ts — the footer wiring (Task 6.3) is Dev-B's boundary. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
65
extension/src/vault/__tests__/status-integration.test.ts
Normal file
65
extension/src/vault/__tests__/status-integration.test.ts
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
import { handleGetVaultStatus } from '../../service-worker/vault';
|
||||||
|
import { renderStatusIndicator } from '../vault-status';
|
||||||
|
import type { Manifest, ManifestEntry } from '../../shared/types';
|
||||||
|
|
||||||
|
// Integration seam: the get_vault_status SW handler (Phase 6 Task 6.1) produces
|
||||||
|
// the exact data shape the sidebar renderer (Task 6.2) consumes. This pins the
|
||||||
|
// contract between the two so a future change to either side can't silently
|
||||||
|
// drift the keys apart. It does NOT touch vault-sidebar.ts — the wiring layer
|
||||||
|
// (Task 6.3) is Dev-B's boundary and lands separately.
|
||||||
|
|
||||||
|
const cache = (lastSyncAt: number | null, ahead = 0, behind = 0) =>
|
||||||
|
({ lastSyncAt, ahead, behind });
|
||||||
|
|
||||||
|
function manifestWith(activeCount: number, trashedCount = 0): Manifest {
|
||||||
|
const items: Record<string, ManifestEntry> = {};
|
||||||
|
for (let i = 0; i < activeCount; i++) {
|
||||||
|
items[`a${i}`] = { trashed_at: undefined } as ManifestEntry;
|
||||||
|
}
|
||||||
|
for (let i = 0; i < trashedCount; i++) {
|
||||||
|
items[`t${i}`] = { trashed_at: 1000 } as ManifestEntry;
|
||||||
|
}
|
||||||
|
return { items } as Manifest;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('vault status: handler → renderer integration', () => {
|
||||||
|
it('renders "in sync" from a freshly-synced, no-pending handler response', () => {
|
||||||
|
const resp = handleGetVaultStatus({ gitHost: cache(1700000000), manifest: manifestWith(0) });
|
||||||
|
expect(resp.ok).toBe(true);
|
||||||
|
if (!resp.ok) return;
|
||||||
|
const el = document.createElement('div');
|
||||||
|
renderStatusIndicator(el, resp.data);
|
||||||
|
expect(el.textContent).toMatch(/in sync/i);
|
||||||
|
expect(el.textContent).toMatch(/last sync/i);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('surfaces the handler\'s active-item count as "N pending" in the DOM', () => {
|
||||||
|
const resp = handleGetVaultStatus({ gitHost: cache(1700000000), manifest: manifestWith(7, 3) });
|
||||||
|
expect(resp.ok).toBe(true);
|
||||||
|
if (!resp.ok) return;
|
||||||
|
expect(resp.data.pendingItems).toBe(7);
|
||||||
|
const el = document.createElement('div');
|
||||||
|
renderStatusIndicator(el, resp.data);
|
||||||
|
expect(el.textContent).toMatch(/7 pending/i);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('surfaces cached ahead/behind from the handler in the DOM', () => {
|
||||||
|
const resp = handleGetVaultStatus({ gitHost: cache(1700000000, 2, 1), manifest: manifestWith(0) });
|
||||||
|
expect(resp.ok).toBe(true);
|
||||||
|
if (!resp.ok) return;
|
||||||
|
const el = document.createElement('div');
|
||||||
|
renderStatusIndicator(el, resp.data);
|
||||||
|
expect(el.textContent).toMatch(/2 ahead/i);
|
||||||
|
expect(el.textContent).toMatch(/1 behind/i);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders "never synced" when the handler reports a null lastSyncAt', () => {
|
||||||
|
const resp = handleGetVaultStatus({ gitHost: cache(null), manifest: manifestWith(0) });
|
||||||
|
expect(resp.ok).toBe(true);
|
||||||
|
if (!resp.ok) return;
|
||||||
|
const el = document.createElement('div');
|
||||||
|
renderStatusIndicator(el, resp.data);
|
||||||
|
expect(el.textContent).toMatch(/never synced/i);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -2113,3 +2113,15 @@ textarea {
|
|||||||
.history-index-row__info { flex: 1; display: flex; flex-direction: column; }
|
.history-index-row__info { flex: 1; display: flex; flex-direction: column; }
|
||||||
.history-index-row__title { color: var(--text); }
|
.history-index-row__title { color: var(--text); }
|
||||||
.history-index-row__meta { font-size: 11px; }
|
.history-index-row__meta { font-size: 11px; }
|
||||||
|
|
||||||
|
/* Sidebar-footer vault status indicator (Plan C Phase 6, vault-status.ts).
|
||||||
|
The footer slot + refresh button are wired by vault-sidebar.ts in Task 6.3. */
|
||||||
|
.vault-status {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2px;
|
||||||
|
font-size: 11px;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
.vault-status__state { color: var(--text-dim); }
|
||||||
|
.vault-status__ts { color: var(--text-muted); }
|
||||||
|
|||||||
Reference in New Issue
Block a user