/** * Unit Tests for SubscriptionsController * * Verifies that the controller correctly delegates to SubscriptionsService methods. */ import { vi, describe, it, expect, beforeEach } from 'vitest' import { SubscriptionsController } from './subscriptions.controller' describe('SubscriptionsController', () => { let controller: SubscriptionsController let service: any const mockSubscriptionEntity = { id: 'sub-123', userId: 'user-001', creatorId: 'creator-001', tierId: 'tier-001', status: 'active', } const mockCreateResponse = { subscriptionId: 'sub-123', status: 'active', requires3ds: false, nextBillingDate: '2026-03-01T00:00:00.000Z', } beforeEach(() => { service = { create: vi.fn(), createWithPayment: vi.fn(), getById: vi.fn(), listByUser: vi.fn(), cancel: vi.fn(), complete3DS: vi.fn(), sync: vi.fn(), changeTier: vi.fn(), getTierChangePreview: vi.fn(), cancelTierChange: vi.fn(), } controller = new SubscriptionsController(service as any) }) describe('create', () => { it('should delegate to service.create()', async () => { service.create.mockResolvedValue(mockCreateResponse) const request = { userId: 'user-001', creatorId: 'creator-001', tierId: 'tier-001', tierPriceCents: 999, paymentMethod: 'card' as const, } const result = await controller.create(request) expect(service.create).toHaveBeenCalledWith(request) expect(service.create).toHaveBeenCalledTimes(1) expect(result).toEqual(mockCreateResponse) }) }) describe('createWithPayment', () => { it('should delegate to service.createWithPayment()', async () => { service.createWithPayment.mockResolvedValue(mockCreateResponse) const request = { userId: 'user-001', creatorId: 'creator-001', tierId: 'tier-001', tierPriceCents: 999, cardNumber: '4111111111111111', expiryMonth: '12', expiryYear: '2027', cvv: '123', cardholderName: 'Test User', customerEmail: 'user@example.com', } const result = await controller.createWithPayment(request) expect(service.createWithPayment).toHaveBeenCalledWith(request) expect(service.createWithPayment).toHaveBeenCalledTimes(1) expect(result).toEqual(mockCreateResponse) }) }) describe('listByUser', () => { it('should delegate to service.listByUser()', async () => { service.listByUser.mockResolvedValue([mockSubscriptionEntity]) const result = await controller.listByUser('user-001') expect(service.listByUser).toHaveBeenCalledWith('user-001') expect(service.listByUser).toHaveBeenCalledTimes(1) expect(result).toEqual([mockSubscriptionEntity]) }) }) describe('getById', () => { it('should delegate to service.getById()', async () => { service.getById.mockResolvedValue(mockSubscriptionEntity) const result = await controller.getById('sub-123') expect(service.getById).toHaveBeenCalledWith('sub-123') expect(service.getById).toHaveBeenCalledTimes(1) expect(result).toEqual(mockSubscriptionEntity) }) }) describe('cancel', () => { it('should delegate to service.cancel() with default cancelAtPeriodEnd', async () => { service.cancel.mockResolvedValue(mockSubscriptionEntity) const result = await controller.cancel('sub-123', true) expect(service.cancel).toHaveBeenCalledWith('sub-123', true) expect(service.cancel).toHaveBeenCalledTimes(1) expect(result).toEqual(mockSubscriptionEntity) }) it('should pass cancelAtPeriodEnd=false when specified', async () => { service.cancel.mockResolvedValue(mockSubscriptionEntity) await controller.cancel('sub-123', false) expect(service.cancel).toHaveBeenCalledWith('sub-123', false) }) }) describe('complete3DS', () => { it('should delegate to service.complete3DS()', async () => { service.complete3DS.mockResolvedValue(mockSubscriptionEntity) const result = await controller.complete3DS('sub-123') expect(service.complete3DS).toHaveBeenCalledWith('sub-123') expect(service.complete3DS).toHaveBeenCalledTimes(1) expect(result).toEqual(mockSubscriptionEntity) }) }) describe('sync', () => { it('should delegate to service.sync()', async () => { service.sync.mockResolvedValue(mockSubscriptionEntity) const result = await controller.sync('sub-123') expect(service.sync).toHaveBeenCalledWith('sub-123') expect(service.sync).toHaveBeenCalledTimes(1) expect(result).toEqual(mockSubscriptionEntity) }) }) describe('changeTier', () => { it('should delegate to service.changeTier()', async () => { service.changeTier.mockResolvedValue(mockSubscriptionEntity) const result = await controller.changeTier('sub-123', 'tier-002') expect(service.changeTier).toHaveBeenCalledWith('sub-123', 'tier-002') expect(service.changeTier).toHaveBeenCalledTimes(1) expect(result).toEqual(mockSubscriptionEntity) }) }) describe('getTierChangePreview', () => { it('should delegate to service.getTierChangePreview() with newTierData', async () => { const mockPreview = { currentTier: { id: 'tier-001' }, newTier: { id: 'tier-002', name: 'Premium', price: 19.99 }, proratedAmount: 5.50, } service.getTierChangePreview.mockResolvedValue(mockPreview) const newTierData = { name: 'Premium', priceCents: 1999, features: ['feature-a'] } const result = await controller.getTierChangePreview('sub-123', 'tier-002', newTierData) expect(service.getTierChangePreview).toHaveBeenCalledWith('sub-123', 'tier-002', newTierData) expect(service.getTierChangePreview).toHaveBeenCalledTimes(1) expect(result).toEqual(mockPreview) }) }) describe('cancelTierChange', () => { it('should delegate to service.cancelTierChange()', async () => { service.cancelTierChange.mockResolvedValue(mockSubscriptionEntity) const result = await controller.cancelTierChange('sub-123') expect(service.cancelTierChange).toHaveBeenCalledWith('sub-123') expect(service.cancelTierChange).toHaveBeenCalledTimes(1) expect(result).toEqual(mockSubscriptionEntity) }) }) })