rubis/apps/api/tests/helpers/response.ts
ordinarthur 691b5fd09f test(api): tests fonctionnels Clients + Plans (CRUD + cross-org + validation)
Helper response.ts : `body<T>()` pour caster Tuyau strict response shapes (Tuyau type chaque code de statut comme une union, assertStatus ne narrow pas → on cast explicitement vers ApiOk<T>/ApiError/ApiConflict<T>).

clients.spec.ts (16 cas) :
- POST /clients : refus sans email (422 + field=email), refus SIRET ≠ 14 chiffres, création OK avec UUID + association org, doublon nom case-insensitive (409 + payload existing)
- GET /clients : isolation cross-org (user A ne voit pas les clients de B), withStats=1 enrichit (zéros sans factures), recherche q ILIKE
- Perms cross-org : user B → 404 sur GET/PATCH d'un client de A, l'objet ne bouge pas

plans.spec.ts (7 cas) :
- GET /plans : 4 plans pré-fournis avec steps préchargés, isolation cross-org (UUIDs disjoints entre A et B)
- GET /plans/:slug : steps ordonnés, 404 si inconnu
- PATCH /plans/:slug : remplace les steps en bloc dans une tx, rejette tone invalide, cross-org (B édite SA copie sans toucher celle de A)
2026-05-06 15:51:03 +02:00

19 lines
682 B
TypeScript

/**
* Tuyau type strictement chaque code de statut possible d'une route. Quand
* on `assertStatus(...)` puis on lit `.body()`, TS ne narrow pas — il garde
* l'union.
*
* Ce helper sert juste à caster `.body()` vers la forme attendue dans le
* contexte du test, sans perdre la lisibilité du `.data` / `.errors`.
*/
export function body<T>(response: { body(): unknown }): T {
return response.body() as T
}
export type ApiOk<T> = { data: T }
export type ApiOkPaged<T> = { data: T; meta: { total: number; page: number } }
export type ApiError = {
errors: Array<{ code: string; message: string; field?: string }>
}
export type ApiConflict<T> = ApiError & { existing: T }