template-saas/apps/backend/dist/modules/billing/__tests__/plans.service.spec.js
rckrdmrd 50a821a415
Some checks failed
CI / Backend CI (push) Has been cancelled
CI / Frontend CI (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / CI Summary (push) Has been cancelled
[SIMCO-V38] feat: Actualizar a SIMCO v3.8.0
- HERENCIA-SIMCO.md actualizado con directivas v3.7 y v3.8
- Actualizaciones de configuracion

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-10 08:53:08 -06:00

250 lines
10 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const testing_1 = require("@nestjs/testing");
const typeorm_1 = require("@nestjs/typeorm");
const common_1 = require("@nestjs/common");
const plans_service_1 = require("../services/plans.service");
const plan_entity_1 = require("../entities/plan.entity");
describe('PlansService', () => {
let service;
let planRepo;
const mockPlan = {
id: '550e8400-e29b-41d4-a716-446655440001',
name: 'Professional',
slug: 'professional',
description: 'For growing businesses',
tagline: 'Best for teams',
price_monthly: 79,
price_yearly: 790,
currency: 'USD',
features: [
{ name: 'Up to 50 users', value: true, highlight: false },
{ name: 'Storage', value: '100 GB', highlight: true },
{ name: 'API access', value: true },
],
included_features: ['Priority support', 'Custom integrations'],
limits: { max_users: 50, storage_gb: 100 },
is_popular: true,
is_enterprise: false,
is_active: true,
is_visible: true,
sort_order: 2,
trial_days: 14,
metadata: { promotion: 'summer2026' },
created_at: new Date('2026-01-01'),
updated_at: new Date('2026-01-01'),
};
const mockFreePlan = {
id: '550e8400-e29b-41d4-a716-446655440002',
name: 'Free',
slug: 'free',
description: 'Perfect for getting started',
tagline: null,
price_monthly: 0,
price_yearly: 0,
currency: 'USD',
features: [
{ name: 'Up to 3 users', value: true },
{ name: 'Basic features', value: true },
],
included_features: ['Community support'],
limits: { max_users: 3, storage_gb: 1 },
is_popular: false,
is_enterprise: false,
is_active: true,
is_visible: true,
sort_order: 1,
trial_days: 0,
metadata: null,
created_at: new Date('2026-01-01'),
updated_at: new Date('2026-01-01'),
};
const mockEnterprisePlan = {
id: '550e8400-e29b-41d4-a716-446655440003',
name: 'Enterprise',
slug: 'enterprise',
description: 'For large organizations',
tagline: 'Custom solutions',
price_monthly: null,
price_yearly: null,
currency: 'USD',
features: [
{ name: 'Unlimited users', value: true },
{ name: 'SSO/SAML', value: true },
],
included_features: ['Dedicated support', 'SLA guarantee'],
limits: {},
is_popular: false,
is_enterprise: true,
is_active: true,
is_visible: true,
sort_order: 4,
trial_days: 30,
metadata: null,
created_at: new Date('2026-01-01'),
updated_at: new Date('2026-01-01'),
};
beforeEach(async () => {
const mockPlanRepo = {
find: jest.fn(),
findOne: jest.fn(),
};
const module = await testing_1.Test.createTestingModule({
providers: [
plans_service_1.PlansService,
{ provide: (0, typeorm_1.getRepositoryToken)(plan_entity_1.Plan), useValue: mockPlanRepo },
],
}).compile();
service = module.get(plans_service_1.PlansService);
planRepo = module.get((0, typeorm_1.getRepositoryToken)(plan_entity_1.Plan));
});
afterEach(() => {
jest.clearAllMocks();
});
describe('findAll', () => {
it('should return all visible and active plans', async () => {
const plans = [mockFreePlan, mockPlan, mockEnterprisePlan];
planRepo.find.mockResolvedValue(plans);
const result = await service.findAll();
expect(result).toHaveLength(3);
expect(planRepo.find).toHaveBeenCalledWith({
where: {
is_active: true,
is_visible: true,
},
order: {
sort_order: 'ASC',
},
});
});
it('should return empty array when no plans exist', async () => {
planRepo.find.mockResolvedValue([]);
const result = await service.findAll();
expect(result).toHaveLength(0);
expect(result).toEqual([]);
});
it('should transform plan entity to response DTO correctly', async () => {
planRepo.find.mockResolvedValue([mockPlan]);
const result = await service.findAll();
expect(result[0]).toMatchObject({
id: mockPlan.id,
name: mockPlan.name,
slug: mockPlan.slug,
display_name: mockPlan.name,
description: mockPlan.description,
tagline: mockPlan.tagline,
price_monthly: 79,
price_yearly: 790,
currency: 'USD',
is_popular: true,
trial_days: 14,
});
});
it('should extract features as string array', async () => {
planRepo.find.mockResolvedValue([mockPlan]);
const result = await service.findAll();
expect(result[0].features).toContain('Up to 50 users');
expect(result[0].features).toContain('Storage: 100 GB');
expect(result[0].features).toContain('API access');
expect(result[0].features).toContain('Priority support');
expect(result[0].features).toContain('Custom integrations');
});
it('should handle null prices correctly', async () => {
planRepo.find.mockResolvedValue([mockEnterprisePlan]);
const result = await service.findAll();
expect(result[0].price_monthly).toBe(0);
expect(result[0].price_yearly).toBe(0);
});
it('should include limits in response', async () => {
planRepo.find.mockResolvedValue([mockPlan]);
const result = await service.findAll();
expect(result[0].limits).toEqual({ max_users: 50, storage_gb: 100 });
});
});
describe('findOne', () => {
it('should return plan by ID', async () => {
planRepo.findOne.mockResolvedValue(mockPlan);
const result = await service.findOne(mockPlan.id);
expect(result).toBeDefined();
expect(result.id).toBe(mockPlan.id);
expect(planRepo.findOne).toHaveBeenCalledWith({
where: { id: mockPlan.id },
});
});
it('should throw NotFoundException when plan not found', async () => {
planRepo.findOne.mockResolvedValue(null);
await expect(service.findOne('non-existent-id')).rejects.toThrow(common_1.NotFoundException);
await expect(service.findOne('non-existent-id')).rejects.toThrow('Plan with ID "non-existent-id" not found');
});
it('should return detailed DTO with additional fields', async () => {
planRepo.findOne.mockResolvedValue(mockPlan);
const result = await service.findOne(mockPlan.id);
expect(result.is_enterprise).toBeUndefined();
expect(result.detailed_features).toEqual(mockPlan.features);
expect(result.metadata).toEqual({ promotion: 'summer2026' });
});
it('should include is_enterprise flag for enterprise plans', async () => {
planRepo.findOne.mockResolvedValue(mockEnterprisePlan);
const result = await service.findOne(mockEnterprisePlan.id);
expect(result.is_enterprise).toBe(true);
});
});
describe('findBySlug', () => {
it('should return plan by slug', async () => {
planRepo.findOne.mockResolvedValue(mockPlan);
const result = await service.findBySlug('professional');
expect(result).toBeDefined();
expect(result.slug).toBe('professional');
expect(planRepo.findOne).toHaveBeenCalledWith({
where: { slug: 'professional' },
});
});
it('should throw NotFoundException when plan not found by slug', async () => {
planRepo.findOne.mockResolvedValue(null);
await expect(service.findBySlug('non-existent')).rejects.toThrow(common_1.NotFoundException);
await expect(service.findBySlug('non-existent')).rejects.toThrow('Plan with slug "non-existent" not found');
});
});
describe('feature extraction', () => {
it('should handle empty features array', async () => {
const planWithNoFeatures = {
...mockPlan,
features: [],
included_features: [],
};
planRepo.find.mockResolvedValue([planWithNoFeatures]);
const result = await service.findAll();
expect(result[0].features).toEqual([]);
});
it('should handle boolean feature values', async () => {
const planWithBooleanFeatures = {
...mockPlan,
features: [
{ name: 'Feature enabled', value: true },
{ name: 'Feature disabled', value: false },
],
included_features: [],
};
planRepo.find.mockResolvedValue([planWithBooleanFeatures]);
const result = await service.findAll();
expect(result[0].features).toContain('Feature enabled');
expect(result[0].features).not.toContain('Feature disabled');
});
it('should handle string feature values', async () => {
const planWithStringFeatures = {
...mockPlan,
features: [{ name: 'Storage', value: '500 GB' }],
included_features: [],
};
planRepo.find.mockResolvedValue([planWithStringFeatures]);
const result = await service.findAll();
expect(result[0].features).toContain('Storage: 500 GB');
});
it('should handle null tagline', async () => {
planRepo.find.mockResolvedValue([mockFreePlan]);
const result = await service.findAll();
expect(result[0].tagline).toBeUndefined();
});
});
});
//# sourceMappingURL=plans.service.spec.js.map