Просмотр исходного кода

test(cfc-frontend): S-cfc-132 契约测试 family.signature.healthPlanSummary - health-plan-summary.vue 摘要组件未落地(RED 8失败待GREEN)

Sisyphus Agent 1 день назад
Родитель
Сommit
a3585aa579

+ 137 - 0
cfc-frontend/__tests__/pages/signature/signature.healthPlanSummary.test.js

@@ -0,0 +1,137 @@
+/**
+ * 契约级单测(TDD-RED)——能力键 family.signature.healthPlanSummary(S-cfc-132)
+ *
+ * 溯源:
+ *   requirement: docs/superpowers/specs/2026-11-07-signature-page-landscape.md
+ *                §3 AC-R3(签署回传)、§5 WI-3(问卷完成签名改造:移除内嵌画布 → 「去签名」按钮 + 已签预览;
+ *                确认按钮仍依 signatureDataUrl 判空禁用)+ B-135-1(前端 16 红登记:
+ *                pages/signature/components/ 子组件为真缺口,非假 RED)
+ *   design:      cfc-frontend/pages/signature/components/health-plan-summary.vue
+ *                —— Step 3 健康计划摘要子组件(新建:展示 计划名 / 周期 / 项目 / 参与人;提供确认回调;实现仅在 feature 分支,
+ *                不得假定包路径,组件落地后本套件转绿)
+ *
+ * 说明:本文件与 __tests__/pages/signature/signature.healthPlan.test.js(S-cfc-52 键 family.signature.healthPlan)
+ * 锚定同一设计组件;本文件为能力键 family.signature.healthPlanSummary(S-cfc-132,B-135-1 重新登记键)的契约登记。
+ * 两套件均只读 .vue 源码做结构/行为契约断言,不求值 import、不修改 pages/、components/、utils/ 任何业务代码。
+ *
+ * TDD 现状(预期 RED):
+ *   pages/signature/components/ 下当前仅有 hand-signature/,health-plan-summary.vue 尚未落地 →
+ *   - 存在性断言失败(主红信号);
+ *   - 契约断言经 loadTemplate/loadScript 加载组件时抛出「契约未落地」错误(溯源清晰的次红信号)。
+ * 实现方在后续 GREEN 阶段落地该组件并导出健康计划摘要契约后,本文件断言即翻绿。
+ */
+
+const fs = require('fs')
+const path = require('path')
+
+const HEALTH_PLAN_SUMMARY = path.join(
+  __dirname,
+  '../../../pages/signature/components/health-plan-summary.vue'
+)
+
+// ---------------------------------------------------------------------------
+// 工具:加载真实 SFC 的 <template>/<script> 文本(组件落地后生效;缺失时抛「契约未落地」)
+// ---------------------------------------------------------------------------
+
+function ensureExists() {
+  if (!fs.existsSync(HEALTH_PLAN_SUMMARY)) {
+    throw new Error('契约未落地:pages/signature/components/health-plan-summary.vue 不存在(GREEN 阶段需新建该组件)')
+  }
+}
+
+function loadTemplate() {
+  ensureExists()
+  const src = fs.readFileSync(HEALTH_PLAN_SUMMARY, 'utf8')
+  const m = src.match(/<template>([\s\S]*?)<\/template>/)
+  if (!m) throw new Error('health-plan-summary.vue 缺少 <template> 块')
+  return m[1]
+}
+
+function loadScript() {
+  ensureExists()
+  const src = fs.readFileSync(HEALTH_PLAN_SUMMARY, 'utf8')
+  const m = src.match(/<script>([\s\S]*?)<\/script>/)
+  if (!m) throw new Error('health-plan-summary.vue 缺少 <script> 块')
+  return m[1]
+}
+
+// ---------------------------------------------------------------------------
+// AC1 组件存在性(TDD-RED 主红信号)
+// ---------------------------------------------------------------------------
+
+describe('AC1 契约:health-plan-summary.vue 存在', function () {
+  test('组件文件 pages/signature/components/health-plan-summary.vue 存在', function () {
+    expect(fs.existsSync(HEALTH_PLAN_SUMMARY)).toBe(true)
+  })
+})
+
+// ---------------------------------------------------------------------------
+// AC2 Step 3 展示健康计划摘要:计划名 / 周期 / 项目 / 参与人
+// ---------------------------------------------------------------------------
+
+describe('AC2 契约:Step 3 展示健康计划摘要(计划名/周期/项目/参与人)', function () {
+  test('展示「计划名」及数据绑定', function () {
+    const tpl = loadTemplate()
+    expect(tpl).toMatch(/计划名/)
+    expect(tpl).toMatch(/planName|plan\.name|plan_name/)
+  })
+
+  test('展示「周期」及数据绑定', function () {
+    const tpl = loadTemplate()
+    expect(tpl).toMatch(/周期/)
+    expect(tpl).toMatch(/cycle|cycleText|周期/)
+  })
+
+  test('展示「项目」列表(label + 列表渲染)', function () {
+    const tpl = loadTemplate()
+    expect(tpl).toMatch(/项目/)
+    expect(tpl).toMatch(/items|projects|planItems/)
+    expect(tpl).toMatch(/v-for/)
+  })
+
+  test('展示「参与人」列表(label + 列表渲染)', function () {
+    const tpl = loadTemplate()
+    expect(tpl).toMatch(/参与人/)
+    expect(tpl).toMatch(/participants|participant|members/)
+    expect(tpl).toMatch(/v-for/)
+  })
+})
+
+// ---------------------------------------------------------------------------
+// AC3 提供确认回调
+// ---------------------------------------------------------------------------
+
+describe('AC3 契约:提供确认回调', function () {
+  test('模板将确认按钮绑定到 onConfirm(含「确认」文案)', function () {
+    const tpl = loadTemplate()
+    expect(tpl).toMatch(/@(?:click|tap)="onConfirm"/)
+    expect(tpl).toMatch(/确认/)
+  })
+
+  test('script 定义 onConfirm 方法并 emit confirm 事件', function () {
+    const script = loadScript()
+    expect(script).toMatch(/onConfirm\s*:/)
+    expect(script).toMatch(/emit\(['"]confirm/)
+  })
+})
+
+// ---------------------------------------------------------------------------
+// AC4 Vue 组件导出
+// ---------------------------------------------------------------------------
+
+describe('AC4 契约:Vue 组件导出', function () {
+  test('script 通过 export default 导出组件(Option API)', function () {
+    const script = loadScript()
+    expect(script).toMatch(/export\s+default/)
+  })
+})
+
+// ---------------------------------------------------------------------------
+// 权限流:健康计划签署页 Step 3 摘要组件面向「家长端问卷完成签署」,
+// 无角色门禁分支(家长/成长规划师均可用,规格未定义角色差异),
+// 属《编排派发》中「权限(适用时)」的不适用项,显式记录。
+// ---------------------------------------------------------------------------
+
+describe.skip('权限流:健康计划签署无角色门禁,不适用', function () {
+  test('占位:该能力面向问卷完成签署组件,无 role 分支(详见汇报)', function () {})
+})