1e86d9745c
removeCollectionRow expose un callback onSuccess declenche uniquement apres une suppression serveur confirmee (pas sur le retrait d'un brouillon local). Cable sur Client / Fournisseur / Prestataire / Transporteur via notifyRemovalSuccess, avec un message i18n generique success.deleted.
128 lines
5.2 KiB
TypeScript
128 lines
5.2 KiB
TypeScript
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<string, string>[] = [{}, {}]
|
|
const deleteRow = vi.fn().mockResolvedValue(undefined)
|
|
const onError = vi.fn()
|
|
const onSuccess = vi.fn()
|
|
|
|
const removed = await removeCollectionRow({
|
|
rows, errors, index: 0,
|
|
endpoint: '/client_contacts',
|
|
deleteRow, makeEmpty, onError, onSuccess,
|
|
})
|
|
|
|
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()
|
|
// Toast de succes uniquement sur suppression serveur confirmee.
|
|
expect(onSuccess).toHaveBeenCalledOnce()
|
|
})
|
|
|
|
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<string, string>[] = [{}, {}]
|
|
const deleteRow = vi.fn().mockResolvedValue(undefined)
|
|
const onError = vi.fn()
|
|
const onSuccess = vi.fn()
|
|
|
|
const removed = await removeCollectionRow({
|
|
rows, errors, index: 1,
|
|
endpoint: '/client_contacts',
|
|
deleteRow, makeEmpty, onError, onSuccess,
|
|
})
|
|
|
|
expect(deleteRow).not.toHaveBeenCalled()
|
|
expect(removed).toBe(true)
|
|
expect(rows).toEqual([{ id: 10, label: 'A' }])
|
|
// Retrait d'un simple brouillon local : pas de toast « supprime ».
|
|
expect(onSuccess).not.toHaveBeenCalled()
|
|
})
|
|
|
|
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<string, string>[] = [{}, {}]
|
|
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<string, string>[] = [{}]
|
|
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)
|
|
})
|
|
})
|