feat(front) : onglet contact prestataire
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 2m36s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Has been cancelled

This commit is contained in:
2026-06-15 09:22:38 +02:00
parent 7ad44fd366
commit ad4bbab372
9 changed files with 709 additions and 6 deletions
@@ -41,10 +41,17 @@ vi.stubGlobal('usePermissions', () => ({
}))
const { useProviderForm, buildProviderCreateTabKeys } = await import('../useProviderForm')
const { emptyProviderContact } = await import('~/modules/technique/types/providerForm')
type ProviderForm = ReturnType<typeof useProviderForm>
const SITE_86 = '/api/sites/1'
const CAT_MAINT = '/api/categories/7'
/** Accede a un bloc contact (cast : sous noUncheckedIndexedAccess l'index est optionnel). */
function contactAt(form: ProviderForm, index = 0) {
return form.contacts.value[index] ?? emptyProviderContact()
}
describe('useProviderForm', () => {
beforeEach(() => {
mockPost.mockReset()
@@ -190,3 +197,110 @@ describe('useProviderForm', () => {
expect(mockPatch).toHaveBeenCalledWith('/providers/9', { siren: '123456789' }, { toast: false })
})
})
describe('useProviderForm — onglet Contact (ERP-142)', () => {
beforeEach(() => {
mockPost.mockReset()
mockPatch.mockReset()
permState.accountingView = false
})
/** Place le formulaire en etat « prestataire cree » (onglet Contact accessible). */
function createdForm() {
const form = useProviderForm()
form.providerId.value = 7
return form
}
it('RG-3.04 : « + Nouveau contact » desactive tant que le dernier bloc est vide', () => {
const form = createdForm()
expect(form.canAddContact.value).toBe(false)
// addContact est un no-op tant que le bloc est vide.
form.addContact()
expect(form.contacts.value).toHaveLength(1)
contactAt(form).lastName = 'Doe'
expect(form.canAddContact.value).toBe(true)
form.addContact()
expect(form.contacts.value).toHaveLength(2)
})
it('removeContact retire le bloc et son erreur de ligne', () => {
const form = createdForm()
contactAt(form).lastName = 'Doe'
form.addContact()
form.contactErrors.value = [{}, { lastName: 'x' }]
form.removeContact(1)
expect(form.contacts.value).toHaveLength(1)
expect(form.contactErrors.value).toHaveLength(1)
})
it('submitContacts : POST des nouveaux, capture id + IRI, finalise l\'onglet', async () => {
mockPost.mockResolvedValueOnce({ '@id': '/api/provider_contacts/55', id: 55 })
const form = createdForm()
contactAt(form).lastName = 'Doe'
const ok = await form.submitContacts(vi.fn())
expect(ok).toBe(true)
const [url, body, opts] = mockPost.mock.calls[0] ?? []
expect(url).toBe('/providers/7/contacts')
expect(body).toMatchObject({ lastName: 'Doe' })
expect(opts).toMatchObject({ toast: false, headers: { Accept: 'application/ld+json' } })
expect(contactAt(form).id).toBe(55)
expect(contactAt(form).iri).toBe('/api/provider_contacts/55')
expect(form.isValidated('contact')).toBe(true)
})
it('submitContacts : PATCH des contacts existants sur /provider_contacts/{id}', async () => {
mockPatch.mockResolvedValueOnce({})
const form = createdForm()
contactAt(form).id = 55
contactAt(form).lastName = 'Doe'
await form.submitContacts(vi.fn())
expect(mockPost).not.toHaveBeenCalled()
expect(mockPatch).toHaveBeenCalledWith('/provider_contacts/55', expect.objectContaining({ lastName: 'Doe' }), { toast: false })
})
it('RG-3.12 : onglet vide -> soumet l\'amorce pour declencher la 422 firstName inline', async () => {
mockPost.mockRejectedValueOnce({
response: {
status: 422,
_data: { violations: [{ propertyPath: 'firstName', message: 'Au moins un champ du contact est obligatoire.' }] },
},
})
const form = createdForm()
const ok = await form.submitContacts(vi.fn())
expect(ok).toBe(false)
expect(mockPost).toHaveBeenCalledTimes(1)
expect(form.contactErrors.value[0]?.firstName).toBe('Au moins un champ du contact est obligatoire.')
expect(form.isValidated('contact')).toBe(false)
})
it('mappe les erreurs 422 PAR LIGNE (le bloc 2 echoue, le bloc 1 passe)', async () => {
mockPost
.mockResolvedValueOnce({ '@id': '/api/provider_contacts/1', id: 1 })
.mockRejectedValueOnce({
response: {
status: 422,
_data: { violations: [{ propertyPath: 'email', message: 'L\'adresse email n\'est pas valide.' }] },
},
})
const form = createdForm()
contactAt(form).lastName = 'Doe'
form.addContact()
contactAt(form, 1).email = 'invalide'
const ok = await form.submitContacts(vi.fn())
expect(ok).toBe(false)
expect(form.contactErrors.value[0]).toBeUndefined()
expect(form.contactErrors.value[1]?.email).toBe('L\'adresse email n\'est pas valide.')
})
})