58 lines
3.1 KiB
TypeScript
58 lines
3.1 KiB
TypeScript
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
import { createPaymentOrder, createPaymentRefund, formatYuan, getPaymentOrder, getPaymentRefund, listAdminPaymentOrders, listPaymentRefunds, parseYuanToFen } from "@/lib/client/payment-api";
|
|
|
|
afterEach(() => vi.unstubAllGlobals());
|
|
|
|
describe("recharge amounts", () => {
|
|
it("converts decimal yuan to exact integer fen within the server range", () => {
|
|
expect(parseYuanToFen("1", 100, 1_000_000)).toBe(100);
|
|
expect(parseYuanToFen("1.01", 100, 1_000_000)).toBe(101);
|
|
expect(parseYuanToFen(" 10000.00 ", 100, 1_000_000)).toBe(1_000_000);
|
|
expect(formatYuan(101)).toBe("1.01");
|
|
});
|
|
|
|
it.each(["0.99", "1.001", "1e2", "-1", "+1", "1,000", "01", "10000.01", "0", "1."])("rejects %s", (value) => {
|
|
expect(parseYuanToFen(value, 100, 1_000_000)).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe("admin payment requests", () => {
|
|
it("lists across organizations or filters by organization and page", async () => {
|
|
const fetchMock = vi.fn().mockResolvedValue({ ok: true, json: async () => ({ orders: [], hasMore: false, enabled: true }) });
|
|
vi.stubGlobal("fetch", fetchMock);
|
|
await listAdminPaymentOrders("org/a", 50);
|
|
expect(fetchMock.mock.calls[0][0]).toBe("/api/payments/admin/orders?limit=50&offset=50&organizationId=org%2Fa");
|
|
await listAdminPaymentOrders("", 0);
|
|
expect(fetchMock.mock.calls[1][0]).toBe("/api/payments/admin/orders?limit=50&offset=0");
|
|
});
|
|
|
|
it("uses admin endpoints and preserves the refund attempt key", async () => {
|
|
const fetchMock = vi.fn().mockResolvedValue({ ok: true, json: async () => ({ refund: { id: "r1", status: "pending" }, refunds: [] }) });
|
|
vi.stubGlobal("fetch", fetchMock);
|
|
await createPaymentRefund("a/b", 250, "客户申请", "same-attempt");
|
|
expect(fetchMock.mock.calls[0][0]).toBe("/api/payments/admin/orders/a%2Fb/refunds");
|
|
expect(JSON.parse(fetchMock.mock.calls[0][1].body)).toEqual({ amountFen: 250, reason: "客户申请", requestKey: "same-attempt" });
|
|
await listPaymentRefunds("a/b");
|
|
expect(fetchMock.mock.calls[1][0]).toBe("/api/payments/admin/orders/a%2Fb/refunds");
|
|
await getPaymentRefund("r/1");
|
|
expect(fetchMock.mock.calls[2][0]).toBe("/api/payments/admin/refunds/r%2F1");
|
|
});
|
|
});
|
|
|
|
describe("payment requests", () => {
|
|
it("sends integer fen and a stable idempotency key", async () => {
|
|
const fetchMock = vi.fn().mockResolvedValue({ ok: true, json: async () => ({ order: { id: "pay_1", status: "pending" } }) });
|
|
vi.stubGlobal("fetch", fetchMock);
|
|
await createPaymentOrder(10000, "same-attempt");
|
|
const [, init] = fetchMock.mock.calls[0];
|
|
expect(JSON.parse(init.body)).toEqual({ amountFen: 10000, requestKey: "same-attempt" });
|
|
});
|
|
|
|
it("escapes order IDs and reports server errors", async () => {
|
|
const fetchMock = vi.fn().mockResolvedValue({ ok: false, status: 404, json: async () => ({ error: "订单不存在" }) });
|
|
vi.stubGlobal("fetch", fetchMock);
|
|
await expect(getPaymentOrder("a/b")).rejects.toThrow("订单不存在");
|
|
expect(fetchMock.mock.calls[0][0]).toBe("/api/payments/orders/a%2Fb");
|
|
});
|
|
});
|