UNPKG

wxt-zustand

Version:

High-performance Zustand state management for WXT web extensions with seamless cross-tab synchronization and sub-10ms React re-renders

79 lines 3.03 kB
import { beforeEach, describe, expect, mock, test } from 'bun:test'; import { createStore } from 'zustand/vanilla'; // Mock @webext-core/proxy-service before importing modules that depend on it const serviceObj = { dispatch: mock(async () => ({})) }; const mockDefineProxyService = mock((_name, _factory) => { return [mock(() => { }), mock(() => serviceObj)]; }); // Storage.watch mock to capture unwatch calls const unwatchMock = mock(() => { }); const watchMock = mock((_key, _cb) => { return unwatchMock; }); mock.module('wxt/utils/storage', () => ({ storage: { watch: watchMock, // Other methods unused in this test getItem: mock(async () => undefined), setItem: mock(async () => { }), getItems: mock(async () => ({})), setItems: mock(async () => { }), }, })); mock.module('@webext-core/proxy-service', () => ({ defineProxyService: mockDefineProxyService, })); const { setupBidirectionalSync } = await import('./sync'); describe('setupBidirectionalSync cleanup', () => { beforeEach(() => { mockDefineProxyService.mockClear(); serviceObj.dispatch.mockClear(); unwatchMock.mockClear(); watchMock.mockClear(); }); test('cleanup unsubscribes local and unwatch remote, idempotent', () => { const base = createStore(() => ({ n: 0 })); // Wrap subscribe to count unsubscribe calls const realSubscribe = base.subscribe.bind(base); let unsubscribeCount = 0; base.subscribe = ((listener) => { const unsub = realSubscribe(listener); return () => { unsubscribeCount++; unsub(); }; }); const { cleanup } = setupBidirectionalSync('alpha', base); expect(typeof cleanup).toBe('function'); expect(watchMock).toHaveBeenCalledTimes(1); expect(unwatchMock).toHaveBeenCalledTimes(0); expect(unsubscribeCount).toBe(0); cleanup(); expect(unwatchMock).toHaveBeenCalledTimes(1); expect(unsubscribeCount).toBe(1); // Second cleanup does nothing (idempotent) cleanup(); expect(unwatchMock).toHaveBeenCalledTimes(1); expect(unsubscribeCount).toBe(1); }); }); test('dispatch invalidation triggers reload', async () => { const base = createStore(() => ({ n: 0 })); // Simulate extension context invalidated on dispatch serviceObj.dispatch = mock(async () => { throw new Error('Extension context invalidated.'); }); // Spy reload const originalWin = globalThis.window; const reload = mock(() => { }); globalThis.window = { location: { reload } }; const { cleanup } = setupBidirectionalSync('beta', base); // trigger a change base.setState({ n: 1 }); // allow promise microtask to run await new Promise((r) => setTimeout(r, 0)); expect(reload).toHaveBeenCalledTimes(1); cleanup(); globalThis.window = originalWin; }); //# sourceMappingURL=sync.test.js.map