feat(extension): settings pane revamp — synced/local split + session timeout UI

This commit is contained in:
adlee-was-taken
2026-05-30 01:25:08 -04:00
parent 1edfa67a51
commit 299e7db1ab
4 changed files with 204 additions and 78 deletions

View File

@@ -40,19 +40,30 @@ describe('settings-vault', () => {
beforeEach(() => {
document.body.innerHTML = '<div id="app"></div>';
vi.mocked(sendMessage).mockReset();
vi.mocked(sendMessage).mockResolvedValue({ ok: true });
// Default: get_session_config returns inactivity/15, everything else ok
vi.mocked(sendMessage).mockImplementation(async (msg: any) => {
if (msg.type === 'get_session_config') {
return { ok: true, data: { config: { mode: 'inactivity', minutes: 15 } } };
}
return { ok: true };
});
});
it('renders with seeded vault-settings values', () => {
it('renders with seeded vault-settings values', async () => {
const app = document.getElementById('app')!;
renderVaultSettings(app);
expect(app.textContent).toContain('vault settings');
// Initial synchronous render paints the vault settings section headers
expect(app.querySelector('.section-header')?.textContent).toContain('VAULT SETTINGS');
expect(app.textContent).toContain('github.com');
expect(app.textContent).toContain('example.com');
const trashSel = document.getElementById('trash-retention') as HTMLSelectElement;
expect(trashSel.value).toBe('days:30');
const histSel = document.getElementById('history-retention') as HTMLSelectElement;
expect(histSel.value).toBe('forever');
// After get_session_config resolves, SESSION row appears
await new Promise((r) => setTimeout(r, 10));
expect(app.textContent).toContain('SESSION');
expect(app.textContent).toContain('after inactivity');
});
it('renders origin acks sorted by recency (descending)', () => {
@@ -70,7 +81,7 @@ describe('settings-vault', () => {
const trashSel = document.getElementById('trash-retention') as HTMLSelectElement;
trashSel.value = 'forever';
trashSel.dispatchEvent(new Event('change', { bubbles: true }));
expect(saveBtn.disabled).toBe(false);
expect((document.getElementById('save-btn') as HTMLButtonElement).disabled).toBe(false);
});
it('revoke button removes origin from pending and enables save', () => {
@@ -95,4 +106,28 @@ describe('settings-vault', () => {
expect(payload.settings.autofill_origin_acks).not.toHaveProperty('github.com');
expect(payload.settings.autofill_origin_acks).toHaveProperty('example.com');
});
it('section headers render in correct order: VAULT SETTINGS, THIS DEVICE, ACTIONS', () => {
const app = document.getElementById('app')!;
renderVaultSettings(app);
const headers = Array.from(document.querySelectorAll('.section-header')).map((e) => e.textContent?.trim());
expect(headers[0]).toContain('VAULT SETTINGS');
expect(headers[1]).toContain('THIS DEVICE');
expect(headers[2]).toContain('ACTIONS');
});
it('subtitle shows "no changes" initially', () => {
const app = document.getElementById('app')!;
renderVaultSettings(app);
expect(app.querySelector('.settings-header__sub')?.textContent).toBe('no changes');
});
it('subtitle shows "unsaved · esc to cancel" after making a change', () => {
const app = document.getElementById('app')!;
renderVaultSettings(app);
const trashSel = document.getElementById('trash-retention') as HTMLSelectElement;
trashSel.value = 'forever';
trashSel.dispatchEvent(new Event('change', { bubbles: true }));
expect(document.querySelector('.settings-header__sub')?.textContent).toContain('unsaved');
});
});