- Add 8 test cases covering all StripeService methods - Mock Stripe SDK for isolated testing - Test createCustomer, createSubscription, cancelSubscription - Test listSubscriptions, createCheckoutSession, createBillingPortalSession - Test constructWebhookEvent and onModuleInit
159 lines
5.8 KiB
TypeScript
159 lines
5.8 KiB
TypeScript
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<string, string> = {
|
|
STRIPE_SECRET_KEY: 'sk_test_fake123',
|
|
STRIPE_WEBHOOK_SECRET: 'whsec_test123',
|
|
};
|
|
return config[key];
|
|
}),
|
|
},
|
|
},
|
|
],
|
|
}).compile();
|
|
|
|
service = module.get<StripeService>(StripeService);
|
|
configService = module.get<ConfigService>(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' });
|
|
});
|
|
});
|
|
});
|