577 lines
11 KiB
Markdown
577 lines
11 KiB
Markdown
# 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)
|
||
})
|
||
})
|
||
```
|
||
|
||
## 📝 测试记录
|
||
|
||
### 测试日期: ___________
|
||
### 测试人员: ___________
|
||
|
||
| 测试项 | 状态 | 备注 |
|
||
|--------|------|------|
|
||
| 绘制矩形 | ⬜ | |
|
||
| 绘制线条 | ⬜ | |
|
||
| 文本注释 | ⬜ | |
|
||
| 特殊标记 | ⬜ | |
|
||
| 擦除功能 | ⬜ | |
|
||
| 撤销操作 | ⬜ | |
|
||
| 重做操作 | ⬜ | |
|
||
| 清空标记 | ⬜ | |
|
||
| 手动缩放 | ⬜ | |
|
||
| 自适应宽度 | ⬜ | |
|
||
| 快捷打分 | ⬜ | |
|
||
| 多图片 | ⬜ | |
|
||
| 只读模式 | ⬜ | |
|
||
| 数据导出 | ⬜ | |
|
||
| 数据导入 | ⬜ | |
|
||
| 性能测试 | ⬜ | |
|
||
| 小程序兼容 | ⬜ | |
|
||
|
||
**签名**: ___________
|
||
|