- HERENCIA-SIMCO.md actualizado con directivas v3.7 y v3.8 - Actualizaciones de configuracion Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
250 lines
10 KiB
JavaScript
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
|