- Add Vitest + jsdom test framework with V8 coverage - 118 tests across 7 test files covering AppState, ProgressManager, EpisodeManager, FileListManager, fileUtils, main.js logic, renderer escapeHtml, preload module polyfill - Fix async bug in extractFileDuration (await in non-async callback) - CI enforces 85% coverage threshold on testable modules - Exclude Electron IPC wrappers (FileManager, SearchManager, TagManager, ModalManager, UIManager) from coverage as they require Electron runtime
156 lines
3.2 KiB
JavaScript
156 lines
3.2 KiB
JavaScript
import { vi } from 'vitest';
|
|
|
|
// Mock Electron modules globally
|
|
vi.mock('electron', () => ({
|
|
app: {
|
|
whenReady: vi.fn(() => Promise.resolve()),
|
|
on: vi.fn(),
|
|
quit: vi.fn(),
|
|
},
|
|
BrowserWindow: vi.fn().mockImplementation(() => ({
|
|
loadFile: vi.fn(),
|
|
webContents: {
|
|
send: vi.fn(),
|
|
},
|
|
onClose: vi.fn(),
|
|
})),
|
|
ipcMain: {
|
|
handle: vi.fn(),
|
|
on: vi.fn(),
|
|
},
|
|
dialog: {
|
|
showOpenDialog: vi.fn(),
|
|
},
|
|
contextBridge: {
|
|
exposeInMainWorld: vi.fn(),
|
|
},
|
|
ipcRenderer: {
|
|
invoke: vi.fn(),
|
|
on: vi.fn(),
|
|
},
|
|
}));
|
|
|
|
// Mock fluent-ffmpeg
|
|
vi.mock('fluent-ffmpeg', () => ({
|
|
ffprobe: vi.fn((filePath, callback) => {
|
|
callback(null, {
|
|
format: { duration: 65 },
|
|
streams: [
|
|
{
|
|
codec_type: 'video',
|
|
width: 1920,
|
|
height: 1080,
|
|
r_frame_rate: '30/1',
|
|
},
|
|
],
|
|
});
|
|
}),
|
|
}));
|
|
|
|
// Mock dotenv
|
|
vi.mock('dotenv', () => ({
|
|
config: vi.fn(),
|
|
}));
|
|
|
|
// Mock fs
|
|
vi.mock('fs', () => ({
|
|
default: {
|
|
existsSync: vi.fn(() => true),
|
|
readFileSync: vi.fn(() => ''),
|
|
writeFileSync: vi.fn(),
|
|
appendFileSync: vi.fn(),
|
|
statSync: vi.fn(() => ({
|
|
isFile: vi.fn(() => true),
|
|
isDirectory: vi.fn(() => false),
|
|
size: 1024,
|
|
mtime: new Date(),
|
|
})),
|
|
accessSync: vi.fn(),
|
|
renameSync: vi.fn(),
|
|
mkdirSync: vi.fn(),
|
|
rmSync: vi.fn(),
|
|
},
|
|
existsSync: vi.fn(() => true),
|
|
readFileSync: vi.fn(() => ''),
|
|
writeFileSync: vi.fn(),
|
|
appendFileSync: vi.fn(),
|
|
statSync: vi.fn(() => ({
|
|
isFile: vi.fn(() => true),
|
|
isDirectory: vi.fn(() => false),
|
|
size: 1024,
|
|
mtime: new Date(),
|
|
})),
|
|
accessSync: vi.fn(),
|
|
renameSync: vi.fn(),
|
|
mkdirSync: vi.fn(),
|
|
rmSync: vi.fn(),
|
|
constants: { W_OK: 2 },
|
|
promises: {
|
|
readdir: vi.fn(() => Promise.resolve(['file1.mp4', 'file2.mkv', 'folder1'])),
|
|
stat: vi.fn(() =>
|
|
Promise.resolve({
|
|
isFile: () => true,
|
|
isDirectory: () => false,
|
|
size: 1024,
|
|
mtime: new Date(),
|
|
})
|
|
),
|
|
},
|
|
}));
|
|
|
|
// Mock path
|
|
vi.mock('path', () => ({
|
|
default: {
|
|
join: (...args) => args.join('/'),
|
|
dirname: (p) => p.substring(0, p.lastIndexOf('/')),
|
|
basename: (p) => p.split('/').pop(),
|
|
extname: (p) => '.' + p.split('.').pop(),
|
|
sep: '/',
|
|
resolve: (...args) => args.join('/'),
|
|
},
|
|
join: (...args) => args.join('/'),
|
|
dirname: (p) => p.substring(0, p.lastIndexOf('/')),
|
|
basename: (p) => p.split('/').pop(),
|
|
extname: (p) => '.' + p.split('.').pop(),
|
|
sep: '/',
|
|
resolve: (...args) => args.join('/'),
|
|
}));
|
|
|
|
// Mock child_process
|
|
vi.mock('child_process', () => ({
|
|
execFile: vi.fn((cmd, args, callback) => {
|
|
callback(null, '', '');
|
|
}),
|
|
exec: vi.fn((cmd, callback) => {
|
|
callback(null, '', '');
|
|
}),
|
|
}));
|
|
|
|
// Mock axios
|
|
vi.mock('axios', () => ({
|
|
default: {
|
|
get: vi.fn(() =>
|
|
Promise.resolve({
|
|
data: {
|
|
data: {
|
|
id: 'series-12345',
|
|
name: 'Test Show',
|
|
seasons: [],
|
|
},
|
|
},
|
|
})
|
|
),
|
|
post: vi.fn(() =>
|
|
Promise.resolve({
|
|
data: {
|
|
data: {
|
|
token: 'test-token',
|
|
},
|
|
},
|
|
})
|
|
),
|
|
},
|
|
}));
|
|
|
|
globalThis.__dirname = '/tmp/MovieMapper';
|