feat(transport) : page répertoire transporteurs (ERP-164)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 2m54s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m33s

This commit is contained in:
2026-06-16 16:21:15 +02:00
parent 3b474f83f5
commit 1ef4215ebf
5 changed files with 774 additions and 0 deletions
@@ -0,0 +1,96 @@
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { useCarriersRepository, type Carrier } from '../useCarriersRepository'
const mockApiGet = vi.hoisted(() => vi.fn())
vi.stubGlobal('useApi', () => ({ get: mockApiGet }))
/**
* Tests du repertoire transporteurs (ERP-164).
*
* `useCarriersRepository` est une fine enveloppe de `usePaginatedList<Carrier>`
* sur `/carriers`. Les invariants generiques de pagination sont deja couverts par
* `usePaginatedList.test.ts` ; on verifie ici le CONTRAT propre au repertoire :
* - la ressource ciblee est bien `/carriers` ;
* - l'enveloppe Hydra (member / totalItems) est consommee ;
* - le header `Accept: application/ld+json` est envoye (sinon API Platform 4
* renvoie un tableau plat sans pagination) ;
* - EXCLUSION DES ARCHIVES PAR DEFAUT : aucun `includeArchived` n'est envoye
* tant que l'utilisateur ne coche pas le filtre (le back masque alors les
* archives — RG-4.04) ; le filtre est bien transmis une fois applique.
*/
describe('useCarriersRepository', () => {
beforeEach(() => {
mockApiGet.mockReset()
})
/** Une page de transporteurs Hydra, avec qualimatCarrier embarque (RG-4.04). */
const PAGE: Carrier[] = [
{
id: 1,
name: 'TRANSPORTS ACME',
certificationType: 'QUALIMAT',
qualimatCarrier: {
id: '42',
name: 'TRANSPORTS ACME',
validityDate: '2027-01-15',
status: 'VALIDE',
},
updatedAt: '2026-06-15T08:12:01+02:00',
isArchived: false,
},
]
it('cible /carriers, consomme l\'enveloppe Hydra et envoie l\'Accept ld+json', async () => {
mockApiGet.mockResolvedValueOnce({ member: PAGE, totalItems: 1 })
const repo = useCarriersRepository()
await repo.fetch()
expect(mockApiGet).toHaveBeenCalledTimes(1)
const [url, query, opts] = mockApiGet.mock.calls[0]
expect(url).toBe('/carriers')
expect(query).toMatchObject({ page: 1, itemsPerPage: 10 })
expect(opts).toMatchObject({
toast: false,
headers: { Accept: 'application/ld+json' },
})
expect(repo.items.value).toEqual(PAGE)
expect(repo.totalItems.value).toBe(1)
})
it('exclut les archives par defaut : aucun includeArchived au premier fetch', async () => {
mockApiGet.mockResolvedValueOnce({ member: PAGE, totalItems: 1 })
const repo = useCarriersRepository()
await repo.fetch()
const query = mockApiGet.mock.calls[0][1] as Record<string, unknown>
expect(query.includeArchived).toBeUndefined()
})
it('transmet includeArchived une fois le filtre applique (retour page 1)', async () => {
mockApiGet.mockResolvedValueOnce({ member: PAGE, totalItems: 1 })
const repo = useCarriersRepository()
await repo.fetch()
mockApiGet.mockResolvedValueOnce({ member: PAGE, totalItems: 1 })
await repo.setFilters({ includeArchived: true })
expect(repo.currentPage.value).toBe(1)
const query = mockApiGet.mock.calls.at(-1)?.[1] as Record<string, unknown>
expect(query.includeArchived).toBe(true)
})
it('transmet les certifications multiples + la recherche', async () => {
mockApiGet.mockResolvedValueOnce({ member: PAGE, totalItems: 1 })
const repo = useCarriersRepository()
await repo.fetch()
mockApiGet.mockResolvedValueOnce({ member: PAGE, totalItems: 1 })
await repo.setFilters({ search: 'acme', 'certificationType[]': ['QUALIMAT', 'AUTRE'] })
const query = mockApiGet.mock.calls.at(-1)?.[1] as Record<string, unknown>
expect(query.search).toBe('acme')
expect(query['certificationType[]']).toEqual(['QUALIMAT', 'AUTRE'])
})
})