import { StatisticsService } from './statistics.service'; import { PrismaService } from '../prisma/prisma.service'; describe('StatisticsService', () => { let service: StatisticsService; let prisma: { colony: { groupBy: jest.Mock; findMany: jest.Mock }; inspection: { findMany: jest.Mock }; queen: { findMany: jest.Mock }; queenEvaluation: { findMany: jest.Mock }; apiary: { findMany: jest.Mock }; varroaMeasurement: { findMany: jest.Mock }; treatment: { groupBy: jest.Mock }; harvest: { findMany: jest.Mock }; honeyBatch: { findMany: jest.Mock }; feeding: { findMany: jest.Mock }; }; beforeEach(() => { prisma = { colony: { groupBy: jest.fn().mockResolvedValue([]), findMany: jest.fn().mockResolvedValue([]), }, inspection: { findMany: jest.fn().mockResolvedValue([]) }, queen: { findMany: jest.fn().mockResolvedValue([]) }, queenEvaluation: { findMany: jest.fn().mockResolvedValue([]) }, apiary: { findMany: jest.fn().mockResolvedValue([]) }, varroaMeasurement: { findMany: jest.fn().mockResolvedValue([]) }, treatment: { groupBy: jest.fn().mockResolvedValue([]) }, harvest: { findMany: jest.fn().mockResolvedValue([]) }, honeyBatch: { findMany: jest.fn().mockResolvedValue([]) }, feeding: { findMany: jest.fn().mockResolvedValue([]) }, }; service = new StatisticsService(prisma as unknown as PrismaService); }); describe('colonies', () => { it('groups losses by year using deactivatedAt, falling back to updatedAt', async () => { prisma.colony.groupBy.mockResolvedValueOnce([ { status: 'ACTIVE', _count: { _all: 5 } }, ]); prisma.colony.findMany.mockResolvedValueOnce([ { deactivatedAt: new Date('2025-09-01'), updatedAt: new Date('2025-09-01'), }, { deactivatedAt: null, updatedAt: new Date('2024-03-01') }, ]); const result = await service.colonies(); expect(result.byStatus).toEqual([{ status: 'ACTIVE', count: 5 }]); expect(result.lossesByYear).toEqual({ '2025': 1, '2024': 1 }); }); }); describe('queens', () => { it('averages evaluation dimensions per queen and sorts by honey yield descending', async () => { prisma.queen.findMany.mockResolvedValueOnce([ { id: 'q1', code: 'K-001', status: 'ACTIVE', createdAt: new Date('2024-01-01'), deactivatedAt: null, }, { id: 'q2', code: 'K-002', status: 'ACTIVE', createdAt: new Date('2024-01-01'), deactivatedAt: null, }, ]); prisma.queenEvaluation.findMany.mockResolvedValueOnce([ { queenId: 'q1', colonyStrength: 3, gentleness: 3, combBuild: 3, swarmingTendency: 3, broodPattern: 3, honeyYield: 2, }, { queenId: 'q2', colonyStrength: 5, gentleness: 5, combBuild: 5, swarmingTendency: 5, broodPattern: 5, honeyYield: 5, }, ]); const result = await service.queens(); expect(result.evaluationAverages.map((row) => row.queenId)).toEqual([ 'q2', 'q1', ]); expect(result.evaluationAverages[0].honeyYield).toBe(5); }); it('computes average lifespan only from retired queens', async () => { prisma.queen.findMany.mockResolvedValueOnce([ { id: 'q1', code: 'K-001', status: 'RETIRED', createdAt: new Date('2024-01-01'), deactivatedAt: new Date('2024-01-11'), }, { id: 'q2', code: 'K-002', status: 'ACTIVE', createdAt: new Date('2024-01-01'), deactivatedAt: null, }, ]); const result = await service.queens(); expect(result.averageLifespanDays).toBe(10); }); }); describe('apiaries', () => { it('computes honey totals and colony counts per apiary', async () => { prisma.apiary.findMany.mockResolvedValueOnce([ { id: 'a1', name: 'Wabenhain Nord', colonies: [ { id: 'c1', status: 'ACTIVE' }, { id: 'c2', status: 'DECEASED' }, ], harvests: [{ netWeight: 10 }, { netWeight: 5 }], }, ]); const result = await service.apiaries(); expect(result).toEqual([ { apiaryId: 'a1', name: 'Wabenhain Nord', activeColonies: 1, lostColonies: 1, totalHoneyKg: 15, averageHoneyKgPerColony: 7.5, }, ]); }); }); describe('varroa', () => { it('returns measurements and treatment counts per colony', async () => { prisma.varroaMeasurement.findMany.mockResolvedValueOnce([ { colonyId: 'c1', date: new Date('2025-07-01'), miteCount: 4, method: 'PUDERZUCKER', }, ]); prisma.treatment.groupBy.mockResolvedValueOnce([ { colonyId: 'c1', _count: { _all: 2 } }, ]); const result = await service.varroa(); expect(result.measurements).toHaveLength(1); expect(result.treatmentCountByColony).toEqual([ { colonyId: 'c1', treatmentCount: 2 }, ]); }); }); describe('honey', () => { it('sums yield per year and per apiary', async () => { prisma.harvest.findMany.mockResolvedValueOnce([ { apiaryId: 'a1', date: new Date('2025-06-01'), netWeight: 10 }, { apiaryId: 'a1', date: new Date('2024-06-01'), netWeight: 6 }, { apiaryId: 'a2', date: new Date('2025-06-01'), netWeight: 4 }, ]); prisma.honeyBatch.findMany.mockResolvedValueOnce([ { amount: 8, createdAt: new Date() }, ]); const result = await service.honey(); expect(result.totalHarvestKg).toBe(20); expect(result.totalHoneyBatchKg).toBe(8); expect(result.yieldPerYear).toEqual({ '2025': 14, '2024': 6 }); expect(result.yieldPerApiary).toEqual({ a1: 16, a2: 4 }); }); }); describe('feeding', () => { it('sums feeding amount per colony and per season', async () => { prisma.feeding.findMany.mockResolvedValueOnce([ { colonyId: 'c1', date: new Date('2025-09-01'), amount: 5, unit: 'l' }, { colonyId: 'c1', date: new Date('2025-09-15'), amount: 3, unit: 'l' }, { colonyId: 'c2', date: new Date('2024-09-01'), amount: 2, unit: 'l' }, ]); const result = await service.feeding(); expect(result.byColony).toEqual({ c1: 8, c2: 2 }); expect(result.bySeason).toEqual({ '2025': 8, '2024': 2 }); }); }); });