import { describe, it, expect, vi, beforeEach } from 'vitest' import { ref } from 'vue' import { useMemberPayment } from '../../../app/composables/useMemberPayment.js' // Stub Vue's ref/readonly as Nuxt auto-imports vi.stubGlobal('ref', ref) vi.stubGlobal('readonly', (v) => v) const memberData = ref(null) const checkMemberStatus = vi.fn() vi.stubGlobal('useAuth', () => ({ memberData, checkMemberStatus })) const initializeHelcimPay = vi.fn() const verifyPayment = vi.fn() const cleanupHelcimPay = vi.fn() vi.stubGlobal('useHelcimPay', () => ({ initializeHelcimPay, verifyPayment, cleanup: cleanupHelcimPay, })) const $fetch = vi.fn() vi.stubGlobal('$fetch', $fetch) describe('useMemberPayment.initiatePaymentSetup — shortcut path', () => { beforeEach(() => { vi.clearAllMocks() memberData.value = null $fetch.mockReset() }) it('skips getOrCreateCustomer when both helcim ids are cached AND a card is on file', async () => { memberData.value = { helcimCustomerId: 'cust-123', helcimCustomerCode: 'CST-ABC', contributionAmount: 15, } $fetch.mockImplementation((path) => { if (path === '/api/helcim/existing-card') { return Promise.resolve({ cardToken: 'tok-xyz' }) } if (path === '/api/helcim/subscription') { return Promise.resolve({ success: true }) } return Promise.reject(new Error(`Unexpected $fetch call: ${path}`)) }) const { initiatePaymentSetup } = useMemberPayment() const result = await initiatePaymentSetup() expect(result.success).toBe(true) // The whole point: get-or-create-customer was NOT called. const calledPaths = $fetch.mock.calls.map((c) => c[0]) expect(calledPaths).not.toContain('/api/helcim/get-or-create-customer') expect(calledPaths).not.toContain('/api/helcim/customer-code') // We did call existing-card (once) and subscription (once). expect(calledPaths.filter((p) => p === '/api/helcim/existing-card')).toHaveLength(1) expect(calledPaths.filter((p) => p === '/api/helcim/subscription')).toHaveLength(1) // HelcimPay modal not opened — card was already on file. expect(initializeHelcimPay).not.toHaveBeenCalled() expect(verifyPayment).not.toHaveBeenCalled() // Subscription called with the cached id/code from memberData. const subscriptionCall = $fetch.mock.calls.find((c) => c[0] === '/api/helcim/subscription') expect(subscriptionCall[1].body).toMatchObject({ customerId: 'cust-123', customerCode: 'CST-ABC', cardToken: 'tok-xyz', contributionAmount: 15, }) }) it('falls through to get-or-create-customer when helcimCustomerCode is missing', async () => { memberData.value = { helcimCustomerId: 'cust-123', // helcimCustomerCode missing — must NOT take shortcut contributionAmount: 15, } $fetch.mockImplementation((path) => { if (path === '/api/helcim/customer-code') { return Promise.resolve({ customerId: 'cust-123', customerCode: 'CST-FRESH' }) } if (path === '/api/helcim/existing-card') { return Promise.resolve({ cardToken: 'tok-xyz' }) } if (path === '/api/helcim/subscription') { return Promise.resolve({ success: true }) } return Promise.reject(new Error(`Unexpected $fetch call: ${path}`)) }) const { initiatePaymentSetup } = useMemberPayment() await initiatePaymentSetup() const calledPaths = $fetch.mock.calls.map((c) => c[0]) // Existing helcimCustomerId path -> /api/helcim/customer-code is called. expect(calledPaths).toContain('/api/helcim/customer-code') }) it('falls through to get-or-create-customer when no card is on file', async () => { memberData.value = { helcimCustomerId: 'cust-123', helcimCustomerCode: 'CST-ABC', contributionAmount: 15, } initializeHelcimPay.mockResolvedValue(undefined) verifyPayment.mockResolvedValue({ success: true, cardToken: 'tok-new' }) let existingCardCalls = 0 $fetch.mockImplementation((path) => { if (path === '/api/helcim/existing-card') { existingCardCalls++ return Promise.resolve(null) // no card on file } if (path === '/api/helcim/customer-code') { return Promise.resolve({ customerId: 'cust-123', customerCode: 'CST-ABC' }) } if (path === '/api/helcim/verify-payment') { return Promise.resolve({ success: true }) } if (path === '/api/helcim/subscription') { return Promise.resolve({ success: true }) } return Promise.reject(new Error(`Unexpected $fetch call: ${path}`)) }) const { initiatePaymentSetup } = useMemberPayment() await initiatePaymentSetup() // Falls into the full flow — modal opens, verify runs. expect(initializeHelcimPay).toHaveBeenCalled() expect(verifyPayment).toHaveBeenCalled() const calledPaths = $fetch.mock.calls.map((c) => c[0]) expect(calledPaths).toContain('/api/helcim/customer-code') // existing-card was reused from the shortcut probe — should not refetch. expect(existingCardCalls).toBe(1) }) })