xlx_teacher_app/.task/dom-rendering-test-guide.md

577 lines
11 KiB
Markdown
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.

# DOM 渲染功能测试指南
## 🎯 测试目标
验证从 Konva Canvas 迁移到 DOM 渲染后,所有功能正常工作,特别是在微信小程序环境中。
## 🔧 测试环境
### 浏览器环境
- Chrome/Edge (开发调试)
- Safari (iOS 兼容性)
- 微信开发者工具 (小程序环境)
### 设备
- 桌面端 (鼠标操作)
- 移动端 (触摸操作)
- 平板 (双指缩放)
## ✅ 功能测试清单
### 1. 基础绘制功能
#### 1.1 矩形工具
**测试步骤**:
1. 选择矩形工具
2. 在画布上按下鼠标/手指
3. 拖动到目标位置
4. 释放鼠标/手指
**预期结果**:
- ✅ 矩形正确绘制
- ✅ 矩形位置、大小准确
- ✅ 矩形颜色、边框宽度符合设置
- ✅ 可以绘制负方向矩形(从右下往左上拖)
**测试数据**:
```typescript
// 预期数据结构
{
id: "shape_xxx",
type: "rect",
x: 100,
y: 100,
width: 200,
height: 150,
stroke: "#ff0000",
strokeWidth: 2
}
```
#### 1.2 笔工具(线条)
**测试步骤**:
1. 选择笔工具
2. 在画布上绘制任意路径
3. 释放鼠标/手指
**预期结果**:
- ✅ 线条流畅,无断点
- ✅ 线条颜色、粗细符合设置
- ✅ 线条端点圆滑lineCap: round
- ✅ 快速绘制时不丢失点
**测试数据**:
```typescript
{
id: "shape_xxx",
type: "line",
x: 0,
y: 0,
points: [100, 100, 105, 102, 110, 105, ...],
stroke: "#ff0000",
strokeWidth: 2
}
```
#### 1.3 文本注释
**测试步骤**:
1. 选择文本工具
2. 点击画布位置
3. 输入文本内容
4. 确认
**预期结果**:
- ✅ 弹出输入框
- ✅ 文本正确显示在点击位置
- ✅ 文本大小、颜色符合设置
- ✅ 支持多行文本
- ✅ 支持特殊字符
**测试用例**:
- 普通文本: "扣1分"
- 数字: "123"
- 特殊字符: "+5", "-2"
- 多行文本: "第一行\n第二行"
#### 1.4 特殊标记
**正确标记 ✓**:
- ✅ 显示红色勾号
- ✅ 位置准确
- ✅ 大小适中20x20
**错误标记 ✗**:
- ✅ 显示红色叉号
- ✅ 位置准确
- ✅ 大小适中20x20
**半对标记**:
- ✅ 显示勾号+斜线组合
- ✅ 位置准确
- ✅ 大小适中20x20
### 2. 擦除功能
#### 2.1 点击擦除
**测试步骤**:
1. 绘制多个不同类型的标记
2. 选择擦除工具
3. 点击各个标记
**预期结果**:
- ✅ 点击矩形内部,矩形被删除
- ✅ 点击线条附近5px内线条被删除
- ✅ 点击特殊标记,标记被删除
- ✅ 点击文本,文本被删除
- ✅ 点击空白处,无反应
**碰撞检测测试**:
```typescript
// 矩形边界测试
点击 (100, 100) -> 在矩形内
点击 (99, 99) -> 在矩形外
点击 (300, 250) -> 在矩形内
点击 (301, 251) -> 在矩形外
// 线条距离测试
点击距离线条 3px -> 命中
点击距离线条 10px -> 未命中
// 特殊标记测试(中心点 100, 100
点击 (100, 100) -> 命中
点击 (90, 90) -> 命中
点击 (110, 110) -> 命中
点击 (89, 89) -> 未命中
```
#### 2.2 拖动擦除
**测试步骤**:
1. 绘制多个标记
2. 选择擦除工具
3. 按住鼠标/手指拖动经过标记
**预期结果**:
- ✅ 经过的标记被连续删除
- ✅ 擦除流畅,无卡顿
### 3. 撤销/重做功能
#### 3.1 撤销操作
**测试步骤**:
1. 依次绘制:矩形 -> 线条 -> 文本
2. 点击撤销按钮 3 次
**预期结果**:
- ✅ 第1次撤销文本消失
- ✅ 第2次撤销线条消失
- ✅ 第3次撤销矩形消失
- ✅ 第4次撤销按钮禁用无反应
**命令栈验证**:
```typescript
// 初始状态
commandStack: []
currentIndex: -1
canUndo: false
// 绘制矩形后
commandStack: [AddShapeCommand(rect)]
currentIndex: 0
canUndo: true
// 绘制线条后
commandStack: [AddShapeCommand(rect), AddShapeCommand(line)]
currentIndex: 1
canUndo: true
// 撤销一次后
commandStack: [AddShapeCommand(rect), AddShapeCommand(line)]
currentIndex: 0
canUndo: true
canRedo: true
```
#### 3.2 重做操作
**测试步骤**:
1. 绘制标记
2. 撤销
3. 点击重做
**预期结果**:
- ✅ 标记重新出现
- ✅ 位置、样式与原来一致
#### 3.3 撤销后新建
**测试步骤**:
1. 绘制A -> B -> C
2. 撤销 2 次(剩下 A
3. 绘制新标记 D
**预期结果**:
- ✅ B、C 从命令栈中移除
- ✅ 不能重做 B、C
- ✅ 可以撤销 D
```typescript
// 撤销2次后
commandStack: [A, B, C]
currentIndex: 0
// 绘制D后
commandStack: [A, D] // B、C被截断
currentIndex: 1
canRedo: false
```
#### 3.4 清空所有标记
**测试步骤**:
1. 绘制多个标记
2. 点击"清空"按钮
3. 点击撤销
**预期结果**:
- ✅ 所有标记消失
- ✅ 撤销后所有标记恢复
### 4. 缩放功能
#### 4.1 手动缩放
**测试步骤**:
1. 设置缩放比例为 0.5
2. 绘制标记
3. 设置缩放比例为 2.0
**预期结果**:
- ✅ 图片大小正确变化
- ✅ 标记跟随图片缩放
- ✅ 标记位置相对图片不变
- ✅ 新绘制的标记坐标正确
**坐标转换验证**:
```typescript
// 缩放 0.5 时点击屏幕 (100, 100)
实际坐标 = (100 / 0.5, 100 / 0.5) = (200, 200)
// 缩放 2.0 时点击屏幕 (100, 100)
实际坐标 = (100 / 2.0, 100 / 2.0) = (50, 50)
```
#### 4.2 自适应宽度模式
**测试步骤**:
1. 启用自适应宽度
2. 调整浏览器窗口宽度
**预期结果**:
- ✅ 图片宽度自动适应容器
- ✅ 高度按比例缩放
- ✅ 标记位置正确
#### 4.3 双指缩放(触摸设备)
**测试步骤**:
1. 在触摸设备上打开
2. 双指捏合/展开
**预期结果**:
- ✅ 图片跟随手势缩放
- ✅ 显示缩放百分比提示
- ✅ 标记跟随缩放
### 5. 快捷打分功能
#### 5.1 加分模式
**测试步骤**:
1. 设置快捷打分:加分模式,分值 2
2. 启用快捷打分点击模式
3. 点击画布
**预期结果**:
- ✅ 显示 "+2" 文本标记
- ✅ 分数增加 2 分
- ✅ 文本颜色为红色
- ✅ 不能超过满分
**边界测试**:
```typescript
满分: 10
当前: 9
点击加2 -> 分数变为 10
再次点击 -> 无反应
```
#### 5.2 减分模式
**测试步骤**:
1. 设置快捷打分:减分模式,分值 1
2. 启用快捷打分点击模式
3. 点击画布
**预期结果**:
- ✅ 显示 "-1" 文本标记
- ✅ 分数减少 1 分
- ✅ 文本颜色为蓝色
- ✅ 不能低于 0 分
### 6. 多图片场景
#### 6.1 多图片渲染
**测试步骤**:
1. 加载包含 3 张图片的题目
2. 在每张图片上绘制不同标记
**预期结果**:
- ✅ 每张图片独立渲染
- ✅ 标记数据互不干扰
- ✅ 撤销操作针对最后操作的图片
#### 6.2 横向/纵向布局
**测试步骤**:
1. 切换图片布局模式
**预期结果**:
- ✅ 横向布局:图片水平排列
- ✅ 纵向布局:图片垂直排列
- ✅ 标记位置不受影响
### 7. 只读模式
#### 7.1 历史记录查看
**测试步骤**:
1. 打开已批改的试卷
2. 查看标记
**预期结果**:
- ✅ 所有标记正确显示
- ✅ 不响应点击事件
- ✅ 不显示工具栏
### 8. 数据持久化
#### 8.1 数据导出
**测试步骤**:
1. 绘制多种标记
2. 导出数据
**预期结果**:
```json
{
"version": "1.0",
"shapes": [
{
"id": "shape_xxx",
"type": "rect",
"x": 100,
"y": 100,
"width": 200,
"height": 150,
"stroke": "#ff0000",
"strokeWidth": 2
}
],
"specialMarks": [
{
"id": "mark_xxx",
"type": "correct",
"x": 300,
"y": 200
}
],
"annotations": [
{
"id": "text_xxx",
"x": 400,
"y": 300,
"text": "扣1分",
"fontSize": 14,
"color": "#000000"
}
]
}
```
#### 8.2 数据导入
**测试步骤**:
1. 导入上述 JSON 数据
2. 查看渲染结果
**预期结果**:
- ✅ 所有标记正确恢复
- ✅ 位置、样式一致
### 9. 性能测试
#### 9.1 大量标记渲染
**测试步骤**:
1. 导入包含 100+ 标记的数据
2. 观察渲染性能
**预期结果**:
- ✅ 初始渲染 < 1s
- 滚动流畅无卡顿
- 内存占用合理
#### 9.2 快速连续绘制
**测试步骤**:
1. 快速绘制多条线条
**预期结果**:
- 线条流畅无延迟
- 不丢失点
- 不出现重复标记
### 10. 兼容性测试
#### 10.1 微信小程序
**测试步骤**:
1. 在微信开发者工具中运行
2. 测试所有功能
**预期结果**:
- 所有功能正常
- 触摸事件响应正常
- 无控制台错误
#### 10.2 不同分辨率
**测试设备**:
- iPhone SE (375x667)
- iPhone 14 Pro (393x852)
- iPad (768x1024)
- Desktop (1920x1080)
**预期结果**:
- 布局自适应
- 标记大小合适
- 触摸区域足够大
## 🐛 Bug 报告模板
```markdown
### Bug 描述
简要描述问题
### 复现步骤
1. 步骤1
2. 步骤2
3. 步骤3
### 预期行为
应该发生什么
### 实际行为
实际发生了什么
### 环境信息
- 设备: iPhone 14
- 系统: iOS 16.0
- 浏览器: 微信开发者工具
- 版本: 1.0.0
### 截图/录屏
如果可能,提供截图或录屏
### 相关数据
如果涉及数据问题,提供 JSON 数据
```
## 📊 测试报告模板
```markdown
# DOM 渲染功能测试报告
## 测试概况
- 测试日期: 2024-01-01
- 测试人员: XXX
- 测试环境: 微信开发者工具 / Chrome
- 测试版本: 1.0.0
## 测试结果汇总
| 功能模块 | 测试用例数 | 通过 | 失败 | 通过率 |
|---------|-----------|------|------|--------|
| 基础绘制 | 10 | 10 | 0 | 100% |
| 擦除功能 | 5 | 5 | 0 | 100% |
| 撤销重做 | 8 | 8 | 0 | 100% |
| 缩放功能 | 6 | 6 | 0 | 100% |
| 快捷打分 | 4 | 4 | 0 | 100% |
| 多图片 | 3 | 3 | 0 | 100% |
| 只读模式 | 2 | 2 | 0 | 100% |
| 数据持久化 | 4 | 4 | 0 | 100% |
| 性能测试 | 3 | 3 | 0 | 100% |
| 兼容性 | 5 | 5 | 0 | 100% |
| **总计** | **50** | **50** | **0** | **100%** |
## 详细测试结果
[详细记录每个测试用例的结果]
## 发现的问题
[列出发现的所有问题]
## 建议
[提出改进建议]
## 结论
✅ 通过 / ❌ 不通过
```
## 🎯 自动化测试(可选)
### 单元测试示例
```typescript
import { describe, it, expect } from 'vitest'
import { useSimpleDomLayer } from './useMarkingDom'
describe('useMarkingDom', () => {
it('should add shape correctly', () => {
const layer = useSimpleDomLayer({...})
// 模拟绘制矩形
layer.handleMouseDown(mockEvent, mockRect)
layer.handleMouseMove(mockEvent, mockRect)
layer.handleMouseUp()
expect(layer.markingData.value.shapes).toHaveLength(1)
expect(layer.markingData.value.shapes[0].type).toBe('rect')
})
it('should undo correctly', () => {
const layer = useSimpleDomLayer({...})
// 添加标记
layer.handleMouseDown(mockEvent, mockRect)
layer.handleMouseUp()
expect(layer.markingData.value.shapes).toHaveLength(1)
// 撤销
layer.undo()
expect(layer.markingData.value.shapes).toHaveLength(0)
})
})
```
## 📝 测试记录
### 测试日期: ___________
### 测试人员: ___________
| 测试项 | 状态 | 备注 |
|--------|------|------|
| 绘制矩形 | | |
| 绘制线条 | | |
| 文本注释 | | |
| 特殊标记 | | |
| 擦除功能 | | |
| 撤销操作 | | |
| 重做操作 | | |
| 清空标记 | | |
| 手动缩放 | | |
| 自适应宽度 | | |
| 快捷打分 | | |
| 多图片 | | |
| 只读模式 | | |
| 数据导出 | | |
| 数据导入 | | |
| 性能测试 | | |
| 小程序兼容 | | |
**签名**: ___________