import { beforeEach, describe, expect, it, vi } from 'vitest'; import { registerHost, __resetHostForTests, getState, setState, navigate, sendMessage, } from '../state'; import type { StateHost } from '../state'; import type { PopupState } from '../popup-state'; function makeHost(initial?: Partial): StateHost { let state: PopupState = { view: 'list', entries: [], selectedId: null, selectedItem: null, selectedIndex: 0, searchQuery: '', activeGroup: null, error: null, loading: false, capturedTabId: null, capturedUrl: '', newType: null, vaultSettings: null, generatorDefaults: null, historyItemId: null, ...initial, }; return { getState: () => state, setState: (partial) => { state = { ...state, ...partial }; }, navigate: vi.fn(), sendMessage: vi.fn().mockResolvedValue({ ok: true }), escapeHtml: (s) => s, popOutToTab: vi.fn(), isInTab: () => false, openVaultTab: vi.fn(), }; } describe('shared/state', () => { beforeEach(() => { __resetHostForTests(); }); it('register-then-getState round-trips', () => { const host = makeHost({ view: 'detail' }); registerHost(host); expect(getState().view).toBe('detail'); }); it('double-register throws', () => { registerHost(makeHost()); expect(() => registerHost(makeHost())).toThrow(/already registered/); }); it('__resetHostForTests clears the singleton', () => { registerHost(makeHost()); __resetHostForTests(); expect(() => getState()).toThrow(/No state host/); }); it('getState without host throws', () => { expect(() => getState()).toThrow(/No state host/); }); it('setState merges partial state', () => { const host = makeHost(); registerHost(host); setState({ loading: true }); expect(getState().loading).toBe(true); }); it('navigate delegates to host', () => { const host = makeHost(); registerHost(host); navigate('settings'); expect(host.navigate).toHaveBeenCalledWith('settings', undefined); }); it('sendMessage delegates to host', async () => { const host = makeHost(); registerHost(host); const resp = await sendMessage({ type: 'is_unlocked' }); expect(host.sendMessage).toHaveBeenCalledWith({ type: 'is_unlocked' }); expect(resp).toEqual({ ok: true }); }); });