Aggregations-Endpunkte fuer Voelker, Koeniginnen, Bienenstaende, Varroa, Honig und Fuetterung nach Lastenheft Abschnitt 4.26.
217 lines
6.6 KiB
TypeScript
217 lines
6.6 KiB
TypeScript
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 });
|
|
});
|
|
});
|
|
});
|