Status: done
作为测试开发者, 我想要编写订单附件管理的 E2E 测试, 以便验证添加订单附件的功能。
Given 订单管理 Page Object 已创建 When 编写附件管理测试用例 Then 包含以下测试场景:
为订单添加附件
附件文件格式验证
测试文件: web/tests/e2e/specs/admin/order-attachment.spec.ts
openAddAttachmentDialog() 方法可用(已更新为使用"资源上传"按钮)uploadAttachment(personIdentifier, fileName, mimeType, fileType) 方法可用(已更新为使用 fileChooser 事件)getAttachmentListFromDetail() 方法可用(已存在)closeUploadDialog() 方法)web/tests/e2e/specs/admin/order-attachment.spec.tsconsole.log 改为 console.debugtest.skipEpic 10: 订单管理 E2E 测试 (Epic C - 业务测试 Epic)
依赖:
从 Story 10.8 学到的经验:
订单详情对话框结构:
openDetailDialog(orderName) 打开订单详情对话框closeDetailDialog() 关闭对话框附件列表获取:
getAttachmentListFromDetail() 方法已实现(行 752-818)从 Story 10.9 学到的经验:
API 直接创建测试数据:
createDisabledPersonViaAPI() 创建残疾人数据人员管理验证:
getPersonListFromDetail() 方法已修复(正确选择绑定人员列表表格)hasText: '工作状态' 作为筛选条件测试数据隔离:
testDataCounter 全局计数器确保唯一性订单附件管理相关方法 (web/tests/e2e/pages/admin/order-management.page.ts):
| 方法 | 说明 | 当前状态 | 本 Story 需求 |
|---|---|---|---|
openAddAttachmentDialog() |
打开添加附件对话框 | 已实现 (行 1032-1036) | 可直接使用 |
uploadAttachment(personName, fileName, mimeType) |
上传附件 | 已实现 (行 1044-1067) | 需验证UI 结构 |
getAttachmentListFromDetail() |
获取附件列表 | 已实现 (行 752-818) | 验证附件后检查 |
openAddAttachmentDialog() 方法当前实现(行 1032-1036):
async openAddAttachmentDialog() {
const attachmentButton = this.page.getByRole('button', { name: /添加附件|上传附件/ });
await attachmentButton.click();
await this.page.waitForSelector('[role="dialog"]', { state: 'visible', timeout: TIMEOUTS.DIALOG });
}
uploadAttachment() 方法当前实现(行 1044-1067):
async uploadAttachment(personName: string, fileName: string, mimeType: string = 'image/jpeg') {
// 选择订单人员
const personSelect = this.page.getByLabel(/选择人员|订单人员/);
await personSelect.click();
await this.page.getByRole('option', { name: personName }).click();
// 查找文件上传输入框
const fileInput = this.page.locator('input[type="file"]');
await fileInput.setInputFiles({
name: fileName,
mimeType,
buffer: Buffer.from(`fake ${fileName} content`),
});
// 等待上传处理
await this.page.waitForTimeout(TIMEOUTS.MEDIUM);
// 提交
const submitButton = this.page.getByRole('button', { name: /^(上传|确定|保存)$/ });
await submitButton.click();
await this.page.waitForLoadState('networkidle');
await this.page.waitForTimeout(TIMEOUTS.LONG);
}
潜在问题:
getByLabel + getByRole('option'))setInputFiles 的 buffer 模式(而非 fixtures 文件路径)需要验证的 UI 结构:
<input type="file"> 标准 HTML 元素为订单添加附件:
附件文件格式验证:
附件管理对话框结构假设(需要验证):
添加附件按钮位置:
添加附件对话框结构:
<input type="file"> 元素附件列表展示:
探索策略:
// 步骤1: 打开订单详情
await orderPage.openDetailDialog(orderName);
// 步骤2: 查找添加附件按钮
const attachmentButton = page.getByRole('button', { name: /添加附件|上传附件/ });
// 或
const attachmentButton = page.getByTestId('add-attachment-button');
// 步骤3: 点击并验证对话框打开
await attachmentButton.click();
await page.waitForSelector('[role="dialog"]', { state: 'visible' });
// 步骤4: 探索对话框结构
// - 人员选择器
const personSelect = page.getByLabel(/选择人员|订单人员/);
// 或 Radix Select
await selectRadixOption(page, '订单人员', personName);
// - 文件上传输入框
const fileInput = page.locator('input[type="file"]');
// 使用 fixtures 文件
await fileInput.setInputFiles('web/tests/fixtures/images/sample-id-card.jpg');
// 步骤5: 提交并验证
const submitButton = page.getByRole('button', { name: /^(上传|确定|保存)$/ });
await submitButton.click();
// 步骤6: 验证附件列表
const attachments = await orderPage.getAttachmentListFromDetail();
Fixtures 文件 (位于 web/tests/fixtures/images/):
sample-id-card.jpg - 身份证照片(JPG 格式)sample-disability-card.jpg - 残疾证照片(JPG 格式)id-card-front.jpg - 身份证正面(JPG 格式)id-card-back.jpg - 身份证反面(JPG 格式)disability-card.jpg - 残疾证照片(JPG 格式)photo.jpg - 个人照片(JPG 格式)photo.png - 个人照片(PNG 格式)photo.webp - 个人照片(WEBP 格式)large-file.jpg - 大文件(用于测试文件大小限制)invalid.txt - 无效格式文件(用于测试格式验证)测试数据创建流程:
遵循 Epic 9.6 并行执行决策:
test.describe.serial遵循项目的类型规范:
WORK_STATUS 和 WORK_STATUS_LABELS 常量WorkStatus 类型别名遵循项目的测试模式:
data-sonner-toast 选择器role="dialog" 或 role="alertdialog"测试数据隔离:
createDisabledPersonViaAPI() 创建残疾人数据orderManagementPage.createOrder() 创建测试订单orderManagementPage.addPersonToOrder() 添加人员到订单测试文件位置:
web/tests/e2e/
├── pages/admin/
│ └── order-management.page.ts (已有附件方法)
└── specs/admin/
└── order-attachment.spec.ts (新建)
测试 Fixtures 位置:
web/tests/fixtures/
└── images/
├── sample-id-card.jpg
├── sample-disability-card.jpg
├── photo.jpg
├── photo.png
├── photo.webp
└── invalid.txt
与其他测试的关系:
order-create.spec.ts: 创建订单测试(提供订单数据源)order-person.spec.ts: 人员关联测试(提供人员数据源)order-detail.spec.ts: 订单详情测试(验证附件列表显示)本 Story 完成后的影响:
Epic 需求来源:
Page Object 现有实现:
前序 Story 学习:
项目上下文:
Epic 9 并行执行决策:
claude-opus-4-5-20251101
关键发现:
UI 结构不同于预期:
人员姓名 vs ID:
getPersonListFromDetail() 返回的 name 字段实际是人员 ID文件上传机制:
waitForEvent('filechooser') 监听文件选择器fileChooser.setFiles() 方法设置文件Story 创建完成 - 2026-01-13
开发阶段完成 - 2026-01-13
UI 结构探索:
Page Object 更新:
openAddAttachmentDialog() 使用"资源上传"按钮uploadAttachment() 使用 fileChooser 事件和人员 ID 匹配closeUploadDialog() 方法测试文件创建:
web/tests/e2e/specs/admin/order-attachment.spec.ts已知问题:
@d8d/shared-types 导入错误(预先存在的问题)测试完成 - 2026-01-13
测试全部通过 (5/5):
最终修复:
uploadFileToField 工具函数代替 fileChooser 事件data-testid@d8d/shared-types 依赖到 web/package.json代码审查修复 - 2026-01-13
代码审查问题修复:
console.log 改为 console.debug (行 193, 197)test.skip(改为让测试在数据缺失时失败)已知限制:
代码审查完成 - 2026-01-13
已创建/修改的文件:
web/tests/e2e/specs/admin/order-attachment.spec.ts - 附件管理测试文件(新建,5/5 测试通过)web/tests/e2e/pages/admin/order-management.page.ts - 订单管理 Page Object(更新附件方法)web/package.json - 添加 @d8d/shared-types 依赖相关参考文件:
_bmad-output/implementation-artifacts/10-8-order-detail-tests.md - 订单详情测试参考_bmad-output/implementation-artifacts/10-9-order-person-tests.md - 人员关联测试参考sprint-status.yaml 更新说明:
由于 sprint-status.yaml 文件不存在,Story 10-10 的状态无法通过文件更新。
建议运行 bmad:bmm:workflows:sprint-status 工作流来初始化或更新 sprint status 文件。
手动更新指令(如果文件存在):
# 在 sprint-status.yaml 中
stories:
10-10:
status: review # 从 in-progress 改为 review