# 深层交互用例步骤优化 执行计划文档

> **文档版本**: v1.0
> **创建日期**: 2026-07-22
> **关联 PRD**: _PRD_需求文档_深层交互用例步骤优化.md v1.0
> **负责人**: czj

---

## 一、执行概述

### 1.1 项目背景

当前管理看板、运维管理、数据分析三个模块的 25 个深层交互用例执行通过率低（约 30%），主要问题：canvas 等待超时、重复登录、选择器不精确、导航等待不足。本计划针对这些问题，优化步骤定义和用例创建脚本。

### 1.2 执行目标

| 目标 | 描述 | 验收标准 |
|------|------|---------|
| 移除冗余登录 | 删除 build_base_steps()，用例步骤从导航开始 | 深层用例无登录步骤，auto_login 正常工作 |
| 优化 canvas 等待 | 超时 30s + networkidle 前置等待 | 管理看板/数据分析用例 canvas 不再超时 |
| 优化导航等待 | networkidle + 特征元素等待 | 菜单点击后页面加载完成再操作 |
| 优化选择器 | 增加上下文限定和多选器回退 | 筛选器操作不再误匹配 |
| 步骤模板化 | 统一深层用例步骤模板 | 新增用例可复用模板，order 从 1 开始 |

### 1.3 技术选型

| 项目 | 选择 | 说明 |
|------|------|------|
| 步骤格式 | 现有 StepDefinition JSON | 无需修改 Schema，利用已有 selectors/wait_after 等字段 |
| 超时策略 | canvas 30s + networkidle 前置 | 利用执行器已有的 _do_wait + _wait_for_element |
| 选择器回退 | selectors 列表 + page_key/element_key | 利用执行器已有的 _resolve_selectors |
| 数据更新 | API 批量更新 | 通过 /api/cases/{id} PUT 接口更新 |

### 1.4 预计工期

| 阶段 | 内容 | 预计时间 |
|------|------|---------|
| Phase 1 | 重写用例创建脚本 | 1 天 |
| Phase 2 | 更新数据库中的深层用例 | 0.5 天 |
| Phase 3 | 执行验证 | 0.5 天 |
| **总计** | | **2 天** |

---

## 二、任务分解与实施计划

### 2.1 Phase 1: 重写用例创建脚本（预计 1 天）

#### 2.1.1 任务清单

| 任务ID | 任务名称 | 说明 | 优先级 | 预计工时 |
|--------|---------|------|--------|---------|
| P1-001 | 删除 `build_base_steps()` 函数 | 移除冗余登录步骤构建 | P0 | 0.1 天 |
| P1-002 | 新建 `build_navigate_steps()` 模板 | 导航+networkidle+特征元素等待，order 从 1 开始 | P0 | 0.3 天 |
| P1-003 | 新建 `build_canvas_page_steps()` 模板 | 适用于图表页面：导航→等networkidle→等canvas(30s)→操作→断言 | P0 | 0.3 天 |
| P1-004 | 新建 `build_table_page_steps()` 模板 | 适用于表格页面：导航→等networkidle→等table→操作→断言 | P0 | 0.2 天 |
| P1-005 | 重写管理看板 6 个用例 | 使用新模板，优化 canvas 等待和选择器 | P0 | 0.2 天 |
| P1-006 | 重写运维管理 7 个用例 | 使用新模板，优化表格等待和选择器 | P0 | 0.2 天 |
| P1-007 | 重写数据分析 12 个用例 | 使用新模板，优化 canvas/表格等待和选择器 | P0 | 0.3 天 |
| P1-008 | 增加用例更新逻辑 | 脚本支持按名称查找并更新已有用例 | P0 | 0.2 天 |

#### 2.1.2 代码变更

**文件：`backend/scripts/create_deep_interaction_cases_v2.py`**

##### 变更 1：删除 `build_base_steps()` 函数

删除整个 `build_base_steps()` 函数（原第 42-94 行）。所有用例不再包含登录步骤。

##### 变更 2：新增模板函数

