import { describe, expect, it } from 'vitest'; import type { ProsthesisCatalogEntry } from '@/types/treatment-catalog'; import { ARCH_TOOTH_LOWER, ARCH_TOOTH_UPPER, applyLeafToJobs, canStackLeaf, catalogByCode, effectiveChartRegion, PARTIAL_DENTURE_CODE, toothRegionColors, } from './prosthesisTree'; const CATALOG: ProsthesisCatalogEntry[] = [ { code: 'pfm_crown', sortOrder: 1, label: 'PFM Crown', category: 'crown', subcategory: '', chartRegion: 'crown', stackGroup: 'restoration', }, { code: 'monolithic_zirconia', sortOrder: 2, label: 'Monolithic Zirconia', category: 'crown', subcategory: '', chartRegion: 'crown', stackGroup: 'restoration', }, { code: 'zirconia_abutment', sortOrder: 3, label: 'Zirconia Abutment', category: 'implant', subcategory: '', chartRegion: 'root', stackGroup: 'implant', }, { code: 'screw_retained', sortOrder: 4, label: 'Screw Retained', category: 'implant', subcategory: '', chartRegion: 'crown', stackGroup: 'implant', }, { code: 'cast_post_core', sortOrder: 5, label: 'Cast Post & Core', category: 'post_core', subcategory: '', chartRegion: 'root', stackGroup: 'post_core', }, { code: PARTIAL_DENTURE_CODE, sortOrder: 6, label: 'Partial Denture', category: 'removable', subcategory: '', chartRegion: 'arch', stackGroup: 'arch', }, { code: 'night_guard_soft', sortOrder: 7, label: 'Night Guard', category: 'appliance', subcategory: 'night_guard', chartRegion: 'arch', stackGroup: 'arch', }, ]; const byCode = catalogByCode(CATALOG); describe('canStackLeaf', () => { it('allows an implant plus a crown restoration on the same tooth', () => { expect(canStackLeaf(['zirconia_abutment'], 'pfm_crown', byCode)).toBe(true); }); it('refuses a post & core alongside an implant', () => { expect(canStackLeaf(['zirconia_abutment'], 'cast_post_core', byCode)).toBe(false); }); it('refuses an implant alongside a post & core', () => { expect(canStackLeaf(['cast_post_core'], 'zirconia_abutment', byCode)).toBe(false); }); it('refuses a second restoration once screw-retained already paints the crown', () => { expect(canStackLeaf(['screw_retained'], 'pfm_crown', byCode)).toBe(false); }); it('allows two restorations to replace each other (no illegal stack)', () => { expect(canStackLeaf(['pfm_crown'], 'monolithic_zirconia', byCode)).toBe(true); }); it('refuses a code the catalog does not have', () => { expect(canStackLeaf([], 'gold_foil', byCode)).toBe(false); }); }); describe('applyLeafToJobs', () => { it('stacks an implant and a crown restoration on one tooth', () => { const jobs = applyLeafToJobs(['zirconia_abutment'], 'pfm_crown', byCode); expect(jobs.sort()).toEqual(['pfm_crown', 'zirconia_abutment'].sort()); }); it('a same-stack-group leaf replaces rather than stacking beside the old one', () => { // PFM previewed on 13, then PFZ heard for the same tooth: the second live test this repo // ran on real recordings — the first stack rule bug that had to be fixed. const jobs = applyLeafToJobs(['pfm_crown'], 'monolithic_zirconia', byCode); expect(jobs).toEqual(['monolithic_zirconia']); }); it('leaves the jobs untouched when the stack rules refuse the leaf', () => { const jobs = applyLeafToJobs(['zirconia_abutment'], 'cast_post_core', byCode); expect(jobs).toEqual(['zirconia_abutment']); }); }); describe('effectiveChartRegion', () => { it('overrides partial_denture to crown even though its catalog chartRegion is arch', () => { expect(effectiveChartRegion({ code: PARTIAL_DENTURE_CODE, chartRegion: 'arch' })).toBe('crown'); }); it('leaves every other code as the catalog says', () => { expect(effectiveChartRegion({ code: 'zirconia_abutment', chartRegion: 'root' })).toBe('root'); }); }); describe('toothRegionColors', () => { it('paints a crown-region code into crownColors only', () => { const { crown, root } = toothRegionColors( [{ tooth: '12', prosthesisTypeCode: 'pfm_crown' }], CATALOG, ); expect(crown['12']).toBeTruthy(); expect(root['12']).toBeUndefined(); }); it('paints a root-region code into rootColors only', () => { const { crown, root } = toothRegionColors( [{ tooth: '12', prosthesisTypeCode: 'zirconia_abutment' }], CATALOG, ); expect(root['12']).toBeTruthy(); expect(crown['12']).toBeUndefined(); }); it('paints both crown and root for an arch-region code on a real tooth', () => { const { crown, root } = toothRegionColors( [{ tooth: '12', prosthesisTypeCode: 'night_guard_soft' }], CATALOG, ); expect(crown['12']).toBeTruthy(); expect(root['12']).toBeTruthy(); }); it('skips jaw sentinel rows — they have no crown or root to paint', () => { const { crown, root } = toothRegionColors( [ { tooth: ARCH_TOOTH_UPPER, prosthesisTypeCode: 'night_guard_soft' }, { tooth: ARCH_TOOTH_LOWER, prosthesisTypeCode: 'night_guard_soft' }, ], CATALOG, ); expect(Object.keys(crown)).toHaveLength(0); expect(Object.keys(root)).toHaveLength(0); }); });