Files
cozsweet-frontend-nextjs/src/data/dto/payment/__tests__/payment_plan.test.ts
T

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",
},
],
});
});
});