fix payment resume result consistency

This commit is contained in:
IanShaw027
2026-04-21 02:08:34 +08:00
parent e12599c1b9
commit a27a7add3d
6 changed files with 264 additions and 14 deletions

View File

@@ -194,6 +194,10 @@ const countdownDisplay = computed(() => {
return m.toString().padStart(2, '0') + ':' + s.toString().padStart(2, '0')
})
function isSuccessStatus(status: string | null | undefined): boolean {
return status === 'COMPLETED' || status === 'PAID' || status === 'RECHARGING'
}
function reopenPopup() {
if (props.payUrl) {
const win = window.open(props.payUrl, 'paymentPopup', POPUP_WINDOW_FEATURES)
@@ -222,7 +226,7 @@ async function pollStatus() {
if (!props.orderId || outcome.value) return
const order = await paymentStore.pollOrderStatus(props.orderId)
if (!order) return
if (order.status === 'COMPLETED' || order.status === 'PAID') {
if (isSuccessStatus(order.status)) {
cleanup()
paidOrder.value = order
setOutcome('success')

View File

@@ -0,0 +1,99 @@
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { flushPromises, mount } from '@vue/test-utils'
const pollOrderStatus = vi.hoisted(() => vi.fn())
const cancelOrder = vi.hoisted(() => vi.fn())
const showError = vi.hoisted(() => vi.fn())
const toCanvas = vi.hoisted(() => vi.fn())
vi.mock('vue-i18n', async () => {
const actual = await vi.importActual<typeof import('vue-i18n')>('vue-i18n')
return {
...actual,
useI18n: () => ({
t: (key: string) => key,
}),
}
})
vi.mock('@/stores/payment', () => ({
usePaymentStore: () => ({
pollOrderStatus,
}),
}))
vi.mock('@/stores', () => ({
useAppStore: () => ({
showError,
}),
}))
vi.mock('@/api/payment', () => ({
paymentAPI: {
cancelOrder,
},
}))
vi.mock('qrcode', () => ({
default: {
toCanvas,
},
}))
import PaymentStatusPanel from '../PaymentStatusPanel.vue'
const orderFactory = (status: string) => ({
id: 42,
user_id: 9,
amount: 88,
pay_amount: 88,
fee_rate: 0,
payment_type: 'alipay',
out_trade_no: 'sub2_20260420abcd1234',
status,
order_type: 'balance',
created_at: '2026-04-20T12:00:00Z',
expires_at: '2099-01-01T12:30:00Z',
refund_amount: 0,
})
describe('PaymentStatusPanel', () => {
beforeEach(() => {
vi.useFakeTimers()
pollOrderStatus.mockReset()
cancelOrder.mockReset()
showError.mockReset()
toCanvas.mockReset().mockResolvedValue(undefined)
})
afterEach(() => {
vi.useRealTimers()
})
it('treats RECHARGING as a successful terminal state', async () => {
pollOrderStatus.mockResolvedValue(orderFactory('RECHARGING'))
const wrapper = mount(PaymentStatusPanel, {
props: {
orderId: 42,
qrCode: 'https://pay.example.com/qr/42',
expiresAt: '2099-01-01T12:30:00Z',
paymentType: 'alipay',
orderType: 'balance',
},
global: {
stubs: {
Icon: true,
},
},
})
await flushPromises()
await vi.advanceTimersByTimeAsync(3000)
await flushPromises()
expect(pollOrderStatus).toHaveBeenCalledWith(42)
expect(wrapper.text()).toContain('payment.result.success')
expect(wrapper.emitted('success')).toHaveLength(1)
})
})