import {afterEach, expect, test, vi} from 'vitest'; import { executeAdminRechargeRefund, getAdminUserDetail, listAdminRechargeOrders, resolveAdminRechargeRefundManualReview, } from './adminApiClient'; afterEach(() => { vi.unstubAllGlobals(); }); test('充值订单查询按后台契约序列化筛选参数', async () => { const fetchMock = vi.fn().mockResolvedValue( new Response(JSON.stringify({entries: []}), { status: 200, headers: {'content-type': 'application/json'}, }), ); vi.stubGlobal('fetch', fetchMock); await listAdminRechargeOrders('token-1', { orderId: 'order 1', userId: 'user-1', providerTransactionId: 'wx-1', paymentChannel: 'wechat_native', status: 'paid', createdAfter: '2026-07-01T00:00:00.000Z', createdBefore: '2026-07-13T23:59:00.000Z', limit: 50, }); const requestUrl = String(fetchMock.mock.calls[0]?.[0]); const parsed = new URL(requestUrl, 'http://admin.local'); expect(parsed.pathname).toBe('/admin/api/profile/recharge-orders'); expect(Object.fromEntries(parsed.searchParams)).toEqual({ orderId: 'order 1', providerTransactionId: 'wx-1', userId: 'user-1', paymentChannel: 'wechat_native', status: 'paid', createdAfter: '2026-07-01T00:00:00.000Z', createdBefore: '2026-07-13T23:59:00.000Z', limit: '50', }); }); test('用户详情只发送实际提供的用户定位字段', async () => { const fetchMock = vi.fn().mockResolvedValue( new Response(JSON.stringify({userId: 'user-1'}), {status: 200}), ); vi.stubGlobal('fetch', fetchMock); await getAdminUserDetail('token-1', {publicUserCode: 'TN1001'}); const requestUrl = String(fetchMock.mock.calls[0]?.[0]); const parsed = new URL(requestUrl, 'http://admin.local'); expect(parsed.pathname).toBe('/admin/api/profile/users/detail'); expect(Object.fromEntries(parsed.searchParams)).toEqual({ publicUserCode: 'TN1001', }); }); test('退款执行使用独立 execute 管理员路由', async () => { const fetchMock = vi.fn().mockResolvedValue( new Response(JSON.stringify({outRefundNo: 'refund-1'}), {status: 200}), ); vi.stubGlobal('fetch', fetchMock); await executeAdminRechargeRefund('token-1', { orderId: 'order-1', refundAmountCents: 300, requestId: 'request-1', reason: '用户申请', }); expect(String(fetchMock.mock.calls[0]?.[0])).toBe( '/admin/api/profile/recharge-refunds/execute', ); expect(fetchMock.mock.calls[0]?.[1]).toEqual( expect.objectContaining({ method: 'POST', body: JSON.stringify({ orderId: 'order-1', refundAmountCents: 300, requestId: 'request-1', reason: '用户申请', }), }), ); }); test('退款人工复核使用独立 resolve 管理员路由', async () => { const fetchMock = vi.fn().mockResolvedValue( new Response(JSON.stringify({outRefundNo: 'refund-1'}), {status: 200}), ); vi.stubGlobal('fetch', fetchMock); await resolveAdminRechargeRefundManualReview('token-1', { outRefundNo: 'refund-1', reason: '已核对微信商户平台原始账单', }); expect(String(fetchMock.mock.calls[0]?.[0])).toBe( '/admin/api/profile/recharge-refunds/manual-review/resolve', ); expect(fetchMock.mock.calls[0]?.[1]).toEqual( expect.objectContaining({ method: 'POST', body: JSON.stringify({ outRefundNo: 'refund-1', reason: '已核对微信商户平台原始账单', }), }), ); });