Files
prompt-optimizer/tests/unit/App.test.js
T
linshen 5468f272da feat: 重构项目,调整服务层架构 (master)
本次提交对项目进行了大规模重构,主要调整了服务层架构,以实现更清晰的职责划分和更好的可维护性。
具体变更包括:

- 移除 `src/api/llm.js` 文件,相关 API 密钥管理逻辑已迁移到 `src/services/model/manager.js` 中。
- 移除 `src/config/llm.js` 文件,LLM 配置逻辑已迁移到 `src/services/model/manager.js` 和 `src/services/llm/service.js` 中。
- 移除 `src/services/llm.js` 文件,LLM 服务逻辑已迁移到 `src/services/llm/service.js` 中。
- 移除 `src/services/promptManager.js` 文件,提示词模板管理逻辑已迁移到 `src/services/prompt/service.js` 中,历史记录管理已迁移到 `src/services/history/manager.js` 中。
- 重构 `src/components/ModelManager.vue` 组件,使用新的模型管理服务。
- 重构 `src/App.vue` 组件,使用新的服务层架构。
- 修改 `tests/unit/services/llm.test.js` 文件,适应新的服务层架构。
- 修改 `tests/integration/services/llm/common.test.js`, `tests/integration/services/llm/custom.test.js`, `tests/integration/services/llm/deepseek.test.js`, `tests/integration/services/llm/gemini.test.js` 文件,适应新的服务层架构。
- 修改 `tests/unit/App.test.js` 文件,适应新的服务层架构。
- 修改 `src/components/OutputPanel.vue` 组件,添加复制选中内容功能。
- 更新 `experience.md`,记录重构经验。
- 更新 `scratchpad.md`,添加重构计划和日志。

本次重构的主要目标是:

- 更清晰的职责划分:将模型管理、LLM 服务、提示词模板管理和历史记录管理分离到独立的模块中。
- 更好的可维护性:通过模块化设计,降低代码耦合度,提高代码可读性和可维护性。
- 更高的可扩展性:新的架构更易于添加新的模型和功能。

本次重构对现有功能没有影响,所有测试均已通过。
2025-01-21 23:25:18 +08:00