```python
def build_navigate_steps(menu_name: str, wait_selector: str = "body",
                         wait_timeout: int = 10000, order_start: int = 1):
    """
    构建导航到目标菜单的步骤（含 networkidle 等待）

    Args:
        menu_name: 菜单名称
        wait_selector: 页面加载后等待的特征元素选择器
        wait_timeout: 等待超时时间(ms)
        order_start: 起始步骤编号
    """
    return [
        {
            "order": order_start,
            "name": f"点击{menu_name}菜单",
            "action": "click",
            "params": {"selector": f'.block:has-text("{menu_name}")'},
        },
        {
            "order": order_start + 1,
            "name": "等待页面加载完成",
            "action": "wait",
            "params": {"selector": wait_selector, "timeout": wait_timeout},
        },
        {
            "order": order_start + 2,
            "name": "等待页面渲染",
            "action": "wait",
            "params": {"selector": "body", "timeout": 3000},
            "wait_after": 2000,  # 额外 2s 等待动画
        },
    ]


def build_canvas_wait_steps(order_start: int = 4):
    """构建 canvas 图表等待步骤（超时 30s，支持 iframe）"""
    return [
        {
            "order": order_start,
            "name": "等待图表加载",
            "action": "wait",
            "params": {
                "selector": "canvas",
                "timeout": 30000,  # 从 15s 提升到 30s
            },
        },
    ]


def build_table_wait_steps(order_start: int = 4):
    """构建表格数据等待步骤"""
    return [
        {
            "order": order_start,
            "name": "等待表格数据加载",
            "action": "wait",
            "params": {
                "selector": ".el-table",
                "timeout": 20000,
            },
        },
    ]
```

##### 变更 3：重写管理看板用例示例

以"管理看板-时间范围筛选验证"为例，步骤从导航开始：

```python
cases.append({
    "name": "管理看板-时间范围筛选验证",
    "description": "验证管理看板页面时间范围下拉筛选功能",
    "module_id": DASHBOARD_MODULE_ID,
    "priority": "high",
    "order": 200,
    "config": DEFAULT_CONFIG,  # auto_login=True 保持不变
    "steps": build_navigate_steps("管理看板", "canvas", 30000)  # 1-3
    + build_canvas_wait_steps(4)  # 4
    + [
        {
            "order": 5,
            "name": "验证筛选器存在",
            "action": "assert",
            "params": {
                "type": "element_count_min",
                "selector": ".el-select",
                "min_count": 1,
            },
        },
        {
            "order": 6,
            "name": "点击第一个筛选下拉框",
            "action": "click",
            "params": {
                "selectors": [
                    ".filter-bar .el-select:first-child .el-input",
                    ".el-select:first-child .el-input",
                ],
            },
        },
        {
            "order": 7,
            "name": "选择第一个选项",
            "action": "click",
            "params": {
                "selectors": [
                    ".el-select-dropdown:visible .el-select-dropdown__item:first-child",
                    ".el-select-dropdown__item:first-child",
                ],
                "timeout": 5000,
            },
        },
        {
            "order": 8,
            "name": "等待图表刷新",
            "action": "wait",
            "params": {"selector": "canvas", "timeout": 10000},
        },
        {
            "order": 9,
            "name": "验证图表仍正常显示",
            "action": "assert",
            "params": {"type": "element_exists", "selector": "canvas"},
        },
    ],
})
```

##### 变更 4：增加用例更新逻辑

脚本中增加按名称查找已有用例并更新的能力：

```python
async def update_or_create_case(client, case_data):
    """更新已有用例或创建新用例"""
    # 先按名称查找
    r = await client.get(f"{BASE_URL}/api/cases", params={"keyword": case_data["name"]})
    if r.status_code == 200:
        data = r.json()
        items = data.get("items", [])
        for item in items:
            if item.get("name") == case_data["name"]:
                # 找到同名用例，更新
                case_id = item["id"]
                r2 = await client.put(f"{BASE_URL}/api/cases/{case_id}", json=case_data)
                if r2.status_code == 200:
                    return "updated", case_id
                else:
                    return "update_failed", r2.text[:100]
    # 未找到，创建
    r = await client.post(f"{BASE_URL}/api/cases", json=case_data)
    if r.status_code == 201:
        return "created", r.json().get("id", "")
    return "create_failed", r.text[:100]
```

