From eab3dbae2f287cf14de19fc140eb8c2f1f4e5c46 Mon Sep 17 00:00:00 2001 From: Horizontal42 <75383519+Horizontal42@users.noreply.github.com> Date: Wed, 8 Jul 2026 15:44:38 +0300 Subject: [PATCH] add tests for storage.ts Covers isTauri, and loadSettings/saveSettings across both the Tauri invoke path and the localStorage fallback, including corrupt-data and thrown-error recovery. --- src/storage.test.ts | 96 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 src/storage.test.ts diff --git a/src/storage.test.ts b/src/storage.test.ts new file mode 100644 index 0000000..f43c6f7 --- /dev/null +++ b/src/storage.test.ts @@ -0,0 +1,96 @@ +import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; +import { isTauri, loadSettings, saveSettings, defaultSettingsData } from './storage'; +import { invoke } from '@tauri-apps/api/core'; + +vi.mock('@tauri-apps/api/core', () => ({ + invoke: vi.fn(), +})); + +describe('storage', () => { + beforeEach(() => { + vi.resetAllMocks(); + vi.stubGlobal('window', {}); + vi.stubGlobal('localStorage', { + getItem: vi.fn(), + setItem: vi.fn(), + }); + vi.stubGlobal('console', { warn: vi.fn() }); + }); + + afterEach(() => { + vi.unstubAllGlobals(); + }); + + describe('isTauri', () => { + it('returns false when not in Tauri', () => { + expect(isTauri()).toBe(false); + }); + + it('returns true when in Tauri', () => { + vi.stubGlobal('window', { __TAURI_INTERNALS__: {} }); + expect(isTauri()).toBe(true); + }); + }); + + describe('loadSettings', () => { + it('loads from localStorage when not in Tauri', async () => { + vi.mocked(localStorage.getItem).mockReturnValue(JSON.stringify({ precision: 5 })); + const settings = await loadSettings(); + expect(localStorage.getItem).toHaveBeenCalledWith('summarum.settings'); + expect(settings.precision).toBe(5); + expect(settings.theme).toBe(defaultSettingsData.theme); + }); + + it('loads via invoke when in Tauri', async () => { + vi.stubGlobal('window', { __TAURI_INTERNALS__: {} }); + vi.mocked(invoke).mockResolvedValue(JSON.stringify({ precision: 8 })); + const settings = await loadSettings(); + expect(invoke).toHaveBeenCalledWith('load_file', { name: 'settings.json' }); + expect(settings.precision).toBe(8); + expect(settings.theme).toBe(defaultSettingsData.theme); + }); + + it('falls back to defaultSettingsData if localStorage throws', async () => { + vi.mocked(localStorage.getItem).mockImplementation(() => { throw new Error('localStorage error'); }); + const settings = await loadSettings(); + expect(console.warn).toHaveBeenCalledWith('loadSettings failed', expect.any(Error)); + expect(settings).toEqual(defaultSettingsData); + }); + + it('falls back to defaultSettingsData if invoke throws', async () => { + vi.stubGlobal('window', { __TAURI_INTERNALS__: {} }); + vi.mocked(invoke).mockRejectedValue(new Error('invoke error')); + const settings = await loadSettings(); + expect(console.warn).toHaveBeenCalledWith('loadSettings failed', expect.any(Error)); + expect(settings).toEqual(defaultSettingsData); + }); + + it('falls back to defaultSettingsData if localStorage returns null', async () => { + vi.mocked(localStorage.getItem).mockReturnValue(null); + const settings = await loadSettings(); + expect(settings).toEqual(defaultSettingsData); + }); + + it('falls back to defaultSettingsData if JSON is invalid', async () => { + vi.mocked(localStorage.getItem).mockReturnValue("invalid json"); + const settings = await loadSettings(); + expect(console.warn).toHaveBeenCalledWith('loadSettings failed', expect.any(Error)); + expect(settings).toEqual(defaultSettingsData); + }); + }); + + describe('saveSettings', () => { + it('saves to localStorage when not in Tauri', async () => { + const settings = { ...defaultSettingsData, precision: 10 }; + await saveSettings(settings); + expect(localStorage.setItem).toHaveBeenCalledWith('summarum.settings', JSON.stringify(settings, null, 2)); + }); + + it('saves via invoke when in Tauri', async () => { + vi.stubGlobal('window', { __TAURI_INTERNALS__: {} }); + const settings = { ...defaultSettingsData, precision: 12 }; + await saveSettings(settings); + expect(invoke).toHaveBeenCalledWith('save_file', { name: 'settings.json', contents: JSON.stringify(settings, null, 2) }); + }); + }); +});