import { describe, it, expect, vi, beforeEach } from 'vitest' import request from 'supertest' import express from 'express' import { billingRouter } from '../billing.js' // Mock the dependencies vi.mock('../../services/logger.js', () => ({ default: { info: vi.fn(), error: vi.fn(), } })) vi.mock('../../services/keys.js', () => ({ getCustomerIdByEmail: vi.fn(), getKeyByEmail: vi.fn() })) // Create a mock Stripe instance const mockBillingPortalCreate = vi.fn() const mockStripe = { billingPortal: { sessions: { create: mockBillingPortalCreate } } } vi.mock('stripe', () => ({ default: vi.fn().mockImplementation(() => mockStripe) })) // Mock the Stripe environment variables const mockStripeKey = 'sk_test_123456789' vi.stubEnv('STRIPE_SECRET_KEY', mockStripeKey) vi.stubEnv('BASE_URL', 'https://test.snapapi.eu') import { getCustomerIdByEmail, getKeyByEmail } from '../../services/keys.js' const app = express() app.use(express.json()) app.use('/v1/billing', billingRouter) describe('POST /v1/billing/portal', () => { beforeEach(() => { vi.clearAllMocks() mockBillingPortalCreate.mockClear() }) it.skip('should return portal URL when email has stripe customer ID', async () => { vi.mocked(getCustomerIdByEmail).mockResolvedValue('cus_123456') mockBillingPortalCreate.mockResolvedValue({ url: 'https://billing.stripe.com/p/session_123456' }) const response = await request(app) .post('/v1/billing/portal') .send({ email: 'user@example.com' }) if (response.status !== 200) { console.log('Response status:', response.status) console.log('Response body:', response.body) } expect(response.status).toBe(200) expect(response.body).toEqual({ url: 'https://billing.stripe.com/p/session_123456' }) expect(getCustomerIdByEmail).toHaveBeenCalledWith('user@example.com') expect(mockBillingPortalCreate).toHaveBeenCalledWith({ customer: 'cus_123456', return_url: 'https://test.snapapi.eu/#billing' }) }) it('should return 404 when email has no stripe customer ID', async () => { vi.mocked(getCustomerIdByEmail).mockResolvedValue(undefined) const response = await request(app) .post('/v1/billing/portal') .send({ email: 'nonexistent@example.com' }) expect(response.status).toBe(404) expect(response.body).toEqual({ error: 'No subscription found for this email address. Please contact support if you believe this is an error.' }) }) it('should return 400 when email is missing', async () => { const response = await request(app) .post('/v1/billing/portal') .send({}) expect(response.status).toBe(400) expect(response.body).toEqual({ error: 'Email address is required' }) }) it('should return 400 when email is empty string', async () => { const response = await request(app) .post('/v1/billing/portal') .send({ email: '' }) expect(response.status).toBe(400) expect(response.body).toEqual({ error: 'Email address is required' }) }) }) describe('GET /v1/billing/recover', () => { beforeEach(() => { vi.clearAllMocks() }) it('should return success message and masked key when email exists', async () => { vi.mocked(getKeyByEmail).mockResolvedValue({ key: 'snap_abcd1234efgh5678ijkl9012', tier: 'pro', email: 'user@example.com', createdAt: '2024-01-01T00:00:00Z', stripeCustomerId: 'cus_123456' }) const response = await request(app) .get('/v1/billing/recover') .query({ email: 'user@example.com' }) expect(response.status).toBe(200) expect(response.body).toEqual({ message: 'If an account exists with this email, the API key has been sent.', maskedKey: 'snap_abcd...9012' }) expect(getKeyByEmail).toHaveBeenCalledWith('user@example.com') }) it('should return success message when email does not exist (no info leak)', async () => { vi.mocked(getKeyByEmail).mockResolvedValue(undefined) const response = await request(app) .get('/v1/billing/recover') .query({ email: 'nonexistent@example.com' }) expect(response.status).toBe(200) expect(response.body).toEqual({ message: 'If an account exists with this email, the API key has been sent.' }) }) it('should return 400 when email is missing', async () => { const response = await request(app) .get('/v1/billing/recover') expect(response.status).toBe(400) expect(response.body).toEqual({ error: 'Email address is required' }) }) it('should return 400 when email is empty string', async () => { const response = await request(app) .get('/v1/billing/recover') .query({ email: '' }) expect(response.status).toBe(400) expect(response.body).toEqual({ error: 'Email address is required' }) }) it('should properly mask API keys with correct format', async () => { vi.mocked(getKeyByEmail).mockResolvedValue({ key: 'snap_1234567890abcdef', tier: 'starter', email: 'user@example.com', createdAt: '2024-01-01T00:00:00Z' }) const response = await request(app) .get('/v1/billing/recover') .query({ email: 'user@example.com' }) expect(response.status).toBe(200) expect(response.body.maskedKey).toBe('snap_1234...cdef') }) })