#### 2.1.3 全部 25 个用例步骤重写清单

**管理看板（6 个）**：

| # | 用例名 | 页面类型 | 等待元素 | 关键优化 |
|---|--------|---------|---------|---------|
| 1 | 管理看板-时间范围筛选验证 | 图表 | canvas 30s | 删除登录步骤，筛选器选择器增加上下文 |
| 2 | 管理看板-图表数量验证 | 图表 | canvas 30s | 删除登录步骤，canvas 超时 30s |
| 3 | 管理看板-表格数据验证 | 表格 | .el-table 20s | 删除登录步骤 |
| 4 | 管理看板-多筛选器组合验证 | 图表 | canvas 30s | 删除登录步骤，筛选器选择器优化 |
| 5 | 会议概览-筛选器交互验证 | 图表 | canvas 30s | 删除登录步骤 |
| 6 | 会议室概览-筛选器验证 | 图表 | canvas 30s | 删除登录步骤 |

**运维管理（7 个）**：

| # | 用例名 | 页面类型 | 等待元素 | 关键优化 |
|---|--------|---------|---------|---------|
| 1 | 巡检报表-配置按钮验证 | 表格 | .el-table 20s | 删除登录步骤 |
| 2 | 巡检报表-分页功能验证 | 表格 | .el-table 20s | 删除登录步骤 |
| 3 | 巡检报表-下拉筛选验证 | 表格 | .el-table 20s | 删除登录步骤，筛选器选择器优化 |
| 4 | 运维统计-表格数据验证 | 表格 | .el-table 20s | 删除登录步骤 |
| 5 | 运维统计-筛选器验证 | 表格 | .el-table 20s | 删除登录步骤，筛选器选择器优化 |
| 6 | 运维统计-分页验证 | 表格 | .el-table 20s | 删除登录步骤 |
| 7 | 运维数据-页面筛选器验证 | 通用 | body 10s | 删除登录步骤，断言选择器增加回退 |

**数据分析（12 个）**：

| # | 用例名 | 页面类型 | 等待元素 | 关键优化 |
|---|--------|---------|---------|---------|
| 1 | 预定数据-多筛选器组合验证 | 图表 | canvas 30s | 删除登录步骤，canvas 超时 30s |
| 2 | 预定数据-图表数量验证 | 图表 | canvas 30s | 删除登录步骤 |
| 3 | 故障数据-日期范围筛选验证 | 图表 | canvas 30s | 删除登录步骤，日期选择器选择器优化 |
| 4 | 故障数据-图表数量验证 | 图表 | canvas 30s | 删除登录步骤 |
| 5 | 使用数据-图表数量验证 | 图表 | canvas 30s | 删除登录步骤 |
| 6 | 会议统计-下拉筛选验证 | 图表 | canvas 30s | 删除登录步骤，筛选器选择器优化 |
| 7 | 会议室统计-筛选器验证 | 图表 | canvas 30s | 删除登录步骤 |
| 8 | 历史记录-RSE-表格数据验证 | 表格 | .el-table 20s | 删除登录步骤 |
| 9 | 历史记录-SMC3.0-表格数据验证 | 表格 | .el-table 20s | 删除登录步骤 |
| 10 | 历史记录-WeLink-表格筛选验证 | 表格 | .el-table 20s | 删除登录步骤 |
| 11 | 通知统计-筛选器验证 | 图表 | canvas 30s | 删除登录步骤 |
| 12 | 会议服务统计-页面元素验证 | 图表 | canvas 30s | 删除登录步骤 |

---

### 2.2 Phase 2: 更新数据库中的深层用例（预计 0.5 天）

#### 2.2.1 任务清单

| 任务ID | 任务名称 | 说明 | 优先级 | 预计工时 |
|--------|---------|------|--------|---------|
| P2-001 | 运行脚本更新数据库 | 执行重写后的脚本，通过 API 更新/创建 25 个用例 | P0 | 0.2 天 |
| P2-002 | 验证数据库数据 | 检查用例步骤是否正确更新（无登录步骤、order 连续） | P0 | 0.1 天 |
| P2-003 | 备份数据库 | 更新前备份 test_platform.db | P0 | 0.05 天 |

