d3ro-voice/apps/desktop/tests/red/ipc-surfaces.usecase.test.ts
Yun Chan 708e20f747
Some checks failed
CI Pipeline / Code Quality & Typecheck (push) Waiting to run
CI Pipeline / Test Suite (macos-latest) (push) Blocked by required conditions
CI Pipeline / Test Suite (ubuntu-latest) (push) Blocked by required conditions
CI Pipeline / Test Suite (windows-latest) (push) Blocked by required conditions
CI Pipeline / Build Validation (admin) (push) Blocked by required conditions
CI Pipeline / Build Validation (desktop) (push) Blocked by required conditions
Deploy Landing Page / deploy (push) Blocked by required conditions
Deploy Landing Page / build (push) Waiting to run
Release & Packaging Pipeline / Build & Publish Admin Docker Image (push) Failing after 8s
Release & Code Signing CA Pipeline / build-and-sign-windows (push) Failing after 1m51s
Build macOS / Build & Package (macOS) (push) Failing after 4s
Build macOS / Build & Package (macOS)-1 (push) Failing after 5s
Release & Code Signing CA Pipeline / build-and-sign-macos (push) Failing after 3s
Release & Packaging Pipeline / Package macOS Desktop App (push) Failing after 4s
Release & Packaging Pipeline / Package Windows Desktop App (push) Failing after 2m28s
Release & Packaging Pipeline / Publish Official GitHub Release (push) Has been skipped
feat: complete release preparation, 10+ ad mediation, CI/CD, and docker deployment
2026-08-20 11:12:05 +09:00

214 lines
8.4 KiB
TypeScript

