172 lines
4.4 KiB
TypeScript
172 lines
4.4 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { z } from "zod";
|
|
|
|
import {
|
|
PaymentPlan,
|
|
PaymentPlansResponse,
|
|
TipPaymentPlansResponse,
|
|
} from "@/data/dto/payment";
|
|
|
|
describe("PaymentPlan", () => {
|
|
it("parses the camelCase payment plan shape", () => {
|
|
const plan = PaymentPlan.from({
|
|
planId: "vip_monthly",
|
|
planName: "VIP Monthly",
|
|
orderType: "vip_monthly",
|
|
vipDays: 30,
|
|
dolAmount: null,
|
|
creditBalance: 3000,
|
|
amountCents: 1999,
|
|
originalAmountCents: 2499,
|
|
dailyPriceCents: 66,
|
|
currency: "JPY",
|
|
});
|
|
|
|
expect(plan.planId).toBe("vip_monthly");
|
|
expect(plan.creditBalance).toBe(3000);
|
|
expect(plan.toJson()).toEqual({
|
|
planId: "vip_monthly",
|
|
planName: "VIP Monthly",
|
|
orderType: "vip_monthly",
|
|
vipDays: 30,
|
|
dolAmount: null,
|
|
creditBalance: 3000,
|
|
amountCents: 1999,
|
|
originalAmountCents: 2499,
|
|
dailyPriceCents: 66,
|
|
currency: "JPY",
|
|
isFirstRechargeOffer: false,
|
|
firstRechargeDiscountPercent: null,
|
|
promotionType: null,
|
|
});
|
|
});
|
|
|
|
it("rejects the legacy snake_case payment plan shape", () => {
|
|
expect(() =>
|
|
PaymentPlan.fromJson({
|
|
plan_id: "vip_monthly",
|
|
plan_name: "VIP Monthly",
|
|
order_type: "vip_monthly",
|
|
amount_cents: 1999,
|
|
original_amount_cents: 2499,
|
|
daily_price_cents: 66,
|
|
currency: "JPY",
|
|
vip_days: 30,
|
|
dol_amount: null,
|
|
}),
|
|
).toThrow(z.ZodError);
|
|
});
|
|
});
|
|
|
|
describe("PaymentPlansResponse", () => {
|
|
it("parses plans from the new backend response data shape", () => {
|
|
const response = PaymentPlansResponse.from({
|
|
plans: [
|
|
{
|
|
planId: "dol_1000",
|
|
planName: "1000 Credits",
|
|
orderType: "dol",
|
|
vipDays: null,
|
|
dolAmount: 1000,
|
|
creditBalance: 1000,
|
|
amountCents: 990,
|
|
originalAmountCents: null,
|
|
dailyPriceCents: null,
|
|
currency: "USD",
|
|
},
|
|
],
|
|
});
|
|
|
|
expect(response.plans).toHaveLength(1);
|
|
expect(response.plans[0]?.dolAmount).toBe(1000);
|
|
});
|
|
|
|
it("parses first recharge offer metadata", () => {
|
|
const response = PaymentPlansResponse.from({
|
|
isFirstRecharge: true,
|
|
firstRechargeOffer: {
|
|
enabled: true,
|
|
type: "first_recharge_half_price",
|
|
discountPercent: 50,
|
|
},
|
|
plans: [
|
|
{
|
|
planId: "vip_monthly",
|
|
planName: "VIP Monthly",
|
|
orderType: "vip_monthly",
|
|
vipDays: 30,
|
|
dolAmount: null,
|
|
creditBalance: 3000,
|
|
amountCents: 995,
|
|
originalAmountCents: 1990,
|
|
dailyPriceCents: null,
|
|
currency: "USD",
|
|
isFirstRechargeOffer: true,
|
|
firstRechargeDiscountPercent: 50,
|
|
promotionType: "first_recharge_half_price",
|
|
},
|
|
],
|
|
});
|
|
|
|
expect(response.isFirstRecharge).toBe(true);
|
|
expect(response.firstRechargeOffer?.discountPercent).toBe(50);
|
|
expect(response.plans[0]).toMatchObject({
|
|
amountCents: 995,
|
|
originalAmountCents: 1990,
|
|
isFirstRechargeOffer: true,
|
|
firstRechargeDiscountPercent: 50,
|
|
promotionType: "first_recharge_half_price",
|
|
});
|
|
});
|
|
|
|
it("defaults nullable first recharge offer metadata", () => {
|
|
const response = PaymentPlansResponse.from({
|
|
isFirstRecharge: true,
|
|
firstRechargeOffer: {
|
|
enabled: null,
|
|
type: null,
|
|
discountPercent: null,
|
|
},
|
|
plans: [],
|
|
});
|
|
|
|
expect(response.firstRechargeOffer).toEqual({
|
|
enabled: false,
|
|
type: "",
|
|
discountPercent: 0,
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("TipPaymentPlansResponse", () => {
|
|
it("keeps only fields used by the tip payment flow", () => {
|
|
const response = TipPaymentPlansResponse.fromJson({
|
|
plans: [
|
|
{
|
|
planId: "tip_coffee_usd_4_99",
|
|
planName: "Small Coffee",
|
|
orderType: "tip",
|
|
tipType: "coffee_small",
|
|
description: "Buy Elio a small coffee",
|
|
amountCents: 499,
|
|
currency: "USD",
|
|
autoRenew: false,
|
|
isFirstRechargeOffer: false,
|
|
firstRechargeDiscountPercent: 0,
|
|
},
|
|
],
|
|
});
|
|
|
|
expect(response.toJson()).toEqual({
|
|
plans: [
|
|
{
|
|
planId: "tip_coffee_usd_4_99",
|
|
planName: "Small Coffee",
|
|
amountCents: 499,
|
|
currency: "USD",
|
|
},
|
|
],
|
|
});
|
|
});
|
|
});
|