import { describe, it, expect } from "vitest"; import { safeParse } from "valibot"; import { CheckoutSessionSchema, SubscriptionSchema, InvoiceSchema, } from "./webhook"; describe("CheckoutSessionSchema", () => { it("accepts valid checkout session data", () => { const data = { id: "cs_test123", subscription: "sub_123", metadata: { userId: "user_123" }, }; const result = safeParse(CheckoutSessionSchema, data); expect(result.success).toBe(true); if (result.success) { expect(result.output.id).toBe("cs_test123"); expect(result.output.metadata?.userId).toBe("user_123"); } }); it("accepts session without optional fields", () => { const data = { id: "cs_test123" }; const result = safeParse(CheckoutSessionSchema, data); expect(result.success).toBe(true); }); it("rejects missing required id", () => { const data = { subscription: "sub_123" }; const result = safeParse(CheckoutSessionSchema, data); expect(result.success).toBe(false); }); it("rejects non-string id", () => { const data = { id: 123 }; const result = safeParse(CheckoutSessionSchema, data); expect(result.success).toBe(false); }); }); describe("SubscriptionSchema", () => { it("accepts valid subscription data with integer timestamps", () => { const data = { id: "sub_123", status: "active", current_period_start: 1700000000, current_period_end: 1702678400, cancel_at_period_end: "false", metadata: { userId: "user_123" }, items: { data: { price: { id: "price_basic" } }, }, }; const result = safeParse(SubscriptionSchema, data); expect(result.success).toBe(true); if (result.success) { expect(result.output.current_period_start).toBe(1700000000); expect(result.output.items?.data?.price?.id).toBe("price_basic"); } }); it("rejects non-integer timestamps", () => { const data = { id: "sub_123", current_period_start: "not-a-number", }; const result = safeParse(SubscriptionSchema, data); expect(result.success).toBe(false); }); it("defaults cancel_at_period_end when not provided", () => { const data = { id: "sub_123" }; const result = safeParse(SubscriptionSchema, data); expect(result.success).toBe(true); if (result.success) { expect(result.output.cancel_at_period_end).toBe("false"); } }); it("accepts string cancel_at_period_end", () => { const data = { id: "sub_123", cancel_at_period_end: "true" }; const result = safeParse(SubscriptionSchema, data); expect(result.success).toBe(true); }); it("rejects missing required id", () => { const data = { status: "active" }; const result = safeParse(SubscriptionSchema, data); expect(result.success).toBe(false); }); it("handles extra unexpected fields gracefully", () => { const data = { id: "sub_123", status: "active", unknown_field: "should be ignored", }; const result = safeParse(SubscriptionSchema, data); expect(result.success).toBe(true); }); }); describe("InvoiceSchema", () => { it("accepts valid invoice data", () => { const data = { subscription: "sub_123" }; const result = safeParse(InvoiceSchema, data); expect(result.success).toBe(true); if (result.success) { expect(result.output.subscription).toBe("sub_123"); } }); it("accepts invoice without subscription (for partial invoices)", () => { const data = { id: "in_123" }; const result = safeParse(InvoiceSchema, data); expect(result.success).toBe(true); }); it("rejects non-string subscription", () => { const data = { subscription: 123 }; const result = safeParse(InvoiceSchema, data); expect(result.success).toBe(false); }); }); describe("Webhook data validation - malformed payloads", () => { it("handles empty object", () => { const result = safeParse(SubscriptionSchema, {}); expect(result.success).toBe(false); }); it("handles completely wrong data shape", () => { const result = safeParse(SubscriptionSchema, "not an object"); expect(result.success).toBe(false); }); it("handles unexpected fields without crashing", () => { const data = { id: "sub_123", status: "active", unknown_field: "should be ignored", another_unknown: 42, }; const result = safeParse(SubscriptionSchema, data); expect(result.success).toBe(true); }); });