309 lines
9.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, it, expect, beforeEach, vi } from 'vitest'
import { mount } from '@vue/test-utils'
import { nextTick } from 'vue'
import App from '../../src/App.vue'
import { createLLMService } from '../../src/services/llm/service'
import { createPromptService } from '../../src/services/prompt/service'
import { modelManager } from '../../src/services/model/manager'
// Mock toast functions
const mockSuccess = vi.fn()
const mockError = vi.fn()
const mockInfo = vi.fn()
const mockWarning = vi.fn()
// Mock useToast
vi.mock('../../src/composables/useToast', () => ({
useToast: () => ({
success: mockSuccess,
error: mockError,
info: mockInfo,
warning: mockWarning
})
}))
// Mock services
const mockLLMService = {
sendMessage: vi.fn(() => Promise.resolve('Test response')),
optimizePrompt: vi.fn(() => Promise.resolve('Optimized prompt')),
iteratePrompt: vi.fn(() => Promise.resolve('Iterated prompt'))
}
const mockPromptService = {
optimizePrompt: vi.fn(() => Promise.resolve('Optimized prompt')),
iteratePrompt: vi.fn(() => Promise.resolve('Iterated prompt')),
testPrompt: vi.fn(() => Promise.resolve('Test response')),
getHistory: vi.fn(() => [])
}
vi.mock('../../src/services/llm/service', () => ({
createLLMService: vi.fn(() => mockLLMService)
}))
vi.mock('../../src/services/prompt/service', () => ({
createPromptService: vi.fn(() => mockPromptService)
}))
vi.mock('../../src/services/model/manager', () => ({
modelManager: {
getAllModels: vi.fn(() => [
{ key: 'test', name: 'Test Model', model: 'test-model', enabled: true }
])
}
}))
// Mock components
const createComponent = (name, template = '<div><slot></slot></div>') => ({
name,
template,
props: {
modelValue: String,
model: String,
models: Array,
label: String,
placeholder: String,
modelLabel: String,
buttonText: String,
loadingText: String,
loading: Boolean,
disabled: Boolean,
optimizedPrompt: String,
error: String,
result: String,
isIterating: Boolean
},
emits: ['update:modelValue', 'update:model', 'submit', 'copy', 'iterate']
})
describe('App.vue', () => {
let wrapper
beforeEach(() => {
// 重置 mocks
vi.clearAllMocks()
mockSuccess.mockClear()
mockError.mockClear()
mockInfo.mockClear()
mockWarning.mockClear()
wrapper = mount(App, {
global: {
stubs: {
InputPanel: createComponent('InputPanel'),
PromptPanel: createComponent('PromptPanel'),
OutputPanel: createComponent('OutputPanel'),
ModelManager: createComponent('ModelManager'),
HistoryDrawer: createComponent('HistoryDrawer'),
Toast: createComponent('Toast')
}
}
})
})
describe('初始化', () => {
it('应该正确渲染标题', () => {
expect(wrapper.find('h1').text()).toBe('Prompt Optimizer')
})
it('应该渲染所有主要组件', () => {
expect(wrapper.findComponent({ name: 'InputPanel' }).exists()).toBe(true)
expect(wrapper.findComponent({ name: 'PromptPanel' }).exists()).toBe(true)
expect(wrapper.findComponent({ name: 'OutputPanel' }).exists()).toBe(true)
})
it('应该正确初始化', async () => {
expect(modelManager.getAllModels).toHaveBeenCalled()
expect(wrapper.vm.models.length).toBe(1)
expect(wrapper.vm.optimizeModel).toBe('test')
expect(wrapper.vm.selectedModel).toBe('test')
})
})
describe('提示词优化功能', () => {
it('应该正确处理提示词优化', async () => {
const testPrompt = '你是一个作家'
const optimizedPrompt = '优化后的提示词'
// 设置模拟返回值
mockPromptService.optimizePrompt.mockResolvedValue(optimizedPrompt)
// 找到第一个 InputPanel(提示词输入)
const inputPanel = wrapper.findComponent({ name: 'InputPanel' })
// 触发输入
await inputPanel.vm.$emit('update:modelValue', testPrompt)
// 触发提交
await inputPanel.vm.$emit('submit')
// 等待异步操作
await nextTick()
// 验证服务调用
expect(mockPromptService.optimizePrompt).toHaveBeenCalledWith(testPrompt, 'test')
// 验证结果更新
expect(wrapper.vm.optimizedPrompt).toBe(optimizedPrompt)
// 验证成功提示
expect(mockSuccess).toHaveBeenCalledWith('优化成功')
})
it('应该处理优化失败的情况', async () => {
const testPrompt = '测试提示词'
const errorMessage = '优化失败'
// 设置模拟错误
mockPromptService.optimizePrompt.mockRejectedValue(new Error(errorMessage))
// 找到输入面板
const inputPanel = wrapper.findComponent({ name: 'InputPanel' })
// 触发输入和提交
await inputPanel.vm.$emit('update:modelValue', testPrompt)
await inputPanel.vm.$emit('submit')
// 等待异步操作
await nextTick()
// 验证错误状态
expect(wrapper.vm.isOptimizing).toBe(false)
expect(mockError).toHaveBeenCalledWith(errorMessage)
})
})
describe('测试功能', () => {
it('应该正确处理测试请求', async () => {
const testContent = '测试内容'
const testResult = '测试结果'
const systemPrompt = '系统提示词'
// 设置初始状态
wrapper.vm.optimizedPrompt = systemPrompt
// 设置模拟返回值
mockPromptService.testPrompt.mockResolvedValue(testResult)
// 找到测试输入面板(第二个 InputPanel)
const inputPanels = wrapper.findAllComponents({ name: 'InputPanel' })
const testPanel = inputPanels[1]
// 触发输入
await testPanel.vm.$emit('update:modelValue', testContent)
// 触发提交
await testPanel.vm.$emit('submit')
// 等待异步操作
await nextTick()
// 验证服务调用
expect(mockPromptService.testPrompt).toHaveBeenCalledWith(
systemPrompt,
testContent,
'test'
)
// 验证结果更新
expect(wrapper.vm.testResult).toBe(testResult)
})
it('应该在没有优化提示词时使用原始提示词', async () => {
const testContent = '测试内容'
const originalPrompt = '原始提示词'
const testResult = '测试结果'
// 设置初始状态
wrapper.vm.prompt = originalPrompt
wrapper.vm.optimizedPrompt = ''
// 设置模拟返回值
mockPromptService.testPrompt.mockResolvedValue(testResult)
// 找到测试输入面板
const inputPanels = wrapper.findAllComponents({ name: 'InputPanel' })
const testPanel = inputPanels[1]
// 触发输入和提交
await testPanel.vm.$emit('update:modelValue', testContent)
await testPanel.vm.$emit('submit')
// 等待异步操作
await nextTick()
// 验证服务调用使用了原始提示词
expect(mockPromptService.testPrompt).toHaveBeenCalledWith(
originalPrompt,
testContent,
'test'
)
})
it('应该处理测试失败的情况', async () => {
const testContent = '测试内容'
const errorMessage = '测试失败'
// 设置模拟错误
mockPromptService.testPrompt.mockRejectedValue(new Error(errorMessage))
// 找到测试输入面板
const inputPanels = wrapper.findAllComponents({ name: 'InputPanel' })
const testPanel = inputPanels[1]
// 触发输入和提交
await testPanel.vm.$emit('update:modelValue', testContent)
await testPanel.vm.$emit('submit')
// 等待异步操作
await nextTick()
// 验证错误状态
expect(wrapper.vm.isTesting).toBe(false)
expect(wrapper.vm.testError).toBe('测试失败:' + errorMessage)
})
})
describe('历史记录功能', () => {
it('应该在优化成功后立即更新历史记录', async () => {
const testPrompt = '测试提示词'
const optimizedPrompt = '优化后的提示词'
const mockHistory = [{ id: '1', prompt: testPrompt, result: optimizedPrompt }]
mockPromptService.optimizePrompt.mockResolvedValue(optimizedPrompt)
mockPromptService.getHistory.mockReturnValue(mockHistory)
// 触发优化
const inputPanel = wrapper.findComponent({ name: 'InputPanel' })
await inputPanel.vm.$emit('update:modelValue', testPrompt)
await inputPanel.vm.$emit('submit')
// 等待异步操作
await nextTick()
// 验证历史记录更新
expect(mockPromptService.getHistory).toHaveBeenCalled()
expect(wrapper.vm.history).toEqual(mockHistory)
})
it('应该在迭代优化成功后立即更新历史记录', async () => {
const originalPrompt = '原始提示词'
const iterateInput = '迭代输入'
const iteratedPrompt = '迭代后的提示词'
const mockHistory = [{ id: '1', prompt: originalPrompt, result: iteratedPrompt }]
mockPromptService.iteratePrompt.mockResolvedValue(iteratedPrompt)
mockPromptService.getHistory.mockReturnValue(mockHistory)
// 触发迭代
const promptPanel = wrapper.findComponent({ name: 'PromptPanel' })
await promptPanel.vm.$emit('iterate', { originalPrompt, iterateInput })
// 等待异步操作
await nextTick()
// 验证历史记录更新
expect(mockPromptService.getHistory).toHaveBeenCalled()
expect(wrapper.vm.history).toEqual(mockHistory)
})
})
})