import { beforeEach, describe, expect, it, vi } from "vitest"; const httpClientMock = vi.hoisted(() => vi.fn()); vi.mock("../http_client", () => ({ httpClient: httpClientMock, })); import { PaymentApi } from "../payment_api"; describe("PaymentApi", () => { beforeEach(() => { httpClientMock.mockReset(); }); it("loads the complete public gift catalog for a character", async () => { httpClientMock.mockResolvedValue({ success: true, data: { characterId: "elio", categories: [ { category: "coffee", name: "Coffee", productCount: 1, imageUrl: null, }, ], plans: [ { planId: "tip_coffee_usd_19_99", planName: "Large Coffee", orderType: "tip", tipType: "coffee_large", category: "coffee", characterId: "elio", description: "Buy Elio a large coffee", imageUrl: null, amountCents: 1999, currency: "USD", autoRenew: false, isFirstRechargeOffer: false, firstRechargeDiscountPercent: 0, promotionType: null, }, ], }, }); const response = await new PaymentApi().getGiftProducts("elio"); expect(httpClientMock).toHaveBeenCalledWith( "/api/payment/gift-products", { query: { characterId: "elio" } }, ); expect(response.categories[0]?.category).toBe("coffee"); expect(response.plans[0]?.planId).toBe("tip_coffee_usd_19_99"); }); it("posts the paid order id when loading the Tip message", async () => { httpClientMock.mockResolvedValue({ success: true, data: { orderId: "pay_xxx", characterId: "elio", planId: "tip_coffee_usd_19_99", productName: "Large Coffee", tipCount: 1, poolIndex: 7, message: "Thank you for the thoughtful gift.", }, }); const response = await new PaymentApi().getTipMessage({ orderId: "pay_xxx", }); expect(httpClientMock).toHaveBeenCalledWith("/api/payment/tip-message", { method: "POST", body: { orderId: "pay_xxx" }, }); expect(response.message).toBe("Thank you for the thoughtful gift."); }); it("accepts a server-issued offer before opening the subscription page", async () => { httpClientMock.mockResolvedValue({ success: true, data: { commercialOfferId: "offer-1", planId: "vip_annual", subscriptionType: "vip", discountPercent: 30, pricePercent: 70, expiresAt: "2026-07-24T08:00:00+00:00", message: "I got it for you.", promotionType: "commercial_seven_discount", }, }); const response = await new PaymentApi().acceptCommercialOffer("offer-1"); expect(httpClientMock).toHaveBeenCalledWith( "/api/payment/commercial-offers/offer-1/accept", { method: "POST" }, ); expect(response.discountPercent).toBe(30); }); it("requests an offer-scoped plan catalog without changing the public call", async () => { httpClientMock.mockResolvedValue({ success: true, data: { plans: [] } }); await new PaymentApi().getPlans("offer-1"); expect(httpClientMock).toHaveBeenCalledWith("/api/payment/plans", { query: { commercialOfferId: "offer-1" }, }); }); });