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
180 lines
6.7 KiB
TypeScript
180 lines
6.7 KiB
TypeScript
import { describe, it, expect } from 'vitest'
|
|
import { D3ROError, ErrorCode } from '@d3ro/core/errors'
|
|
import { getDictationTemplateService } from '../../src/main/services/DictationTemplateService'
|
|
import { getMeetingDocTemplateService } from '../../src/main/services/MeetingDocTemplateService'
|
|
import { useRedHarness } from './harness'
|
|
import { USER_TEXT } from './fixtures'
|
|
|
|
useRedHarness()
|
|
|
|
describe('유스케이스: 딕테이션 템플릿 CRUD / 필드 세션', () => {
|
|
it('빌트인 템플릿이 있다', () => {
|
|
const all = getDictationTemplateService().getAll()
|
|
expect(all.length).toBeGreaterThanOrEqual(3)
|
|
expect(all.some((t) => t.id === 'builtin-email')).toBe(true)
|
|
})
|
|
|
|
it('사용자 템플릿을 만든다', () => {
|
|
const created = getDictationTemplateService().create({
|
|
name: '내 템플릿',
|
|
description: 'd',
|
|
fields: [{ id: 'f1', name: 'f1', label: 'F', promptText: 'say', required: true, maxDurationSec: 10 }],
|
|
outputFormat: '{{f1}}',
|
|
})
|
|
expect(created.isBuiltin).toBe(false)
|
|
expect(getDictationTemplateService().getById(created.id)?.name).toBe('내 템플릿')
|
|
})
|
|
|
|
it('없는 템플릿 수정은 TemplateNotFound 다', () => {
|
|
expect(() => getDictationTemplateService().update({ id: 'missing', name: 'x' })).toThrow(
|
|
D3ROError,
|
|
)
|
|
try {
|
|
getDictationTemplateService().update({ id: 'missing', name: 'x' })
|
|
} catch (err) {
|
|
expect((err as D3ROError).code).toBe(ErrorCode.TemplateNotFound)
|
|
}
|
|
})
|
|
|
|
it('빌트인 삭제는 거부된다', () => {
|
|
expect(() => getDictationTemplateService().delete('builtin-email')).toThrow(D3ROError)
|
|
expect(getDictationTemplateService().getById('builtin-email')).not.toBeNull()
|
|
})
|
|
|
|
it('사용자 템플릿은 삭제된다', () => {
|
|
const created = getDictationTemplateService().create({
|
|
name: 'del',
|
|
description: '',
|
|
fields: [{ id: 'f1', name: 'f1', label: 'F', promptText: 'p', required: false, maxDurationSec: 5 }],
|
|
outputFormat: '{{f1}}',
|
|
})
|
|
getDictationTemplateService().delete(created.id)
|
|
expect(getDictationTemplateService().getById(created.id)).toBeNull()
|
|
})
|
|
|
|
it('없는 템플릿 세션 시작은 TemplateNotFound 다', () => {
|
|
expect(() => getDictationTemplateService().startSession('missing')).toThrow(D3ROError)
|
|
})
|
|
|
|
it('이메일 템플릿 세션을 시작하고 필드를 채운다', () => {
|
|
const svc = getDictationTemplateService()
|
|
svc.startSession('builtin-email')
|
|
const state = svc.getSessionState()
|
|
expect(state?.templateId).toBe('builtin-email')
|
|
expect(state?.currentField?.id).toBe('recipient')
|
|
svc.setFieldValue('recipient', 'a@b.c')
|
|
expect(svc.getSessionState()?.currentField?.id).toBe('subject')
|
|
})
|
|
|
|
it('이미 세션이 있으면 재시작은 TemplateSessionAlreadyActive 다', () => {
|
|
const svc = getDictationTemplateService()
|
|
svc.startSession('builtin-email')
|
|
expect(() => svc.startSession('builtin-report')).toThrow(D3ROError)
|
|
try {
|
|
svc.startSession('builtin-report')
|
|
} catch (err) {
|
|
expect((err as D3ROError).code).toBe(ErrorCode.TemplateSessionAlreadyActive)
|
|
}
|
|
})
|
|
|
|
it('세션 없이 필드 입력은 TemplateSessionNotActive 다', () => {
|
|
expect(() => getDictationTemplateService().setFieldValue('x', 'y')).toThrow(D3ROError)
|
|
})
|
|
|
|
it('세션을 취소하면 상태가 null 이다', () => {
|
|
const svc = getDictationTemplateService()
|
|
svc.startSession('builtin-email')
|
|
svc.cancelSession()
|
|
expect(svc.getSessionState()).toBeNull()
|
|
})
|
|
|
|
it('모든 필드를 채우면 출력이 치환되고 세션이 끝난다', () => {
|
|
const svc = getDictationTemplateService()
|
|
let output: string | null = null
|
|
svc.on('session-completed', (e: { outputText: string }) => {
|
|
output = e.outputText
|
|
})
|
|
svc.startSession('builtin-email')
|
|
svc.setFieldValue('recipient', 'to@x.test')
|
|
svc.setFieldValue('subject', 'hello')
|
|
svc.setFieldValue('body', USER_TEXT.KO)
|
|
expect(svc.getSessionState()).toBeNull()
|
|
expect(output).toContain('to@x.test')
|
|
expect(output).toContain('hello')
|
|
expect(output).toContain(USER_TEXT.KO)
|
|
})
|
|
|
|
it('빈 필드 템플릿은 시작할 수 없다', () => {
|
|
const created = getDictationTemplateService().create({
|
|
name: 'nofield',
|
|
description: '',
|
|
fields: [],
|
|
outputFormat: 'x',
|
|
})
|
|
expect(() => getDictationTemplateService().startSession(created.id)).toThrow(D3ROError)
|
|
})
|
|
})
|
|
|
|
describe('유스케이스: 회의 문서 템플릿 CRUD', () => {
|
|
it('빌트인 회의록/보고서/아이디어/마인드맵이 있다', () => {
|
|
const all = getMeetingDocTemplateService().getAll()
|
|
expect(all.some((t) => t.id === 'builtin-minutes')).toBe(true)
|
|
expect(all.some((t) => t.id === 'builtin-report')).toBe(true)
|
|
expect(all.some((t) => t.id === 'builtin-idea-note')).toBe(true)
|
|
expect(all.some((t) => t.id === 'builtin-mindmap')).toBe(true)
|
|
})
|
|
|
|
it('커스텀 문서 템플릿을 만든다', () => {
|
|
const created = getMeetingDocTemplateService().create({
|
|
name: '내 양식',
|
|
description: 'd',
|
|
systemPrompt: '요약만',
|
|
})
|
|
expect(created.isBuiltin).toBe(false)
|
|
expect(getMeetingDocTemplateService().getById(created.id)?.systemPrompt).toBe('요약만')
|
|
})
|
|
|
|
it('없는 템플릿 수정은 MeetingDocTemplateNotFound 다', () => {
|
|
expect(() => getMeetingDocTemplateService().update({ id: 'missing', name: 'x' })).toThrow(
|
|
D3ROError,
|
|
)
|
|
try {
|
|
getMeetingDocTemplateService().update({ id: 'missing', name: 'x' })
|
|
} catch (err) {
|
|
expect((err as D3ROError).code).toBe(ErrorCode.MeetingDocTemplateNotFound)
|
|
}
|
|
})
|
|
|
|
it('빌트인 삭제는 MeetingDocTemplateBuiltinDelete 다', () => {
|
|
expect(() => getMeetingDocTemplateService().delete('builtin-minutes')).toThrow(D3ROError)
|
|
try {
|
|
getMeetingDocTemplateService().delete('builtin-minutes')
|
|
} catch (err) {
|
|
expect((err as D3ROError).code).toBe(ErrorCode.MeetingDocTemplateBuiltinDelete)
|
|
}
|
|
})
|
|
|
|
it('커스텀 템플릿은 삭제된다', () => {
|
|
const created = getMeetingDocTemplateService().create({
|
|
name: 'del',
|
|
description: '',
|
|
systemPrompt: 'p',
|
|
})
|
|
getMeetingDocTemplateService().delete(created.id)
|
|
expect(getMeetingDocTemplateService().getById(created.id)).toBeNull()
|
|
})
|
|
|
|
it('없는 템플릿 삭제는 MeetingDocTemplateNotFound 다', () => {
|
|
expect(() => getMeetingDocTemplateService().delete('missing')).toThrow(D3ROError)
|
|
})
|
|
|
|
it('템플릿 이름 수정이 반영된다', () => {
|
|
const created = getMeetingDocTemplateService().create({
|
|
name: 'old',
|
|
description: '',
|
|
systemPrompt: 'p',
|
|
})
|
|
const updated = getMeetingDocTemplateService().update({ id: created.id, name: 'new' })
|
|
expect(updated.name).toBe('new')
|
|
})
|
|
})
|