import { DashboardService } from './dashboard.service'; import { PrismaService } from '../prisma/prisma.service'; describe('DashboardService', () => { let service: DashboardService; let prisma: { apiary: { count: jest.Mock }; colony: { count: jest.Mock; findMany: jest.Mock }; queen: { count: jest.Mock }; task: { count: jest.Mock; findMany: jest.Mock }; honeyBatch: { count: jest.Mock }; stockItem: { findMany: jest.Mock }; swarmControlCheck: { findMany: jest.Mock }; }; beforeEach(() => { prisma = { apiary: { count: jest.fn().mockResolvedValue(2) }, colony: { count: jest.fn().mockResolvedValue(5), findMany: jest.fn().mockResolvedValue([]), }, queen: { count: jest.fn().mockResolvedValue(4) }, task: { count: jest.fn().mockResolvedValue(3), findMany: jest.fn().mockResolvedValue([]), }, honeyBatch: { count: jest.fn().mockResolvedValue(1) }, stockItem: { findMany: jest.fn().mockResolvedValue([]) }, swarmControlCheck: { findMany: jest.fn().mockResolvedValue([]) }, }; service = new DashboardService(prisma as unknown as PrismaService); }); it('summary counts low-stock items below their minimum threshold', async () => { prisma.stockItem.findMany.mockResolvedValue([ { id: 'item-1', quantity: 2, minThreshold: 5 }, { id: 'item-2', quantity: 10, minThreshold: 5 }, ]); const summary = await service.summary(); expect(summary.stockItemsLowCount).toBe(1); expect(summary.apiariesActive).toBe(2); expect(summary.coloniesActive).toBe(5); }); it('alerts flags overdue tasks, attention colonies, and low stock', async () => { prisma.task.findMany.mockResolvedValue([ { id: 'task-1', title: 'Beute prüfen' }, ]); prisma.colony.findMany.mockResolvedValue([ { id: 'colony-1', code: 'V-001', status: 'WEAK' }, ]); prisma.stockItem.findMany.mockResolvedValue([ { id: 'item-1', name: 'Zuckerlösung', quantity: 2, minThreshold: 5 }, ]); const alerts = await service.alerts(); expect(alerts).toHaveLength(3); expect(alerts.map((alert) => alert.type)).toEqual([ 'OVERDUE_TASK', 'COLONY_ATTENTION', 'LOW_STOCK', ]); }); it('flags a colony whose most recent swarm check is overdue', async () => { prisma.swarmControlCheck.findMany.mockResolvedValue([ { colonyId: 'colony-1', nextCheckDate: new Date('2020-01-01'), colony: { code: 'V-001' }, }, ]); const alerts = await service.alerts(); expect(alerts).toEqual([ { type: 'OVERDUE_SWARM_CHECK', message: 'Schwarmkontrolle für Volk V-001 überfällig', relatedType: 'Colony', relatedId: 'colony-1', }, ]); }); it('ignores an overdue swarm check when a newer check already superseded it', async () => { prisma.swarmControlCheck.findMany.mockResolvedValue([ { colonyId: 'colony-1', date: new Date('2026-06-10'), nextCheckDate: null, colony: { code: 'V-001' }, }, { colonyId: 'colony-1', date: new Date('2026-06-01'), nextCheckDate: new Date('2020-01-01'), colony: { code: 'V-001' }, }, ]); const alerts = await service.alerts(); expect(alerts).toHaveLength(0); }); describe('OLD_QUEEN', () => { it('flags a colony whose queen is at least 3 years old', async () => { prisma.colony.findMany .mockResolvedValueOnce([]) // attentionColonies .mockResolvedValueOnce([ { id: 'colony-1', code: 'V-001', currentQueen: { hatchYear: 2020 } }, ]); const alerts = await service.alerts(); expect(alerts).toHaveLength(1); expect(alerts[0].type).toBe('OLD_QUEEN'); expect(alerts[0].relatedId).toBe('colony-1'); }); it('does not flag a queen younger than the threshold', async () => { const currentYear = new Date().getFullYear(); prisma.colony.findMany.mockResolvedValueOnce([]).mockResolvedValueOnce([ { id: 'colony-1', code: 'V-001', currentQueen: { hatchYear: currentYear }, }, ]); const alerts = await service.alerts(); expect(alerts).toHaveLength(0); }); }); });