Przeglądaj źródła

test(cfc-web): S-cfc-72 admin.familyCoupon.backToList — RED 契约单测(3例全红)

能力键:admin.familyCoupon.backToList
溯源:docs/superpowers/specs/2026-11-08-family-admin-list-polish.md §需求1

契约断言:
- 从家庭管理列表进入优惠券管理页时,PageHeader 渲染返回按钮(back=true)
- 点击返回按钮应 router.push 回 /admin/families(显式导航)
- 返回列表不使用 history.back(),而是 router.push 指定目标路径

当前实现未落地,预期 RED;GREEN 阶段实现后三例转绿。
参考 PageHeader 现有 idiom(OrderDetail.vue back + @back 显式 push)。
Sisyphus 5 dni temu
rodzic
commit
dfde764a5e

+ 91 - 0
cfc-web/src/__tests__/views/admin/FamilyCouponManage.backToList.spec.js

@@ -0,0 +1,91 @@
+import { shallowMount, createLocalVue } from '@vue/test-utils'
+import FamilyCouponManage from '@/views/admin/FamilyCouponManage.vue'
+
+jest.mock('@/api/coupon', () => ({
+  getCouponList: jest.fn(() => Promise.resolve({ data: { records: [] } })),
+  issueFamilyCoupon: jest.fn(() => Promise.resolve({ code: 200 })),
+  getFamilyCoupons: jest.fn(() => Promise.resolve({ data: { records: [], total: 0 } })),
+  getFamilyCouponUsage: jest.fn(() => Promise.resolve({ data: { records: [], total: 0 } }))
+}))
+
+const localVue = createLocalVue()
+localVue.directive('loading', {})
+
+/**
+ * PageHeader 真实组件支持 back prop(为 true 时渲染返回按钮并 emit 'back' 事件),
+ * 与 OrderDetail.vue 的 `back @back="..."` 用法一致。这里用同形态的桩组件承载契约断言。
+ */
+const PageHeaderStub = {
+  name: 'PageHeader',
+  props: ['title', 'subtitle', 'back', 'count'],
+  template: `
+    <div class="page-header-stub">
+      <button v-if="back" class="back-btn" @click="$emit('back')">返回</button>
+      <h2>{{ title }}</h2>
+    </div>
+  `
+}
+
+const stubs = {
+  PageHeader: PageHeaderStub,
+  StatusTag: true,
+  'el-card': true,
+  'el-tabs': true,
+  'el-tab-pane': true,
+  'el-form': true,
+  'el-form-item': true,
+  'el-select': true,
+  'el-option': true,
+  'el-input-number': true,
+  'el-button': true,
+  'el-table': true,
+  'el-table-column': true,
+  'el-pagination': true
+}
+
+let pushMock
+let replaceMock
+let backMock
+
+function mount({ familyId = '7' } = {}) {
+  return shallowMount(FamilyCouponManage, {
+    localVue,
+    stubs,
+    mocks: {
+      $route: { query: { familyId } },
+      $router: { push: pushMock, replace: replaceMock, back: backMock },
+      $message: { warning: jest.fn(), error: jest.fn(), success: jest.fn() }
+    }
+  })
+}
+
+describe('admin.familyCoupon.backToList 返回家庭列表', () => {
+  beforeEach(() => {
+    jest.clearAllMocks()
+    pushMock = jest.fn()
+    replaceMock = jest.fn()
+    backMock = jest.fn()
+  })
+
+  it('从家庭管理列表进入时应渲染返回按钮(PageHeader back=true)', () => {
+    const wrapper = mount({ familyId: '7' })
+    const header = wrapper.findComponent(PageHeaderStub)
+    expect(header.exists()).toBe(true)
+    expect(header.props('back')).toBe(true)
+  })
+
+  it('点击返回按钮应 router.push 回 /admin/families', async () => {
+    const wrapper = mount({ familyId: '7' })
+    const header = wrapper.findComponent(PageHeaderStub)
+    await header.find('.back-btn').trigger('click')
+    expect(pushMock).toHaveBeenCalledWith({ path: '/admin/families' })
+  })
+
+  it('返回列表应使用显式 router.push,而非 history.back()', async () => {
+    const wrapper = mount({ familyId: '7' })
+    const header = wrapper.findComponent(PageHeaderStub)
+    await header.vm.$emit('back')
+    expect(pushMock).toHaveBeenCalledWith({ path: '/admin/families' })
+    expect(backMock).not.toHaveBeenCalled()
+  })
+})