import { defineGlobalStore, useGlobalStore, emitGlobalStoreEvent } from './store'; import { BroadcastStrategy } from './enums'; describe('defineGlobalStore', () => { beforeEach(() => { // Reset global registry between tests jest.resetModules(); }); it('should create and retrieve a store', () => { const store = defineGlobalStore('test', { count: 0 }); expect(store.get()).toEqual({ count: 0 }); const retrieved = useGlobalStore('test'); expect(retrieved).toBe(store); }); it('should throw if store name is already registered', () => { defineGlobalStore('duplicate', { foo: 1 }); expect(() => defineGlobalStore('duplicate', { foo: 2 })).toThrow(); }); it('should update state and notify listeners', () => { const store = defineGlobalStore('notify', { value: 1 }); const listener = jest.fn(); store.on(listener); store.set({ value: 2 }); expect(store.get()).toEqual({ value: 2 }); expect(listener).toHaveBeenCalledWith({ value: 2 }); }); it('should remove listener when unsubscribed', () => { const store = defineGlobalStore('off', { x: 1 }); const listener = jest.fn(); const off = store.on(listener); off(); store.set({ x: 2 }); expect(listener).not.toHaveBeenCalled(); }); it('should persist state if persist option is true', async () => { const persistState = jest.fn(); jest.doMock('./storage', () => ({ ...jest.requireActual('./storage'), persistState, getPersistedState: async () => ({ persisted: true }) })); const { defineGlobalStore } = await import('./store'); const store = defineGlobalStore('persist', { persisted: false }, { persist: true }); // Wait for async state load await new Promise((r) => setTimeout(r, 0)); expect(store.get()).toEqual({ persisted: true }); }); it('should broadcast state changes when enabled', () => { const postMessage = jest.fn(); global.BroadcastChannel = jest.fn(() => ({ postMessage })) as any; const store = defineGlobalStore('broadcast', { foo: 1 }, { broadcast: BroadcastStrategy.CrossTab }); store.set({ foo: 2 }); expect(postMessage).toHaveBeenCalledWith({ foo: 2 }); }); }); describe('emitGlobalStoreEvent', () => { it('should dispatch event on window for local/all', () => { const dispatchEvent = jest.spyOn(window, 'dispatchEvent'); emitGlobalStoreEvent('event', { foo: 1 }, BroadcastStrategy.Local); expect(dispatchEvent).toHaveBeenCalled(); dispatchEvent.mockRestore(); }); it('should use BroadcastChannel for cross-tab/all', () => { const postMessage = jest.fn(); global.BroadcastChannel = jest.fn(() => ({ postMessage })) as any; emitGlobalStoreEvent('event', { bar: 2 }, BroadcastStrategy.CrossTab); expect(postMessage).toHaveBeenCalledWith({ bar: 2 }); }); }); describe('store.ts specific line coverage', () => { afterEach(() => { jest.restoreAllMocks(); // Reset the global registry if needed jest.resetModules(); }); it('should call channel.postMessage(state) when broadcasting (line 62)', () => { const postMessage = jest.fn(); global.BroadcastChannel = jest.fn(() => ({ postMessage })) as any; const store = defineGlobalStore('broadcast-test', { foo: 1 }, { broadcast: BroadcastStrategy.CrossTab }); store.set({ foo: 2 }); expect(postMessage).toHaveBeenCalledWith({ foo: 2 }); }); it('should merge state, notify, broadcast, and persist on set (line 74)', () => { const postMessage = jest.fn(); global.BroadcastChannel = jest.fn(() => ({ postMessage })) as any; const listener = jest.fn(); const store = defineGlobalStore('set-test', { a: 1 }, { broadcast: BroadcastStrategy.CrossTab, persist: false }); store.on(listener); store.set({ b: 2 } as any); expect(store.get()).toEqual({ a: 1, b: 2 } as any); expect(listener).toHaveBeenCalledWith({ a: 1, b: 2 }); expect(postMessage).toHaveBeenCalledWith({ a: 1, b: 2 }); }); it('should throw if useGlobalStore is called with unknown name (line 106)', () => { expect(() => useGlobalStore('unknown')).toThrowError('[stadojs] Store "unknown" not found.'); }); });