import { Logger } from '@common/Logger'; import { CORE_PERF_THRESHOLDS, PerfMonitor } from '@common/PerfMonitor'; import { PERF_TOUCH_RESPONSE_MAX_MS, PERF_COMBO_RECOGNITION_MAX_MS, MAX_FIRST_PACKAGE_BYTES, MAX_AUDIO_BUNDLE_BYTES, MAX_MEMORY_PEAK_BYTES, } from '@common/Constants'; describe('PerfMonitor — threshold catalog (req 18 & 20)', () => { it('includes every KPI threshold called out in requirements 20.1-20.5', () => { const names = CORE_PERF_THRESHOLDS.map((t) => t.metric); expect(names).toContain('input/touchStart'); expect(names).toContain('jump/state_toggle_ms'); expect(names).toContain('input/combo_recognition_ms'); expect(names).toContain('input/parabolic_accuracy'); expect(names).toContain('jump/air_jump_block_rate'); }); }); describe('PerfMonitor — pass/fail evaluation', () => { function seedPassing(logger: Logger): void { for (let i = 0; i < 100; i++) { logger.metric({ name: 'input/touchStart', value: 20 }); logger.metric({ name: 'jump/state_toggle_ms', value: 25 }); logger.metric({ name: 'input/combo_recognition_ms', value: 40 }); } logger.metric({ name: 'input/parabolic_accuracy', value: 0.97 }); logger.metric({ name: 'jump/air_jump_block_rate', value: 0.995 }); } it('passes when all metrics are within budget', () => { const logger = new Logger(); seedPassing(logger); const monitor = new PerfMonitor(logger); const report = monitor.collectReport(); expect(report.allPassing).toBe(true); }); it('fails when no samples exist for a threshold', () => { const monitor = new PerfMonitor(new Logger()); const report = monitor.collectReport(); expect(report.allPassing).toBe(false); expect(report.checks[0].reason).toMatch(/no samples/); }); it('fails when p95 latency exceeds the limit', () => { const logger = new Logger(); seedPassing(logger); // Push a huge batch of slow touches so p95 exceeds budget. for (let i = 0; i < 200; i++) { logger.metric({ name: 'input/touchStart', value: PERF_TOUCH_RESPONSE_MAX_MS + 50 }); } const report = new PerfMonitor(logger).collectReport(); const touchCheck = report.checks.find((c) => c.threshold.metric === 'input/touchStart')!; expect(touchCheck.passing).toBe(false); }); it('fails when parabolic accuracy drops below 95%', () => { const logger = new Logger(); seedPassing(logger); logger.resetMetrics(); logger.metric({ name: 'input/touchStart', value: 20 }); logger.metric({ name: 'jump/state_toggle_ms', value: 20 }); logger.metric({ name: 'input/combo_recognition_ms', value: 20 }); logger.metric({ name: 'input/parabolic_accuracy', value: 0.8 }); logger.metric({ name: 'jump/air_jump_block_rate', value: 0.999 }); const report = new PerfMonitor(logger).collectReport(); expect(report.allPassing).toBe(false); }); it('evaluates build-size budget when provided', () => { const logger = new Logger(); logger.metric({ name: 'input/touchStart', value: 10 }); logger.metric({ name: 'jump/state_toggle_ms', value: 10 }); logger.metric({ name: 'input/combo_recognition_ms', value: 10 }); logger.metric({ name: 'input/parabolic_accuracy', value: 1 }); logger.metric({ name: 'jump/air_jump_block_rate', value: 1 }); const monitor = new PerfMonitor(logger); const okReport = monitor.collectReport({ firstPackageBytes: MAX_FIRST_PACKAGE_BYTES - 1, audioBundleBytes: MAX_AUDIO_BUNDLE_BYTES - 1, memoryPeakBytes: MAX_MEMORY_PEAK_BYTES - 1, }); expect(okReport.sizeBudgetPassing).toBe(true); expect(okReport.allPassing).toBe(true); const badReport = monitor.collectReport({ firstPackageBytes: MAX_FIRST_PACKAGE_BYTES + 1, audioBundleBytes: MAX_AUDIO_BUNDLE_BYTES + 1, memoryPeakBytes: MAX_MEMORY_PEAK_BYTES + 1, }); expect(badReport.sizeBudgetPassing).toBe(false); expect(badReport.allPassing).toBe(false); }); it('honours the <= comparator at exactly the boundary', () => { const logger = new Logger(); logger.metric({ name: 'input/touchStart', value: PERF_TOUCH_RESPONSE_MAX_MS }); logger.metric({ name: 'jump/state_toggle_ms', value: 10 }); logger.metric({ name: 'input/combo_recognition_ms', value: PERF_COMBO_RECOGNITION_MAX_MS }); logger.metric({ name: 'input/parabolic_accuracy', value: 1 }); logger.metric({ name: 'jump/air_jump_block_rate', value: 1 }); const report = new PerfMonitor(logger).collectReport(); const touch = report.checks.find((c) => c.threshold.metric === 'input/touchStart')!; expect(touch.passing).toBe(true); }); });