feat: complete release preparation, 10+ ad mediation, CI/CD, and docker deployment
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
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
This commit is contained in:
parent
5cd1de6859
commit
708e20f747
406 changed files with 42464 additions and 6199 deletions
214
apps/desktop/tests/red/ipc-surfaces.usecase.test.ts
Normal file
214
apps/desktop/tests/red/ipc-surfaces.usecase.test.ts
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
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)
|
||||
})
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue