fix: harden alipay direct pay flow

This commit is contained in:
daguimu
2026-03-10 11:52:37 +08:00
parent 2492031e13
commit 8b10bc3bd5
30 changed files with 1893 additions and 437 deletions

View File

@@ -0,0 +1,39 @@
import { describe, expect, it, vi } from 'vitest';
vi.mock('@/lib/config', () => ({
getEnv: () => ({
ADMIN_TOKEN: 'test-admin-token',
}),
}));
import {
ORDER_STATUS_ACCESS_QUERY_KEY,
buildOrderResultUrl,
createOrderStatusAccessToken,
verifyOrderStatusAccessToken,
} from '@/lib/order/status-access';
describe('order status access token helpers', () => {
it('creates and verifies a token bound to the order id', () => {
const token = createOrderStatusAccessToken('order-001');
expect(token).toBeTruthy();
expect(verifyOrderStatusAccessToken('order-001', token)).toBe(true);
expect(verifyOrderStatusAccessToken('order-002', token)).toBe(false);
});
it('rejects missing or malformed tokens', () => {
expect(verifyOrderStatusAccessToken('order-001', null)).toBe(false);
expect(verifyOrderStatusAccessToken('order-001', undefined)).toBe(false);
expect(verifyOrderStatusAccessToken('order-001', 'short')).toBe(false);
});
it('builds a result url with order id and access token', () => {
const url = new URL(buildOrderResultUrl('https://pay.example.com', 'order-009'));
expect(url.origin + url.pathname).toBe('https://pay.example.com/pay/result');
expect(url.searchParams.get('order_id')).toBe('order-009');
const token = url.searchParams.get(ORDER_STATUS_ACCESS_QUERY_KEY);
expect(token).toBeTruthy();
expect(verifyOrderStatusAccessToken('order-009', token)).toBe(true);
});
});

View File

@@ -0,0 +1,66 @@
import { describe, expect, it } from 'vitest';
import { ORDER_STATUS } from '@/lib/constants';
import { deriveOrderState, getOrderDisplayState } from '@/lib/order/status';
describe('order status helpers', () => {
it('derives paid_pending after successful payment but before recharge completion', () => {
const state = deriveOrderState({
status: ORDER_STATUS.PAID,
paidAt: new Date('2026-03-09T10:00:00Z'),
completedAt: null,
});
expect(state).toEqual({
paymentSuccess: true,
rechargeSuccess: false,
rechargeStatus: 'paid_pending',
});
});
it('maps recharge failure after payment to a payment-success display state', () => {
const display = getOrderDisplayState({
status: ORDER_STATUS.FAILED,
paymentSuccess: true,
rechargeSuccess: false,
rechargeStatus: 'failed',
});
expect(display.label).toBe('支付成功');
expect(display.message).toContain('自动重试');
});
it('maps failed order before payment success to failed display', () => {
const display = getOrderDisplayState({
status: ORDER_STATUS.FAILED,
paymentSuccess: false,
rechargeSuccess: false,
rechargeStatus: 'failed',
});
expect(display.label).toBe('支付失败');
expect(display.message).toContain('重新发起支付');
});
it('maps completed order to success display', () => {
const display = getOrderDisplayState({
status: ORDER_STATUS.COMPLETED,
paymentSuccess: true,
rechargeSuccess: true,
rechargeStatus: 'success',
});
expect(display.label).toBe('充值成功');
expect(display.icon).toBe('✓');
});
it('maps pending order to waiting-for-payment display', () => {
const display = getOrderDisplayState({
status: ORDER_STATUS.PENDING,
paymentSuccess: false,
rechargeSuccess: false,
rechargeStatus: 'not_paid',
});
expect(display.label).toBe('等待支付');
});
});