import "@testing-library/jest-dom/vitest"; import { vi, beforeEach } from "vitest"; // Mock Tauri invoke API const mockInvokeResults: Record = {}; export function setMockInvokeResult(command: string, result: unknown) { mockInvokeResults[command] = result; } export function clearMockInvokeResults() { Object.keys(mockInvokeResults).forEach((key) => delete mockInvokeResults[key]); } vi.mock("@tauri-apps/api/core", () => ({ invoke: vi.fn((command: string) => { if (command in mockInvokeResults) { const result = mockInvokeResults[command]; if (result instanceof Error) { return Promise.reject(result); } return Promise.resolve(result); } // Default return values for common commands switch (command) { case "get_config": return Promise.resolve({ model: null, api_key: null, custom_instructions: null, mcp_servers_json: null, auto_granted_tools: [], theme: "dark", greeting_enabled: true, greeting_custom_prompt: null, notifications_enabled: true, notification_volume: 0.7, always_on_top: false, update_checks_enabled: true, character_panel_width: null, font_size: 14, minimize_to_tray: false, streamer_mode: false, streamer_hide_paths: false, compact_mode: false, profile_name: null, profile_avatar_path: null, profile_bio: null, custom_theme_colors: {}, }); case "list_quick_actions": return Promise.resolve([]); case "list_snippets": return Promise.resolve([]); case "list_sessions": return Promise.resolve([]); case "get_usage_stats": return Promise.resolve({ total_messages: 0, total_sessions: 0, total_tokens: 0, total_cost: 0, }); case "get_persisted_stats": return Promise.resolve({ lifetime_messages: 0, lifetime_sessions: 0, lifetime_tokens: 0, lifetime_cost: 0, achievements: [], unlocked_achievements: [], }); case "load_saved_achievements": return Promise.resolve([]); case "list_clipboard_entries": return Promise.resolve([]); case "cleanup_temp_files": return Promise.resolve(); case "validate_directory": return Promise.resolve(true); case "git_status": return Promise.resolve({ branch: "main", files: [], ahead: 0, behind: 0, }); default: return Promise.resolve(null); } }), })); // Mock Tauri event API const eventListeners: Map void>> = new Map(); export function emitMockEvent(eventName: string, payload: unknown) { const listeners = eventListeners.get(eventName) || []; listeners.forEach((listener) => listener({ payload })); } export function clearMockEventListeners() { eventListeners.clear(); } vi.mock("@tauri-apps/api/event", () => ({ listen: vi.fn((eventName: string, handler: (event: { payload: unknown }) => void) => { const listeners = eventListeners.get(eventName) || []; listeners.push(handler); eventListeners.set(eventName, listeners); // Return an unlisten function return Promise.resolve(() => { const currentListeners = eventListeners.get(eventName) || []; const index = currentListeners.indexOf(handler); if (index > -1) { currentListeners.splice(index, 1); } }); }), emit: vi.fn(), })); // Mock Tauri plugins vi.mock("@tauri-apps/plugin-dialog", () => ({ save: vi.fn(() => Promise.resolve(null)), open: vi.fn(() => Promise.resolve(null)), message: vi.fn(() => Promise.resolve()), ask: vi.fn(() => Promise.resolve(true)), confirm: vi.fn(() => Promise.resolve(true)), })); vi.mock("@tauri-apps/plugin-fs", () => ({ writeTextFile: vi.fn(() => Promise.resolve()), readTextFile: vi.fn(() => Promise.resolve("{}")), exists: vi.fn(() => Promise.resolve(false)), mkdir: vi.fn(() => Promise.resolve()), remove: vi.fn(() => Promise.resolve()), readDir: vi.fn(() => Promise.resolve([])), })); vi.mock("@tauri-apps/plugin-opener", () => ({ openPath: vi.fn(() => Promise.resolve()), openUrl: vi.fn(() => Promise.resolve()), })); vi.mock("@tauri-apps/plugin-notification", () => ({ sendNotification: vi.fn(() => Promise.resolve()), requestPermission: vi.fn(() => Promise.resolve("granted")), isPermissionGranted: vi.fn(() => Promise.resolve(true)), })); vi.mock("@tauri-apps/plugin-clipboard-manager", () => ({ writeText: vi.fn(() => Promise.resolve()), readText: vi.fn(() => Promise.resolve("")), writeImage: vi.fn(() => Promise.resolve()), readImage: vi.fn(() => Promise.resolve(null)), })); vi.mock("@tauri-apps/plugin-os", () => ({ platform: vi.fn(() => Promise.resolve("linux")), arch: vi.fn(() => Promise.resolve("x86_64")), type: vi.fn(() => Promise.resolve("Linux")), version: vi.fn(() => Promise.resolve("1.0.0")), })); vi.mock("@tauri-apps/plugin-http", () => ({ fetch: vi.fn(() => Promise.resolve({ ok: true, status: 200, json: () => Promise.resolve({}), text: () => Promise.resolve(""), }) ), })); // Mock browser APIs class MockAudioElement { src = ""; volume = 1; loop = false; currentTime = 0; paused = true; preload = "auto"; onloadeddata: (() => void) | null = null; onended: (() => void) | null = null; onerror: ((e: Event) => void) | null = null; play() { this.paused = false; return Promise.resolve(); } pause() { this.paused = true; } load() { if (this.onloadeddata) { setTimeout(() => this.onloadeddata?.(), 0); } } addEventListener(event: string, handler: () => void) { if (event === "loadeddata") this.onloadeddata = handler; if (event === "ended") this.onended = handler; } removeEventListener() { // No-op for tests } } // @ts-expect-error - Mock Audio constructor globalThis.Audio = MockAudioElement; // Mock localStorage const localStorageStore: Record = {}; Object.defineProperty(globalThis, "localStorage", { value: { getItem: vi.fn((key: string) => localStorageStore[key] || null), setItem: vi.fn((key: string, value: string) => { localStorageStore[key] = value; }), removeItem: vi.fn((key: string) => { delete localStorageStore[key]; }), clear: vi.fn(() => { Object.keys(localStorageStore).forEach((key) => delete localStorageStore[key]); }), key: vi.fn((index: number) => Object.keys(localStorageStore)[index] || null), get length() { return Object.keys(localStorageStore).length; }, }, writable: true, }); // Mock matchMedia Object.defineProperty(globalThis, "matchMedia", { writable: true, value: vi.fn((query: string) => ({ matches: query.includes("dark"), media: query, onchange: null, addListener: vi.fn(), removeListener: vi.fn(), addEventListener: vi.fn(), removeEventListener: vi.fn(), dispatchEvent: vi.fn(), })), }); // Mock ResizeObserver class MockResizeObserver { observe = vi.fn(); unobserve = vi.fn(); disconnect = vi.fn(); } globalThis.ResizeObserver = MockResizeObserver as unknown as typeof ResizeObserver; // Mock IntersectionObserver class MockIntersectionObserver { observe = vi.fn(); unobserve = vi.fn(); disconnect = vi.fn(); } globalThis.IntersectionObserver = MockIntersectionObserver as unknown as typeof IntersectionObserver; // Mock requestAnimationFrame globalThis.requestAnimationFrame = vi.fn((callback) => { return setTimeout(callback, 0) as unknown as number; }); globalThis.cancelAnimationFrame = vi.fn((id) => { clearTimeout(id); }); // Reset all mocks before each test beforeEach(() => { vi.clearAllMocks(); clearMockInvokeResults(); clearMockEventListeners(); });