82 lines
3.1 KiB
TypeScript
82 lines
3.1 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import {
|
|
calculateCp707Uniformity,
|
|
getCp707UniformityStatus,
|
|
CP707_UNIFORMITY_TARGET,
|
|
} from '../weightUtils.ts';
|
|
|
|
/**
|
|
* Keseragaman dihitung ulang dari `avg` + `Standard_deviasi` menurut CP 707
|
|
* (persen ayam dalam ±10% dari rata-rata), bukan diambil dari field
|
|
* `uniformity` milik API `distribusi_bobot` yang memakai band ±5%.
|
|
*
|
|
* Nilai acuan di bawah berasal dari respons API sungguhan dan dicocokkan
|
|
* dengan perhitungan referensi `math.erf` di Python.
|
|
*/
|
|
describe('calculateCp707Uniformity', () => {
|
|
it.each([
|
|
// tanggal, avg (g), Standard_deviasi (g), harapan (%)
|
|
['2026-08-10', 1123.53, 161.3, 51.4],
|
|
['2026-08-05', 806.79, 26.87, 99.7],
|
|
['2026-08-04', 667.31, 139.71, 36.7],
|
|
['2026-06-18', 1324.8, 106.5, 78.6],
|
|
])('cocok dengan perhitungan referensi untuk %s', (_tanggal, avg, sd, harapan) => {
|
|
expect(calculateCp707Uniformity(avg, sd)).toBeCloseTo(harapan as number, 0);
|
|
});
|
|
|
|
it('tidak terpengaruh lebar bucket 50 g di awal siklus', () => {
|
|
// Bobot 75 g: band ±10% hanya 15 g, jauh lebih sempit dari bucket 50 g milik
|
|
// API. Perhitungan berbasis bucket gagal di sini; berbasis SD tidak.
|
|
expect(calculateCp707Uniformity(75.4, 3.3)).toBeCloseTo(97.8, 0);
|
|
});
|
|
|
|
it('mengembalikan 100 saat tidak ada variasi bobot', () => {
|
|
expect(calculateCp707Uniformity(1000, 0)).toBe(100);
|
|
});
|
|
|
|
it('hasilnya selalu berada di rentang 0-100', () => {
|
|
for (const [avg, sd] of [
|
|
[1000, 1],
|
|
[1000, 5000],
|
|
[50, 0.1],
|
|
]) {
|
|
const v = calculateCp707Uniformity(avg, sd);
|
|
expect(v).not.toBeNull();
|
|
expect(v as number).toBeGreaterThanOrEqual(0);
|
|
expect(v as number).toBeLessThanOrEqual(100);
|
|
}
|
|
});
|
|
|
|
it('mengembalikan null, bukan angka karangan, saat data tidak memadai', () => {
|
|
expect(calculateCp707Uniformity(null, 10)).toBeNull();
|
|
expect(calculateCp707Uniformity(1000, null)).toBeNull();
|
|
expect(calculateCp707Uniformity(undefined, undefined)).toBeNull();
|
|
expect(calculateCp707Uniformity(0, 10)).toBeNull();
|
|
expect(calculateCp707Uniformity(-100, 10)).toBeNull();
|
|
expect(calculateCp707Uniformity(1000, -5)).toBeNull();
|
|
expect(calculateCp707Uniformity(NaN, 10)).toBeNull();
|
|
expect(calculateCp707Uniformity(1000, Infinity)).toBeNull();
|
|
});
|
|
|
|
it('naik saat sebaran menyempit', () => {
|
|
const ketat = calculateCp707Uniformity(1000, 30) as number;
|
|
const longgar = calculateCp707Uniformity(1000, 150) as number;
|
|
expect(ketat).toBeGreaterThan(longgar);
|
|
});
|
|
});
|
|
|
|
describe('getCp707UniformityStatus', () => {
|
|
it('memakai ambang CP 707 (>80%), bukan ambang lama 85/75', () => {
|
|
expect(getCp707UniformityStatus(CP707_UNIFORMITY_TARGET)).toBe('ok');
|
|
expect(getCp707UniformityStatus(82)).toBe('ok');
|
|
// 82 dulu berstatus "warning" dengan ambang lama 85.
|
|
expect(getCp707UniformityStatus(75)).toBe('warning');
|
|
expect(getCp707UniformityStatus(70)).toBe('warning');
|
|
expect(getCp707UniformityStatus(69.9)).toBe('critical');
|
|
});
|
|
|
|
it('memperlakukan data tidak tersedia sebagai critical', () => {
|
|
expect(getCp707UniformityStatus(null)).toBe('critical');
|
|
});
|
|
});
|