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
179 lines
6.4 KiB
TypeScript
179 lines
6.4 KiB
TypeScript
import { describe, it, expect } from 'vitest'
|
|
import { ErrorCode } from '@d3ro/core/errors'
|
|
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
|
import { getCustomInstructionService } from '../../src/main/services/CustomInstructionService'
|
|
import { registerInstructionHandlers } from '../../src/main/ipc/instruction-handlers'
|
|
import { invokeIpc, useRedHarness } from './harness'
|
|
import { USER_TEXT } from './fixtures'
|
|
|
|
useRedHarness()
|
|
|
|
describe('유스케이스: 커스텀 명령어 CRUD / 프리셋 보호 / IPC', () => {
|
|
it('첫 실행 시 빌트인 5개가 있다', () => {
|
|
const svc = getCustomInstructionService()
|
|
svc.initialize()
|
|
expect(svc.getAll()).toHaveLength(5)
|
|
expect(svc.getAll().every((i) => i.isBuiltin)).toBe(true)
|
|
})
|
|
|
|
it('빌트인 번역 명령어를 id 로 연다', () => {
|
|
const svc = getCustomInstructionService()
|
|
svc.initialize()
|
|
expect(svc.getById('builtin-translate')?.id).toBe('builtin-translate')
|
|
})
|
|
|
|
it('없는 명령어 조회는 null 이다', () => {
|
|
const svc = getCustomInstructionService()
|
|
svc.initialize()
|
|
expect(svc.getById('nope')).toBeNull()
|
|
})
|
|
|
|
it('사용자 명령어를 추가하면 목록이 6개가 된다', () => {
|
|
const svc = getCustomInstructionService()
|
|
svc.initialize()
|
|
const created = svc.create({
|
|
name: '내 명령',
|
|
description: '설명',
|
|
prompt: '다음을 고쳐라: {{text}}',
|
|
icon: 'Edit',
|
|
})
|
|
expect(created.isBuiltin).toBe(false)
|
|
expect(svc.getAll()).toHaveLength(6)
|
|
})
|
|
|
|
it('빈 이름 명령어 추가는 거부된다', () => {
|
|
const svc = getCustomInstructionService()
|
|
svc.initialize()
|
|
expect(() =>
|
|
svc.create({ name: ' ', description: 'd', prompt: 'p', icon: 'Edit' }),
|
|
).toThrow()
|
|
})
|
|
|
|
it('빈 프롬프트 추가는 거부된다', () => {
|
|
const svc = getCustomInstructionService()
|
|
svc.initialize()
|
|
expect(() =>
|
|
svc.create({ name: 'n', description: 'd', prompt: '', icon: 'Edit' }),
|
|
).toThrow()
|
|
})
|
|
|
|
it('사용자 명령어 이름을 수정한다', () => {
|
|
const svc = getCustomInstructionService()
|
|
svc.initialize()
|
|
const created = svc.create({ name: 'old', description: 'd', prompt: 'p', icon: 'Edit' })
|
|
const updated = svc.update(created.id, { name: 'new' })
|
|
expect(updated?.name).toBe('new')
|
|
})
|
|
|
|
it('빌트인은 이름 수정이 적용되지 않고 프롬프트만 바뀐다', () => {
|
|
const svc = getCustomInstructionService()
|
|
svc.initialize()
|
|
const updated = svc.update('builtin-summarize', { name: '해킹', prompt: '새 프롬프트' })
|
|
expect(updated?.name).not.toBe('해킹')
|
|
expect(updated?.prompt).toBe('새 프롬프트')
|
|
})
|
|
|
|
it('없는 명령어 수정은 null 이다', () => {
|
|
const svc = getCustomInstructionService()
|
|
svc.initialize()
|
|
expect(svc.update('missing', { name: 'x' })).toBeNull()
|
|
})
|
|
|
|
it('사용자 명령어는 삭제된다', () => {
|
|
const svc = getCustomInstructionService()
|
|
svc.initialize()
|
|
const created = svc.create({ name: 'del', description: 'd', prompt: 'p', icon: 'Edit' })
|
|
expect(svc.delete(created.id)).toBe(true)
|
|
expect(svc.getById(created.id)).toBeNull()
|
|
})
|
|
|
|
it('빌트인 삭제는 거부된다', () => {
|
|
const svc = getCustomInstructionService()
|
|
svc.initialize()
|
|
expect(svc.delete('builtin-translate')).toBe(false)
|
|
expect(svc.getById('builtin-translate')).not.toBeNull()
|
|
})
|
|
|
|
it('없는 명령어 삭제는 false 이다', () => {
|
|
const svc = getCustomInstructionService()
|
|
svc.initialize()
|
|
expect(svc.delete('missing')).toBe(false)
|
|
})
|
|
|
|
it('순서를 바꾸면 getAll 순서가 바뀐다', () => {
|
|
const svc = getCustomInstructionService()
|
|
svc.initialize()
|
|
const ids = svc.getAll().map((i) => i.id).reverse()
|
|
svc.reorder(ids)
|
|
expect(svc.getAll().map((i) => i.id)).toEqual(ids)
|
|
})
|
|
|
|
it('resetBuiltins 후 빌트인이 다시 5개다', () => {
|
|
const svc = getCustomInstructionService()
|
|
svc.initialize()
|
|
svc.update('builtin-translate', { prompt: 'changed' })
|
|
svc.create({ name: 'keep', description: 'd', prompt: 'p', icon: 'Edit' })
|
|
svc.resetBuiltins()
|
|
expect(svc.getById('builtin-translate')?.prompt).not.toBe('changed')
|
|
expect(svc.getAll().filter((i) => !i.isBuiltin)).toHaveLength(1)
|
|
})
|
|
|
|
it('유니코드 이름/프롬프트가 저장된다', () => {
|
|
const svc = getCustomInstructionService()
|
|
svc.initialize()
|
|
const created = svc.create({
|
|
name: USER_TEXT.UNICODE,
|
|
description: USER_TEXT.UNICODE,
|
|
prompt: USER_TEXT.UNICODE,
|
|
icon: 'Edit',
|
|
})
|
|
expect(svc.getById(created.id)?.name).toBe(USER_TEXT.UNICODE)
|
|
})
|
|
|
|
it('IPC instruction:getAll 은 초기화 후 5개 이상이다', async () => {
|
|
getCustomInstructionService().initialize()
|
|
registerInstructionHandlers()
|
|
const res = await invokeIpc(IPC_CHANNELS.INSTRUCTION.GET_ALL)
|
|
expect(res.success).toBe(true)
|
|
if (res.success) expect((res.data as unknown[]).length).toBeGreaterThanOrEqual(5)
|
|
})
|
|
|
|
it('IPC instruction:create 왕복', async () => {
|
|
getCustomInstructionService().initialize()
|
|
registerInstructionHandlers()
|
|
const res = await invokeIpc(IPC_CHANNELS.INSTRUCTION.CREATE, {
|
|
name: 'ipc',
|
|
description: 'd',
|
|
prompt: 'p',
|
|
})
|
|
expect(res.success).toBe(true)
|
|
if (res.success) expect(res.data.name).toBe('ipc')
|
|
})
|
|
|
|
it('IPC instruction:delete 빌트인은 실패한다', async () => {
|
|
getCustomInstructionService().initialize()
|
|
registerInstructionHandlers()
|
|
const res = await invokeIpc(IPC_CHANNELS.INSTRUCTION.DELETE, { id: 'builtin-formal' })
|
|
expect(res.success).toBe(false)
|
|
})
|
|
|
|
it('IPC instruction:delete 없는 id 는 빌트인 삭제와 다른 코드다', async () => {
|
|
getCustomInstructionService().initialize()
|
|
registerInstructionHandlers()
|
|
const missing = await invokeIpc(IPC_CHANNELS.INSTRUCTION.DELETE, { id: 'missing' })
|
|
const builtin = await invokeIpc(IPC_CHANNELS.INSTRUCTION.DELETE, { id: 'builtin-explain-code' })
|
|
expect(missing.success).toBe(false)
|
|
expect(builtin.success).toBe(false)
|
|
if (!missing.success && !builtin.success) {
|
|
expect(missing.error.code).not.toBe(builtin.error.code)
|
|
}
|
|
})
|
|
|
|
it('IPC instruction:getById 없는 id 는 null 이다', async () => {
|
|
getCustomInstructionService().initialize()
|
|
registerInstructionHandlers()
|
|
const res = await invokeIpc(IPC_CHANNELS.INSTRUCTION.GET_BY_ID, { id: 'missing' })
|
|
expect(res.success).toBe(true)
|
|
if (res.success) expect(res.data).toBeNull()
|
|
})
|
|
})
|