# HANDOFF — UI自动化测试交接文档

> **生成时间**: 2026-08-21
> **当前分支**: `platform-auto-test`
> **最近提交**: `26dbafbf` docs(handoff): 更新会话35 P1 遗留待办闭环记录
> **状态**: 🟢 **会话37：会议室列表 + 资产信息 navigate 直达 URL 化改造 + 5.60 生产部署。10 个用例（7+3）全量重写，本地执行 10/10 通过 100%；执行器 `element_count_min` 新增 micro-app 轮询兜底。**

---

## 📊 当前状态（会话 37，2026-08-21）

**会议室列表 + 资产信息模块通过 `/sut-explore` 探测完成 navigate 直达 URL 改造**：原有 7 个会议室列表用例 + 3 个资产信息用例全部从「click 导航」改为「navigate 直达 URL」模式；`page_url_mapping.json` 补充 `asset_info` 页面完整配置（url_patterns/fingerprint/match_rules/skip_steps）；新增执行器 `element_count_min` micro-app 轮询兜底（8s 轮询）。本地执行 **10/10 通过，100%**。已通过 `sync_to_560_full.py` 部署到 5.60 生产。

### ✅ 会议室列表直达 URL 改造（会话 37，2026-08-21）

**背景**：既有 7 个会议室列表用例首步为 click 导航，headless 下微前端菜单不稳定 → 全部改为 navigate 直达 `MeetingRoomList` URL。

**改动清单**：

| 文件 | 改动 |
|------|------|
| `backend/scripts/generate_meetingroom_cases.py` | 7 个用例全量重写为首步 navigate 直达 MeetingRoomList URL（页面访问/查看详情/预览功能/搜索/筛选/预约会议/预览详情） |
| `backend/scripts/fix_meetingroom_cases_r2.py` | 第二轮修复 4 个失败用例（详见下） |
| `backend/app/executors/playwright_executor.py` | **`element_count_min` 新增 micro-app 轮询兜底**：`query_selector_all` 无法穿透 `<micro-app-body>`，8s 轮询调用 `_do_in_micro_apps('count', selector)` 直到 count ≥ min_count |

**2 轮迭代执行结果（本地）**：

| 轮次 | 执行 | 结果 | 失败根因 |
|------|------|------|----------|
| R1 `exec_7d4610da` | 3 pass / 4 fail | ① 预约会议 step 3 名称含"新建会议" → 触发 `create_meeting` 页面识别跳过（score 4.5 > meeting_room_list 3.0）② 查看详情/预览详情 element_exists 5s 超时（micro-app 内容渲染慢）③ 筛选功能 `element_count_min` 零等待返回 0 |
| R2 `exec_ba70a09e` | **7 pass / 0 fail（100%）** | 修复后全绿 |

**R2 修复详情**：

| 用例 | 失败根因 | 修复 |
|------|----------|------|
| 预约会议验证 | step 3 名称"点击新建会议按钮"含"新建会议"→ `create_meeting` 页面识别得分 4.5 > meeting_room_list 3.0 → step 被 skip → 后续断言失败 | 重命名为"点击预约会议入口"（不含"新建会议"→ create_meeting 降为 2.5，meeting_room_list 3.0 获胜） |
| 查看详情 | element_exists `input[placeholder='日期']` 5s 超时（micro-app 内容渲染慢） | 添加 wait `.room_item` 20000ms 等待卡片加载 |
| 预览详情 | element_exists `button:has-text('预览')` 5s 超时 | 同上，添加 wait `.room_item` 20000ms |
| 筛选功能验证 | `element_count_min input.el-input__inner ≥ 2` 零等待返回 0（micro-app 内容未渲染） | 改为 wait `input[placeholder='日期']` 20000ms + 逐个 element_exists 断言 |

**最终 7 用例结果（R2）**：

| 用例 | 用时 | 状态 |
|------|------|------|
| 会议室列表页面访问验证 | 14.5s | ✅ |
| 会议室列表-查看详情 | 13.5s | ✅ |
| 会议室列表-预览功能 | 15.8s | ✅ |
| 会议室列表-搜索功能 | 14.2s | ✅ |
| 会议室列表-筛选功能验证 | 15.1s | ✅ |
| 会议室列表-预约会议验证 | 18.9s | ✅ |
| 会议室列表-预览详情验证 | 15.6s | ✅ |

### ✅ 资产信息探测与直达 URL 改造（会话 37，2026-08-21）

