/** * ROI 引擎纯函数单元测试。 * 仅测不依赖 DB 的逻辑;聚合/查询走集成测试。 */ import { describe, it, expect } from 'bun:test'; import { evaluateConfidence } from '../../src/services/roi/confidence-evaluator'; import { bepFromTotals } from '../../src/services/roi/bep-calculator'; describe('confidence-evaluator', () => { it('returns low when no events at all', () => { expect(evaluateConfidence([], [])).toBe('low'); }); it('returns low when only cost, no revenue', () => { expect(evaluateConfidence([{ dataSource: 'manual' }], [])).toBe('low'); }); it('returns low when all cost is auto-estimated', () => { const costs = [ { dataSource: 'auto_commits' }, { dataSource: 'auto_tasks' }, ]; const revenues = [{ dataSource: 'manual' }]; expect(evaluateConfidence(costs, revenues)).toBe('low'); }); it('returns high when 80%+ cost is plane_actual/manual + revenue exists', () => { const costs = [ { dataSource: 'plane_actual' }, { dataSource: 'plane_actual' }, { dataSource: 'manual' }, { dataSource: 'manual' }, { dataSource: 'auto_commits' }, // 1/5 = 20% 自动,刚好满足 80%+ 高质量 ]; const revenues = [{ dataSource: 'api_pulled' }]; expect(evaluateConfidence(costs, revenues)).toBe('high'); }); it('returns medium when high-quality cost ratio is between 1% and 80%', () => { const costs = [ { dataSource: 'plane_actual' }, { dataSource: 'auto_commits' }, { dataSource: 'auto_commits' }, ]; const revenues = [{ dataSource: 'manual' }]; // 1/3 = 33% 高质量,落在 medium 区间 expect(evaluateConfidence(costs, revenues)).toBe('medium'); }); it('returns high when all cost manual', () => { const costs = [{ dataSource: 'manual' }, { dataSource: 'manual' }]; const revenues = [{ dataSource: 'manual' }]; expect(evaluateConfidence(costs, revenues)).toBe('high'); }); }); describe('bepFromTotals', () => { it('returns 0 when already broken even (revenue >= cost)', () => { expect(bepFromTotals(100000, 100000, 0, 0)).toBe(0); expect(bepFromTotals(100000, 150000, 0, 0)).toBe(0); }); it('returns null when recent net income is non-positive', () => { // 累计亏 5w,近 30 天净产出为 0 expect(bepFromTotals(100000, 50000, 30000, 30000)).toBe(null); // 近 30 天还在亏 expect(bepFromTotals(100000, 50000, 30000, 20000)).toBe(null); }); it('returns positive days when on track to break even', () => { // 总投入 100w,总产出 80w => 缺口 20w // 近 30 天:成本 3w,收入 6w => 日均净 1000 元 // 预计天数 = 200000 / 1000 = 200 天 expect(bepFromTotals(1_000_000, 800_000, 30_000, 60_000)).toBe(200); }); it('rounds up partial days', () => { // 缺口 1000,日均净 300 => 3.33 天向上取整 = 4 expect(bepFromTotals(2000, 1000, 0, 9000)).toBe(4); // daily = 9000/30 = 300 }); it('respects custom windowDays', () => { // 缺口 1000,近 10 天净 1000 => 日均 100 => 10 天回本 expect(bepFromTotals(2000, 1000, 0, 1000, 10)).toBe(10); }); });