Browse Source

test(测试负责人·70轮后·场景变更): 家庭加入身份改由邀请人指定(ec6aa0d49) → 新增TC-FA-01~17设计态契约用例 | approve-request新JoinApproveDTO必填校验+relation_type列+绝对辈分推导+配偶称谓修正 | 待实现+mvn转实测态(承袭R-3)

E2E Test Bot 5 days ago
parent
commit
837bccbb9d
1 changed files with 79 additions and 0 deletions
  1. 79 0
      docs/tdd/test/family-join-dynamic-identity-cases.md

+ 79 - 0
docs/tdd/test/family-join-dynamic-identity-cases.md

@@ -0,0 +1,79 @@
+# 家庭加入身份改由邀请人指定 · 测试用例更新(TC-FA 系列)
+
+> 触发源:`docs/superpowers/specs/2026-11-07-family-join-dynamic-identity.md`(已裁决,2026-11-07 18:28 落库 `ec6aa0d49`)
+> 场景溯源:SC-P-02 / SC-X-04 / SC-G-04
+> 影响范围:`FamilyInviteController` / `FamilyJoinRequestService` / `FamilyRelationshipService` / `FamilyMemberService` / `family_relationships.relation_type`(迁移 454/455)
+> 用例状态:**设计态**(后端实现未落地 + 沙箱无 mvn,待实现并授权 mvn 后转 @Test / E2E 实测态,闭环标准见文末)
+
+---
+
+## 一、需求变更对照(契约差异)
+
+| # | 接口/模块 | 变更前 | 变更后 | 规格锚点 |
+|---|---|---|---|---|
+| C1 | `POST /api/family/invite/request-join-by-code` | 读并落库 `familyRole` | `familyRole` **保留接收但忽略**,不写库(避免老客户端 400) | §4.1 |
+| C2 | `POST /api/user/join-family` | 同上 | 同上 | §4.2 |
+| C3 | `POST /api/family/invite/approve-request` | `Map<String,Object>` 只有 requestId/comment | 新 `JoinApproveDTO`:`generationLevel` 必填(7 档)、`peerType`(peer 时必填);校验失败 `Result.error("请选择辈分关系")` / `Result.error("请选择同辈关系类型")` | §4.3 |
+| C4 | `POST /api/family/invite/pending-requests` | `FamilyJoinRequestDTO` 无身份字段 | 新增 `requesterRealName` / `assignedGeneration` / `assignedPeerType` / `assignedPeerLabel` | §4.4 |
+| C5 | `family_relationships` | 无 `relation_type` 列 | 新列 `relation_type`(`lineal`/`sibling`/`spouse`),迁移 454 | §3/§5 |
+| C6 | `family_join_requests` | 无 assigned 列 | 新列 `assigned_generation` / `assigned_peer_type`,迁移 455 | §5 |
+| C7 | `FamilyRelationshipService.computeRelationshipLabel` | 2 参(仅 generationValue+gender,`case 0` 一律兄弟/姐妹) | 3 参 + relationType:`spouse`→男「丈夫」/女「妻子」;`sibling`→「兄弟/姐妹」;`lineal`→原逻辑;保留 2 参重载 | §6.1 |
+| C8 | `FamilyJoinRequestService.approveJoinRequest` | 3 参(requestId/approverUserId/comment) | 扩展 5 参(+generationLevel/peerType);绝对辈分 = 审批人成员辈分 + offset;写 `generate`/`isSpouse`;重建双向关系;`user.familyRole` 按绝对辈分+性别推导 | §6.2 |
+| C9 | `POST /api/family/invite/accept`(直加通道) | 读 `familyRole` | 保留兼容忽略;前端当前无调用点不扩展 | §4.5 |
+
+---
+
+## 二、新增用例(TC-FA-01 ~ TC-FA-12)
+
+> 落点建议:C3/C4/C8 → `ScG04InviteRegisterContractTest`(纯 Mockito,SC-G-04 同源)或新建 `FamilyInviteApproveContractTest`;C7 → `FamilyRelationshipService` 单测;C1/C2 → 控制器契约单测;C5/C6 → 迁移测试;C9/C10/C11 → `tests/e2e-live/` 复刻 `health-contract.spec.js` 模式。
+
+### 2.1 契约校验类(approve-request)
+- **TC-FA-01**:`approve-request` 请求体缺 `generationLevel` → `Result.error("请选择辈分关系")`(code≠200)。
+- **TC-FA-02**:`generationLevel=peer` 且缺 `peerType` → `Result.error("请选择同辈关系类型")`。
+- **TC-FA-03**:`generationLevel=parent`(非 peer)缺 `peerType` → 放行(成功路径,无类型要求)。
+- **TC-FA-04**:`generationLevel` 非法枚举 → 校验拒绝(`GenerationLevel.fromValue` 判 null)。
+
+### 2.2 成功路径类(approve-request 身份落地)
+- **TC-FA-05**:审批人成员 `generation=2`、选 `grandchild`(offset=-2) → 加入者绝对辈分=0;`FamilyMember.generation=0` 写入。
+- **TC-FA-06**:选 `peer`+`spouse` → 与既有成员双向 `relation_type='spouse'`;审批人为男 → 加入者为女时 `computeRelationshipLabel(spouse)` 出「妻子」(审批人视角)。
+- **TC-FA-07**:选 `peer`+`sibling` → 双向 `relation_type='sibling'`,label 按各自性别出「兄弟/姐妹」。
+- **TC-FA-08**:选 `parent` → 双向 `relation_type='lineal'`;审批人视角 label 出「儿子/女儿」(按加入者性别)。
+- **TC-FA-09**:审批通过后 `user.familyRole` 按推导表写入:绝对辈分≥2→爷爷/奶奶、1→爸爸/妈妈、≤0→其他(§3 推导表)。
+
+### 2.3 忽略语义类(friendRole 不再自述)
+- **TC-FA-10**:`request-join-by-code` 携带 `familyRole="妈妈"` → 接受不 400,且不写 `family_join_requests.family_role`(查库断言仍为 NULL/默认)。
+- **TC-FA-11**:`join-family` 携带 `familyRole` → 同上忽略。
+
+### 2.4 响应结构类
+- **TC-FA-12**:`pending-requests` 返回元素含 `requesterRealName`(真实姓名缺失回退昵称)、`assignedGeneration`、`assignedPeerType`、`assignedPeerLabel` 四字段,且不再展示申请人自述身份。
+
+### 2.5 数据迁移类
+- **TC-FA-13**:迁移 454 执行后 `family_relationships.relation_type` 存在且历史行默认 `lineal`;迁移 455 执行后 `family_join_requests.assigned_generation` / `assigned_peer_type` 存在(`ensureColumn` 幂等)。
+
+### 2.6 前端交互类(实现后 E2E)
+- **TC-FA-14**:`pages/invite/join-form.vue` 无「家庭身份」字段;副标题为「请填写您的真实姓名,提交后等待邀请人确认」;真实姓名留空提交被拦截「请输入真实姓名」。
+- **TC-FA-15**:审批弹窗(approveModal)不选辈分点确认 → 拦截「请选择辈分关系」;选同辈不选类型 → 拦截「请选择同辈关系类型」。
+- **TC-FA-16**:审批通过后,家庭页以审批人视角见加入者称谓(妻子/丈夫/兄弟/姐妹/儿子等按 TC-FA-06~08 断言);以加入者视角查看同一页见反向称谓(规格 A1~A3 双向断言)。
+
+> 规格 §9 验收用例 A1–A8 与上述用例映射:A1→TC-FA-06+16、A2→TC-FA-08、A3→TC-FA-07、A4→TC-FA-14、A5→TC-FA-15、A6→TC-FA-15、A7→TC-FA-06+13、A8→编辑资料改辈分后关系标签刷新(设计补充用例 TC-FA-17)。
+
+### 2.7 回归确认(存量用例受影响评估)
+| 存量用例 | 影响 | 处置 |
+|---|---|---|
+| `ScG04InviteRegisterContractTest`(SC-G-04 register-with-invite) | 注册链路不走 approve;`familyRole` 语义变化不触碰注册契约 | 不改,实现后补跑确认 |
+| `FamilyControllerTest.guideBindFamily_*`(引导绑定) | 走 `TeacherFamilyBindingRequestService`,不在本次变更范围 | 不改 |
+| `FamilyJoinRequestServiceReferrerBindTest` | 仅 referrer 绑定链路,不触碰 approve 参数 | 不改,补跑确认 |
+| `tests/user-scenarios/应用场景总览.md` SC-P-02 / SC-X-04 | 场景描述需随身份指定流程同步 | 场景文档由主理人/研发侧维护,测试侧引用规格为准 |
+
+---
+
+## 三、证据留档要求(闭环标准)
+
+1. **TC-FA-01~13(后端)**:`mvn -q compile` 通过 + 对应 @Test 0 失败(沙箱授权 mvn 后执行,继承 R-3 环境缺口)。
+2. **TC-FA-14~16(前端)**:前端 Jest 或 H5 E2E 实测截图/断言输出。
+3. **TC-FA-06/07/08(A7 SQL)**:`SELECT relation_type FROM family_relationships` 断言 spouse/sibling/lineal 落库结果。
+4. 全部用例通过后,本文件状态由「设计态」翻转为「实测通过」,并登记进下一轮自动化闭环报告。
+
+---
+
+*产物:docs/tdd/test/family-join-dynamic-identity-cases.md|登记:测试负责人(70 轮后场景变更闸门)|2026-11-07 18:45*