Initial TrueGrowth source import
This commit is contained in:
670
docs/MANUAL_TEST_ANALYSIS.md
Normal file
670
docs/MANUAL_TEST_ANALYSIS.md
Normal file
@@ -0,0 +1,670 @@
|
||||
# Opentu Manual 测试覆盖度分析与扩展计划
|
||||
|
||||
> 生成时间:2026-01-27
|
||||
> 分析范围:整个项目的 Manual 测试覆盖度
|
||||
> 重点模块:AI 输入栏(底部对话模块)及其配套功能
|
||||
|
||||
---
|
||||
|
||||
## 📊 目前已完成的测试覆盖
|
||||
|
||||
### ✅ 已测试模块(100% 完成)
|
||||
|
||||
| 模块 | 静态截图 | 动态 GIF | 测试代码 | 状态 |
|
||||
|------|---------|---------|---------|------|
|
||||
| **工具箱操作** | ✅ | ✅ | ✅ | 🎉 完成 |
|
||||
| **素材库管理** | ✅ | ✅ | ✅ | 🎉 完成 |
|
||||
| **项目管理** | ✅ | ✅ | ✅ | 🎉 完成 |
|
||||
| **备份/恢复** | ✅ | ✅ | ✅ | 🎉 完成 |
|
||||
|
||||
### ⚠️ 部分完成的测试(代码已有,GIF 未生成)
|
||||
|
||||
| 模块 | 静态截图 | 动态 GIF | 测试代码 | GIF 生成 | 状态 |
|
||||
|------|---------|---------|---------|---------|------|
|
||||
| **思维导图** | ⚠️ | ✅ | ✅ | ⏳ | 67% |
|
||||
| **画笔绘制** | ✅ | ✅ | ✅ | ⏳ | 67% |
|
||||
| **AI 图片生成** | ✅ | ✅ | ✅ | ⏳ | 67% |
|
||||
| **画布导航** | ✅ | ✅ | ✅ | ⏳ | 67% |
|
||||
| **形状工具** | ✅ | ✅ | ✅ | ⏳ | 67% |
|
||||
|
||||
---
|
||||
|
||||
## 🚨 **缺失的核心测试:AI 输入栏模块**
|
||||
|
||||
### 🎯 模块概述
|
||||
|
||||
**AI 输入栏**(AIInputBar)是 Opentu 最核心的交互组件,位于画布底部中央,类似 Google Mixboard 的交互模式。它是用户与 AI 功能交互的主入口。
|
||||
|
||||
**相关文件**:
|
||||
```
|
||||
packages/drawnix/src/components/ai-input-bar/
|
||||
├── AIInputBar.tsx (主组件,1872 行)
|
||||
├── ModelDropdown.tsx (模型选择器)
|
||||
├── ParametersDropdown.tsx (参数配置器)
|
||||
├── GenerationTypeDropdown.tsx (生成类型选择)
|
||||
├── CountDropdown.tsx (数量选择)
|
||||
├── PromptHistoryPopover.tsx (历史提示词)
|
||||
├── PromptSuggestionPanel.tsx (智能提示面板)
|
||||
├── SizeDropdown.tsx (尺寸选择)
|
||||
├── KeyboardDropdown.tsx (键盘导航)
|
||||
└── ModelSelector.tsx (模型选择器)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔍 AI 输入栏功能详细分解
|
||||
|
||||
### 1️⃣ **核心功能组(基础交互)**
|
||||
|
||||
#### 📋 功能清单
|
||||
|
||||
| 功能点 | 优先级 | 测试难度 | 预计时长 | 依赖 API |
|
||||
|--------|--------|---------|---------|---------|
|
||||
| **输入框聚焦/失焦** | P0 | 简单 | 5 秒 | ❌ |
|
||||
| **文本输入** | P0 | 简单 | 10 秒 | ❌ |
|
||||
| **输入框展开/收缩** | P0 | 简单 | 8 秒 | ❌ |
|
||||
| **发送按钮交互** | P0 | 简单 | 5 秒 | ❌ |
|
||||
| **清空输入** | P1 | 简单 | 3 秒 | ❌ |
|
||||
|
||||
#### 🎬 测试思路
|
||||
|
||||
```typescript
|
||||
test('AI 输入栏基础交互演示', async ({ page }) => {
|
||||
// 1. 等待页面加载
|
||||
await page.goto('http://localhost:7200/');
|
||||
await page.waitForTimeout(1500);
|
||||
|
||||
// 2. 显示提示:找到 AI 输入栏
|
||||
await showKeyHint(page, '底部 AI 输入栏', 1500);
|
||||
const aiInputBar = page.getByTestId('ai-input-bar');
|
||||
|
||||
// 3. 点击输入框聚焦
|
||||
await clickWithEffect(page, aiInputBar.locator('input'), '点击输入框', 1000);
|
||||
|
||||
// 4. 输入文本
|
||||
await showKeyHint(page, '输入提示词', 1000);
|
||||
await page.keyboard.type('一只可爱的猫咪', { delay: 100 });
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// 5. 展示输入框展开效果
|
||||
await showKeyHint(page, '输入框自动展开', 1500);
|
||||
|
||||
// 6. 清空输入(Ctrl+A + Backspace)
|
||||
await showKeyHint(page, '清空输入', 1000);
|
||||
await page.keyboard.press('Control+A');
|
||||
await page.keyboard.press('Backspace');
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// 7. 失焦收缩
|
||||
await page.keyboard.press('Escape');
|
||||
await showKeyHint(page, '输入框收缩', 1500);
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2️⃣ **模型选择组(关键配置)**
|
||||
|
||||
#### 📋 功能清单
|
||||
|
||||
| 功能点 | 优先级 | 测试难度 | 预计时长 | 子功能 |
|
||||
|--------|--------|---------|---------|--------|
|
||||
| **模型下拉菜单** | P0 | 中等 | 15 秒 | 展开、搜索、选择 |
|
||||
| **模型健康状态** | P1 | 简单 | 5 秒 | 显示模型可用性 |
|
||||
| **模型快捷代码** | P2 | 简单 | 5 秒 | `#imagen3` 显示 |
|
||||
| **模型分类筛选** | P1 | 中等 | 10 秒 | 图片/视频/Agent |
|
||||
|
||||
#### 🎬 测试思路
|
||||
|
||||
```typescript
|
||||
test('模型选择器演示', async ({ page }) => {
|
||||
await page.goto('http://localhost:7200/');
|
||||
const aiInputBar = page.getByTestId('ai-input-bar');
|
||||
|
||||
// 1. 打开模型下拉菜单
|
||||
await showKeyHint(page, '选择生成模型', 1500);
|
||||
const modelDropdown = aiInputBar.locator('.model-dropdown__trigger');
|
||||
await clickWithEffect(page, modelDropdown, '打开模型列表', 1500);
|
||||
|
||||
// 2. 展示模型列表(滚动浏览)
|
||||
await showKeyHint(page, '浏览可用模型', 1500);
|
||||
const modelList = page.locator('.model-dropdown__menu');
|
||||
await modelList.evaluate(el => {
|
||||
el.scrollBy({ top: 100, behavior: 'smooth' });
|
||||
});
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// 3. 健康状态展示
|
||||
await showKeyHint(page, '模型健康状态', 1500);
|
||||
|
||||
// 4. 选择模型
|
||||
const imagen3 = page.locator('.model-dropdown__item').filter({ hasText: 'imagen3' });
|
||||
await clickWithEffect(page, imagen3, '选择 Imagen 3', 1500);
|
||||
|
||||
// 5. 显示快捷代码
|
||||
await showKeyHint(page, '模型快捷代码 #imagen3', 1500);
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3️⃣ **参数配置组(高级功能)**
|
||||
|
||||
#### 📋 功能清单
|
||||
|
||||
| 功能点 | 优先级 | 测试难度 | 预计时长 | 配置项 |
|
||||
|--------|--------|---------|---------|--------|
|
||||
| **参数下拉菜单** | P0 | 中等 | 15 秒 | 展开、平铺展示 |
|
||||
| **尺寸选择** | P0 | 简单 | 8 秒 | 1:1, 16:9, 4:3 等 |
|
||||
| **数量选择** | P0 | 简单 | 8 秒 | 1-20 张 |
|
||||
| **生成类型** | P0 | 简单 | 8 秒 | 图片/视频/Agent |
|
||||
| **键盘导航** | P2 | 复杂 | 10 秒 | 上下左右键 |
|
||||
|
||||
#### 🎬 测试思路
|
||||
|
||||
```typescript
|
||||
test('参数配置演示', async ({ page }) => {
|
||||
await page.goto('http://localhost:7200/');
|
||||
const aiInputBar = page.getByTestId('ai-input-bar');
|
||||
|
||||
// 1. 打开参数配置
|
||||
await showKeyHint(page, '配置生成参数', 1500);
|
||||
const paramsBtn = aiInputBar.locator('.parameters-dropdown__trigger');
|
||||
await clickWithEffect(page, paramsBtn, '打开参数配置', 1500);
|
||||
|
||||
// 2. 展示参数分组(平铺显示)
|
||||
await showKeyHint(page, '所有参数平铺展示', 1500);
|
||||
const paramsPanel = page.locator('.parameters-dropdown__menu');
|
||||
|
||||
// 3. 选择尺寸
|
||||
await showKeyHint(page, '选择图片尺寸', 1000);
|
||||
const size16_9 = paramsPanel.locator('[data-param-value="16:9"]');
|
||||
await clickWithEffect(page, size16_9, '选择 16:9', 1000);
|
||||
|
||||
// 4. 选择数量
|
||||
await showKeyHint(page, '选择生成数量', 1000);
|
||||
const count4 = paramsPanel.locator('[data-param-value="4"]');
|
||||
await clickWithEffect(page, count4, '选择 4 张', 1000);
|
||||
|
||||
// 5. 关闭参数面板
|
||||
await page.keyboard.press('Escape');
|
||||
await showKeyHint(page, '配置已保存', 1500);
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4️⃣ **内容选择组(多模态输入)**
|
||||
|
||||
#### 📋 功能清单
|
||||
|
||||
| 功能点 | 优先级 | 测试难度 | 预计时长 | 子功能 |
|
||||
|--------|--------|---------|---------|--------|
|
||||
| **上传图片** | P0 | 中等 | 10 秒 | 文件选择、预览 |
|
||||
| **从素材库选择** | P0 | 中等 | 12 秒 | 打开模态框、选择 |
|
||||
| **画布元素选择** | P0 | 复杂 | 15 秒 | 自动捕获选中内容 |
|
||||
| **已选内容预览** | P0 | 简单 | 8 秒 | 缩略图展示 |
|
||||
| **移除选中内容** | P1 | 简单 | 5 秒 | 点击 X 移除 |
|
||||
|
||||
#### 🎬 测试思路
|
||||
|
||||
```typescript
|
||||
test('多模态内容选择演示', async ({ page }) => {
|
||||
await page.goto('http://localhost:7200/');
|
||||
const aiInputBar = page.getByTestId('ai-input-bar');
|
||||
|
||||
// 1. 上传图片(模拟)
|
||||
await showKeyHint(page, '上传参考图片', 1500);
|
||||
const uploadBtn = aiInputBar.locator('.ai-input-bar__upload-btn');
|
||||
await clickWithEffect(page, uploadBtn, '上传图片', 1000);
|
||||
// 注意:实际文件上传需要特殊处理
|
||||
await showKeyHint(page, '(演示:文件选择器)', 1500);
|
||||
|
||||
// 2. 从素材库选择
|
||||
await showKeyHint(page, '从素材库选择', 1500);
|
||||
const libraryBtn = aiInputBar.locator('.ai-input-bar__library-btn');
|
||||
await clickWithEffect(page, libraryBtn, '打开素材库', 1500);
|
||||
|
||||
// 假设素材库已打开
|
||||
const firstAsset = page.getByTestId('media-library-grid')
|
||||
.locator('.asset-item').first();
|
||||
if (await firstAsset.isVisible()) {
|
||||
await clickWithEffect(page, firstAsset, '选择素材', 1000);
|
||||
const confirmBtn = page.getByRole('button', { name: '确认' });
|
||||
await clickWithEffect(page, confirmBtn, '确认', 1000);
|
||||
}
|
||||
|
||||
// 3. 展示已选内容预览
|
||||
await showKeyHint(page, '已选内容预览', 1500);
|
||||
const preview = aiInputBar.locator('.selected-content-preview');
|
||||
|
||||
// 4. 移除内容
|
||||
const removeBtn = preview.locator('.remove-btn').first();
|
||||
if (await removeBtn.isVisible()) {
|
||||
await clickWithEffect(page, removeBtn, '移除', 1000);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5️⃣ **智能提示组(体验优化)**
|
||||
|
||||
#### 📋 功能清单
|
||||
|
||||
| 功能点 | 优先级 | 测试难度 | 预计时长 | 特性 |
|
||||
|--------|--------|---------|---------|------|
|
||||
| **历史提示词** | P1 | 中等 | 12 秒 | 悬浮展示、选择 |
|
||||
| **预设提示词** | P1 | 简单 | 10 秒 | 分类展示 |
|
||||
| **置顶提示词** | P2 | 简单 | 5 秒 | Pin 功能 |
|
||||
| **删除历史** | P2 | 简单 | 5 秒 | 删除操作 |
|
||||
| **灵感面板** | P1 | 中等 | 15 秒 | 空画布时显示 |
|
||||
|
||||
#### 🎬 测试思路
|
||||
|
||||
```typescript
|
||||
test('智能提示面板演示', async ({ page }) => {
|
||||
await page.goto('http://localhost:7200/');
|
||||
const aiInputBar = page.getByTestId('ai-input-bar');
|
||||
|
||||
// 1. 显示灵感面板(空画布)
|
||||
await showKeyHint(page, '灵感提示面板', 1500);
|
||||
const inspirationBoard = page.locator('.inspiration-board');
|
||||
if (await inspirationBoard.isVisible()) {
|
||||
await showKeyHint(page, '选择预设提示词', 1500);
|
||||
const card = inspirationBoard.locator('.inspiration-card').first();
|
||||
await clickWithEffect(page, card, '选择灵感', 1500);
|
||||
}
|
||||
|
||||
// 2. 打开历史提示词
|
||||
await showKeyHint(page, '查看历史提示词', 1500);
|
||||
const historyBtn = aiInputBar.locator('.prompt-history-popover__trigger');
|
||||
await page.hover(historyBtn.locator('button'));
|
||||
await page.waitForTimeout(800); // 悬浮延迟
|
||||
|
||||
// 3. 展示历史列表
|
||||
await showKeyHint(page, '历史记录与预设', 1500);
|
||||
const historyPanel = page.locator('.prompt-list-panel');
|
||||
|
||||
// 4. 置顶操作
|
||||
const pinBtn = historyPanel.locator('.pin-btn').first();
|
||||
if (await pinBtn.isVisible()) {
|
||||
await clickWithEffect(page, pinBtn, '置顶', 1000);
|
||||
}
|
||||
|
||||
// 5. 选择提示词
|
||||
const promptItem = historyPanel.locator('.prompt-item').first();
|
||||
await clickWithEffect(page, promptItem, '使用提示词', 1000);
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 6️⃣ **工作流集成组(高级场景)**
|
||||
|
||||
#### 📋 功能清单
|
||||
|
||||
| 功能点 | 优先级 | 测试难度 | 预计时长 | 说明 |
|
||||
|--------|--------|---------|---------|------|
|
||||
| **发送后打开 ChatDrawer** | P0 | 中等 | 10 秒 | 自动打开对话抽屉 |
|
||||
| **Agent 模式** | P1 | 复杂 | 20 秒 | AI 自动选择工具 |
|
||||
| **工作流显示** | P1 | 中等 | 15 秒 | 显示执行步骤 |
|
||||
| **任务状态同步** | P1 | 复杂 | 15 秒 | 实时更新状态 |
|
||||
| **错误处理** | P2 | 中等 | 10 秒 | API 失败提示 |
|
||||
|
||||
#### 🎬 测试思路
|
||||
|
||||
```typescript
|
||||
test('AI 工作流完整演示', async ({ page }) => {
|
||||
await page.goto('http://localhost:7200/');
|
||||
const aiInputBar = page.getByTestId('ai-input-bar');
|
||||
|
||||
// 1. 输入提示词
|
||||
await showKeyHint(page, '输入生成请求', 1500);
|
||||
await clickWithEffect(page, aiInputBar.locator('input'), '输入', 1000);
|
||||
await page.keyboard.type('生成一只猫咪', { delay: 100 });
|
||||
|
||||
// 2. 配置参数(快速)
|
||||
await showKeyHint(page, '配置生成参数', 1000);
|
||||
// ... 选择模型、尺寸等
|
||||
|
||||
// 3. 发送请求
|
||||
await showKeyHint(page, '发送生成请求', 1500);
|
||||
const sendBtn = aiInputBar.locator('.ai-input-bar__send-btn');
|
||||
await clickWithEffect(page, sendBtn, '发送', 1500);
|
||||
|
||||
// 4. 自动打开 ChatDrawer
|
||||
await showKeyHint(page, '对话抽屉自动打开', 1500);
|
||||
const chatDrawer = page.getByTestId('chat-drawer');
|
||||
await page.waitForSelector('[data-testid="chat-drawer"]', {
|
||||
state: 'visible',
|
||||
timeout: 3000
|
||||
});
|
||||
|
||||
// 5. 展示工作流执行
|
||||
await showKeyHint(page, '工作流执行中', 2000);
|
||||
// 注意:实际 AI 生成会很慢,测试中可能需要 mock
|
||||
|
||||
// 6. 关闭抽屉
|
||||
await page.keyboard.press('Escape');
|
||||
await showKeyHint(page, '关闭对话抽屉', 1000);
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 ChatDrawer(对话抽屉)功能分解
|
||||
|
||||
### 1️⃣ **基础交互**
|
||||
|
||||
| 功能点 | 优先级 | 测试难度 | 预计时长 |
|
||||
|--------|--------|---------|---------|
|
||||
| **打开/关闭抽屉** | P0 | 简单 | 8 秒 |
|
||||
| **拖动调整宽度** | P1 | 中等 | 10 秒 |
|
||||
| **会话列表** | P0 | 中等 | 15 秒 |
|
||||
| **新建会话** | P0 | 简单 | 5 秒 |
|
||||
| **切换会话** | P0 | 简单 | 8 秒 |
|
||||
| **删除会话** | P1 | 简单 | 5 秒 |
|
||||
|
||||
### 2️⃣ **消息交互**
|
||||
|
||||
| 功能点 | 优先级 | 测试难度 | 预计时长 |
|
||||
|--------|--------|---------|---------|
|
||||
| **显示用户消息** | P0 | 简单 | 5 秒 |
|
||||
| **显示 AI 响应** | P0 | 中等 | 10 秒 |
|
||||
| **工作流消息** | P1 | 复杂 | 20 秒 |
|
||||
| **重试失败任务** | P1 | 中等 | 12 秒 |
|
||||
| **插入到画布** | P0 | 中等 | 10 秒 |
|
||||
| **下载结果** | P1 | 简单 | 5 秒 |
|
||||
|
||||
### 3️⃣ **高级功能**
|
||||
|
||||
| 功能点 | 优先级 | 测试难度 | 预计时长 |
|
||||
|--------|--------|---------|---------|
|
||||
| **模型切换** | P1 | 简单 | 8 秒 |
|
||||
| **Mermaid 渲染** | P2 | 中等 | 10 秒 |
|
||||
| **代理日志** | P2 | 中等 | 10 秒 |
|
||||
| **会话搜索** | P2 | 中等 | 10 秒 |
|
||||
|
||||
---
|
||||
|
||||
## 📈 测试优先级矩阵
|
||||
|
||||
### 🔥 P0 级(必须测试,核心功能)
|
||||
|
||||
```
|
||||
优先执行顺序:
|
||||
|
||||
1. AI 输入栏基础交互 ⏱️ 8 秒
|
||||
2. 模型选择器 ⏱️ 15 秒
|
||||
3. 参数配置 ⏱️ 15 秒
|
||||
4. 多模态内容选择 ⏱️ 12 秒
|
||||
5. 发送 + ChatDrawer 打开 ⏱️ 10 秒
|
||||
6. ChatDrawer 基础交互 ⏱️ 15 秒
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
总计时长:~75 秒(1 分 15 秒)
|
||||
```
|
||||
|
||||
### ⚡ P1 级(重要功能,增强体验)
|
||||
|
||||
```
|
||||
1. 智能提示面板 ⏱️ 15 秒
|
||||
2. 工作流完整演示 ⏱️ 20 秒
|
||||
3. 会话管理 ⏱️ 15 秒
|
||||
4. ChatDrawer 拖动调整 ⏱️ 10 秒
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
总计时长:~60 秒(1 分钟)
|
||||
```
|
||||
|
||||
### 🎨 P2 级(锦上添花,可选)
|
||||
|
||||
```
|
||||
1. 键盘快捷键导航 ⏱️ 10 秒
|
||||
2. 历史提示词置顶/删除 ⏱️ 8 秒
|
||||
3. Mermaid 流程图渲染 ⏱️ 10 秒
|
||||
4. 代理日志查看 ⏱️ 10 秒
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
总计时长:~38 秒
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎬 推荐测试计划
|
||||
|
||||
### 📅 阶段 1:核心功能覆盖(Week 1)
|
||||
|
||||
#### Day 1-2: AI 输入栏基础
|
||||
```
|
||||
✅ test('AI 输入栏基础交互演示') - 8 秒
|
||||
✅ test('模型选择器演示') - 15 秒
|
||||
✅ test('参数配置演示') - 15 秒
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
合计 GIF: ~38 秒
|
||||
```
|
||||
|
||||
#### Day 3-4: 内容选择与工作流
|
||||
```
|
||||
✅ test('多模态内容选择演示') - 12 秒
|
||||
✅ test('AI 工作流完整演示') - 20 秒
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
合计 GIF: ~32 秒
|
||||
```
|
||||
|
||||
#### Day 5: ChatDrawer 基础
|
||||
```
|
||||
✅ test('ChatDrawer 基础交互演示') - 15 秒
|
||||
✅ test('会话管理演示') - 15 秒
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
合计 GIF: ~30 秒
|
||||
```
|
||||
|
||||
### 📅 阶段 2:体验优化(Week 2)
|
||||
|
||||
#### Day 1-2: 智能提示
|
||||
```
|
||||
✅ test('智能提示面板演示') - 15 秒
|
||||
✅ test('灵感面板演示') - 12 秒
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
合计 GIF: ~27 秒
|
||||
```
|
||||
|
||||
#### Day 3-4: 高级功能
|
||||
```
|
||||
✅ test('ChatDrawer 高级功能演示') - 20 秒
|
||||
✅ test('工作流重试与插入演示') - 15 秒
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
合计 GIF: ~35 秒
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ 技术实现建议
|
||||
|
||||
### 1. Mock API 响应
|
||||
|
||||
由于 AI 生成需要较长时间(10-60 秒),测试中建议 mock:
|
||||
|
||||
```typescript
|
||||
// 在测试开始前注入 mock
|
||||
await page.route('**/api/generation/**', route => {
|
||||
route.fulfill({
|
||||
status: 200,
|
||||
body: JSON.stringify({
|
||||
id: 'mock-task-id',
|
||||
status: 'completed',
|
||||
result_url: 'https://example.com/mock-image.png',
|
||||
}),
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### 2. Service Worker 通信
|
||||
|
||||
AI 输入栏通过 Service Worker 处理任务,测试时需要:
|
||||
|
||||
```typescript
|
||||
// 等待 SW 就绪
|
||||
await page.waitForFunction(() => {
|
||||
return navigator.serviceWorker.controller !== null;
|
||||
});
|
||||
|
||||
// 监听 SW 消息
|
||||
await page.evaluate(() => {
|
||||
window.__swMessages = [];
|
||||
navigator.serviceWorker.addEventListener('message', (event) => {
|
||||
window.__swMessages.push(event.data);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### 3. 文件上传测试
|
||||
|
||||
对于图片上传功能:
|
||||
|
||||
```typescript
|
||||
// 方式 1: 使用测试图片文件
|
||||
await page.setInputFiles(
|
||||
'input[type="file"]',
|
||||
'apps/web-e2e/fixtures/test-image.png'
|
||||
);
|
||||
|
||||
// 方式 2: 创建临时 Blob(仅演示界面)
|
||||
await page.evaluate(() => {
|
||||
const input = document.querySelector('input[type="file"]');
|
||||
const dataTransfer = new DataTransfer();
|
||||
const file = new File(['mock'], 'test.png', { type: 'image/png' });
|
||||
dataTransfer.items.add(file);
|
||||
input.files = dataTransfer.files;
|
||||
input.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 最终测试覆盖度预期
|
||||
|
||||
### 完成阶段 1 后
|
||||
|
||||
```
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100%
|
||||
|
||||
静态截图: ████████████████████████████████ 100% (21/21)
|
||||
动态 GIF: ████████████████████████████░░░░ 80% (15/19)
|
||||
测试代码: ████████████████████████████░░░░ 80% (13/16)
|
||||
已生成 GIF: ██████████████░░░░░░░░░░░░░░░░░░ 50% (10/19)
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
总进度: ███████████████████████████████░ 90%
|
||||
```
|
||||
|
||||
### 完成阶段 2 后
|
||||
|
||||
```
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100%
|
||||
|
||||
静态截图: ████████████████████████████████ 100% (21/21)
|
||||
动态 GIF: ████████████████████████████████ 100% (19/19)
|
||||
测试代码: ████████████████████████████████ 100% (16/16)
|
||||
已生成 GIF: ████████████████████████████████ 100% (19/19)
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
总进度: ████████████████████████████████ 100%
|
||||
|
||||
🎊 完整测试体系达成!
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📦 其他需要补充的测试模块
|
||||
|
||||
### 🎨 绘图工具详细测试
|
||||
|
||||
| 模块 | 当前状态 | 缺失测试 |
|
||||
|------|---------|---------|
|
||||
| **铅笔工具** | 有基础 GIF | 压感、橡皮擦、设置面板 |
|
||||
| **形状工具** | 有基础 GIF | 圆角调整、布尔运算、组合 |
|
||||
| **文本工具** | ❌ | 字体、大小、颜色、对齐 |
|
||||
| **渐变编辑器** | ❌ | 多色渐变、角度调整 |
|
||||
|
||||
### 🖼️ 画布操作测试
|
||||
|
||||
| 模块 | 当前状态 | 缺失测试 |
|
||||
|------|---------|---------|
|
||||
| **缩放平移** | 有基础 GIF | 快捷键、手势、小地图 |
|
||||
| **多选操作** | ❌ | 框选、Shift 多选、群组 |
|
||||
| **图层管理** | ❌ | 上移、下移、置顶、置底 |
|
||||
| **对齐分布** | ❌ | 左对齐、居中、等间距 |
|
||||
|
||||
### 🔧 工具箱详细测试
|
||||
|
||||
| 模块 | 当前状态 | 缺失测试 |
|
||||
|------|---------|---------|
|
||||
| **工具列表** | ✅ 完成 | - |
|
||||
| **工具窗口** | ✅ 完成 | - |
|
||||
| **自定义工具** | ❌ | 添加、配置、删除 |
|
||||
| **工具设置** | ❌ | iframe 配置、权限设置 |
|
||||
|
||||
### 📚 其他功能模块
|
||||
|
||||
| 模块 | 优先级 | 预计时长 |
|
||||
|------|--------|---------|
|
||||
| **应用设置** | P1 | 15 秒 |
|
||||
| **语言切换** | P2 | 5 秒 |
|
||||
| **快捷键面板** | P2 | 10 秒 |
|
||||
| **版本更新提示** | P2 | 5 秒 |
|
||||
| **性能面板** | P2 | 8 秒 |
|
||||
| **小地图** | P1 | 10 秒 |
|
||||
| **导出功能** | P1 | 12 秒 |
|
||||
|
||||
---
|
||||
|
||||
## 🎯 总结与建议
|
||||
|
||||
### ✅ 已完成的优势
|
||||
|
||||
1. ✅ **核心项目管理功能**:工具箱、素材库、项目管理、备份恢复全覆盖
|
||||
2. ✅ **测试框架完善**:DSL 配置 + 手动录制双轨系统
|
||||
3. ✅ **视觉效果统一**:品牌色、动画、标注完全一致
|
||||
4. ✅ **代码质量高**:清晰注释、容错处理、可维护性强
|
||||
|
||||
### 🚨 最大缺口:AI 交互模块
|
||||
|
||||
**AI 输入栏 + ChatDrawer** 是 Opentu 的核心竞争力,但目前 **0% 测试覆盖**!
|
||||
|
||||
**重要性评分**:⭐⭐⭐⭐⭐ (5/5)
|
||||
**紧急程度**:🔥🔥🔥🔥🔥 (5/5)
|
||||
**用户影响**:🎯🎯🎯🎯🎯 (5/5)
|
||||
|
||||
### 📋 行动建议
|
||||
|
||||
#### 短期(本周)
|
||||
|
||||
1. ✅ 完成 AI 输入栏基础交互测试(3 个 GIF,~38 秒)
|
||||
2. ✅ 完成 ChatDrawer 基础交互测试(2 个 GIF,~30 秒)
|
||||
3. ✅ 添加 Mock API 支持,避免长时间等待
|
||||
|
||||
#### 中期(下周)
|
||||
|
||||
1. ✅ 完成智能提示面板测试(2 个 GIF,~27 秒)
|
||||
2. ✅ 完成工作流高级功能测试(2 个 GIF,~35 秒)
|
||||
3. ✅ 补充文本工具、多选、图层管理测试
|
||||
|
||||
#### 长期(本月内)
|
||||
|
||||
1. ✅ 达成 100% Manual 测试覆盖
|
||||
2. ✅ 建立 CI/CD 自动化测试流程
|
||||
3. ✅ 完善国际化(英文)测试
|
||||
|
||||
---
|
||||
|
||||
## 🔗 相关文档
|
||||
|
||||
- `docs/CODING_RULES.md` - 编码规则
|
||||
- `docs/FEATURE_FLOWS.md` - 功能流程
|
||||
- `apps/web-e2e/src/manual-gen/gif-recordings.manual.spec.ts` - 现有 GIF 测试
|
||||
- `packages/drawnix/src/components/ai-input-bar/` - AI 输入栏源码
|
||||
- `packages/drawnix/src/components/chat-drawer/` - ChatDrawer 源码
|
||||
|
||||
---
|
||||
|
||||
**生成时间**:2026-01-27
|
||||
**分析师**:Claude Sonnet 4.5
|
||||
**版本**:v1.0
|
||||
Reference in New Issue
Block a user