Files
hikari-desktop/vitest.setup.ts
T
hikari d3bb62210d
Security Scan and Upload / Security & DefectDojo Upload (pull_request) Successful in 53s
CI / Lint & Test (pull_request) Failing after 5m54s
CI / Build Linux (pull_request) Has been skipped
CI / Build Windows (cross-compile) (pull_request) Has been skipped
style: fix lint errors in test files
- Remove unused imports in config.test.ts and conversations.test.ts
- Remove unused handler variable in tauri.test.ts
- Remove unused _args parameter in vitest.setup.ts mock
- Add coverage/ to eslint ignore list
2026-01-25 23:28:45 -08:00

289 lines
7.8 KiB
TypeScript

import "@testing-library/jest-dom/vitest";
import { vi } from "vitest";
// Mock Tauri invoke API
const mockInvokeResults: Record<string, unknown> = {};
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<string, Array<(event: { payload: unknown }) => 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<string, string> = {};
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();
});