// Tests for shared/clinical/ros-pe-dx.ts. The clinical tables here // are load-bearing — a silent reorder or deletion changes AI output. // These tests catch that class of regression. import { describe, expect, it } from 'vitest'; import { ROS_SYSTEMS, PE_SYSTEMS, COMMON_DX, formatRosForAI, formatDxForAI, } from './ros-pe-dx'; describe('reference tables', () => { it('ROS has the 15 systems vanilla shipped, in order', () => { expect(ROS_SYSTEMS.length).toBe(15); expect(ROS_SYSTEMS[0].key).toBe('constitutional'); expect(ROS_SYSTEMS[ROS_SYSTEMS.length - 1].key).toBe('developmental'); }); it('PE has the 17 systems vanilla shipped, in order', () => { expect(PE_SYSTEMS.length).toBe(17); expect(PE_SYSTEMS[0].key).toBe('general'); expect(PE_SYSTEMS[PE_SYSTEMS.length - 1].key).toBe('pePsych'); }); it('COMMON_DX has the 28 pediatric diagnoses vanilla shipped', () => { expect(COMMON_DX.length).toBe(28); // Z00.129 is the default pediatric well-visit code — must be first. expect(COMMON_DX[0]).toEqual({ code: 'Z00.129', name: 'Routine child health exam, no abnormal findings' }); }); it('every ROS/PE entry has a non-empty label + detail string', () => { for (const s of [...ROS_SYSTEMS, ...PE_SYSTEMS]) { expect(s.key).toBeTruthy(); expect(s.label).toBeTruthy(); expect(s.detail).toBeTruthy(); } }); }); describe('formatRosForAI', () => { const TWO = [ROS_SYSTEMS[0], ROS_SYSTEMS[1]]; it('returns empty string when nothing is reviewed', () => { expect(formatRosForAI(TWO, {}, 'ROS')).toBe(''); }); it('emits NORMAL with the domain hint for WNL systems', () => { const out = formatRosForAI(TWO, { constitutional: { status: 'wnl' } }, 'ROS'); expect(out).toContain('Constitutional: NORMAL [domain: fever, fatigue, weight loss/gain, appetite]'); }); it('emits ABNORMAL with the user note inline', () => { const out = formatRosForAI(TWO, { eyes: { status: 'abnormal', note: 'conjunctival injection' } }, 'ROS'); expect(out).toContain('Eyes: ABNORMAL — conjunctival injection'); }); it('calls out systems marked Not Reviewed explicitly', () => { const out = formatRosForAI(TWO, { eyes: { status: 'notrev' } }, 'ROS'); expect(out).toContain('Eyes: Not reviewed'); }); it('omits systems with no status set', () => { const out = formatRosForAI(TWO, { constitutional: { status: 'wnl' } }, 'ROS'); expect(out).not.toContain('Eyes'); }); }); describe('formatDxForAI', () => { it('returns empty when no dx AND no free text', () => { expect(formatDxForAI([], '')).toBe(''); }); it('prefixes codes when present', () => { const out = formatDxForAI([{ code: 'J06.9', name: 'URI' }], ''); expect(out).toContain('- J06.9 URI'); }); it('skips code prefix for free-text-only diagnoses', () => { const out = formatDxForAI([{ code: '', name: 'Parental anxiety' }], ''); expect(out).toContain('- Parental anxiety'); expect(out).not.toContain(' Parental'); }); it('appends trimmed free-text as its own bullet', () => { const out = formatDxForAI([{ code: 'R50.9', name: 'Fever' }], ' Rule out UTI '); expect(out).toMatch(/Fever[\s\S]*Rule out UTI/); expect(out).not.toContain(' Rule out UTI'); }); });