**背景**：`page_url_mapping.json` 会话 35 已注册 `asset_info` 条目但 url_patterns/fingerprint 留空。通过 `/sut-explore 资产信息` 探测真实 DOM 与 URL，完成完整配置。

**探测发现**（Chrome DevTools MCP 真机）：
- 直达 URL：`https://192.168.5.44/#/meetingV3?meetingV3=%2FmeetingV3%2F%23%2FAssetinformation`
- 真实 DOM：`input[placeholder='请输入关键字查询']`、`input[placeholder='请选择状态']`（readonly）、按钮「添加条目/下载模板/导入表格/批量报修/批量报废/批量删除」
- 表格 26 条数据，选择器 `.el-table__row`
- **操作按钮为 `<div class="operation_btn">` 非 `<button>`**（关键发现）

**改动清单**：

| 文件 | 改动 |
|------|------|
| `backend/app/data/page_url_mapping.json` | `asset_info` 条目补全：url（直达 Assetinformation URL）、url_patterns（`Assetinformation`）、fingerprint（`input[placeholder='请输入关键字查询']`）、match_rules（step_name_contains: 资产信息 + url_contains: Assetinformation）、skip_steps（资产信息/点击进入主页 + click） |
| `backend/scripts/generate_asset_info_cases.py` | 3 个用例全量重写为首步 navigate 直达（页面访问验证/表格数据验证/筛选器交互验证） |

**2 轮迭代执行结果（本地）**：

| 轮次 | 执行 | 结果 | 失败根因 |
|------|------|------|----------|
| R1 `exec_129e8410` | 2 pass / 1 fail | 表格数据验证 step 6 `button:has-text('编辑')` 5s 超时 → 操作按钮是 `<div class="operation_btn">` 不是 `<button>`，`:has-text()` 是 Playwright 伪选择器在 micro-app eval 中被剥离 |
| R2 `exec_adf5c2fc` | **3 pass / 0 fail（100%）** | 修复后全绿（选择器从 `button:has-text('编辑')` 改为 `.operation_btn`，`button:has-text('删除')` 改为 `element_count_min .operation_btn ≥ 2`） |

**最终 3 用例结果（R2）**：

| 用例 | 用时 | 状态 |
|------|------|------|
| 资产信息-页面访问验证 | 12.3s | ✅ |
| 资产信息-表格数据验证 | 12.8s | ✅ |
| 资产信息-筛选器交互验证 | 14.1s | ✅ |

### ✅ 5.60 生产部署（会话 37，2026-08-21）

**部署内容**（`sync_to_560_full.py` 一键同步）：

| 项目 | 说明 |
|------|------|
| 5 个后端文件 | `playwright_executor.py`（148KB，含 element_count_min 轮询增强）、`smart_locate_service.py`（90KB）、`execution_service.py`（40KB）、`scheduled_tasks.py`（11KB）、`page_url_mapping.json`（12KB，含 asset_info 完整配置） |
| 314 个用例 | UPSERT 到 MySQL `test_cases` 表（含 7 个会议室列表 + 3 个资产信息新用例） |
| 容器重启 | `docker restart plat-auto-test-app` → healthy |
| 验证 | 7 个会议室用例全部存在、`page_url_mapping.json` md5 本地与远程一致（`cb02b6603275422bb531489e3bf8284a`） |

---

**P1 遗留待办已闭环并提交**（`466b9f40`）：验证字段统一 + 断言补全 + 前端验证编辑区 + 二级菜单注册 19 页。详见 `Docs/PRD/需求文档/用例管理/_PRD_需求文档_P1遗留_验证步骤前端适配与定位器优化.md`。

---

## 📊 会话历史时间线

| 会话 | 日期 | 主题 | 结果 |
|------|------|------|------|
| 37 | 08-21 | **会议室列表 + 资产信息直达 URL 化改造 + 5.60 部署**：7+3 用例 navigate 直达；page_url_mapping 补全 asset_info；`element_count_min` micro-app 8s 轮询兜底 | ✅ 本地 10/10、已部署 5.60 |
| 36 | 08-21 | **会议模板/参会人模板直达 URL 化改造**：9 用例 navigate 直达；注册 2 页；修复 2 个执行器 BUG | ✅ 本地 9/9 |
| 35 | 08-21 | **P1 遗留待办闭环**：verify 字段统一 + body_not_contains 断言 + 前端编辑 + 二级菜单 19 页注册 | ✅ 后端 239 测试、前端 build 通过 |
| 34 | 08-20 | **修复门口屏发布 2 用例 micro-app 穿透**：`_ensure_micro_app_loaded` 阶段1 deadline 毫秒未转秒 bug（8ms→8s）；阶段2 无条件 hash 重置 | ✅ Round 15 2/2 全绿 65.4s |
| 33 | 08-20 | **5.41 服务器部署最新版前后端包** | ✅ 容器 healthy |
| 31 | 08-19 | **定时任务「立即执行」不生成记录修复 + 取消即停**：`manual` 参数区分触发来源；`request_cancel` 信号中断工作线程 | ✅ 4 文件已部署 5.44+5.202 |
| 30 | 08-19 | **数据统计模块新增 10 用例 + `/sut-explore` Skill 沉淀**：V4 全量 10/10 通过 | ✅ 本地验收通过，待同步 5.60 |
| 29 | 08-19 | **修复 MySQL 1205 行锁取消 + SUT URL 校验加固**：置 running 后立即 commit；身份映射隐藏 bug 修复；`_validate_sut_url` 拒绝非法地址 | ✅ 后端 186 测试、已部署 5.60、取消 91ms |
| 28 | 08-19 | **系统配置切换 SUT 后用例自动跟随（地址重写）**：`_rebase_sut_url` 130 条存量硬编码自动跟随 | ✅ 后端 182 测试、已部署 5.60 |
| 27 | 08-19 | **UI自动化定时任务模块 + 系统配置SUT URL**：调度引擎/CRUD/报告/配置持久化 | ✅ 后端 179 测试、已部署 5.60 |
| 26 | 08-19 | **新建会议 step 11/17 执行失败修复**：保留页面直达 + 策略5 增强 + step 12 改「保持立即开始」 | ✅ 本地+生产各 3 次全绿 |
| 25 | 08-19 | 新建会议执行失败根因定位（页面直达+表格懒加载+checkbox 隐藏） | ✅ 已定位 |
| 24 | 08-18 | finally api_call 真实化 + 完整 17 步验收通过 | ✅ 5.60 全绿 |
| 23 | 08-18 | 语义化机制部署 5.60 + 生产验证（连跑两次全绿） | ✅ 已部署 |
| 22 | 08-18 | 语义化机制真实验证（16 步主流程连跑两次全绿） | ✅ 验证通过 |
| 21 | 08-18 | 语义化阶段6：前端语义编辑 + 示范用例 + 参数持久化修复 | ✅ 代码已提交 |
| 20~9 | 08-11~18 | 映射修复/部署/智能定位/Claude 语义增强/微前端支持/Phase1-6 | ✅ 全部完成 |
| 1~7 | 08-05~07 | 验证类步骤自动识别/智能定位 Phase1-6 端到端验证 | ✅ 完成 |

---

## ⚠️ 关键约束

| # | 约束 | 说明 |
|---|------|------|
| 1 | **Playwright 必须同步 API** | Windows 异步 API 无法启动。`main.py` 已配 ProactorEventLoop；`execution_service` 经 `run_in_executor` 线程池执行 |
| 2 | **工作线程 `asyncio.set_event_loop(None)`** | 在 `start()` 内绕过 Playwright 的 `get_running_loop()` 检测 |
| 3 | **每用例新建 PlaywrightExecutor 实例** | 共享实例 `stop()` 后 `_is_running=False`，下次 `start()` 失败 |
| 4 | **前端 axios baseURL 必须空字符串** | 路径写完整 `/api/...`，否则 `/api/api/cases` 404 |
| 5 | **`useRoute()` 必须在 setup 顶层** | computed 内调用报错，页面空白 |
| 6 | **前端 axios 超时 5 分钟** | `request.ts` 已配 300000ms |
| 7 | **SQLite 并发写锁** | 已配 `check_same_thread=False` + `pool_pre_ping=True` |
| 8 | **uvicorn 勿加 `--reload`（Windows）** | WatchFiles 卡死，改后必须重启进程 |
| 9 | **MySQL 密码勿含 `@`** | 生产用 `PlatApp2026`；ID 字段 `String(64)` |
| 10 | **page_url_mapping.json 单例不热加载** | 新增条目需重启 uvicorn |
| 11 | **操作按钮 selector 注意** | 资产信息等页面操作按钮是 `<div class="operation_btn">` 非 `<button>`，`:has-text()` 在 micro-app eval 中被剥离 |
| 12 | **语义化开关（settings flag）** | `SEMANTIC_ENABLED` / `USE_KEYWORD_MATCHER` / `USE_FUZZY_MAPPING`（默认 false）/ `ENFORCE_VERIFICATION` |
| 13 | **tar 打包前端 dist 用 `arcname='dist'`** | 否则解压后嵌套目录，`assets/` 为空 → 容器启动报错 |

---

## 🔑 关键配置信息

| 项目 | 值 |
|------|-----|
| 服务器 IP | 192.168.5.60（Docker 容器化，`plat-auto-test-app`） |
| 5.41（测试管理平台部署服务器） | root / **Ubains@123** · 端口 8081 · 单独部署脚本 `deploy/deploy.41.sh` |
| 5.44 SSH（平台部署服务器 + 被测系统） | root / **Ubains@123** |
| 5.60 SSH 用户/密码 | ubains / **Ubains@123** |
| 部署目录 | `/data/third_party/plat-auto-test/` |
| 前端 / API / 健康检查 | http://192.168.5.60 / `/docs` / `/health` |
| MySQL 外部访问 | 192.168.5.60:3307 · platapp / **PlatApp2026** |
| 被测系统 | https://192.168.5.44（微前端 micro-app） |
| 登录凭据 | admin@xty / **Ubains@13579** · 验证码固定 `csba` |
| 远程仓库 | http://git.ubainsyun.com/bing/ubains-module-test.git |

---

## 🚀 启动与运维

```bash
# 后端（端口 8001；勿加 --reload）
cd backend && pip install -r requirements.txt && playwright install chromium
uvicorn app.main:app --port 8001

# 前端（端口 3000，代理指向 8001）
cd frontend && npm install && npm run dev

# 测试
cd backend && pytest tests/ -v --cov=app --cov-report=html
cd frontend && npm run build
```

---

## 📑 文档索引

| 文档 | 路径 |
|------|------|
| 项目指南 | `CLAUDE.md` |
| 多窗口并行开发指南 | `Docs/多窗口并行开发指南.md` |
| 主 PRD | `Docs/PRD/需求文档/总览/_PRD_平台自动化测试可视化系统需求文档.md` |
| 语义化用例执行 PRD/计划 | `Docs/PRD/需求文档/用例管理/_PRD_复杂用例通用执行机制_语义化用例执行.md` |
| 定时任务模块 PRD/计划 | `Docs/PRD/需求文档/定时任务/_PRD_需求文档_UI自动化定时任务模块与系统配置被测系统URL.md` |
| P1 遗留待办 PRD/计划 | `Docs/PRD/需求文档/用例管理/_PRD_需求文档_P1遗留_验证步骤前端适配与定位器优化.md` |
| 新建会议问题处理 | `Docs/PRD/问题处理/会议管理/_问题处理_新建会议用例执行失败_页面直达后会议室表格checkbox不可见.md` |
| HANDOFF 总交接 | `HANDOFF.md` |
| V2 部署交接 | `HANDOFF_V2部署升级.md` |
| 安全测试交接 | `HANDOFF_安全测试.md` |

---

## ✅ 待办事项（仅未完成）

### P2（低优先级）

- [ ] 完善二级菜单映射表（`menu_mapping.py`）
- [ ] 智能定位 API 与用例执行路径统一（当前两者逻辑分离）
- [ ] Claude 调用性能优化（缓存结果、减少超时时间）
- [ ] 维护 jieba 自定义词典（专业术语分词优化）
- [ ] Docker 容器安装中文字体（修复截图乱码，不影响定位）

### 待验证（会话 31 产出）

- [ ] **5.44 前端点击「立即执行」验证**：此前点击不会生成新执行记录；修复后应生成新 execution，`status` 应为 `triggered`
- [ ] **5.44 取消即停验证**：执行中点击取消 → 工作线程在用例/步骤边界退出，`run_execution` 快速返回，锁释放，可立即再点执行
- [ ] **前端 `status` 字段消费**（可选增强）：后端已返回 `status: triggered/skipped` + `running_execution_id`

---

*本文档由 Claude Code 于 2026-08-21 更新（会话 37：会议室列表 + 资产信息 navigate 直达 URL 化改造——7+3=10 个用例全量重写，本地执行 10/10 通过 100%，已部署 5.60 生产，执行器 element_count_min 新增 micro-app 轮询兜底）。*