ec952896ba
Auto Tag Develop / tag (push) Successful in 10s
## Objectif Retirer le bloc « contact principal » (Nom, Prénom, Téléphone, Téléphone 2, Email) des trois écrans Client — **création**, **consultation**, **modification** — ainsi que des types, mappeurs, validations et clés i18n associés. La saisie des contacts passe désormais exclusivement par l'onglet **Contacts** (`ClientContactBlock`, inchangé). Dépend du ticket **1/3 (back)** : l'API ne renvoie/n'accepte plus ces 5 champs sur `client`. Contexte : `docs/specs/M1-clients/refonte-contact/README.md`. ## Changements - **`pages/clients/new.vue`** : bloc principal réduit à Nom entreprise / Catégories / Relation / Triage. Suppression de `main.firstName/lastName/email`, `mainPhones`, `addMainPhone()`, `prefillFirstContact()`. `isMainValid` ne dépend plus que de `companyName` + ≥ 1 catégorie + relation valide. Payload POST et `ClientResponse` nettoyés. - **`pages/clients/[id]/edit.vue`** : mêmes champs retirés, `isMainValid` simplifié. - **`pages/clients/[id]/index.vue`** : affichage lecture seule des 5 champs retiré. - **`utils/clientEdit.ts`** : `MainFormDraft`, `mapMainDraft()`, `buildMainPayload()` débarrassés des 5 champs + `hasSecondaryPhone`. - **`utils/clientConsultation.ts`** : `ClientDetail` débarrassé des champs inline (`ContactRead` conservé). - **`i18n/locales/fr.json`** : clés `form.main.firstName/lastName/email/phonePrimary/phoneSecondary/addPhone` supprimées. `form.contact.*` conservé. - **Tests** : `clientEdit.spec.ts` ajusté (factory, `MAIN_KEYS`, assertions `mapMainDraft`, test téléphone secondaire obsolète retiré). ## Vérifications - `make nuxt-test` : suites `clientEdit` / `clientConsultation` / `clientFormRules` vertes. Les 2 échecs restants (`useClientReferentials.spec.ts`, libellé de site) sont **pré-existants** sur `develop` (confirmé par `git stash`), sans rapport avec ce ticket. - `eslint` sur les fichiers touchés : OK, aucun import/variable mort. - Zéro référence orpheline aux clés `form.main.*` supprimées ; JSON i18n valide. ## Reste à faire - Golden path navigateur (création → consultation → modification sans bloc inline) à valider manuellement. Reviewed-on: #57 Co-authored-by: tristan <tristan@yuno.malio.fr> Co-committed-by: tristan <tristan@yuno.malio.fr>
75 lines
3.1 KiB
TypeScript
75 lines
3.1 KiB
TypeScript
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
|
|
// `useApi` est un auto-import Nuxt : on le stubbe globalement pour intercepter
|
|
// les appels de chargement des referentiels et simuler un endpoint en echec
|
|
// (ex: 403 sur /categories pour un role sans la permission de lecture).
|
|
// Meme pattern que useClientsRepository.spec.ts.
|
|
const mockGet = vi.hoisted(() => vi.fn())
|
|
vi.stubGlobal('useApi', () => ({
|
|
get: mockGet,
|
|
post: vi.fn(),
|
|
put: vi.fn(),
|
|
patch: vi.fn(),
|
|
delete: vi.fn(),
|
|
}))
|
|
|
|
// Import APRES le stub pour que useApi soit bien resolu au top-level du module.
|
|
const { useClientReferentials } = await import('../useClientReferentials')
|
|
|
|
describe('useClientReferentials.loadCommon (resilience ERP-102)', () => {
|
|
beforeEach(() => {
|
|
mockGet.mockReset()
|
|
})
|
|
|
|
it('un referentiel en echec (403) ne vide QUE son select, pas les autres', async () => {
|
|
// /categories rejette (simulateur d'un 403), tous les autres repondent.
|
|
mockGet.mockImplementation((url: string) => {
|
|
if (url === '/categories') {
|
|
return Promise.reject(new Error('403 Forbidden'))
|
|
}
|
|
if (url === '/sites') {
|
|
return Promise.resolve({ member: [{ '@id': '/api/sites/1', name: 'Chatellerault', postalCode: '86100' }] })
|
|
}
|
|
return Promise.resolve({
|
|
member: [{ '@id': '/api/x/1', code: 'X', label: 'Libelle X' }],
|
|
})
|
|
})
|
|
|
|
const refs = useClientReferentials()
|
|
// loadCommon ne doit JAMAIS rejeter : l'echec d'un referentiel est isole.
|
|
await refs.loadCommon()
|
|
|
|
// Resilience : les referentiels OK sont peuples malgre l'echec de /categories.
|
|
// Le libelle d'un site est son numero de departement (2 premiers chiffres du code postal).
|
|
expect(refs.sites.value).toEqual([{ value: '/api/sites/1', label: '86' }])
|
|
expect(refs.tvaModes.value).toEqual([{ value: '/api/x/1', label: 'Libelle X' }])
|
|
expect(refs.banks.value).toEqual([{ value: '/api/x/1', label: 'Libelle X' }])
|
|
|
|
// Seul le select en echec reste vide.
|
|
expect(refs.categories.value).toEqual([])
|
|
})
|
|
|
|
it('charge tous les referentiels quand tout repond', async () => {
|
|
mockGet.mockImplementation((url: string) => {
|
|
if (url === '/categories') {
|
|
return Promise.resolve({
|
|
member: [{ '@id': '/api/categories/1', code: 'SECTEUR', name: 'Secteur' }],
|
|
})
|
|
}
|
|
if (url === '/sites') {
|
|
return Promise.resolve({ member: [{ '@id': '/api/sites/1', name: 'Chatellerault', postalCode: '86100' }] })
|
|
}
|
|
return Promise.resolve({ member: [] })
|
|
})
|
|
|
|
const refs = useClientReferentials()
|
|
await refs.loadCommon()
|
|
|
|
expect(refs.categories.value).toEqual([
|
|
{ value: '/api/categories/1', label: 'Secteur', code: 'SECTEUR' },
|
|
])
|
|
// Le libelle d'un site est son numero de departement (2 premiers chiffres du code postal).
|
|
expect(refs.sites.value).toEqual([{ value: '/api/sites/1', label: '86' }])
|
|
})
|
|
})
|