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
214 lines
8.4 KiB
TypeScript
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)
|
|
})
|
|
})
|