d3ro-voice/apps/desktop/tests/setup.ts
2026-08-29 19:19:19 +09:00

156 lines
4.3 KiB
TypeScript

// tests/setup.ts
// vitest 글로벌 셋업: electron 모듈 모킹
import { vi } from 'vitest'
import os from 'os'
import path from 'path'
import fs from 'fs'
const TEST_USER_DATA = path.join(os.tmpdir(), 'd3ro-vitest-userData')
const TEST_DOCS = path.join(os.tmpdir(), 'd3ro-vitest-docs')
fs.mkdirSync(TEST_USER_DATA, { recursive: true })
fs.mkdirSync(TEST_DOCS, { recursive: true })
// electron 모듈 모킹 — 테스트에서 electron import 시 에러 방지
vi.mock('electron', () => ({
app: {
getPath: vi.fn((name: string) => {
if (name === 'temp') return os.tmpdir()
if (name === 'documents') return TEST_DOCS
return TEST_USER_DATA
}),
getVersion: vi.fn(() => '1.0.0'),
quit: vi.fn(),
on: vi.fn(),
whenReady: vi.fn(() => Promise.resolve()),
getLoginItemSettings: vi.fn(() => ({ openAtLogin: false })),
setLoginItemSettings: vi.fn(),
isPackaged: false,
getAppPath: vi.fn(() => TEST_USER_DATA),
},
ipcMain: {
handle: vi.fn(),
on: vi.fn(),
removeHandler: vi.fn(),
},
BrowserWindow: Object.assign(vi.fn(), {
getAllWindows: vi.fn(() => []),
}),
Tray: vi.fn(),
Menu: vi.fn(),
nativeImage: {
createFromPath: vi.fn(),
},
dialog: {
showErrorBox: vi.fn(),
showSaveDialog: vi.fn(async () => ({ canceled: true, filePath: undefined })),
showOpenDialog: vi.fn(async () => ({ canceled: true, filePaths: [] })),
},
session: {
defaultSession: {
setDisplayMediaRequestHandler: vi.fn(),
},
},
desktopCapturer: {
getSources: vi.fn(async () => []),
},
screen: {
getPrimaryDisplay: vi.fn(() => ({
workArea: { x: 0, y: 0, width: 1920, height: 1080 },
})),
},
clipboard: {
readText: vi.fn(() => ''),
writeText: vi.fn(),
readHTML: vi.fn(() => ''),
readRTF: vi.fn(() => ''),
readImage: vi.fn(() => ({ isEmpty: () => true, toPNG: () => Buffer.alloc(0) })),
write: vi.fn(),
},
shell: {
openExternal: vi.fn(async () => undefined),
},
safeStorage: {
isEncryptionAvailable: vi.fn(() => false),
encryptString: vi.fn((s: string) => Buffer.from(s, 'utf-8')),
decryptString: vi.fn((b: Buffer) => b.toString('utf-8')),
},
Notification: vi.fn(),
globalShortcut: {
register: vi.fn(() => true),
unregister: vi.fn(),
unregisterAll: vi.fn(),
isRegistered: vi.fn(() => false),
},
}))
// Unit tests must not load the native global keyboard hook. Linux shell runners
// intentionally do not provide an X11 session or libXrandr, and product-level
// hook behaviour is covered by runtime/E2E validation instead.
vi.mock('uiohook-napi', () => ({
uIOhook: {
on: vi.fn(),
removeListener: vi.fn(),
start: vi.fn(),
stop: vi.fn(),
},
UiohookKey: new Proxy<Record<string, number>>({}, {
get: (_target, property) => Array.from(String(property)).reduce(
(value, character) => ((value * 31) + character.charCodeAt(0)) & 0x7fffffff,
17,
),
}),
}))
// WindowManager 모킹 — VoiceModeService가 import하므로 필요
vi.mock('../src/main/windows/WindowManager', () => ({
showRecordingTip: vi.fn(),
hideRecordingTip: vi.fn(),
updateRecordingTipState: vi.fn(),
sendAudioLevelToTip: vi.fn(),
sendPartialTranscriptToTip: vi.fn(),
showResultPopup: vi.fn(),
hideResultPopup: vi.fn(),
getMainWindow: vi.fn(),
createMainWindow: vi.fn(),
hideCaptionOverlay: vi.fn(),
showCaptionOverlay: vi.fn(),
sendToCaptionOverlay: vi.fn(),
reapplyThemeToAllPopups: vi.fn(),
}))
// electron-log 모킹
vi.mock('electron-log', () => {
const noop = vi.fn()
return {
default: {
info: noop,
warn: noop,
error: noop,
debug: noop,
create: () => ({
info: noop,
warn: noop,
error: noop,
debug: noop,
}),
},
}
})
// electron-store v10 ESM — 템플릿 서비스 생성자에서 동기 import
vi.mock('electron-store', () => {
class MemoryStore<T extends Record<string, unknown>> {
store: T
constructor(opts?: { defaults?: T; name?: string }) {
this.store = { ...(opts?.defaults as T) }
}
get<K extends keyof T>(key: K, def?: T[K]): T[K] {
return (this.store[key] ?? def) as T[K]
}
set<K extends keyof T>(key: K, value: T[K]): void {
this.store[key] = value
}
}
return { default: MemoryStore }
})