|
@@ -0,0 +1,466 @@
|
|
|
+# 表格列配置功能 E2E 测试方案
|
|
|
+
|
|
|
+## 功能概述
|
|
|
+
|
|
|
+为 Worklist 和 History 等页面的表格添加列显示控制功能,支持通过配置信息控制显示哪些列。配置信息可来自本地硬编码或远程 API。
|
|
|
+
|
|
|
+## 架构设计
|
|
|
+
|
|
|
+### 端口适配器模式
|
|
|
+
|
|
|
+采用端口适配器模式,支持两种配置源:
|
|
|
+
|
|
|
+1. **本地适配器** (LocalColumnConfigAdapter) - 硬编码配置
|
|
|
+2. **远程适配器** (RemoteColumnConfigAdapter) - API 获取配置
|
|
|
+
|
|
|
+### 数据流
|
|
|
+
|
|
|
+```
|
|
|
+配置源 (本地/远程)
|
|
|
+ ↓
|
|
|
+ColumnConfigService (领域服务)
|
|
|
+ ↓
|
|
|
+父组件 (worklist.tsx / HistoryList.tsx)
|
|
|
+ ↓ (通过 props)
|
|
|
+WorklistTable (表格组件)
|
|
|
+ ↓
|
|
|
+渲染过滤后的列
|
|
|
+```
|
|
|
+
|
|
|
+## 测试套件设计
|
|
|
+
|
|
|
+### 测试套件 1:Worklist 列配置
|
|
|
+
|
|
|
+**文件路径**: `cypress/e2e/patient/worklist/column-config.cy.ts`
|
|
|
+
|
|
|
+#### TC-WL-COL-01: 使用本地配置显示列
|
|
|
+
|
|
|
+**测试目标**: 验证在无网络配置时,表格使用本地硬编码配置
|
|
|
+
|
|
|
+**验证点**:
|
|
|
+
|
|
|
+1. 只显示配置中 visible=true 的列
|
|
|
+2. 列按 order 排序
|
|
|
+3. 隐藏的列不显示
|
|
|
+
|
|
|
+**预期列数**: 9 个(示例)
|
|
|
+
|
|
|
+**前置条件**:
|
|
|
+
|
|
|
+- Mock API 失败,强制使用本地配置
|
|
|
+- 已登录系统
|
|
|
+- 进入 worklist 页面
|
|
|
+
|
|
|
+#### TC-WL-COL-02: 使用远程API配置显示列
|
|
|
+
|
|
|
+**测试目标**: 验证从 API 获取配置并正确应用
|
|
|
+
|
|
|
+**验证点**:
|
|
|
+
|
|
|
+1. 成功调用配置 API
|
|
|
+2. 表格显示 API 配置的列
|
|
|
+3. 列顺序符合 API 配置
|
|
|
+
|
|
|
+**Mock 配置示例**:
|
|
|
+
|
|
|
+```json
|
|
|
+{
|
|
|
+ "tableName": "worklist",
|
|
|
+ "columns": [
|
|
|
+ { "key": "PatientID", "visible": true, "order": 1, "width": 120 },
|
|
|
+ { "key": "PatientName", "visible": true, "order": 2, "width": 150 },
|
|
|
+ { "key": "Modality", "visible": true, "order": 3, "width": 100 },
|
|
|
+ { "key": "StudyStatus", "visible": true, "order": 4, "width": 100 }
|
|
|
+ ]
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+#### TC-WL-COL-03: API失败时回退到本地配置
|
|
|
+
|
|
|
+**测试目标**: 验证配置提供者的容错机制
|
|
|
+
|
|
|
+**验证点**:
|
|
|
+
|
|
|
+1. API 调用失败(500错误)
|
|
|
+2. 自动使用本地配置
|
|
|
+3. 表格正常显示
|
|
|
+
|
|
|
+#### TC-WL-COL-04: 验证特定列的显示/隐藏
|
|
|
+
|
|
|
+**测试目标**: 验证列配置的可见性控制
|
|
|
+
|
|
|
+**验证点**:
|
|
|
+
|
|
|
+1. PatientID 显示
|
|
|
+2. StudyInstanceUID 隐藏
|
|
|
+3. 配置中的列数与显示列数一致
|
|
|
+
|
|
|
+#### TC-WL-COL-05: 验证列的显示顺序
|
|
|
+
|
|
|
+**测试目标**: 验证列按配置顺序排列
|
|
|
+
|
|
|
+**验证点**:
|
|
|
+
|
|
|
+1. 第一列是 order=1 的列
|
|
|
+2. 列顺序与配置 order 一致
|
|
|
+3. 不同配置显示不同顺序
|
|
|
+
|
|
|
+**特殊配置示例**:
|
|
|
+
|
|
|
+```json
|
|
|
+{
|
|
|
+ "columns": [
|
|
|
+ { "key": "StudyStatus", "visible": true, "order": 1 },
|
|
|
+ { "key": "PatientID", "visible": true, "order": 2 },
|
|
|
+ { "key": "Modality", "visible": true, "order": 3 },
|
|
|
+ { "key": "PatientName", "visible": true, "order": 4 }
|
|
|
+ ]
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+#### TC-WL-COL-06: 验证列宽配置
|
|
|
+
|
|
|
+**测试目标**: 验证列宽度应用
|
|
|
+
|
|
|
+**验证点**:
|
|
|
+
|
|
|
+1. 配置的列宽被应用
|
|
|
+2. 未配置列宽使用默认值(150px)
|
|
|
+
|
|
|
+#### TC-WL-COL-07: 无配置时显示所有列
|
|
|
+
|
|
|
+**测试目标**: 验证默认行为(向后兼容)
|
|
|
+
|
|
|
+**验证点**:
|
|
|
+
|
|
|
+1. columnConfig 为空数组时
|
|
|
+2. 显示所有35个列
|
|
|
+3. 保持当前行为不变
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 测试套件 2:History 列配置
|
|
|
+
|
|
|
+**文件路径**: `cypress/e2e/patient/history/column-config.cy.ts`
|
|
|
+
|
|
|
+#### TC-HIS-COL-01: History表格使用独立配置
|
|
|
+
|
|
|
+**测试目标**: 验证 history 使用与 worklist 不同的配置
|
|
|
+
|
|
|
+**验证点**:
|
|
|
+
|
|
|
+1. 加载 history 专属配置
|
|
|
+2. 显示的列与 worklist 不同
|
|
|
+3. 列顺序与 worklist 不同
|
|
|
+
|
|
|
+**示例配置**:
|
|
|
+
|
|
|
+```json
|
|
|
+{
|
|
|
+ "tableName": "history",
|
|
|
+ "columns": [
|
|
|
+ { "key": "StudyID", "visible": true, "order": 1 },
|
|
|
+ { "key": "IsExported", "visible": true, "order": 2 },
|
|
|
+ { "key": "StudyDescription", "visible": true, "order": 3 }
|
|
|
+ ]
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+#### TC-HIS-COL-02: 验证History特有列显示
|
|
|
+
|
|
|
+**测试目标**: 验证 history 特有列的配置
|
|
|
+
|
|
|
+**验证点**:
|
|
|
+
|
|
|
+1. IsExported 列显示
|
|
|
+2. 其他 history 特定列正确显示
|
|
|
+
|
|
|
+#### TC-HIS-COL-03: 多表格配置隔离
|
|
|
+
|
|
|
+**测试目标**: 验证不同表格配置互不影响
|
|
|
+
|
|
|
+**验证点**:
|
|
|
+
|
|
|
+1. 同时打开 worklist 和 history
|
|
|
+2. 各自使用独立配置
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 测试套件 3:配置适配器
|
|
|
+
|
|
|
+**文件路径**: `cypress/e2e/patient/column-config-adapters.cy.ts`
|
|
|
+
|
|
|
+#### TC-ADP-01: 本地适配器可用性
|
|
|
+
|
|
|
+**测试目标**: 验证本地适配器总是可用
|
|
|
+
|
|
|
+**验证点**:
|
|
|
+
|
|
|
+1. isAvailable() 返回 true
|
|
|
+2. 能获取所有表格配置
|
|
|
+
|
|
|
+#### TC-ADP-02: 远程适配器可用性检查
|
|
|
+
|
|
|
+**测试目标**: 验证远程适配器的可用性检测
|
|
|
+
|
|
|
+**验证点**:
|
|
|
+
|
|
|
+1. API 正常时返回 true
|
|
|
+2. API 异常时返回 false
|
|
|
+
|
|
|
+#### TC-ADP-03: 配置服务切换适配器
|
|
|
+
|
|
|
+**测试目标**: 验证运行时切换配置源
|
|
|
+
|
|
|
+**验证点**:
|
|
|
+
|
|
|
+1. 切换到远程适配器
|
|
|
+2. 切换到本地适配器
|
|
|
+3. 表格配置相应更新
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 测试数据
|
|
|
+
|
|
|
+### 本地默认配置(Worklist)
|
|
|
+
|
|
|
+```typescript
|
|
|
+const worklistDefaultColumns = [
|
|
|
+ { key: 'PatientID', visible: true, order: 1, width: 120 },
|
|
|
+ { key: 'PatientName', visible: true, order: 2, width: 150 },
|
|
|
+ { key: 'StudyID', visible: true, order: 3, width: 120 },
|
|
|
+ { key: 'AccessionNumber', visible: true, order: 4, width: 150 },
|
|
|
+ { key: 'StudyStatus', visible: true, order: 5, width: 100 },
|
|
|
+ { key: 'Modality', visible: true, order: 6, width: 100 },
|
|
|
+ { key: 'StudyStartDatetime', visible: true, order: 7, width: 180 },
|
|
|
+ { key: 'PatientAge', visible: true, order: 8, width: 80 },
|
|
|
+ { key: 'PatientSex', visible: true, order: 9, width: 80 },
|
|
|
+ // 其他列 visible: false
|
|
|
+];
|
|
|
+```
|
|
|
+
|
|
|
+### API Mock 响应格式
|
|
|
+
|
|
|
+```json
|
|
|
+{
|
|
|
+ "success": true,
|
|
|
+ "data": [
|
|
|
+ {
|
|
|
+ "tableName": "worklist",
|
|
|
+ "columns": [...],
|
|
|
+ "version": "1.0.0",
|
|
|
+ "updatedAt": "2025-10-07T10:00:00Z"
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "tableName": "history",
|
|
|
+ "columns": [...],
|
|
|
+ "version": "1.0.0",
|
|
|
+ "updatedAt": "2025-10-07T10:00:00Z"
|
|
|
+ }
|
|
|
+ ]
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## Page Object 扩展
|
|
|
+
|
|
|
+### WorklistPage 新增方法
|
|
|
+
|
|
|
+```typescript
|
|
|
+class WorklistPage {
|
|
|
+ // 现有方法
|
|
|
+ getTable() { ... }
|
|
|
+
|
|
|
+ // 新增:获取表头
|
|
|
+ getTableHeaders() {
|
|
|
+ return cy.get('table thead th').not(':first'); // 排除选择框列
|
|
|
+ }
|
|
|
+
|
|
|
+ // 新增:获取特定列
|
|
|
+ getColumn(columnName: string) {
|
|
|
+ return cy.get('table thead th').contains(columnName);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 新增:验证列是否存在
|
|
|
+ columnExists(columnName: string) {
|
|
|
+ return this.getTableHeaders().contains(columnName).should('exist');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 新增:验证列不存在
|
|
|
+ columnNotExists(columnName: string) {
|
|
|
+ return this.getTableHeaders().contains(columnName).should('not.exist');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 新增:获取列宽
|
|
|
+ getColumnWidth(columnName: string) {
|
|
|
+ return cy.get('table thead th')
|
|
|
+ .contains(columnName)
|
|
|
+ .invoke('width');
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## Mock Handlers
|
|
|
+
|
|
|
+### 文件: `cypress/support/mock/handlers/columnConfig.ts`
|
|
|
+
|
|
|
+```typescript
|
|
|
+export const mockColumnConfigSuccess = () => {
|
|
|
+ cy.intercept('GET', '/api/config/table-columns', {
|
|
|
+ statusCode: 200,
|
|
|
+ body: {
|
|
|
+ success: true,
|
|
|
+ data: [
|
|
|
+ {
|
|
|
+ tableName: 'worklist',
|
|
|
+ columns: [
|
|
|
+ { key: 'PatientID', visible: true, order: 1, width: 120 },
|
|
|
+ { key: 'PatientName', visible: true, order: 2, width: 150 },
|
|
|
+ { key: 'StudyID', visible: true, order: 3, width: 120 },
|
|
|
+ { key: 'AccessionNumber', visible: true, order: 4, width: 150 },
|
|
|
+ { key: 'StudyStatus', visible: true, order: 5, width: 100 },
|
|
|
+ { key: 'Modality', visible: true, order: 6, width: 100 },
|
|
|
+ { key: 'StudyStartDatetime', visible: true, order: 7, width: 180 },
|
|
|
+ { key: 'PatientAge', visible: true, order: 8, width: 80 },
|
|
|
+ { key: 'PatientSex', visible: true, order: 9, width: 80 },
|
|
|
+ ],
|
|
|
+ version: '1.0.0',
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ },
|
|
|
+ }).as('columnConfig');
|
|
|
+};
|
|
|
+
|
|
|
+export const mockColumnConfigFail = () => {
|
|
|
+ cy.intercept('GET', '/api/config/table-columns', {
|
|
|
+ statusCode: 500,
|
|
|
+ }).as('columnConfigFail');
|
|
|
+};
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 测试执行计划
|
|
|
+
|
|
|
+### 第一阶段:核心功能测试(优先级高)
|
|
|
+
|
|
|
+- TC-WL-COL-01 ✓
|
|
|
+- TC-WL-COL-02 ✓
|
|
|
+- TC-WL-COL-03 ✓
|
|
|
+- TC-WL-COL-04 ✓
|
|
|
+
|
|
|
+### 第二阶段:扩展功能测试(优先级中)
|
|
|
+
|
|
|
+- TC-WL-COL-05 ✓
|
|
|
+- TC-WL-COL-06 ✓
|
|
|
+- TC-HIS-COL-01 ✓
|
|
|
+
|
|
|
+### 第三阶段:边界和容错测试(优先级低)
|
|
|
+
|
|
|
+- TC-WL-COL-07 ✓
|
|
|
+- TC-ADP-01 ✓
|
|
|
+- TC-ADP-02 ✓
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 测试覆盖率目标
|
|
|
+
|
|
|
+- **功能覆盖**: 100% - 所有列配置相关功能
|
|
|
+- **代码覆盖**: 80%+ - 核心业务逻辑代码
|
|
|
+- **边界测试**: 包含空配置、API失败等边界情况
|
|
|
+- **兼容性测试**: 验证向后兼容性(无配置时的默认行为)
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 测试环境要求
|
|
|
+
|
|
|
+### 依赖的 Mock Handlers
|
|
|
+
|
|
|
+1. i18n Mocks - 多语言资源
|
|
|
+2. Quota Mocks - 配额检查
|
|
|
+3. Protocol Mocks - 患者类型和身体部位(必需)
|
|
|
+4. User Mocks - 登录认证
|
|
|
+
|
|
|
+### 测试数据准备
|
|
|
+
|
|
|
+- Mock worklist 数据(至少2条)
|
|
|
+- Mock history 数据(至少2条)
|
|
|
+- Mock 列配置(本地和远程)
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 验收标准
|
|
|
+
|
|
|
+### 功能验收
|
|
|
+
|
|
|
+- ✅ 所有测试用例通过
|
|
|
+- ✅ 本地配置和远程配置都能正常工作
|
|
|
+- ✅ API 失败时能回退到本地配置
|
|
|
+- ✅ 不同表格使用独立配置
|
|
|
+- ✅ 向后兼容(无配置时显示所有列)
|
|
|
+
|
|
|
+### 性能验收
|
|
|
+
|
|
|
+- ✅ 配置加载不影响页面渲染速度
|
|
|
+- ✅ 列过滤和排序在客户端完成,无额外请求
|
|
|
+
|
|
|
+### 用户体验验收
|
|
|
+
|
|
|
+- ✅ 配置加载失败时有明确的回退行为
|
|
|
+- ✅ 列顺序和宽度按配置正确显示
|
|
|
+- ✅ 现有功能不受影响(排序、调整列宽等)
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 附录
|
|
|
+
|
|
|
+### 完整列定义(35列)
|
|
|
+
|
|
|
+1. StudyInstanceUID
|
|
|
+2. StudyID
|
|
|
+3. SpecificCharacterSet
|
|
|
+4. AccessionNumber
|
|
|
+5. PatientID
|
|
|
+6. PatientName
|
|
|
+7. DisplayPatientName
|
|
|
+8. PatientSize
|
|
|
+9. PatientAge
|
|
|
+10. PatientSex
|
|
|
+11. AdmittingTime
|
|
|
+12. RegSource
|
|
|
+13. StudyStatus
|
|
|
+14. RequestedProcedureID
|
|
|
+15. PerformedProtocolCodeValue
|
|
|
+16. PerformedProtocolCodeMeaning
|
|
|
+17. PerformedProcedureStepID
|
|
|
+18. StudyDescription
|
|
|
+19. StudyStartDatetime
|
|
|
+20. ScheduledProcedureStepStartDate
|
|
|
+21. StudyLock
|
|
|
+22. OperatorID
|
|
|
+23. Modality
|
|
|
+24. Views
|
|
|
+25. Thickness
|
|
|
+26. PatientType
|
|
|
+27. StudyType
|
|
|
+28. QRCode
|
|
|
+29. IsExported
|
|
|
+30. IsEdited
|
|
|
+31. WorkRef
|
|
|
+32. IsAppended
|
|
|
+33. CreationTime
|
|
|
+34. MappedStatus
|
|
|
+35. IsDelete
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 文档版本
|
|
|
+
|
|
|
+- **版本**: 1.0.0
|
|
|
+- **创建日期**: 2025-10-07
|
|
|
+- **最后更新**: 2025-10-07
|
|
|
+- **作者**: Cline AI Assistant
|
|
|
+- **审核**: 待审核
|