// Les filtres de colonnes décident de ce que l'utilisateur voit : un filtre trop // zélé masque un lot sans rien dire, ce qui se remarque d'autant moins que le // tableau reste plausible. Ils sont donc testés cas par cas. import { describe, expect, it } from 'vitest' import { COLONNES, ETAT_INUTILISES, ETAT_UTILISES, TYPE_EN_DESACCORD, VIDE, comparer, groupesFiltre, passeFiltre, valeursDistinctes, } from '../src/components/referentiel/colonnes.js' const colonne = (cle) => COLONNES.find((c) => c.cle === cle) function lot(numero, caracteristiques = null, extra = {}) { return { id: Number(numero), numero, immeuble_id: 1, immeuble_code: '33689020', immeuble_denomination: 'Servient', type_effectif: caracteristiques?.type ?? null, type_ecart: false, nb_revenus: 0, nb_depenses: 0, caracteristiques, ...extra, } } // Un immeuble réduit : un local décrit, un appartement décrit, un lot vierge. const LOTS = [ lot('01', { bat: 'Rue', etage: 'RC', type: 'Loc. Commercial', surface: 148, surface_impots: 146, delta_surface: -2, chauffage: 'Électrique', dpe_classe: 'C', dpe_echeance: '2031-02-08', numero_fiscal: '690123456789', }, { nb_revenus: 5 }), lot('02', { bat: 'Cour', etage: '1', type: 'Appartement T3', surface: 62, surface_impots: 62, delta_surface: 0, chauffage: 'Gaz', dpe_classe: 'F', dpe_echeance: '2020-01-01', }, { nb_revenus: 3, type_ecart: true }), lot('0003'), ] const filtrer = (cle, saisie) => LOTS.filter((l) => passeFiltre(l, colonne(cle), saisie)).map((l) => l.numero) describe('filtres de colonne', () => { it('ne masque rien tant qu’aucune valeur n’est saisie', () => { expect(filtrer('chauffage', '')).toEqual(['01', '02', '0003']) }) it('filtre sur une valeur exacte de liste', () => { expect(filtrer('dpe_classe', 'F')).toEqual(['02']) }) it('isole les lots dont la colonne est vide', () => { expect(filtrer('chauffage', VIDE)).toEqual(['0003']) }) it('isole les types en désaccord avec le PDF', () => { expect(filtrer('type', TYPE_EN_DESACCORD)).toEqual(['02']) }) it('compare les nombres au lieu de comparer leur écriture', () => { // '100' contient '10', mais 62 n'est pas > 100 : une recherche textuelle // renverrait ici les deux lots décrits. expect(filtrer('surface', '> 100')).toEqual(['01']) expect(filtrer('surface', '<=62')).toEqual(['02']) }) it('sait isoler un écart de surface non nul', () => { expect(filtrer('delta_surface', '!=0')).toEqual(['01']) }) it('ne masque rien sur une saisie numérique incomplète', () => { expect(filtrer('surface', '>')).toEqual(['01', '02', '0003']) }) it('ignore casse et accents dans les filtres texte', () => { expect(filtrer('numero_fiscal', '6901')).toEqual(['01']) }) it('filtre par immeuble sur son nom d’usage', () => { const autre = { ...lot('01'), immeuble_id: 2, immeuble_code: 'M', immeuble_denomination: null } const parc = [...LOTS, autre] const servient = parc.filter((l) => passeFiltre(l, colonne('immeuble'), 'Servient')) // Sans nom d'usage, l'immeuble reste filtrable par son code. const marietton = parc.filter((l) => passeFiltre(l, colonne('immeuble'), 'M')) expect(servient).toHaveLength(3) expect(marietton).toEqual([autre]) }) it('sépare les lots rattachés à un compte rendu des autres', () => { expect(filtrer('numero', ETAT_INUTILISES)).toEqual(['0003']) expect(filtrer('numero', ETAT_UTILISES)).toEqual(['01', '02']) }) it('filtre aussi sur un numéro de porte précis', () => { expect(filtrer('numero', '02')).toEqual(['02']) }) it('classe les DPE selon leur péremption', () => { expect(filtrer('dpe_echeance', 'perime')).toEqual(['02']) expect(filtrer('dpe_echeance', 'valide')).toEqual(['01']) expect(filtrer('dpe_echeance', 'absent')).toEqual(['0003']) }) }) describe('listes de choix', () => { it('ne propose que les valeurs présentes, le vide en dernier', () => { // Ordre alphabétique français : « É » se classe avec « E », donc avant « G ». expect(valeursDistinctes(LOTS, colonne('chauffage'))).toEqual(['Électrique', 'Gaz', VIDE]) }) it('propose le désaccord à part des types, quand il y en a un', () => { const groupes = groupesFiltre(LOTS, colonne('type')) expect(groupes[0].options).toEqual([TYPE_EN_DESACCORD]) expect(groupes[1].options).toContain('Appartement T3') }) it('ne propose le contrôle des types que s’il a lieu d’être', () => { const sansDesaccord = LOTS.map((l) => ({ ...l, type_ecart: false })) expect(groupesFiltre(sansDesaccord, colonne('type'))).toHaveLength(1) }) it('propose les numéros de porte en plus du rattachement', () => { const [rattachement, portes] = groupesFiltre(LOTS, colonne('numero')) expect(rattachement.options).toEqual([ETAT_UTILISES, ETAT_INUTILISES]) expect(portes.options).toEqual(['01', '02', '0003']) }) }) describe('tri', () => { it('trie les nombres comme des nombres', () => { const tries = [...LOTS].sort(comparer(colonne('surface'), 'desc')).map((l) => l.numero) expect(tries).toEqual(['01', '02', '0003']) }) it('renvoie les cases vides en fin, dans les deux sens', () => { const asc = [...LOTS].sort(comparer(colonne('surface'), 'asc')).map((l) => l.numero) expect(asc).toEqual(['02', '01', '0003']) }) })