import { describe, it, expect, vi } from 'vitest'
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
import { ErrorCode } from '@d3ro/core/errors'
import { configGet } from '../../src/main/services/ConfigService'
import { registerHotkeyHandlers } from '../../src/main/ipc/hotkey-handlers'
import { registerCaptionHandlers } from '../../src/main/ipc/caption-handlers'
import { registerRAGHandlers } from '../../src/main/ipc/rag-handlers'
import { registerVoiceConversationHandlers } from '../../src/main/ipc/voice-conversation-handlers'
import { registerVoiceActionHandlers } from '../../src/main/ipc/voice-action-handlers'
import { registerFileTranscriptionHandlers } from '../../src/main/ipc/file-transcription-handlers'
import { registerMeetingModeHandlers } from '../../src/main/ipc/meeting-mode-handlers'
import { registerTemplateHandlers } from '../../src/main/ipc/template-handlers'
import { registerMeetingDocTemplateHandlers } from '../../src/main/ipc/meeting-doc-template-handlers'
import { invokeIpc, useRedHarness } from './harness'
vi.mock('../../src/main/services/HotkeyService', () => ({
getHotkeyService: () => ({
loadFromConfig: vi.fn(),
start: vi.fn(),
stop: vi.fn(),
on: vi.fn(),
off: vi.fn(),
}),
}))
useRedHarness()
const SAMPLE_BINDING = {
keyCode: 65,
ctrl: true,
alt: false,
shift: false,
meta: false,
displayLabel: 'Ctrl+A',
}
describe('유스케이스: 핫키 / 캡션 / RAG / 대화 / 액션 / 파일전사 / 회의 IPC', () => {
it('핫키 받아쓰기 단축키를 읽고 쓴다', async () => {
registerHotkeyHandlers()
const set = await invokeIpc(IPC_CHANNELS.HOTKEY.SET_DICTATION_SHORTCUT, { binding: SAMPLE_BINDING })
expect(set.success).toBe(true)
const get = await invokeIpc(IPC_CHANNELS.HOTKEY.GET_DICTATION_SHORTCUT)
expect(get.success).toBe(true)
if (get.success) expect(get.data.displayLabel).toBe('Ctrl+A')
})
it('핫키 핸즈프리 단축키를 읽고 쓴다', async () => {
registerHotkeyHandlers()
await invokeIpc(IPC_CHANNELS.HOTKEY.SET_HANDS_FREE_SHORTCUT, { binding: SAMPLE_BINDING })
const get = await invokeIpc(IPC_CHANNELS.HOTKEY.GET_HANDS_FREE_SHORTCUT)
expect(get.success).toBe(true)
})
it('핫키 명령 단축키를 읽고 쓴다', async () => {
registerHotkeyHandlers()
await invokeIpc(IPC_CHANNELS.HOTKEY.SET_COMMAND_SHORTCUT, { binding: SAMPLE_BINDING })
const get = await invokeIpc(IPC_CHANNELS.HOTKEY.GET_COMMAND_SHORTCUT)
expect(get.success).toBe(true)
})
it('핫키 자막 단축키를 읽고 쓴다', async () => {
registerHotkeyHandlers()
await invokeIpc(IPC_CHANNELS.HOTKEY.SET_CAPTION_SHORTCUT, { binding: SAMPLE_BINDING })
const get = await invokeIpc(IPC_CHANNELS.HOTKEY.GET_CAPTION_SHORTCUT)
expect(get.success).toBe(true)
})
it('핫키 활성 토글을 끈다', async () => {
registerHotkeyHandlers()
const set = await invokeIpc(IPC_CHANNELS.HOTKEY.SET_ENABLED, { enabled: false })
expect(set.success).toBe(true)
const get = await invokeIpc(IPC_CHANNELS.HOTKEY.IS_ENABLED)
expect(get.success).toBe(true)
if (get.success) expect(get.data).toBe(false)
expect(configGet('hotkeyEnabled')).toBe(false)
})
it('핫키 활성 토글을 켠다', async () => {
registerHotkeyHandlers()
await invokeIpc(IPC_CHANNELS.HOTKEY.SET_ENABLED, { enabled: true })
const get = await invokeIpc(IPC_CHANNELS.HOTKEY.IS_ENABLED)
if (get.success) expect(get.data).toBe(true)
})
it('캡션 초기 상태를 읽는다', async () => {
registerCaptionHandlers()
const res = await invokeIpc(IPC_CHANNELS.CAPTION.GET_STATE)
expect(res.success).toBe(true)
if (res.success) expect(res.data).toBe('inactive')
})
it('캡션 설정을 바꾼다', async () => {
registerCaptionHandlers()
const res = await invokeIpc(IPC_CHANNELS.CAPTION.SET_CONFIG, { fontSize: 20, opacity: 0.5 })
expect(res.success).toBe(true)
})
it('캡션 시작 실패는 success:false 로 나온다', async () => {
registerCaptionHandlers()
const res = await invokeIpc(IPC_CHANNELS.CAPTION.START)
if (res.success) {
const stop = await invokeIpc(IPC_CHANNELS.CAPTION.STOP)
expect(stop.success).toBe(true)
} else {
expect(res.error.code).toBeTruthy()
}
})
it('RAG 문서 목록 IPC', async () => {
registerRAGHandlers()
const res = await invokeIpc(IPC_CHANNELS.RAG.GET_DOCUMENTS)
expect(res.success).toBe(true)
if (res.success) expect(Array.isArray(res.data)).toBe(true)
})
it('RAG 질의 실패는 에러다', async () => {
registerRAGHandlers()
const res = await invokeIpc(IPC_CHANNELS.RAG.QUERY, { query: 'hello', topK: 3 })
expect(res.success).toBe(false)
})
it('대화 상태를 읽는다', async () => {
registerVoiceConversationHandlers()
const res = await invokeIpc(IPC_CHANNELS.VOICE_CONVERSATION.GET_STATE)
expect(res.success).toBe(true)
})
it('대화 히스토리를 읽는다', async () => {
registerVoiceConversationHandlers()
const res = await invokeIpc(IPC_CHANNELS.VOICE_CONVERSATION.GET_HISTORY)
expect(res.success).toBe(true)
if (res.success) expect(Array.isArray(res.data)).toBe(true)
})
it('세션 없이 대화 메시지는 실패한다', async () => {
registerVoiceConversationHandlers()
const res = await invokeIpc(IPC_CHANNELS.VOICE_CONVERSATION.SEND_MESSAGE, { text: 'hi' })
expect(res.success).toBe(false)
})
it('보이스 액션 프리셋을 읽는다', async () => {
registerVoiceActionHandlers()
const res = await invokeIpc(IPC_CHANNELS.VOICE_ACTION.GET_PRESETS)
expect(res.success).toBe(true)
if (res.success) expect((res.data as unknown[]).length).toBeGreaterThan(0)
})
it('보이스 액션 활성 토글', async () => {
registerVoiceActionHandlers()
await invokeIpc(IPC_CHANNELS.VOICE_ACTION.SET_ENABLED, { enabled: true })
const res = await invokeIpc(IPC_CHANNELS.VOICE_ACTION.IS_ENABLED)
expect(res.success).toBe(true)
if (res.success) expect(res.data).toBe(true)
})
it('파일 전사 상태를 읽는다', async () => {
registerFileTranscriptionHandlers()
const res = await invokeIpc(IPC_CHANNELS.FILE_TRANSCRIPTION.GET_STATE)
expect(res.success).toBe(true)
if (res.success) expect(res.data.state).toBe('idle')
})
it('파일 전사 잘못된 경로는 실패한다', async () => {
registerFileTranscriptionHandlers()
const res = await invokeIpc(IPC_CHANNELS.FILE_TRANSCRIPTION.START, { filePath: 'nope.txt' })
expect(res.success).toBe(false)
})
it('회의 상태를 읽는다', async () => {
registerMeetingModeHandlers()
const res = await invokeIpc(IPC_CHANNELS.MEETING_MODE.GET_STATE)
expect(res.success).toBe(true)
})
it('회의 세션 목록을 읽는다', async () => {
registerMeetingModeHandlers()
const res = await invokeIpc(IPC_CHANNELS.MEETING_MODE.GET_SESSIONS, { page: 1, pageSize: 10 })
expect(res.success).toBe(true)
})
it('없는 회의 세션 조회는 실패한다', async () => {
registerMeetingModeHandlers()
const res = await invokeIpc(IPC_CHANNELS.MEETING_MODE.GET_SESSION, { sessionId: 'missing' })
expect(res.success).toBe(false)
if (!res.success) expect(res.error.code).toBe(ErrorCode.MeetingSessionNotFound)
})
it('딕테이션 템플릿 목록 IPC', async () => {
registerTemplateHandlers()
const res = await invokeIpc(IPC_CHANNELS.DICTATION_TEMPLATE.GET_ALL)
expect(res.success).toBe(true)
if (res.success) expect((res.data as unknown[]).length).toBeGreaterThan(0)
})
it('없는 딕테이션 템플릿 세션 시작은 실패한다', async () => {
registerTemplateHandlers()
const res = await invokeIpc(IPC_CHANNELS.DICTATION_TEMPLATE.START_SESSION, { templateId: 'missing' })
expect(res.success).toBe(false)
})
it('회의 문서 템플릿 목록 IPC', async () => {
registerMeetingDocTemplateHandlers()
const res = await invokeIpc(IPC_CHANNELS.MEETING_DOC_TEMPLATE.GET_ALL)
expect(res.success).toBe(true)
if (res.success) expect((res.data as unknown[]).length).toBeGreaterThan(0)
})
it('빌트인 회의 템플릿 삭제는 실패한다', async () => {
registerMeetingDocTemplateHandlers()
const res = await invokeIpc(IPC_CHANNELS.MEETING_DOC_TEMPLATE.DELETE, { id: 'builtin-minutes' })
expect(res.success).toBe(false)
if (!res.success) expect(res.error.code).toBe(ErrorCode.MeetingDocTemplateBuiltinDelete)
})
})