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', ]); }); });