import { describe, it, expect, vi } from 'vitest' import { removeCollectionRow, isRowRemovable, type DeletableRow } from '../collectionRow' /** * Tests de `removeCollectionRow` — suppression d'une ligne de collection * (contact / adresse / RIB) avec DELETE immediat de la sous-ressource existante * (ERP-172). Coeur de logique mutualise par les 3 modules (Client / Fournisseur / * Prestataire) : un seul comportement teste ici couvre les 9 cas (3 modules x 3 * blocs). */ interface Row extends DeletableRow { label?: string } function makeEmpty(): Row { return { id: null, label: '' } } describe('removeCollectionRow', () => { it('emet un DELETE sur la sous-ressource quand le bloc est existant (id non null)', async () => { const rows: Row[] = [{ id: 10, label: 'A' }, { id: 11, label: 'B' }] const errors: Record[] = [{}, {}] const deleteRow = vi.fn().mockResolvedValue(undefined) const onError = vi.fn() const removed = await removeCollectionRow({ rows, errors, index: 0, endpoint: '/client_contacts', deleteRow, makeEmpty, onError, }) expect(deleteRow).toHaveBeenCalledOnce() expect(deleteRow).toHaveBeenCalledWith('/client_contacts/10') expect(removed).toBe(true) expect(rows).toEqual([{ id: 11, label: 'B' }]) expect(errors).toHaveLength(1) expect(onError).not.toHaveBeenCalled() }) it('ne fait AUCUN appel reseau pour un bloc jamais persiste (id null) — retrait local', async () => { const rows: Row[] = [{ id: 10, label: 'A' }, { id: null, label: 'brouillon' }] const errors: Record[] = [{}, {}] const deleteRow = vi.fn().mockResolvedValue(undefined) const onError = vi.fn() const removed = await removeCollectionRow({ rows, errors, index: 1, endpoint: '/client_contacts', deleteRow, makeEmpty, onError, }) expect(deleteRow).not.toHaveBeenCalled() expect(removed).toBe(true) expect(rows).toEqual([{ id: 10, label: 'A' }]) }) it('conserve le bloc et remonte l\'erreur si le DELETE serveur echoue (ex. 409 dernier RIB LCR)', async () => { const rows: Row[] = [{ id: 10, label: 'A' }, { id: 11, label: 'B' }] const errors: Record[] = [{}, {}] const error = { response: { status: 409 } } const deleteRow = vi.fn().mockRejectedValue(error) const onError = vi.fn() const removed = await removeCollectionRow({ rows, errors, index: 0, endpoint: '/client_ribs', deleteRow, makeEmpty, onError, }) expect(removed).toBe(false) expect(onError).toHaveBeenCalledWith(error) // Bloc NON retire : la suppression n'a pas ete confirmee par le serveur. expect(rows).toEqual([{ id: 10, label: 'A' }, { id: 11, label: 'B' }]) expect(errors).toHaveLength(2) }) it('garde au moins un bloc visible apres retrait du dernier (amorce vide)', async () => { const rows: Row[] = [{ id: 10, label: 'A' }] const errors: Record[] = [{}] const deleteRow = vi.fn().mockResolvedValue(undefined) await removeCollectionRow({ rows, errors, index: 0, endpoint: '/client_contacts', deleteRow, makeEmpty, onError: vi.fn(), }) expect(rows).toEqual([{ id: null, label: '' }]) }) }) /** * Tests de `isRowRemovable` — la poubelle d'un bloc n'apparait que s'il reste un * AUTRE bloc deja enregistre (id en base). Empeche de supprimer un bloc tant que * rien n'est sauvegarde, et de supprimer son dernier bloc enregistre (ERP-172). */ describe('isRowRemovable', () => { it('faux quand aucun autre bloc n\'est enregistre (que des brouillons)', () => { const rows: Row[] = [{ id: null, label: 'brouillon 1' }, { id: null, label: 'brouillon 2' }] expect(isRowRemovable(rows, 0)).toBe(false) expect(isRowRemovable(rows, 1)).toBe(false) }) it('faux pour le seul bloc enregistre (un brouillon a cote ne compte pas)', () => { const rows: Row[] = [{ id: 10, label: 'enregistre' }, { id: null, label: 'brouillon' }] // Le bloc enregistre ne peut pas etre supprime : aucun AUTRE bloc enregistre. expect(isRowRemovable(rows, 0)).toBe(false) // Le brouillon peut etre jete : il reste le bloc enregistre id=10. expect(isRowRemovable(rows, 1)).toBe(true) }) it('vrai pour chaque bloc des qu\'au moins deux sont enregistres', () => { const rows: Row[] = [{ id: 10, label: 'A' }, { id: 11, label: 'B' }] expect(isRowRemovable(rows, 0)).toBe(true) expect(isRowRemovable(rows, 1)).toBe(true) }) it('faux pour un unique bloc', () => { expect(isRowRemovable([{ id: 10, label: 'A' }], 0)).toBe(false) }) })