DEFECTS-api-remote-findings.md 8.0 KB

缺陷单 — 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 <token>。

预期结果: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 分支确实存在:

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」)。