163 lines
4.8 KiB
TypeScript
163 lines
4.8 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import type { DashboardReportPayload } from '../../types/dashboardReport.ts';
|
|
import { buildReportWorkbook } from '../reportExcel.ts';
|
|
|
|
const snapshot: DashboardReportPayload = {
|
|
cycleId: 'CYCLE-JBW',
|
|
kandangId: 1,
|
|
kandangName: 'Kandang Atas',
|
|
area: 'Sukawarna',
|
|
upToDay: 2,
|
|
generatedAt: '2026-05-24T10:00:00.000Z',
|
|
counting: [
|
|
{
|
|
date: '2026-05-22',
|
|
day: 0,
|
|
countBefore: 100,
|
|
mortality: 0,
|
|
harvest: 0,
|
|
harvestWeight: null,
|
|
countAfter: 100,
|
|
iotCount: 95,
|
|
accuracy: 95,
|
|
},
|
|
],
|
|
weight: [
|
|
{
|
|
date: '2026-05-23',
|
|
day: 1,
|
|
avgManual: 1000,
|
|
avgIot: 900,
|
|
uniformity: 80,
|
|
difference: 100,
|
|
accuracy: 90,
|
|
},
|
|
],
|
|
feedIn: [{ date: '2026-05-22', manualIn: 10, iotIn: 10, accuracy: 100 }],
|
|
feedUse: [{ date: '2026-05-22', day: 0, manualUse: 4, iotUse: 4, accuracy: 100 }],
|
|
};
|
|
|
|
const emptySnapshot: DashboardReportPayload = {
|
|
...snapshot,
|
|
counting: [],
|
|
weight: [],
|
|
feedIn: [],
|
|
feedUse: [],
|
|
};
|
|
|
|
describe('buildReportWorkbook', () => {
|
|
it('creates four sheets with the specified names', async () => {
|
|
const workbook = await buildReportWorkbook(snapshot);
|
|
expect(workbook.worksheets.map((sheet) => sheet.name)).toEqual([
|
|
'Counting',
|
|
'Weight',
|
|
'Feed In',
|
|
'Feed Use',
|
|
]);
|
|
});
|
|
|
|
it('includes chicken age and mortality on Counting, and no chicken-age on Feed In', async () => {
|
|
const workbook = await buildReportWorkbook(snapshot);
|
|
const countingHeaders = workbook.getWorksheet('Counting')?.getRow(2).values ?? [];
|
|
const feedInHeaders = workbook.getWorksheet('Feed In')?.getRow(2).values ?? [];
|
|
|
|
expect(countingHeaders).toEqual(
|
|
expect.arrayContaining(['Umur (hari)', 'Mortalitas'])
|
|
);
|
|
expect(feedInHeaders).toEqual(expect.arrayContaining(['Tanggal', 'Manual masuk', 'IoT masuk']));
|
|
expect(feedInHeaders).not.toEqual(expect.arrayContaining(['Umur (hari)']));
|
|
});
|
|
|
|
it('writes header metadata matching upToDay and generatedAt', async () => {
|
|
const workbook = await buildReportWorkbook(snapshot);
|
|
const headerValues = workbook.getWorksheet('Counting')?.getRow(1).values ?? [];
|
|
const header = (Array.isArray(headerValues) ? headerValues : [])
|
|
.map((value) => (value == null ? '' : String(value)))
|
|
.filter(Boolean)
|
|
.join(' ');
|
|
|
|
expect(header).toContain('Kandang Atas');
|
|
expect(header).toContain('CYCLE-JBW');
|
|
expect(header).toContain('Hari ke-0 s/d ke-2');
|
|
expect(header).toContain('2026-05-24T10:00:00.000Z');
|
|
});
|
|
|
|
it('still produces a workbook when snapshot tables are empty (AE5)', async () => {
|
|
const workbook = await buildReportWorkbook(emptySnapshot);
|
|
expect(workbook.worksheets).toHaveLength(4);
|
|
expect(workbook.getWorksheet('Counting')?.rowCount).toBeGreaterThanOrEqual(2);
|
|
});
|
|
|
|
it('appends a Total row on each sheet', async () => {
|
|
const workbook = await buildReportWorkbook(snapshot);
|
|
const lastValues = (sheetName: string) => {
|
|
const sheet = workbook.getWorksheet(sheetName);
|
|
const values = sheet?.getRow(sheet.rowCount).values;
|
|
return (Array.isArray(values) ? values : []).filter((value) => value != null);
|
|
};
|
|
|
|
expect(lastValues('Counting')[0]).toBe('Total');
|
|
expect(lastValues('Weight')[0]).toBe('2026-05-23');
|
|
expect(lastValues('Feed In')).toEqual(['Total', 10, 10, '100.0%']);
|
|
expect(lastValues('Feed Use')).toEqual(['Total', '—', 4, 4, '100.0%']);
|
|
});
|
|
|
|
it('adds FCR and EEF sheets for an end-cycle snapshot', async () => {
|
|
const workbook = await buildReportWorkbook({
|
|
...snapshot,
|
|
reportType: 'end_cycle',
|
|
fcr: [
|
|
{
|
|
day: 0,
|
|
iotFcr: 1.234,
|
|
feedTotal: 10,
|
|
iotWeight: 45.5,
|
|
chickenLife: 10000,
|
|
harvestWeightTotal: 12000,
|
|
},
|
|
],
|
|
eef: [
|
|
{
|
|
day: 0,
|
|
iotEef: 310.456,
|
|
chickenLifePercentage: 99.5,
|
|
iotAverageHarvestBw: 45.5,
|
|
iotAverageDayWeight: 0.2,
|
|
iotFcr: 1.234,
|
|
},
|
|
],
|
|
});
|
|
|
|
expect(workbook.worksheets.map((sheet) => sheet.name)).toEqual([
|
|
'Counting',
|
|
'Weight',
|
|
'Feed In',
|
|
'Feed Use',
|
|
'FCR',
|
|
'EEF',
|
|
]);
|
|
|
|
const headerCells = (sheetName: string) => {
|
|
const values = workbook.getWorksheet(sheetName)?.getRow(2).values ?? [];
|
|
return (Array.isArray(values) ? values : []).filter((value) => value != null);
|
|
};
|
|
|
|
expect(headerCells('FCR')).toEqual([
|
|
'Umur',
|
|
'Total Pakan',
|
|
'Bobot IoT',
|
|
'Ayam Hidup',
|
|
'Total Bobot Panen',
|
|
'FCR',
|
|
]);
|
|
expect(headerCells('EEF')).toEqual([
|
|
'Umur',
|
|
'Persentase Ayam Hidup',
|
|
'BW Rata-rata Panen',
|
|
'Umur Rata-rata Panen',
|
|
'FCR',
|
|
'EEF',
|
|
]);
|
|
});
|
|
});
|