# 缺陷单 — API 级 e2e 实测发现(远程环境 cfc.iwintrue.com) > 来源:2026-10-30 API 级 e2e 实跑(`tests/playwright.config.api.js`,目标 `http://cfc.iwintrue.com`) > 复现环境:Chromium 1.61.1 + Playwright 1.61.1 / Node 22 / Windows > 账号来源:测试专用直注接口 `/api/auth/direct-register` 自注册(每个用例独立家庭,互不干扰) --- ## CFC-EN-001 — 能量发放接口返回 500「服务器内部错误」 | 项 | 内容 | |---|---| | **模块** | 能量系统 `/api/energy/grant` | | **严重程度** | 高(核心玩法链路不可用) | | **优先级** | P0 | | **类型** | 功能缺陷 / 健壮性(未捕获异常) | | **关联用例** | `tests/e2e/api/energy-api.spec.js` 场景2(fixme)、场景2c(特征化)、场景6(fixme) | **前置条件**:已登录家长账号,所在家庭存在成员记录,`energy_dimension` 五维配置已就绪(`/api/energy/overview` 可正常返回 body/mind/wisdom/action/wealth)。 **复现步骤**: 1. `POST /api/auth/direct-register` 注册家长账号,取得 token 与 familyId。 2. `POST /api/family/member/list`(body `{}`)取得自身 memberId。 3. `POST /api/energy/grant`,body:`{ memberId, taskId: 88888888, amount: 10, dimensionCode: "body" }`,Header 携带 `Authorization: Bearer `。 **预期结果**:`code=200`,返回 `EnergyLog` 记录,能量余额增加且 `/api/energy/logs` 可查到该 `sourceId` 的流水。 **实际结果**:`code=500`,`message="服务器内部错误"`,`data=null`。响应耗时 365–975ms(非超时),带/不带 `dimensionCode` 均复现。 **根因线索(代码级)**: `EnergyController.grantEnergy` → `EnergyService.grantEnergy`(约 1890 行)→ `awardEnergy`(1541 行)→ `awardByConfig` → `executeAward`。 该链路内部存在未捕获异常并被 Spring 兜底为 500,建议在 `executeAward` 中补充成员余额记录存在性校验与 `try/catch`,并把异常转为业务错误(`Result.error(e.getMessage())`)而非「服务器内部错误」。 **修复建议**: 1. `executeAward` 更新成员能量余额前,先校验 `family_members` 记录存在且未删除,避免空指针。 2. 捕获异常并返回可读的业务错误信息,替代兜底 500。 3. 补充单测:空余额记录 / 无 dimension 配置 / 超过日上限 三条边界。 --- ## CFC-FM-001 — 家庭成员更新接口:昵称更新返回成功但未生效 | 项 | 内容 | |---|---| | **模块** | 家庭成员 `/api/family/member/update` | | **严重程度** | 中(数据未按用户操作落库) | | **优先级** | P1 | | **类型** | 功能缺陷(字段级不生效) | | **关联用例** | `tests/e2e/api/family-member-api.spec.js` 场景4(fixme)、场景4c(特征化) | **前置条件**:已登录家庭管理员(家庭创建者),家庭内存在一名「无关联登录账号」的手动成员。 **复现步骤**: 1. 注册家长账号并取得 token。 2. `POST /api/family/member/add`,body `{ generationLevel:"child", nickname:"QA_N1", gender:"male", birthday:"2015-06-15" }`,记录返回的 memberId。 3. `POST /api/family/member/update`,body `{ memberId, nickname:"QA_NICK_NEW" }`。 4. `POST /api/family/member/list` 查看该成员昵称。 **预期结果**:更新后 `code=200`,响应体与成员列表中该成员 `nickname` 均变为 `QA_NICK_NEW`。 **实际结果**:`code=200`、`message="success"`,但**响应体 `nickname` 仍为旧值 `QA_N1`**,成员列表中同样为旧值。 **对照实验(已验证)**:同一次 update 请求中携带 `gender:"female"`、`birthday:"2017-05-05"` 时,这两个字段**均能正确更新并回显**。故问题精确落在 `nickname` 单一字段,非整体 update 失效。 **根因线索(代码级)**: 本地源码 `FamilyMemberService.updateMember`(约 969 行)中 nickname 分支**确实存在**: ```java String oldNickname = member.getNickname(); if (dto.getNickname() != null && !dto.getNickname().trim().isEmpty()) { member.setNickname(dto.getNickname().trim()); } ... familyMemberMapper.updateById(member); ``` `FamilyMember.nickname` 亦为普通字段(无 `FieldStrategy` 排除策略)。 **因此高度怀疑:远程部署构建版本落后于当前代码仓库(远程为较旧构建,尚无 nickname 更新逻辑)**;次要可能为运行时 MyBatis-Plus 更新策略或触发器导致 nickname 列被跳过。 **修复建议**: 1. 研发核对 `http://cfc.iwintrue.com` 所部署的构建版本与 commit,确认是否包含 nickname 更新逻辑;若落后则重新部署并回归。 2. 若版本一致,请在 `updateMember` 内于 `updateById` 后回查一次 `family_members.nickname` 做自校验,不一致即抛业务错误,避免「假成功」。 3. 补充回归用例:昵称更新后必须能从 `/api/family/member/list` 读回新值。 --- ## CFC-ENV-001 — 远程环境未托管前端 SPA,DOM 型 e2e 全面不可用 | 项 | 内容 | |---|---| | **模块** | 部署环境 / 测试基础设施 | | **严重程度** | 中(阻塞 UI 回归) | | **优先级** | P1 | | **类型** | 环境配置 | | **关联用例** | `tests/e2e/*.spec.js`(36 个 DOM 型 spec)、`tests/user-scenarios/*` | **前置条件**:使用 `tests/playwright.remote.config.js`(baseURL = `http://cfc.iwintrue.com`)运行任何基于 `page.goto('/#/pages/...')` 的用例。 **复现步骤**: 1. 浏览器访问 `http://cfc.iwintrue.com/#/pages/family/add-member`。 2. 观察页面内容。 **预期结果**:渲染出前端 SPA 的「添加家庭成员」页面(uni-app 哈希路由)。 **实际结果**:返回 **Spring Boot 白标错误页**: ``` Whitelabel Error Page This application has no explicit mapping for /error, so you are seeing this as a fallback. There was an unexpected error (type=Not Found, status=404). ``` 访问根路径 `http://cfc.iwintrue.com/` 结果相同。说明该 host 仅部署后端 API,**未部署前端静态资源**。 **影响**:原 DOM 型 e2e(家庭成员/能量/文章/联系人/规划师看板等 32 条)在远程**必然全部超时失败**,与业务实现无关。 **修复建议**: 1. 明确前端 SPA 的真实宿主地址(子域 / 端口 / CDN),在 `playwright.remote.config.js` 中与 API host 分离配置(`baseURL` 指前端,`extraHTTPHeaders`/baseURL 供 API 调用)。 2. 若前端暂未部署,请保留 API 级 e2e 作为远程回归主手段(本次已建立,见下)。 --- ## CFC-ENV-002 — 家庭成员新增接口冷启动首调耗时约 16 秒 | 项 | 内容 | |---|---| | **模块** | 家庭成员 `/api/family/member/add` 性能 | | **严重程度** | 低 | | **优先级** | P2 | | **类型** | 性能 | | **关联用例** | `tests/e2e/api/family-member-api.spec.js` 场景2/3/7 | **复现步骤**:同一账号下连续调用 `POST /api/family/member/add` 三次并计时。 **预期结果**:各次响应耗时稳定且在秒级以内。 **实际结果**:**首调 16.3s**,后续 1.5s / 1.5s。首调包含 `unlockGateService.refreshFamilyGates`、通关联动初始化与数据源预热等一次性开销。 **影响**:超过 Playwright 默认 actionTimeout(15s) 会**误报为接口失败**(本次实测即因此产生 8 条假失败)。 **修复建议**: 1. 服务端预热该链路(懒加载改为启动期初始化 / 连接池预热)。 2. 测试侧已放宽超时(`helpers/api.js` 中 `API_TIMEOUT_MS = 60000`,配置 `timeout: 180000`),但仍建议后端优化首调耗时。 --- ## 附:本次 API 级 e2e 实测基线(改造后) | 模块 | 用例数 | 结果 | |---|---|---| | api-smoke | 4 | 全部通过 | | article-api | 7 | 全部通过 | | contact-api | 6 | 全部通过 | | energy-api | 10 | 8 通过 + 2 fixme(受 CFC-EN-001 阻塞) | | family-member-api | 13 | 12 通过 + 1 fixme(受 CFC-FM-001 阻塞) | | **合计** | **40** | **35 通过 / 2 fixme / 3 特征化用例通过** | > 对比:同批场景在 DOM 型 e2e 上为 10 通过 / 32 失败(且失败原因全部为「远程无 SPA」)。