diff --git a/extension/src/shared/__tests__/state.test.ts b/extension/src/shared/__tests__/state.test.ts new file mode 100644 index 0000000..0a707d2 --- /dev/null +++ b/extension/src/shared/__tests__/state.test.ts @@ -0,0 +1,92 @@ +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 }); + }); +});