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
138 lines
4.7 KiB
TypeScript
138 lines
4.7 KiB
TypeScript
import { describe, it, expect } from 'vitest'
|
|
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
|
import { getVoiceCommandService } from '../../src/main/services/VoiceCommandService'
|
|
import { registerVoiceCommandHandlers } from '../../src/main/ipc/voice-command-handlers'
|
|
import { invokeIpc, useRedHarness } from './harness'
|
|
|
|
useRedHarness()
|
|
|
|
describe('유스케이스: 음성 단축키 매칭 / 토글 / 키워드 CRUD', () => {
|
|
it('초기에는 비활성이다', () => {
|
|
const svc = getVoiceCommandService()
|
|
svc.initialize()
|
|
expect(svc.isEnabled()).toBe(false)
|
|
})
|
|
|
|
it('비활성 상태에서는 키워드가 있어도 매칭하지 않는다', () => {
|
|
const svc = getVoiceCommandService()
|
|
svc.initialize()
|
|
svc.initDefaultKeywords()
|
|
const match = svc.match('번역해줘 이 문장')
|
|
expect(match.matched).toBe(false)
|
|
expect(match.cleanedText).toBe('번역해줘 이 문장')
|
|
})
|
|
|
|
it('활성 + 기본 키워드면 prefix 매칭한다', () => {
|
|
const svc = getVoiceCommandService()
|
|
svc.initialize()
|
|
svc.initDefaultKeywords()
|
|
svc.setEnabled(true)
|
|
const match = svc.match('번역해줘 이 문장')
|
|
expect(match.matched).toBe(true)
|
|
expect(match.instructionId).toBe('builtin-translate')
|
|
expect(match.cleanedText).toBe('이 문장')
|
|
expect(match.matchedKeyword).toBe('번역해줘')
|
|
})
|
|
|
|
it('요약 키워드도 매칭한다', () => {
|
|
const svc = getVoiceCommandService()
|
|
svc.initialize()
|
|
svc.initDefaultKeywords()
|
|
svc.setEnabled(true)
|
|
expect(svc.match('요약해줘 긴 글').instructionId).toBe('builtin-summarize')
|
|
})
|
|
|
|
it('매칭 실패 시 cleanedText 는 원문이다', () => {
|
|
const svc = getVoiceCommandService()
|
|
svc.initialize()
|
|
svc.initDefaultKeywords()
|
|
svc.setEnabled(true)
|
|
const match = svc.match('그냥 받아쓰기')
|
|
expect(match.matched).toBe(false)
|
|
expect(match.cleanedText).toBe('그냥 받아쓰기')
|
|
})
|
|
|
|
it('빈 텍스트는 매칭하지 않는다', () => {
|
|
const svc = getVoiceCommandService()
|
|
svc.initialize()
|
|
svc.initDefaultKeywords()
|
|
svc.setEnabled(true)
|
|
expect(svc.match(' ').matched).toBe(false)
|
|
})
|
|
|
|
it('사용자 키워드를 추가하면 contains 로 잡힌다', () => {
|
|
const svc = getVoiceCommandService()
|
|
svc.initialize()
|
|
svc.setEnabled(true)
|
|
svc.setKeywordsForInstruction('builtin-formal', [
|
|
{ keyword: '정중하게', matchMode: 'contains' },
|
|
])
|
|
const match = svc.match('이 메일 정중하게 써줘')
|
|
expect(match.matched).toBe(true)
|
|
expect(match.instructionId).toBe('builtin-formal')
|
|
})
|
|
|
|
it('같은 instruction 키워드를 덮어쓴다', () => {
|
|
const svc = getVoiceCommandService()
|
|
svc.initialize()
|
|
svc.setEnabled(true)
|
|
svc.setKeywordsForInstruction('builtin-formal', [
|
|
{ keyword: 'oldkw', matchMode: 'prefix' },
|
|
])
|
|
svc.setKeywordsForInstruction('builtin-formal', [
|
|
{ keyword: 'newkw', matchMode: 'prefix' },
|
|
])
|
|
expect(svc.match('oldkw x').matched).toBe(false)
|
|
expect(svc.match('newkw x').matched).toBe(true)
|
|
})
|
|
|
|
it('initDefaultKeywords 두 번은 규칙을 복제하지 않는다', () => {
|
|
const svc = getVoiceCommandService()
|
|
svc.initialize()
|
|
svc.initDefaultKeywords()
|
|
const n = svc.getAllRules().length
|
|
svc.initDefaultKeywords()
|
|
expect(svc.getAllRules().length).toBe(n)
|
|
})
|
|
|
|
it('비활성화하면 다시 매칭하지 않는다', () => {
|
|
const svc = getVoiceCommandService()
|
|
svc.initialize()
|
|
svc.initDefaultKeywords()
|
|
svc.setEnabled(true)
|
|
svc.setEnabled(false)
|
|
expect(svc.match('번역해줘 x').matched).toBe(false)
|
|
})
|
|
|
|
it('IPC setEnabled / isEnabled 왕복', async () => {
|
|
getVoiceCommandService().initialize()
|
|
registerVoiceCommandHandlers()
|
|
await invokeIpc(IPC_CHANNELS.VOICE_COMMAND.SET_ENABLED, { enabled: true })
|
|
const res = await invokeIpc(IPC_CHANNELS.VOICE_COMMAND.IS_ENABLED)
|
|
expect(res.success).toBe(true)
|
|
if (res.success) expect(res.data).toBe(true)
|
|
})
|
|
|
|
it('IPC getAll 은 배열이다', async () => {
|
|
const svc = getVoiceCommandService()
|
|
svc.initialize()
|
|
svc.initDefaultKeywords()
|
|
registerVoiceCommandHandlers()
|
|
const res = await invokeIpc(IPC_CHANNELS.VOICE_COMMAND.GET_ALL)
|
|
expect(res.success).toBe(true)
|
|
if (res.success) expect(Array.isArray(res.data)).toBe(true)
|
|
})
|
|
|
|
it('IPC setKeywords 후 매칭된다', async () => {
|
|
const svc = getVoiceCommandService()
|
|
svc.initialize()
|
|
svc.setEnabled(true)
|
|
registerVoiceCommandHandlers()
|
|
const set = await invokeIpc(IPC_CHANNELS.VOICE_COMMAND.SET_KEYWORDS, {
|
|
instructionId: 'builtin-translate',
|
|
keywords: [{ keyword: '영작', matchMode: 'prefix' }],
|
|
})
|
|
expect(set.success).toBe(true)
|
|
expect(svc.match('영작 hello').matched).toBe(true)
|
|
})
|
|
})
|