Status: done
作为测试开发者, 我想要编写备注管理功能的测试, 以便验证备注的添加、修改、删除功能。
Given 残疾人管理 Page Object 已存在 When 编写备注管理测试 Then 包含以下测试场景:
添加备注
修改备注
删除备注
[x] Task 1: 分析备注管理功能的 DOM 结构 (AC: #1, #2, #3)
[x] Task 2: 创建备注测试文件 (AC: #1, #2, #3)
web/tests/e2e/specs/admin/disability-person-note.spec.ts[x] Task 3: 更新 Page Object (AC: #1, #2, #3)
DisabilityPersonManagementPageaddNote() 方法editNote() 方法deleteNote() 方法getNoteList() 方法用于验证[x] Task 4: 运行测试并验证通过 (AC: #1, #2, #3)
pnpm test:e2e:chromium disability-person-note 运行测试Epic 9: 残疾人管理完整 E2E 测试覆盖(含并行隔离)
为残疾人管理功能编写完整的、真正验证业务功能的 E2E 测试,并确保测试可以与未来的区域管理测试并行运行。
Epic 9 的 Story 依赖关系:
备注管理功能概述:
残疾人管理系统中,备注功能用于记录与残疾人相关的额外信息、备注事项、沟通记录等。备注通常支持:
典型功能流程:
当前 Page Object 位置: web/tests/e2e/pages/admin/disability-person.page.ts
从 Story 9.1 和 9.2 学到的模式:
data-testid 选择器最稳定form.getByLabel() 限制范围form.handleSubmit() 并配合 console.debug 调试验证错误web/tests/e2e/
├── specs/
│ └── admin/
│ └── disability-person-note.spec.ts # 本测试文件(需创建)
└── pages/
└── admin/
└── disability-person.page.ts # Page Object(需扩展)
测试文件模板:
// web/tests/e2e/specs/admin/disability-person-note.spec.ts
import { test, expect } from '@playwright/test';
import { DisabilityPersonManagementPage } from '../../pages/admin/disability-person.page';
test.describe('残疾人管理 - 备注管理功能', () => {
let pageObject: DisabilityPersonManagementPage;
const TIMESTAMP = Date.now();
const UNIQUE_ID = `test_note_${TIMESTAMP}`;
test.beforeEach(async ({ page }) => {
pageObject = new DisabilityPersonManagementPage(page);
await pageObject.goto();
await pageObject.openCreateDialog();
await pageObject.fillBasicInfo({
name: UNIQUE_ID,
idCard: `110101199001011234`,
});
});
test('应该成功添加简单备注', async ({ page }) => {
const noteContent = `这是一条测试备注_${UNIQUE_ID}`;
await pageObject.addNote(noteContent);
const noteList = await pageObject.getNoteList();
expect(noteList).toHaveLength(1);
expect(noteList[0]).toContain(noteContent);
});
test('应该成功添加长文本备注', async ({ page }) => {
const longNote = `这是一条很长的备注内容_${UNIQUE_ID}`.repeat(10);
await pageObject.addNote(longNote);
const noteList = await pageObject.getNoteList();
expect(noteList).toHaveLength(1);
expect(noteList[0]).toContain('这是一条很长的备注内容');
});
test('应该成功编辑备注', async ({ page }) => {
const originalNote = `原始备注_${UNIQUE_ID}`;
await pageObject.addNote(originalNote);
const updatedNote = `更新后的备注_${UNIQUE_ID}`;
await pageObject.editNote(0, updatedNote);
const noteList = await pageObject.getNoteList();
expect(noteList[0]).toContain(updatedNote);
expect(noteList[0]).not.toContain(originalNote);
});
test('应该成功删除备注', async ({ page }) => {
const noteContent = `待删除备注_${UNIQUE_ID}`;
await pageObject.addNote(noteContent);
let noteList = await pageObject.getNoteList();
expect(noteList).toHaveLength(1);
await pageObject.deleteNote(0);
noteList = await pageObject.getNoteList();
expect(noteList).toHaveLength(0);
});
test('应该支持添加多条备注', async ({ page }) => {
await pageObject.addNote(`备注1_${UNIQUE_ID}`);
await pageObject.addNote(`备注2_${UNIQUE_ID}`);
await pageObject.addNote(`备注3_${UNIQUE_ID}`);
const noteList = await pageObject.getNoteList();
expect(noteList).toHaveLength(3);
});
});
需要在 DisabilityPersonManagementPage 中添加的方法:
/**
* 添加备注
* @param content 备注内容
*/
async addNote(content: string): Promise<void> {
// 1. 点击"添加备注"按钮
// 2. 等待备注输入区域出现
// 3. 填写备注内容
// 4. 点击保存/确认按钮
// 5. 等待备注出现在列表中
}
/**
* 编辑备注
* @param index 备注索引(第几条,从0开始)
* @param content 更新的备注内容
*/
async editNote(index: number, content: string): Promise<void> {
// 1. 找到指定索引的备注的编辑按钮
// 2. 点击编辑按钮
// 3. 等待编辑区域出现
// 4. 更新备注内容
// 5. 点击保存按钮
// 6. 等待更新完成
}
/**
* 删除备注
* @param index 备注索引(第几条,从0开始)
*/
async deleteNote(index: number): Promise<void> {
// 1. 找到指定索引的备注的删除按钮
// 2. 点击删除按钮
// 3. 等待确认对话框(如有)
// 4. 点击确认按钮
// 5. 等待删除完成
}
/**
* 获取备注列表
* @returns 备注内容数组
*/
async getNoteList(): Promise<string[]> {
// 1. 定位备注列表容器
// 2. 获取所有备注项的文本内容
// 3. 返回备注信息数组
return []; // 实现时返回真实数据
}
/**
* 获取备注数量
* @returns 备注数量
*/
async getNoteCount(): Promise<number> {
return (await this.getNoteList()).length;
}
参考 Story 9.1 和 9.2 的经验:
page.getByRole('button', { name: /添加.*备注/ })form.getByLabel('备注内容') 或 form.getByPlaceholderText('请输入备注')data-testid 或 role="listitem" 选择器示例:
// 点击编辑按钮(第1条备注的编辑按钮)
const notes = page.locator('[data-testid="note-item"]');
await notes.nth(0).getByRole('button', { name: /编辑/ }).click();
// 或使用更具体的选择器
await page.locator('[data-testid="note-item-0"] [data-testid="edit-button"]').click();
参考 Story 9.1 和 9.2 的数据隔离模式:
test.beforeEach(async ({ page }) => {
const timestamp = Date.now();
const uniqueId = `test_note_${timestamp}`;
pageObject = new DisabilityPersonManagementPage(page);
await pageObject.goto();
await pageObject.openCreateDialog();
});
test.afterEach(async ({ page }) => {
// 清理测试数据(根据实际业务逻辑实现)
});
测试目录组织:
.spec.ts 后缀无冲突检测:
Story 9.1 (照片上传功能测试) 的关键经验:
form.getByLabel() 限制查找范围在表单内Date.now() 生成唯一 IDTIMEOUTS 常量统一管理Story 9.2 (银行卡管理功能测试) 的关键经验:
nth(index) 定位列表项getNoteList() 获取列表后验证内容Recent Commits:
a059239 - 完成 Story 10.1: 订单管理 Page Object 代码审查b739b96 - docs(epic-9): 创建 Story 10.2 - 订单列表查看测试5d75cf8 - test(e2e): 完成 Story 9.2 - 银行卡管理功能测试Code Patterns Observed:
disability-person-{feature}.spec.tsaddNote, editNote)基于架构文档的陷阱章节:
陷阱 1: DOM 结构假设必须验证 ⚠️
data-testid 选择器(最稳定)陷阱 2: 精确文本匹配
:text-is() 进行精确文本匹配,而非 :has-text()陷阱 3: 网络空闲等待
陷阱 4: 避免使用 page.evaluate()
page.evaluate() 获取元素内容源文档引用:
前置 Story 参考:
相关组件源码:
Monorepo 结构对齐:
web/tests/e2e/ 目录@d8d/e2e-test-utils文件组织:
web/tests/e2e/specs/admin/disability-person-note.spec.tsweb/tests/e2e/pages/admin/disability-person.page.ts遵循的项目标准:
.spec.ts 后缀(Playwright 测试)specs/ 分离,pages/ Page Object@d8d/e2e-test-utils 工具函数(如需要)docs/standards/e2e-radix-testing.md 标准代码审查发现并修复了以下问题:
HIGH 严重性(2个):
MEDIUM 严重性(5个):
addRemark() 方法修改的文件(代码审查):
web/tests/e2e/specs/admin/disability-person-note.spec.ts - 修复所有 HIGH 和 MEDIUM 问题web/tests/e2e/pages/admin/disability-person.page.ts - 移除冗余方法,添加超时常量Claude Opus 4 (claude-opus-4-5-20251101)
✅ 创建完整的 Story 9.3 文档,包含:
✅ DOM 结构分析完成:
add-remark-button, remove-remark-{index}, remark-content-textarea-{index}, special-needs-switch-{index}✅ 测试文件创建完成:web/tests/e2e/specs/admin/disability-person-note.spec.ts
test.describe.serial 顺序执行(数据隔离需要)✅ 所有 8 个测试通过 (100%):
✅ Page Object 扩展完成:web/tests/e2e/pages/admin/disability-person.page.ts
addNote() 方法editNote() 方法deleteNote() 方法getNoteList() 方法getNoteCount() 方法getNoteSpecialNeedsStatus() 方法isAddNoteButtonDisabled() 方法创建的文件:
_bmad-output/implementation-artifacts/9-3-note-tests.md - 本 story 文档web/tests/e2e/specs/admin/disability-person-note.spec.ts - 备注测试文件(305行,8个测试用例)修改的文件:
_bmad-output/implementation-artifacts/sprint-status.yaml - 更新 Story 9.3 状态web/tests/e2e/pages/admin/disability-person.page.ts - Page Object 扩展(添加备注管理方法,+105行)