- products.controller.spec.ts (16 tests) - Portfolio module - activities.controller.spec.ts (8 tests) - Sales module - leads.controller.spec.ts (9 tests) - Sales module - dashboard.controller.spec.ts (6 tests) - Sales module Total: 39 new tests for previously deleted test files Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
192 lines
6.6 KiB
TypeScript
192 lines
6.6 KiB
TypeScript
import { Test, TestingModule } from '@nestjs/testing';
|
|
import { SalesDashboardController } from '../controllers/dashboard.controller';
|
|
import { SalesDashboardService } from '../services';
|
|
import { LeadStatus, LeadSource, OpportunityStage } from '../entities';
|
|
import {
|
|
SalesDashboardDto,
|
|
LeadsByStatusDto,
|
|
LeadsBySourceDto,
|
|
OpportunitiesByStageDto,
|
|
ConversionFunnelDto,
|
|
SalesPerformanceDto,
|
|
} from '../dto';
|
|
|
|
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 mockSummary: SalesDashboardDto = {
|
|
totalLeads: 150,
|
|
totalOpportunities: 45,
|
|
totalPipelineValue: 1250000,
|
|
wonDeals: 12,
|
|
conversionRate: 26.7,
|
|
averageDealSize: 104166.67,
|
|
activitiesThisWeek: 35,
|
|
currency: 'USD',
|
|
};
|
|
|
|
const mockLeadsByStatus: LeadsByStatusDto[] = [
|
|
{ status: LeadStatus.NEW, count: 50, percentage: 33.3 },
|
|
{ status: LeadStatus.CONTACTED, count: 40, percentage: 26.7 },
|
|
{ status: LeadStatus.QUALIFIED, count: 35, percentage: 23.3 },
|
|
{ status: LeadStatus.CONVERTED, count: 25, percentage: 16.7 },
|
|
];
|
|
|
|
const mockLeadsBySource: LeadsBySourceDto[] = [
|
|
{ source: LeadSource.WEBSITE, count: 60, percentage: 40.0 },
|
|
{ source: LeadSource.REFERRAL, count: 45, percentage: 30.0 },
|
|
{ source: LeadSource.EVENT, count: 25, percentage: 16.7 },
|
|
{ source: LeadSource.COLD_CALL, count: 20, percentage: 13.3 },
|
|
];
|
|
|
|
const mockOpportunitiesByStage: OpportunitiesByStageDto[] = [
|
|
{ stage: OpportunityStage.QUALIFICATION, count: 15, totalAmount: 375000, percentage: 33.3 },
|
|
{ stage: OpportunityStage.PROPOSAL, count: 12, totalAmount: 480000, percentage: 26.7 },
|
|
{ stage: OpportunityStage.NEGOTIATION, count: 10, totalAmount: 350000, percentage: 22.2 },
|
|
{ stage: OpportunityStage.CLOSED_WON, count: 8, totalAmount: 320000, percentage: 17.8 },
|
|
];
|
|
|
|
const mockConversionFunnel: ConversionFunnelDto[] = [
|
|
{ stage: 'leads', count: 150, percentage: 100, conversionFromPrevious: 100 },
|
|
{ stage: 'qualified', count: 75, percentage: 50, conversionFromPrevious: 50 },
|
|
{ stage: 'opportunities', count: 45, percentage: 30, conversionFromPrevious: 60 },
|
|
{ stage: 'proposals', count: 30, percentage: 20, conversionFromPrevious: 66.7 },
|
|
{ stage: 'won', count: 12, percentage: 8, conversionFromPrevious: 40 },
|
|
];
|
|
|
|
const mockSalesPerformance: SalesPerformanceDto[] = [
|
|
{
|
|
userId: 'user-001',
|
|
userName: 'John Doe',
|
|
leadsAssigned: 45,
|
|
opportunitiesWon: 5,
|
|
totalRevenue: 125000,
|
|
conversionRate: 11.1,
|
|
activitiesCompleted: 120,
|
|
},
|
|
{
|
|
userId: 'user-002',
|
|
userName: 'Jane Smith',
|
|
leadsAssigned: 52,
|
|
opportunitiesWon: 7,
|
|
totalRevenue: 175000,
|
|
conversionRate: 13.5,
|
|
activitiesCompleted: 145,
|
|
},
|
|
];
|
|
|
|
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(mockSummary);
|
|
|
|
const result = await controller.getSummary(mockRequestUser);
|
|
|
|
expect(dashboardService.getDashboardSummary).toHaveBeenCalledWith(mockTenantId);
|
|
expect(result).toEqual(mockSummary);
|
|
expect(result.totalLeads).toBe(150);
|
|
expect(result.conversionRate).toBe(26.7);
|
|
});
|
|
});
|
|
|
|
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(4);
|
|
});
|
|
});
|
|
|
|
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.length).toBe(5);
|
|
expect(result[0].stage).toBe('leads');
|
|
});
|
|
});
|
|
|
|
describe('getSalesPerformance', () => {
|
|
it('should return sales performance data', 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);
|
|
expect(result[0].totalRevenue).toBe(125000);
|
|
});
|
|
});
|
|
});
|