159 lines
4.2 KiB
TypeScript
159 lines
4.2 KiB
TypeScript
import { vi } from "vitest";
|
|
import { fromPromise } from "xstate";
|
|
|
|
import {
|
|
CreatePaymentOrderResponse,
|
|
CreatePaymentOrderResponseSchema,
|
|
type PayChannel,
|
|
PaymentOrderStatusResponseSchema,
|
|
PaymentPlansResponse,
|
|
PaymentPlansResponseSchema,
|
|
} from "@/data/schemas/payment";
|
|
import { paymentMachine } from "@/stores/payment/payment-machine";
|
|
import type { PaymentPlanCatalog } from "@/stores/payment/payment-state";
|
|
|
|
export interface PaymentPlansActorInput {
|
|
catalog: PaymentPlanCatalog;
|
|
}
|
|
|
|
export interface CreateOrderInput {
|
|
planId: string;
|
|
payChannel: PayChannel;
|
|
autoRenew: boolean;
|
|
}
|
|
|
|
export type CreateOrderSpy = (input: CreateOrderInput) => void;
|
|
|
|
export const monthlyPlan = {
|
|
planId: "vip_monthly",
|
|
planName: "VIP Monthly",
|
|
orderType: "vip_monthly",
|
|
vipDays: 30,
|
|
dolAmount: null,
|
|
creditBalance: 3000,
|
|
amountCents: 999,
|
|
originalAmountCents: null,
|
|
dailyPriceCents: 33,
|
|
currency: "usd",
|
|
};
|
|
|
|
export const lifetimePlan = {
|
|
planId: "vip_lifetime",
|
|
planName: "VIP Lifetime",
|
|
orderType: "vip_lifetime",
|
|
vipDays: 3650,
|
|
dolAmount: null,
|
|
creditBalance: 0,
|
|
amountCents: 4999,
|
|
originalAmountCents: null,
|
|
dailyPriceCents: null,
|
|
currency: "usd",
|
|
};
|
|
|
|
export const creditPlan = {
|
|
planId: "dol_1000",
|
|
planName: "1000 Credits",
|
|
orderType: "dol",
|
|
vipDays: null,
|
|
dolAmount: 1000,
|
|
creditBalance: 1000,
|
|
amountCents: 990,
|
|
originalAmountCents: null,
|
|
dailyPriceCents: null,
|
|
currency: "usd",
|
|
};
|
|
|
|
export const quarterlyPlan = {
|
|
planId: "vip_quarterly",
|
|
planName: "VIP Quarterly",
|
|
orderType: "vip_quarterly",
|
|
vipDays: 90,
|
|
dolAmount: null,
|
|
creditBalance: 9000,
|
|
amountCents: 2499,
|
|
originalAmountCents: null,
|
|
dailyPriceCents: 28,
|
|
currency: "usd",
|
|
};
|
|
|
|
export const tipPlan = {
|
|
planId: "tip_coffee_usd_4_99",
|
|
planName: "Small Coffee",
|
|
orderType: "tip",
|
|
vipDays: null,
|
|
dolAmount: null,
|
|
creditBalance: 0,
|
|
amountCents: 499,
|
|
originalAmountCents: null,
|
|
dailyPriceCents: null,
|
|
currency: "USD",
|
|
};
|
|
|
|
export function createTestPaymentMachine(
|
|
overrides: Partial<{
|
|
cachedPlans: PaymentPlansResponse | null;
|
|
refreshedPlans: PaymentPlansResponse;
|
|
refreshPlans: () => Promise<PaymentPlansResponse>;
|
|
onLoadCatalog: (catalog: PaymentPlanCatalog) => void;
|
|
onRefreshCatalog: (catalog: PaymentPlanCatalog) => void;
|
|
createOrderSpy: CreateOrderSpy;
|
|
createOrderError: Error;
|
|
orderStatus: "pending" | "paid" | "failed";
|
|
orderStatuses: ("pending" | "paid" | "failed")[];
|
|
}> = {},
|
|
) {
|
|
const createOrderSpy = overrides.createOrderSpy ?? vi.fn<CreateOrderSpy>();
|
|
const orderStatus = overrides.orderStatus ?? "paid";
|
|
const orderStatuses = overrides.orderStatuses ?? [];
|
|
let pollCount = 0;
|
|
|
|
return paymentMachine.provide({
|
|
actors: {
|
|
loadCachedPlans: fromPromise<
|
|
PaymentPlansResponse | null,
|
|
PaymentPlansActorInput
|
|
>(async ({ input }) => {
|
|
overrides.onLoadCatalog?.(input.catalog);
|
|
return overrides.cachedPlans ?? null;
|
|
}),
|
|
refreshPlans: fromPromise<PaymentPlansResponse, PaymentPlansActorInput>(
|
|
async ({ input }) => {
|
|
overrides.onRefreshCatalog?.(input.catalog);
|
|
if (overrides.refreshPlans) return overrides.refreshPlans();
|
|
return (
|
|
overrides.refreshedPlans ??
|
|
PaymentPlansResponseSchema.parse({
|
|
plans: [monthlyPlan, lifetimePlan, creditPlan],
|
|
})
|
|
);
|
|
},
|
|
),
|
|
createOrder: fromPromise<CreatePaymentOrderResponse, CreateOrderInput>(
|
|
async ({ input }) => {
|
|
createOrderSpy(input);
|
|
if (overrides.createOrderError) throw overrides.createOrderError;
|
|
return CreatePaymentOrderResponseSchema.parse({
|
|
orderId: "pay_test_001",
|
|
payParams: {
|
|
provider: "stripe",
|
|
clientSecret: "pi_test_secret_test",
|
|
},
|
|
});
|
|
},
|
|
),
|
|
pollOrderStatus: fromPromise(async () => {
|
|
const status =
|
|
orderStatuses[Math.min(pollCount, orderStatuses.length - 1)] ??
|
|
orderStatus;
|
|
pollCount += 1;
|
|
return PaymentOrderStatusResponseSchema.parse({
|
|
orderId: "pay_test_001",
|
|
status,
|
|
orderType: "vip_monthly",
|
|
planId: "vip_monthly",
|
|
});
|
|
}),
|
|
},
|
|
});
|
|
}
|