template-saas-backend-v2/src/modules/sales/__tests__/dashboard.controller.spec.ts
Adrian Flores Cortes 61d7d29212 test(P2): Add controller tests for sales, commissions, and portfolio
- Add 12 controller test files (117 tests total):
  - sales: leads, opportunities, activities, pipeline, dashboard
  - commissions: schemes, assignments, entries, periods, dashboard
  - portfolio: categories, products
- Fix flaky test in assignments.service.spec.ts (timestamp issue)
- All 441 tests passing for these modules

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 13:25:42 -06:00

172 lines
5.9 KiB
TypeScript

import { Test, TestingModule } from '@nestjs/testing';
import { SalesDashboardController } from '../controllers/dashboard.controller';
import { SalesDashboardService } from '../services/sales-dashboard.service';
import { LeadStatus, LeadSource } from '../entities/lead.entity';
import { OpportunityStage } from '../entities/opportunity.entity';
describe('SalesDashboardController', () => {
let controller: SalesDashboardController;
let dashboardService: jest.Mocked<SalesDashboardService>;
const mockTenantId = '550e8400-e29b-41d4-a716-446655440001';
const mockUserId = '550e8400-e29b-41d4-a716-446655440002';
const mockRequestUser = {
id: mockUserId,
email: 'test@example.com',
tenant_id: mockTenantId,
role: 'admin',
};
const mockDashboardSummary = {
totalLeads: 150,
newLeadsThisMonth: 25,
qualifiedLeads: 45,
convertedLeads: 30,
totalOpportunities: 80,
openOpportunities: 50,
wonOpportunities: 25,
lostOpportunities: 5,
totalPipelineValue: 500000,
wonValue: 150000,
averageDealSize: 6000,
winRate: 83.33,
};
const mockLeadsByStatus = [
{ status: LeadStatus.NEW, count: 50 },
{ status: LeadStatus.CONTACTED, count: 35 },
{ status: LeadStatus.QUALIFIED, count: 45 },
{ status: LeadStatus.CONVERTED, count: 20 },
];
const mockLeadsBySource = [
{ source: LeadSource.WEBSITE, count: 60 },
{ source: LeadSource.REFERRAL, count: 40 },
{ source: LeadSource.SOCIAL_MEDIA, count: 25 },
{ source: LeadSource.EVENT, count: 25 },
];
const mockOpportunitiesByStage = [
{ stage: OpportunityStage.PROSPECTING, count: 15, value: 75000 },
{ stage: OpportunityStage.QUALIFICATION, count: 12, value: 60000 },
{ stage: OpportunityStage.PROPOSAL, count: 10, value: 100000 },
{ stage: OpportunityStage.NEGOTIATION, count: 8, value: 120000 },
{ stage: OpportunityStage.CLOSED_WON, count: 25, value: 150000 },
];
const mockConversionFunnel = [
{ stage: 'Lead Created', count: 150, percentage: 100 },
{ stage: 'Qualified', count: 45, percentage: 30 },
{ stage: 'Opportunity Created', count: 35, percentage: 23 },
{ stage: 'Proposal Sent', count: 25, percentage: 17 },
{ stage: 'Won', count: 20, percentage: 13 },
];
const mockSalesPerformance = [
{ userId: mockUserId, name: 'John Doe', leadsConverted: 10, opportunitiesWon: 5, totalValue: 50000 },
{ userId: 'user-2', name: 'Jane Smith', leadsConverted: 8, opportunitiesWon: 4, totalValue: 40000 },
];
beforeEach(async () => {
const mockDashboardService = {
getDashboardSummary: jest.fn(),
getLeadsByStatus: jest.fn(),
getLeadsBySource: jest.fn(),
getOpportunitiesByStage: jest.fn(),
getConversionFunnel: jest.fn(),
getSalesPerformance: jest.fn(),
};
const module: TestingModule = await Test.createTestingModule({
controllers: [SalesDashboardController],
providers: [
{
provide: SalesDashboardService,
useValue: mockDashboardService,
},
],
}).compile();
controller = module.get<SalesDashboardController>(SalesDashboardController);
dashboardService = module.get(SalesDashboardService);
});
afterEach(() => {
jest.clearAllMocks();
});
describe('getSummary', () => {
it('should return dashboard summary', async () => {
dashboardService.getDashboardSummary.mockResolvedValue(mockDashboardSummary);
const result = await controller.getSummary(mockRequestUser);
expect(dashboardService.getDashboardSummary).toHaveBeenCalledWith(mockTenantId);
expect(result).toEqual(mockDashboardSummary);
expect(result.totalLeads).toBe(150);
expect(result.winRate).toBe(83.33);
});
});
describe('getLeadsByStatus', () => {
it('should return leads grouped by status', async () => {
dashboardService.getLeadsByStatus.mockResolvedValue(mockLeadsByStatus);
const result = await controller.getLeadsByStatus(mockRequestUser);
expect(dashboardService.getLeadsByStatus).toHaveBeenCalledWith(mockTenantId);
expect(result).toEqual(mockLeadsByStatus);
expect(result.length).toBe(4);
});
});
describe('getLeadsBySource', () => {
it('should return leads grouped by source', async () => {
dashboardService.getLeadsBySource.mockResolvedValue(mockLeadsBySource);
const result = await controller.getLeadsBySource(mockRequestUser);
expect(dashboardService.getLeadsBySource).toHaveBeenCalledWith(mockTenantId);
expect(result).toEqual(mockLeadsBySource);
expect(result.length).toBe(4);
});
});
describe('getOpportunitiesByStage', () => {
it('should return opportunities grouped by stage', async () => {
dashboardService.getOpportunitiesByStage.mockResolvedValue(mockOpportunitiesByStage);
const result = await controller.getOpportunitiesByStage(mockRequestUser);
expect(dashboardService.getOpportunitiesByStage).toHaveBeenCalledWith(mockTenantId);
expect(result).toEqual(mockOpportunitiesByStage);
expect(result.length).toBe(5);
});
});
describe('getConversionFunnel', () => {
it('should return conversion funnel data', async () => {
dashboardService.getConversionFunnel.mockResolvedValue(mockConversionFunnel);
const result = await controller.getConversionFunnel(mockRequestUser);
expect(dashboardService.getConversionFunnel).toHaveBeenCalledWith(mockTenantId);
expect(result).toEqual(mockConversionFunnel);
expect(result[0].percentage).toBe(100);
});
});
describe('getSalesPerformance', () => {
it('should return sales performance by user', async () => {
dashboardService.getSalesPerformance.mockResolvedValue(mockSalesPerformance);
const result = await controller.getSalesPerformance(mockRequestUser);
expect(dashboardService.getSalesPerformance).toHaveBeenCalledWith(mockTenantId);
expect(result).toEqual(mockSalesPerformance);
expect(result.length).toBe(2);
});
});
});