112 lines
3.2 KiB
TypeScript
112 lines
3.2 KiB
TypeScript
/**
|
|
* Vitest Test Setup
|
|
* Global test configuration and mocks
|
|
*/
|
|
import { vi } from 'vitest';
|
|
import '@testing-library/jest-dom';
|
|
|
|
// Provide a minimal `electron` mock so tests that transitively import
|
|
// main-process code (logger, store, etc.) don't blow up when the Electron
|
|
// binary is not present (e.g. CI with ELECTRON_SKIP_BINARY_DOWNLOAD=1).
|
|
// Individual test files can override with their own vi.mock('electron', ...).
|
|
vi.mock('electron', () => ({
|
|
app: {
|
|
getPath: vi.fn().mockReturnValue('/tmp/clawx-test'),
|
|
getVersion: vi.fn().mockReturnValue('0.0.0-test'),
|
|
getName: vi.fn().mockReturnValue('clawx-test'),
|
|
isPackaged: false,
|
|
isReady: vi.fn().mockResolvedValue(true),
|
|
on: vi.fn(),
|
|
off: vi.fn(),
|
|
quit: vi.fn(),
|
|
whenReady: vi.fn().mockResolvedValue(undefined),
|
|
},
|
|
BrowserWindow: vi.fn(),
|
|
ipcMain: { on: vi.fn(), handle: vi.fn(), removeHandler: vi.fn() },
|
|
dialog: { showOpenDialog: vi.fn(), showMessageBox: vi.fn() },
|
|
shell: { openExternal: vi.fn() },
|
|
session: { defaultSession: { webRequest: { onBeforeSendHeaders: vi.fn() } } },
|
|
utilityProcess: {},
|
|
}));
|
|
|
|
// Mock window.electron API
|
|
const mockElectron = {
|
|
ipcRenderer: {
|
|
invoke: vi.fn(),
|
|
on: vi.fn(),
|
|
once: vi.fn(),
|
|
off: vi.fn(),
|
|
},
|
|
openExternal: vi.fn(),
|
|
getPathForFile: vi.fn((file: File) => (file as File & { path?: string }).path ?? ''),
|
|
platform: 'darwin',
|
|
isDev: true,
|
|
};
|
|
|
|
if (typeof window !== 'undefined') {
|
|
Object.defineProperty(window, 'electron', {
|
|
value: mockElectron,
|
|
writable: true,
|
|
});
|
|
}
|
|
|
|
// Vitest/jsdom can expose an opaque-origin window where localStorage is absent.
|
|
// The renderer stores use it for small UI caches, so provide the browser shape
|
|
// expected by unit tests when the environment does not.
|
|
if (typeof window !== 'undefined') {
|
|
let needsLocalStorageMock: boolean;
|
|
try {
|
|
needsLocalStorageMock = !window.localStorage;
|
|
} catch {
|
|
needsLocalStorageMock = true;
|
|
}
|
|
|
|
if (needsLocalStorageMock) {
|
|
const storage = new Map<string, string>();
|
|
const localStorageMock: Storage = {
|
|
get length() {
|
|
return storage.size;
|
|
},
|
|
clear: vi.fn(() => storage.clear()),
|
|
getItem: vi.fn((key: string) => storage.get(key) ?? null),
|
|
key: vi.fn((index: number) => Array.from(storage.keys())[index] ?? null),
|
|
removeItem: vi.fn((key: string) => {
|
|
storage.delete(key);
|
|
}),
|
|
setItem: vi.fn((key: string, value: string) => {
|
|
storage.set(key, String(value));
|
|
}),
|
|
};
|
|
Object.defineProperty(window, 'localStorage', {
|
|
value: localStorageMock,
|
|
configurable: true,
|
|
});
|
|
Object.defineProperty(globalThis, 'localStorage', {
|
|
value: localStorageMock,
|
|
configurable: true,
|
|
});
|
|
}
|
|
}
|
|
|
|
// Mock matchMedia
|
|
if (typeof window !== 'undefined') {
|
|
Object.defineProperty(window, 'matchMedia', {
|
|
writable: true,
|
|
value: vi.fn().mockImplementation((query) => ({
|
|
matches: false,
|
|
media: query,
|
|
onchange: null,
|
|
addListener: vi.fn(),
|
|
removeListener: vi.fn(),
|
|
addEventListener: vi.fn(),
|
|
removeEventListener: vi.fn(),
|
|
dispatchEvent: vi.fn(),
|
|
})),
|
|
});
|
|
}
|
|
|
|
// Reset mocks after each test
|
|
afterEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|