#### 2.2.2 验证方法

1. 查询 API 确认用例步骤中不包含登录相关步骤
2. 确认步骤 order 从 1 开始连续编号
3. 确认 canvas 等待超时为 30000ms
4. 确认 `auto_login: True` 配置保持不变

---

### 2.3 Phase 3: 执行验证（预计 0.5 天）

#### 2.3.1 任务清单

| 任务ID | 任务名称 | 说明 | 优先级 | 预计工时 |
|--------|---------|------|--------|---------|
| P3-001 | 单用例执行验证 | 挑选 3 个代表性用例执行（1个图表页+1个表格页+1个筛选器页） | P0 | 0.2 天 |
| P3-002 | 批量执行验证 | 执行全部 25 个深层用例，记录通过率 | P0 | 0.2 天 |
| P3-003 | 问题修复 | 根据执行结果修复剩余问题 | P1 | 0.1 天 |

#### 2.3.2 验证方法

1. 通过 `/api/executions` 创建执行任务
2. 通过 `/api/executions/{id}/run` 触发执行
3. 观察执行日志，确认：
   - 无重复登录
   - canvas 等待不超时
   - 导航后页面正确加载
4. 统计通过率，目标 ≥ 80%

---

## 三、代码文件规划

### 3.1 修改文件清单

```
backend/
├── scripts/
│   └── create_deep_interaction_cases_v2.py    # 重写：删除登录步骤，优化模板和选择器
├── data/
│   └── test_platform.db                       # 数据：25个用例steps更新
```

### 3.2 不修改的文件

- `backend/app/executors/playwright_executor.py` — 执行器无需改动
- `backend/app/services/execution_service.py` — 执行服务无需改动
- `backend/app/schemas/test_case.py` — Schema 无需改动
- `frontend/` — 前端无需改动

### 3.3 依赖关系

```
Phase 1 (脚本重写) ← 独立，无外部依赖
    │
Phase 2 (更新数据库) ← 依赖 Phase 1（脚本可用）
    │
Phase 3 (执行验证) ← 依赖 Phase 2（数据已更新）
```

---

## 四、验证方案

### 4.1 回归测试

| 测试项 | 方法 | 预期 |
|-------|------|------|
| 登录不重复 | 执行深层用例，检查日志 | 仅 auto_login 登录一次，步骤中无登录操作 |
| canvas 不超时 | 执行管理看板用例 | canvas 等待 30s 内成功 |
| 步骤 order 连续 | 查看 API 返回的 steps | order 从 1 开始无 gap |
| 选择器精确 | 执行筛选器操作 | 匹配正确元素，不误点击 |

### 4.2 通过率目标

| 模块 | 用例数 | 目标通过率 | 说明 |
|------|--------|-----------|------|
| 管理看板 | 6 | ≥ 80% | canvas 页面可能因被测系统数据问题断言失败 |
| 运维管理 | 7 | ≥ 85% | 表格页面较稳定 |
| 数据分析 | 12 | ≥ 75% | 混合页面，部分 iframe 可能影响 |
| **总计** | **25** | **≥ 80%** | |

### 4.3 回滚方案

1. 数据库更新前备份 `test_platform.db`
2. 如需回滚，恢复备份即可
3. 脚本保留旧版函数注释，方便对比

---

## 五、风险与缓解

| 风险 | 概率 | 影响 | 缓解措施 |
|------|------|------|---------|
| canvas 30s 仍超时 | 低 | 高 | 进一步增加超时至 45s，或改为 wait_for_timeout + element_exists 宽松断言 |
| 选择器上下文不存在 | 中 | 中 | 使用 selectors 列表提供多选器回退链 |
| 被测系统无数据 | 中 | 低 | 断言使用 element_exists 而非 element_count_min，允许空数据 |
| iframe 中 canvas 无法定位 | 低 | 高 | 执行器 _do_wait 已支持 iframe 回退 |

---

*本文档遵循项目执行计划规范，修改计划时请同步更新。*
