From f1a5eebc655f0e555a235ba3b5026405620b57b5 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 12 Aug 2026 17:06:01 +0000 Subject: [PATCH] refactor: use dedicated logger in storage.ts Replaces raw `console.warn` calls with a dedicated `logger.warn` in `src/storage.ts` to improve maintainability and decouple from the global console object. Updates tests in `src/storage.test.ts` to mock the new logger module appropriately. Co-authored-by: Horizontal42 <75383519+Horizontal42@users.noreply.github.com> --- src/logger.ts | 6 ++++++ src/storage.test.ts | 28 +++++++++++++++------------- src/storage.ts | 24 +++++++++++++----------- 3 files changed, 34 insertions(+), 24 deletions(-) create mode 100644 src/logger.ts diff --git a/src/logger.ts b/src/logger.ts new file mode 100644 index 0000000..8baae69 --- /dev/null +++ b/src/logger.ts @@ -0,0 +1,6 @@ +export const logger = { + info: (...args: unknown[]) => console.info(...args), + warn: (...args: unknown[]) => console.warn(...args), + error: (...args: unknown[]) => console.error(...args), + debug: (...args: unknown[]) => console.debug(...args), +}; diff --git a/src/storage.test.ts b/src/storage.test.ts index 35e00b2..c53ea82 100644 --- a/src/storage.test.ts +++ b/src/storage.test.ts @@ -1,3 +1,5 @@ +import { logger } from "./logger"; + import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import { isTauri, loadSettings, saveSettings, defaultSettingsData, loadAppData, saveAppData, flushAppData, setDataDir, runBackups, backupDeletedSheet, openBackupsFolder, chooseFolder, dataDirHasDocuments, migrateDataDir, fetchRates, fetchHistoricalRates } from './storage'; import { invoke } from '@tauri-apps/api/core'; @@ -14,7 +16,7 @@ describe('storage', () => { getItem: vi.fn(), setItem: vi.fn(), }); - vi.stubGlobal('console', { warn: vi.fn() }); + vi.spyOn(logger, 'warn').mockImplementation(() => {}); vi.stubGlobal('fetch', vi.fn()); }); @@ -54,7 +56,7 @@ describe('storage', () => { 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(logger.warn).toHaveBeenCalledWith('loadSettings failed', expect.any(Error)); expect(settings).toEqual(defaultSettingsData); }); @@ -62,7 +64,7 @@ describe('storage', () => { 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(logger.warn).toHaveBeenCalledWith('loadSettings failed', expect.any(Error)); expect(settings).toEqual(defaultSettingsData); }); @@ -75,7 +77,7 @@ describe('storage', () => { 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(logger.warn).toHaveBeenCalledWith('loadSettings failed', expect.any(Error)); expect(settings).toEqual(defaultSettingsData); }); }); @@ -124,7 +126,7 @@ describe('storage', () => { it('returns null if localStorage throws', async () => { vi.mocked(localStorage.getItem).mockImplementation(() => { throw new Error('localStorage error'); }); const data = await loadAppData(''); - expect(console.warn).toHaveBeenCalledWith('loadAppData failed', expect.any(Error)); + expect(logger.warn).toHaveBeenCalledWith('loadAppData failed', expect.any(Error)); expect(data).toBeNull(); }); @@ -132,7 +134,7 @@ describe('storage', () => { vi.stubGlobal('window', { __TAURI_INTERNALS__: {} }); vi.mocked(invoke).mockRejectedValue(new Error('invoke error')); const data = await loadAppData(''); - expect(console.warn).toHaveBeenCalledWith('loadAppData failed', expect.any(Error)); + expect(logger.warn).toHaveBeenCalledWith('loadAppData failed', expect.any(Error)); expect(data).toBeNull(); }); @@ -145,7 +147,7 @@ describe('storage', () => { it('returns null if JSON is invalid', async () => { vi.mocked(localStorage.getItem).mockReturnValue("invalid json"); const data = await loadAppData(''); - expect(console.warn).toHaveBeenCalledWith('loadAppData failed', expect.any(Error)); + expect(logger.warn).toHaveBeenCalledWith('loadAppData failed', expect.any(Error)); expect(data).toBeNull(); }); }); @@ -223,7 +225,7 @@ describe('storage', () => { await flushAppData(); - expect(console.warn).toHaveBeenCalledWith('saveAppData failed', expect.any(Error)); + expect(logger.warn).toHaveBeenCalledWith('saveAppData failed', expect.any(Error)); }); it('handles invoke throw gracefully in flushAppData', async () => { @@ -234,7 +236,7 @@ describe('storage', () => { await flushAppData(); - expect(console.warn).toHaveBeenCalledWith('saveAppData failed', expect.any(Error)); + expect(logger.warn).toHaveBeenCalledWith('saveAppData failed', expect.any(Error)); }); }); @@ -255,7 +257,7 @@ describe('storage', () => { vi.stubGlobal('window', { __TAURI_INTERNALS__: {} }); vi.mocked(invoke).mockRejectedValue(new Error('invoke error')); await runBackups('dir', 10); - expect(console.warn).toHaveBeenCalledWith('runBackups failed', expect.any(Error)); + expect(logger.warn).toHaveBeenCalledWith('runBackups failed', expect.any(Error)); }); }); @@ -281,7 +283,7 @@ describe('storage', () => { vi.stubGlobal('window', { __TAURI_INTERNALS__: {} }); vi.mocked(invoke).mockRejectedValue(new Error('invoke error')); await backupDeletedSheet('dir', 'title', 'contents'); - expect(console.warn).toHaveBeenCalledWith('backupDeletedSheet failed', expect.any(Error)); + expect(logger.warn).toHaveBeenCalledWith('backupDeletedSheet failed', expect.any(Error)); }); }); @@ -369,7 +371,7 @@ describe('storage', () => { it('returns null if fetch fails', async () => { vi.mocked(fetch).mockRejectedValue(new Error('Network error')); const result = await fetchRates(); - expect(console.warn).toHaveBeenCalledWith('fetchRates failed', expect.any(Error)); + expect(logger.warn).toHaveBeenCalledWith('fetchRates failed', expect.any(Error)); expect(result).toBeNull(); }); @@ -404,7 +406,7 @@ describe('storage', () => { it('returns null if fetch fails', async () => { vi.mocked(fetch).mockRejectedValue(new Error('Network error')); const result = await fetchHistoricalRates('2024-01-01'); - expect(console.warn).toHaveBeenCalledWith('fetchHistoricalRates failed', '2024-01-01', expect.any(Error)); + expect(logger.warn).toHaveBeenCalledWith('fetchHistoricalRates failed', '2024-01-01', expect.any(Error)); expect(result).toBeNull(); }); diff --git a/src/storage.ts b/src/storage.ts index 9544485..39d4fe8 100644 --- a/src/storage.ts +++ b/src/storage.ts @@ -1,3 +1,5 @@ +import { logger } from "./logger"; + // Storage: Tauri commands in the app, localStorage fallback for `vite dev`. export interface DocMeta { @@ -79,7 +81,7 @@ export async function loadSettings(): Promise { : localStorage.getItem("summarum.settings"); if (raw) return { ...defaultSettingsData, ...JSON.parse(raw) }; } catch (e) { - console.warn("loadSettings failed", e); + logger.warn("loadSettings failed", e); } return { ...defaultSettingsData }; } @@ -99,7 +101,7 @@ export async function loadAppData(dataDir: string): Promise { : localStorage.getItem("summarum.documents"); if (raw) return JSON.parse(raw); } catch (e) { - console.warn("loadAppData failed", e); + logger.warn("loadAppData failed", e); } return null; } @@ -132,7 +134,7 @@ export async function flushAppData(): Promise { if (isTauri()) await invoke("save_documents", { dir: dirArg(currentDataDir), contents: raw }); else localStorage.setItem("summarum.documents", raw); } catch (e) { - console.warn("saveAppData failed", e); + logger.warn("saveAppData failed", e); } } @@ -150,7 +152,7 @@ export async function runBackups(dataDir: string, retentionDays: number): Promis try { await invoke("run_backups", { dir: dirArg(dataDir), retentionDays }); } catch (e) { - console.warn("runBackups failed", e); + logger.warn("runBackups failed", e); } } @@ -159,7 +161,7 @@ export async function backupDeletedSheet(dataDir: string, title: string, content try { await invoke("backup_deleted_sheet", { dir: dirArg(dataDir), title, contents }); } catch (e) { - console.warn("backupDeletedSheet failed", e); + logger.warn("backupDeletedSheet failed", e); } } @@ -205,7 +207,7 @@ export async function fetchRates(force = false): Promise { return { date: json.time_last_update_utc, rates: json.rates, fetchedAt: Math.floor(Date.now() / 1000) }; } } catch (e) { - console.warn("fetchRates failed", e); + logger.warn("fetchRates failed", e); } return null; } @@ -227,7 +229,7 @@ export async function fetchHistoricalRatesBatch(dates: string[]): Promise>("fetch_market_data", { symbols }); } catch (e) { - console.warn("fetchMarketData failed", e); + logger.warn("fetchMarketData failed", e); return {}; } } @@ -277,7 +279,7 @@ export async function loadExtensionScripts(): Promise<{ name: string; code: stri try { return await invoke<{ name: string; code: string }[]>("load_extensions"); } catch (e) { - console.warn("loadExtensions failed", e); + logger.warn("loadExtensions failed", e); return []; } } @@ -314,7 +316,7 @@ export async function onFileDrop(cb: (content: string) => void): Promise { const content = await invoke("read_text_file", { path }); cb(content); } catch (e) { - console.warn("file drop rejected", path, e); + logger.warn("file drop rejected", path, e); } } });