diff --git a/backoffice/src/stripe/stripe.service.spec.ts b/backoffice/src/stripe/stripe.service.spec.ts new file mode 100644 index 0000000..06cffee --- /dev/null +++ b/backoffice/src/stripe/stripe.service.spec.ts @@ -0,0 +1,159 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { ConfigService } from '@nestjs/config'; +import { StripeService } from './stripe.service'; + +// Mock Stripe +jest.mock('stripe', () => { + return jest.fn().mockImplementation(() => ({ + customers: { + create: jest.fn().mockResolvedValue({ id: 'cus_test123', email: 'test@example.com' }), + }, + subscriptions: { + create: jest.fn().mockResolvedValue({ id: 'sub_test123', status: 'active' }), + cancel: jest.fn().mockResolvedValue({ id: 'sub_test123', status: 'canceled' }), + list: jest.fn().mockResolvedValue({ data: [] }), + }, + checkout: { + sessions: { + create: jest.fn().mockResolvedValue({ id: 'cs_test123', url: 'https://checkout.stripe.com/test' }), + }, + }, + billingPortal: { + sessions: { + create: jest.fn().mockResolvedValue({ id: 'bps_test123', url: 'https://billing.stripe.com/test' }), + }, + }, + webhooks: { + constructEvent: jest.fn().mockReturnValue({ type: 'checkout.session.completed' }), + }, + })); +}); + +describe('StripeService', () => { + let service: StripeService; + let configService: ConfigService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + StripeService, + { + provide: ConfigService, + useValue: { + get: jest.fn((key: string) => { + const config: Record = { + STRIPE_SECRET_KEY: 'sk_test_fake123', + STRIPE_WEBHOOK_SECRET: 'whsec_test123', + }; + return config[key]; + }), + }, + }, + ], + }).compile(); + + service = module.get(StripeService); + configService = module.get(ConfigService); + + // Initialize the service + service.onModuleInit(); + }); + + describe('onModuleInit', () => { + it('should initialize Stripe client when secret key is configured', () => { + expect(service.getClient()).toBeDefined(); + }); + + it('should warn when STRIPE_SECRET_KEY is not configured', () => { + const warnSpy = jest.spyOn(console, 'warn').mockImplementation(); + jest.spyOn(configService, 'get').mockReturnValue(undefined); + + const newService = new StripeService(configService); + newService.onModuleInit(); + + expect(warnSpy).toHaveBeenCalledWith('STRIPE_SECRET_KEY not configured'); + warnSpy.mockRestore(); + }); + }); + + describe('createCustomer', () => { + it('should create a customer with email and name', async () => { + const result = await service.createCustomer('test@example.com', 'Test User'); + + expect(result).toEqual({ id: 'cus_test123', email: 'test@example.com' }); + expect(service.getClient().customers.create).toHaveBeenCalledWith({ + email: 'test@example.com', + name: 'Test User', + }); + }); + }); + + describe('createSubscription', () => { + it('should create a subscription for a customer', async () => { + const result = await service.createSubscription('cus_test123', 'price_test123'); + + expect(result).toEqual({ id: 'sub_test123', status: 'active' }); + expect(service.getClient().subscriptions.create).toHaveBeenCalledWith({ + customer: 'cus_test123', + items: [{ price: 'price_test123' }], + payment_behavior: 'default_incomplete', + expand: ['latest_invoice.payment_intent'], + }); + }); + }); + + describe('cancelSubscription', () => { + it('should cancel a subscription', async () => { + const result = await service.cancelSubscription('sub_test123'); + + expect(result).toEqual({ id: 'sub_test123', status: 'canceled' }); + }); + }); + + describe('listSubscriptions', () => { + it('should list subscriptions for a customer', async () => { + const result = await service.listSubscriptions('cus_test123'); + + expect(result).toEqual({ data: [] }); + expect(service.getClient().subscriptions.list).toHaveBeenCalledWith({ + customer: 'cus_test123', + status: 'all', + }); + }); + }); + + describe('createCheckoutSession', () => { + it('should create a checkout session', async () => { + const result = await service.createCheckoutSession( + 'cus_test123', + 'price_test123', + 'https://example.com/success', + 'https://example.com/cancel', + ); + + expect(result).toEqual({ id: 'cs_test123', url: 'https://checkout.stripe.com/test' }); + }); + }); + + describe('createBillingPortalSession', () => { + it('should create a billing portal session', async () => { + const result = await service.createBillingPortalSession( + 'cus_test123', + 'https://example.com/return', + ); + + expect(result).toEqual({ id: 'bps_test123', url: 'https://billing.stripe.com/test' }); + }); + }); + + describe('constructWebhookEvent', () => { + it('should construct a webhook event from request body', () => { + const body = Buffer.from('{}'); + const signature = 'test_signature'; + + const result = service.constructWebhookEvent(body, signature); + + expect(result).toEqual({ type: 'checkout.session.completed' }); + }); + }); +});