mirror of
https://github.com/amitwh/markdown-converter.git
synced 2026-08-02 18:10:18 +05:30
feat(renderer): add updater store mirroring main process state
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
import { create } from 'zustand';
|
||||
import { ipc } from '@/lib/ipc';
|
||||
|
||||
type State = 'idle' | 'checking' | 'available' | 'downloading' | 'ready' | 'error';
|
||||
|
||||
interface UpdaterState {
|
||||
state: State;
|
||||
version: string | null;
|
||||
percent: number;
|
||||
lastCheckAt: number;
|
||||
applyStatus: (s: { state: State; version?: string; percent?: number; code?: string }) => void;
|
||||
check: () => Promise<void>;
|
||||
install: () => void;
|
||||
}
|
||||
|
||||
const DEBOUNCE_MS = 60_000;
|
||||
|
||||
export const useUpdaterStore = create<UpdaterState>((set, get) => ({
|
||||
state: 'idle',
|
||||
version: null,
|
||||
percent: 0,
|
||||
lastCheckAt: 0,
|
||||
applyStatus: (s) =>
|
||||
set({
|
||||
state: s.state,
|
||||
version: s.version ?? get().version,
|
||||
percent: s.percent ?? get().percent,
|
||||
}),
|
||||
check: async () => {
|
||||
if (Date.now() - get().lastCheckAt < DEBOUNCE_MS) return;
|
||||
set({ lastCheckAt: Date.now() });
|
||||
await ipc.updater.check();
|
||||
},
|
||||
install: () => ipc.updater.install(),
|
||||
}));
|
||||
|
||||
// Subscribe to live updates from main
|
||||
if (typeof window !== 'undefined' && (window as any).electronAPI?.updater?.onStatus) {
|
||||
(window as any).electronAPI.updater.onStatus((payload: any) => {
|
||||
useUpdaterStore.getState().applyStatus(payload);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import { describe, expect, test, beforeEach, vi } from 'vitest';
|
||||
|
||||
vi.mock('@/lib/ipc', () => ({
|
||||
ipc: {
|
||||
updater: {
|
||||
check: vi.fn(),
|
||||
install: vi.fn(),
|
||||
getState: vi.fn().mockResolvedValue({ state: 'idle' }),
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
import { useUpdaterStore } from '@/lib/updater-store';
|
||||
import { ipc } from '@/lib/ipc';
|
||||
|
||||
beforeEach(() => {
|
||||
useUpdaterStore.setState({
|
||||
state: 'idle',
|
||||
version: null,
|
||||
percent: 0,
|
||||
lastCheckAt: 0,
|
||||
});
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('useUpdaterStore', () => {
|
||||
test('initial state is idle', () => {
|
||||
expect(useUpdaterStore.getState().state).toBe('idle');
|
||||
});
|
||||
|
||||
test('applyStatus updates state from incoming event', () => {
|
||||
useUpdaterStore.getState().applyStatus({ state: 'available', version: '5.0.2' });
|
||||
expect(useUpdaterStore.getState().state).toBe('available');
|
||||
expect(useUpdaterStore.getState().version).toBe('5.0.2');
|
||||
});
|
||||
|
||||
test('check() debounces within 60s', async () => {
|
||||
useUpdaterStore.setState({ lastCheckAt: Date.now() });
|
||||
await useUpdaterStore.getState().check();
|
||||
expect(ipc.updater.check).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('check() invokes ipc.updater.check when not debounced', async () => {
|
||||
await useUpdaterStore.getState().check();
|
||||
expect(ipc.updater.check).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('install() invokes ipc.updater.install', () => {
|
||||
useUpdaterStore.getState().install();
|
||||
expect(ipc.updater.install).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user