import { describe, it, expect } from 'vitest' import { DISPLAY_FIELD_LINE_RE, LOOKUP_DISPLAY_FIELDS, PREFERRED_DISPLAY_FIELDS, parseDisplayFieldLine, preferredDisplayFieldsFor, } from '../display-field.js' const ENTITE_MD = ` ### ENT-001 — Vehicle (agrégat racine) | Attribut | Type | Contraintes | Calculé | |----------|------|-------------|---------| | Id | Guid | PK | — | | Plate | string(20) | requis | — | - **Affichage** : Plate - **Relations** : Vehicle *→1 Site — FK SiteId, scope same-module, onDelete restrict. ### ENT-002 — Assignment (transaction) | Attribut | Type | Contraintes | Calculé | |----------|------|-------------|---------| | Id | Guid | PK | — | - **Affichage** : Id ### ENT-003 — MileageLog (transaction) | Attribut | Type | Contraintes | Calculé | |----------|------|-------------|---------| | Id | Guid | PK | — | | Km | int | requis | — | ` describe('parseDisplayFieldLine — the **Affichage** authoring channel', () => { it('returns the PascalCase token of the entity block', () => { expect(parseDisplayFieldLine(ENTITE_MD, 'Vehicle')).toBe('Plate') }) it("a sibling entity's line never leaks in", () => { // MileageLog has NO Affichage line — Vehicle's Plate and Assignment's Id // must not bleed into it. expect(parseDisplayFieldLine(ENTITE_MD, 'MileageLog')).toBeNull() }) it("returns 'Id' verbatim — the conscious GUID opt-out is the caller's call", () => { expect(parseDisplayFieldLine(ENTITE_MD, 'Assignment')).toBe('Id') }) it('returns null for an unknown entity or an absent line', () => { expect(parseDisplayFieldLine(ENTITE_MD, 'Ghost')).toBeNull() expect(parseDisplayFieldLine('', 'Vehicle')).toBeNull() }) it('the heading match is word-bounded — "Site" never matches "SiteGroup"', () => { const md = `### ENT-009 — SiteGroup (lookup)\n\n- **Affichage** : Label\n` expect(parseDisplayFieldLine(md, 'Site')).toBeNull() expect(parseDisplayFieldLine(md, 'SiteGroup')).toBe('Label') }) it('the line regex anchors on the bullet shape', () => { expect(DISPLAY_FIELD_LINE_RE.test('- **Affichage** : Name')).toBe(true) expect(DISPLAY_FIELD_LINE_RE.test('**Affichage** without the bullet')).toBe(false) // Sanity: the cascade fallback list is available to consumers. expect(PREFERRED_DISPLAY_FIELDS[0]).toBe('Name') }) }) describe('preferredDisplayFieldsFor — a reference value is named by its label', () => { it('drops Code for a lookup, and ONLY for a lookup', () => { expect(preferredDisplayFieldsFor('lookup')).not.toContain('Code') expect(preferredDisplayFieldsFor('agrégat racine')).toContain('Code') expect(preferredDisplayFieldsFor()).toEqual(PREFERRED_DISPLAY_FIELDS) }) it('folds the classification the way the audit does (accents, case, substring)', () => { expect(preferredDisplayFieldsFor('Référentiel LOOKUP')).not.toContain('Code') }) it('keeps the rest of the cascade in order — only Code is removed', () => { expect(LOOKUP_DISPLAY_FIELDS).toEqual(PREFERRED_DISPLAY_FIELDS.filter((f) => f !== 'Code')) }) it('THE regression: Code sits at 3 and Libelle at 5, so a référentiel Code+Libelle showed the code', () => { // Measured: every combobox and column rendered `A_FAIRE` instead of « À faire ». const cascade = preferredDisplayFieldsFor('lookup') const pick = (names: string[]): string | undefined => cascade.find((c) => names.includes(c)) expect(pick(['Code', 'Libelle'])).toBe('Libelle') expect(preferredDisplayFieldsFor('agrégat racine').find((c) => ['Code', 'Libelle'].includes(c))).toBe('Code') }) })