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
180
apps/desktop/tests/red/templates.usecase.test.ts
Normal file
180
apps/desktop/tests/red/templates.usecase.test.ts
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
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')
|
||||
})
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue