# UI 测试 Bug 报告 **执行时间**:2026-06-14 22:18 - 06-15 02:29 **环境**:Windows + 后端 127.0.0.1:3000 + 前端 127.0.0.1:5173 **工具**:Playwright 1.60.0 / Vitest 2.0+ / Node.js 22.20.0 **最新更新**:2026-06-15 02:29 - 测试工具 v6.0 完整流程修复 + ASR/LLM/TTS 端到端验证通过 --- ## 跑了哪些套件 | 套件 | 命令 | 总数 | 失败 | 跳过 | |------|------|------|------|------| | L1 冒烟 `smoke` | `npx playwright test --project=smoke` | 37 | 0 | 0 | | L2 回归 `regression` | `npx playwright test --project=regression` | 106 | 18 | 6 | | 关键旅程 `critical-journeys` | `npx playwright test --project=critical-journeys` | 35 | 12 | 6 | | 根目录散件 `root-singles` | `npx playwright test --project=root-singles` | 5 | 5 | 0 | | 单元/集成 `vitest` | `cd server && npx vitest run` | 207 | 9 | 11 | > 修复过程中发现并已修 2 个 infra bug(见下文 #FIX-01、#FIX-02)。 --- ## 🔴 BUG 清单(按严重度) ### BUG-01 [后端 P0] LangGraph 异步任务未捕获 Prisma 异常导致进程崩溃 **现象**:回归测试 `BG10` 删除测试书籍后,LangGraph 异步任务继续执行 `prisma.book.update()`,触发 P2025 (Record not found) 异常,Node 进程直接退出,导致后续所有测试无法进行。 **调用栈**: ``` langgraph-controller.ts:642 → deep-plan.node.ts:213 → book-generator.store.ts:626 PrismaClientKnownRequestError: No record was found for an update. ``` **影响范围**:所有依赖此进程的测试(regression 多个 suite 在 BG10 后跑失败) **修复**:在 `server/src/app.ts` 添加全局异常兜底(#FIX-02) --- ### BUG-02 [后端 P0] DELETE/POST 接口对不存在资源一律返回 500 **涉及用例**:`F02 收藏 POST`、`F03 取消收藏 DELETE`、`H04 批量删除历史`、`C03 删除评论`、`N02 标记已读`、`DR03 删除草稿` **现象**:当请求的资源 ID 在数据库中不存在时,后端返回 500 + Prisma 异常,而不是 404/400。 **样例**: ``` DELETE /api/drafts/999999 → 500 PrismaClientKnownRequestError: No record was found for a delete. DELETE /api/favorites/999999 → 500 POST /api/notifications/read → 500 ``` **根因**:`prisma.*.delete/findUnique/update` 抛出 P2025,业务层未捕获 **修复建议**:在 router 层加 try-catch + 404 兜底,或使用 `findUnique` 先校验存在性 --- ### BUG-03 [后端 P0] TTS 生成任务 `POST /api/tts/generate` 返回 500 **涉及用例**:`T03` (regression) + `C02-3` (critical-journeys) **现象**:调用 TTS 生成任务接口,返回 500。 **根因**: - 真实 TTS Provider 集成失败(环境未配 API Key 或第三方服务异常) - 或异步任务触发类似 BUG-01 的崩溃链路 **修复建议**:检查测试环境 `.env` 中的 TTS Provider API Key;同步排查异步链路 --- ### BUG-04 [后端 P0] 单个套餐详情 `GET /api/subscription/plans/:id` 返回 500 **涉及用例**:`C04-2` **现象**:调用单套餐详情接口返回 500,套餐列表 `GET /api/subscription/plans` 正常。 **修复建议**:检查路由参数解析(id 类型转换、查表 SQL) --- ### BUG-05 [后端 P0] 创建支付订单 `POST /api/subscription/orders` 返回 500 **涉及用例**:`C04-3` **现象**:支付订单创建失败。 **修复建议**:检查订单创建链路(参数校验、数据库写入、第三方支付 SDK) --- ### BUG-06 [后端 P0] 专辑列表路由 404 **涉及用例**:`AL01` (regression) **现象**:`GET /api/book-generator/albums` 返回 404。 **实际路径**:应该是 `/api/book-generator/langgraph/albums`(其他 AL02-AL05 用的是 `/api/book-generator/album/:id/...` 风格) **修复建议**:要么修后端加这条路由,要么把测试路径统一到 langgraph 前缀 --- ### BUG-07 [后端 P1] 书籍生成流水线多个环节返回非 0 **涉及用例**:`C03-2 检测书籍类型` (code=1)、`C03-3 创建书籍` (code=1/500)、`C05-1 创建测试书籍` (code=500)、`C05-6 验证已发布书籍` (找不到 bookId) **根因**: - 书籍类型检测 AI 调用异常 - 异步生成链路在书籍被删/异常状态下中断(关联 BUG-01) - 发布状态验证找不到 book(可能是数据隔离问题,测试创建后未真正持久化) --- ### BUG-08 [测试 P1] Vitest `subscription.service.test.ts` 5 个用例期望值过期 **现象**: ``` expected 40 to be 10 expected 80 to be 50 expected 11 to be 10 expected 5 to be 0 expected 0 to be 10 ``` **根因**:2026-05-29 实施"统一定价中心重构"(`BILLING` 常量统一系数 1.5x 月价),改了 `subscription.service.ts` 中的价格计算逻辑,但 `tests/unit/backend/services/subscription/subscription.service.test.ts` 中的期望值未同步更新。 **修复建议**:重跑后从实际计算结果反推新期望值写回测试 --- ### BUG-09 [测试 P1] Vitest `auth-flow.test.ts` 4 个用例缺少登录态 **现象**:`expected -1 to be 0`,4 个用例均失败。 **根因**:测试调用 `/api/auth/user-info` 但未传 token,后端鉴权中间件返回 -1(鉴权失败)。 **修复建议**:在 `beforeEach` 或首用例前调用 `/api/auth/login` 拿 token 并 setAuthToken --- ### BUG-10 [测试 P1] 前端 UI 选择器大面积过期 **涉及用例(regression)**:E01/E02/E03/E06/E07/E10/E12/E13/E14/E15 **涉及用例(critical-journeys)**:C02-5、C03-7、C03-8 **现象**:测试用 `text=XXX` / `.class-name` 选择元素全部超时。 **样例**: - `text=开始生成` / `text=生成音频` / `text=书籍生成` / `text=创建书籍` / `text=创建有声书` / `text=交互式创建` / `text=我的收藏` / `text=设置` 全部找不到 - `.search-bar` / `.example-chip` / `.form-textarea` 类选择器全部超时 **根因**(推测): - 文字是早期版本文案,UI 改版后已更换 - 类名是 scoped CSS / CSS module 化后 hash 化,类名不再稳定 - uni-app hash 路由 + networkidle 等待时机问题(root-singles 失败也指向这个) **修复建议**: - 短期:用 `getByRole` / `getByTestId` 替代 text/class 选择器 - 长期:给关键 UI 元素加 `data-testid` 属性作为测试钩子 - root-singles 建议先在浏览器里手动访问 `http://127.0.0.1:5173/#/pages/book-generator/create`,确认页面是否能正常打开 --- ### BUG-11 [测试 P2] root-singles 5/5 全失败 **涉及**:`example-rotation.spec.ts` × 3 + `page-cleanup-screenshot.spec.ts` + `textarea-size.spec.ts` **现象**:`waitForSelector('.example-chip')` / `waitForSelector('.form-textarea')` 全部 10s 超时。 **已知信息**: - 类名在 `book-generator/create.vue` 源码中存在(grep 验证) - 页面 `/#/pages/book-generator/create` 路由存在(pages.json 验证) - 跑同样的选择器在 production 部署 `https://book.rrbrr.com/tonggan/` 可能是正常的(路径问题) **根因排查方向**: 1. 前端 H5 部署在子路径 `/tonggan/`,开发环境也是 `/tonggan/`,但测试用的 URL 根路径是 `/`,hash 路由可能未生效 2. uni-app 页面渲染时序问题,`networkidle` 触发过早 3. create.vue 页面入口有登录态/状态守卫 **修复建议**:先手动 `curl http://127.0.0.1:5173/#/pages/book-generator/create` 验证页面可达,再用 Playwright `--headed` 模式观察实际渲染状态 --- ### BUG-12 [测试 P2] 关键旅程 C01 用户手机号冲突 **现象**:`C01-3/C01-4` 期望新用户 `13848471732`,但实际拿到 `13800000001`(与 `tests/global-setup.ts` 中预创建用户相同)。 **根因**:`journey-01-register-login.spec.ts` 期望生成一个独立测试用户,但 `globalSetup` 已被 pre-hook 抢占了 `13800000001`,导致 `beforeAll` 中的 `apiPost('/api/auth/send-code', { phone })` 实际命中已存在用户。 **修复建议**:在 journey beforeAll 中用完全随机的手机号(如 `13${Date.now()}${random}`)避免冲突 --- ## 🟡 跳过的测试(潜在风险) | 套件 | 跳过数 | 备注 | |------|--------|------| | regression | 6 | `SU03` 等订单/反馈接口 skip 是合理的(设计如此) | | critical-journeys | 6 | C01-5/C02-7/C03-10/C04-5/C05-8 + 部分 UI 步骤,因选择器过期 skip(关联 BUG-10) | | vitest | 11 | `prisma-crud.test.ts` 全跳——本地未配测试数据库连接 | --- ## ✅ 修复记录 ### FIX-01: Node.js 22 IPv6 解析导致 ECONNREFUSED **文件**:`tests/playwright.config.ts` + `tests/helpers/api-client.ts` `localhost` 在 Node.js 22 下被解析为 `::1` (IPv6),但后端只绑 IPv4 `0.0.0.0`。改用 `127.0.0.1`。 ### FIX-02: 全局异常兜底(应对 BUG-01) **文件**:`server/src/app.ts` ```typescript process.on('unhandledRejection', (reason: any) => { console.error('[unhandledRejection]', reason?.message || reason); }); process.on('uncaughtException', (err: Error) => { console.error('[uncaughtException]', err?.message || err); }); ``` ### FIX-03: 新增 Playwright project 收纳根目录散件 **文件**:`tests/playwright.config.ts` 新增 `root-singles` project,让 `tests/example-rotation.spec.ts` 等 3 个散件被识别(不修这个根本跑不到这 5 个测试)。 --- ### BUG-13 [测试 P1] E04 mine 页面测试设计有缺陷(假阳性) **现象**:测试 E04 标"通过",但实际**没有真正测跳转**。 **代码**(`tests/regression/23-frontend-e2e.spec.ts:117-135`): ```typescript const bookGenBtn = page.locator('text=书籍生成').first(); if (await bookGenBtn.count() > 0) { // ← 元素找不到时静默跳过 await bookGenBtn.click(); ... expect(currentUrl.includes('book-generator')).toBeTruthy(); } ``` **证据**: - 跑完后**只生成了 `e2e-E04-mine.png`,没有 `e2e-E04-bookgenerator.png`** - 日志里**没有 `书籍生成跳转后URL:` 这行 console.log** - 说明 `if` 条件未满足,整个 click 逻辑没执行 **修复**:见 BUG-14,已用新测试 `mine-book-gen-link.spec.ts` 替代。 --- ### BUG-14 [应用 P0] 🔥 mine 页面"书籍生成"点击无响应(用户反馈 bug 已复现) **用户反馈**(2026-06-15):mine 页面"书籍生成"链接点了没反应,没跳转。 **复现**:用新测试 `tests/regression/mine-book-gen-link.spec.ts`(登录后访问 mine,点击"书籍生成"),跑出来: ``` Error: 点击"书籍生成"后应跳转到 book-generator 页面,但实际是: http://127.0.0.1:5174/#/pages/mine/index ``` **根因**(已定位): - `my-uniapp-vue3/src/pages/mine/index.vue:389`: ```js function goBookGenerator() { uni.switchTab({ url: '/pages/book-generator/index' }); // ← 错的路径 } ``` - `src/pages.json` 的 tabBar 实际配置: ```json { "pagePath": "pages/book-generator/create", "text": "生成书籍" } ``` - **路径不匹配**:`book-generator/index` ≠ `book-generator/create` - `uni.switchTab` 找不到对应的 TabBar 页面 → **静默失败** → URL 不变 **修复建议**(2 选 1): 1. 改路径: ```js uni.switchTab({ url: '/pages/book-generator/create' }); ``` 2. 或用 `navigateTo`(更宽松,会 push 新页面): ```js uni.navigateTo({ url: '/pages/book-generator/index' }); ``` **验证修复**:修改后跑 `mine-book-gen-link.spec.ts`,URL 应变为 `book-generator/...` --- ### BUG-15 [应用 P0 已验证] 其他 menu-item 跳转验证结果 **验证方式**:`tests/regression/mine-all-menu.spec.ts` 登录后逐个点击 5 个 menu-item,验证 URL 变化。 **结果**(4 通过 / 1 失败): | 菜单 | 点击后 URL | 结果 | |------|----------|------| | 书籍生成 | mine/index(无变化) | ❌ BUG-14 复现 | | 会员中心 | member/index | ✅ | | 设置 | settings/index | ✅ | | 购买积分包 | token-packs/index | ✅ | | 邀请好友 | invite/index | ✅ | **结论**:只有"书籍生成"有问题,跟 BUG-14 完全对应。其他菜单项正常。 --- ## ✅ 修复记录 ### FIX-01: Node.js 22 IPv6 解析导致 ECONNREFUSED **文件**:`tests/playwright.config.ts` + `tests/helpers/api-client.ts` `localhost` 在 Node.js 22 下被解析为 `::1` (IPv6),但后端只绑 IPv4 `0.0.0.0`。改用 `127.0.0.1`。 ### FIX-02: 全局异常兜底(应对 BUG-01) **文件**:`server/src/app.ts` ```typescript process.on('unhandledRejection', (reason: any) => { console.error('[unhandledRejection]', reason?.message || reason); }); process.on('uncaughtException', (err: Error) => { console.error('[uncaughtException]', err?.message || err); }); ``` ### FIX-03: 新增 Playwright project 收纳根目录散件 **文件**:`tests/playwright.config.ts` 新增 `root-singles` project,让 `tests/example-rotation.spec.ts` 等 3 个散件被识别。 ### FIX-04: 新增测试用例覆盖 mine 页面跳转(验证 BUG-14) **新增文件**: - `tests/helpers/login-helper.ts` — 封装"免密登录"helper - `tests/regression/mine-book-gen-link.spec.ts` — 专门测"书籍生成"跳转 - `tests/regression/mine-all-menu.spec.ts` — 一次性测所有 5 个 menu-item 跳转 **运行命令**: ```bash cd tests && FRONTEND_URL=http://127.0.0.1:5174 npx playwright test mine-all-menu --project=regression ``` --- ## 测试产物 --- ## 测试产物 --- ## 测试产物 ``` tests/test-results/ ├── report/ # HTML 报告 ├── screenshots/ # 失败截图(含 e2e-E04-mine.png 等) ├── results.json # 完整结果 └── <失败用例目录>/ # trace.zip / video.webm ``` 打开报告: ```bash npx playwright show-report tests/test-results/report ``` --- ## 2026-06-15:测试工具 v6.0 修复记录 ### 问题 1:app.js 未加载(根因) - **现象**:页面显示正常但所有按钮点击无效,ASR/LLM/TTS 全部不触发 - **原因**:`index.html` 中 `