import type Stripe from 'stripe' import { __setStripeForTests } from '#services/stripe' /** * Helper de test : injecte un client Stripe mocké au niveau du singleton * `getStripe()`. Toutes les fonctions du service `stripe_billing` qui * appellent Stripe taperont alors sur ce mock. * * Usage typique dans un test : * * const mock = installStripeMock({ * subscriptions: { * retrieve: async () => fakeSubscription(...) * }, * }) * await handleCheckoutCompleted(fakeSession({...})) * uninstallStripeMock() * * Pour les `group.each.teardown`, appeler `uninstallStripeMock()`. * * NB : le mock n'a pas besoin d'implémenter tout Stripe, seulement les * méthodes utilisées par le code testé. On le typecast en `Stripe` * pragmatiquement. */ export type StripeMockSpec = { subscriptions?: Partial customers?: Partial checkout?: { sessions?: Partial } billingPortal?: { sessions?: Partial } prices?: Partial webhooks?: Partial } export function installStripeMock(spec: StripeMockSpec): Stripe { const mock = spec as unknown as Stripe __setStripeForTests(mock) return mock } export function uninstallStripeMock(): void { __setStripeForTests(null) } // --------------------------------------------------------------------------- // Factories d'objets Stripe — payloads partiels typés // --------------------------------------------------------------------------- /** * Crée un objet `Stripe.Subscription` minimal pour les tests. Seuls * `items.data[0].price.lookup_key` + `status` + dates sont consommés par * les handlers ; on remplit le reste avec des stubs no-op pour satisfaire * le type runtime. */ export function fakeSubscription(input: { id?: string customerId?: string status?: Stripe.Subscription.Status lookupKey?: string | null currentPeriodEnd?: number | null trialEnd?: number | null cancelAtPeriodEnd?: boolean cancelAt?: number | null organizationId?: string | null }): Stripe.Subscription { const item = { id: 'si_test', price: { id: 'price_test', object: 'price', lookup_key: input.lookupKey ?? 'rubis_pro_monthly', } as unknown as Stripe.Price, current_period_end: input.currentPeriodEnd ?? null, } as unknown as Stripe.SubscriptionItem return { id: input.id ?? 'sub_test', object: 'subscription', customer: input.customerId ?? 'cus_test', status: input.status ?? 'active', items: { data: [item] }, cancel_at_period_end: input.cancelAtPeriodEnd ?? false, cancel_at: input.cancelAt ?? null, trial_end: input.trialEnd ?? null, metadata: input.organizationId ? { organization_id: input.organizationId, plan: 'pro' } : {}, } as unknown as Stripe.Subscription } export function fakeCheckoutSession(input: { id?: string organizationId?: string | null subscriptionId?: string | null }): Stripe.Checkout.Session { return { id: input.id ?? 'cs_test', object: 'checkout.session', subscription: input.subscriptionId ?? null, metadata: input.organizationId ? { organization_id: input.organizationId } : {}, } as unknown as Stripe.Checkout.Session } export function fakeInvoice(input: { customerId?: string | null status?: string }): Stripe.Invoice { return { id: 'in_test', object: 'invoice', customer: input.customerId ?? 'cus_test', status: input.status ?? 'open', } as unknown as Stripe.Invoice }