import { describe, it, expect } from 'vitest' import { mapViolationsToRecord, resolveViolationMessage } from '../api' /** * Tests de `mapViolationsToRecord` — fondation du mapping erreur→champ des * formulaires (ERP-101). Transforme un payload 422 API Platform en * `Record` directement consommable par la prop `:error` * des composants `Malio*`. */ describe('mapViolationsToRecord', () => { it('mappe chaque violation par son propertyPath (format `violations`)', () => { const data = { violations: [ { propertyPath: 'companyName', message: 'Obligatoire.' }, { propertyPath: 'siren', message: 'SIREN deja utilise.' }, ], } expect(mapViolationsToRecord(data)).toEqual({ companyName: 'Obligatoire.', siren: 'SIREN deja utilise.', }) }) it('supporte le format negocie `hydra:violations`', () => { const data = { 'hydra:violations': [ { propertyPath: 'email', message: 'Adresse invalide.' }, ], } expect(mapViolationsToRecord(data)).toEqual({ email: 'Adresse invalide.' }) }) it('renvoie un objet vide quand il n\'y a pas de violation exploitable', () => { expect(mapViolationsToRecord({})).toEqual({}) expect(mapViolationsToRecord(null)).toEqual({}) expect(mapViolationsToRecord({ violations: [] })).toEqual({}) }) it('ignore les violations sans propertyPath', () => { const data = { violations: [ { propertyPath: '', message: 'Erreur globale.' }, { propertyPath: 'iban', message: 'IBAN invalide.' }, ], } expect(mapViolationsToRecord(data)).toEqual({ iban: 'IBAN invalide.' }) }) it('en cas de doublon de propertyPath, la derniere violation gagne', () => { const data = { violations: [ { propertyPath: 'name', message: 'Premier message.' }, { propertyPath: 'name', message: 'Second message.' }, ], } expect(mapViolationsToRecord(data)).toEqual({ name: 'Second message.' }) }) }) /** * Tests de `resolveViolationMessage` — surcharge i18n d'un message back par code * de violation. Le back peut renvoyer un message technique (erreur de type sur * une date non parsable) : on le remplace via le `code` Symfony (stable) par une * cle i18n, sans toucher au back. Le `t` ici renvoie la cle telle quelle. */ describe('resolveViolationMessage', () => { const t = (key: string) => key // Code Symfony Constraints\Type::INVALID_TYPE_ERROR (fige). const TYPE_ERROR = 'ba785a8c-82cb-4283-967c-3cf342181b40' it('surcharge le message technique d\'une erreur de type par la cle i18n', () => { const v = { propertyPath: 'foundedAt', message: 'Cette valeur doit être de type DateTimeImmutable|null.', code: TYPE_ERROR } expect(resolveViolationMessage(v, t)).toBe('errors.validation.invalidDate') }) it('renvoie le message back tel quel quand le code n\'est pas surcharge', () => { const v = { propertyPath: 'companyName', message: 'Le nom est obligatoire.', code: 'c1051bb4-d103-4f74-8988-acbcafc7fdc3' } expect(resolveViolationMessage(v, t)).toBe('Le nom est obligatoire.') }) it('renvoie le message back tel quel quand il n\'y a pas de code', () => { const v = { propertyPath: 'siren', message: 'SIREN deja utilise.', code: '' } expect(resolveViolationMessage(v, t)).toBe('SIREN deja utilise.') }) })