test(commercial) : fix CI anti-N+1 (profiling test) + durcissement 422/gating M2 fournisseurs (ERP-92)
- config/packages/test/doctrine.yaml : force dbal profiling en test pour que doctrine.debug_data_holder existe sous APP_DEBUG=0 (CI). Le test anti-N+1 SupplierListTest passait en local (debug=1) mais cassait en CI. - RBACMatrix/SupplierApi : les 422 RG-2.03 et RG-2.14 assertent desormais le propertyPath / message (plus seulement le code) — un 422 orthogonal ne peut plus faire passer le test. - RBACMatrix : gating bureau/commerciale verifie l'ensemble des champs comptables (accountNumber/nTva/tvaMode/paymentType), plus seulement siren/ribs. - violationsByPath() mutualise dans AbstractSupplierApiTestCase (dedup).
This commit is contained in:
@@ -316,4 +316,24 @@ abstract class AbstractSupplierApiTestCase extends AbstractCommercialApiTestCase
|
|||||||
|
|
||||||
return $entity;
|
return $entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indexe les violations d'un corps de reponse 422 par propertyPath. Permet
|
||||||
|
* d'asserter qu'un 422 porte bien sur le champ attendu (et n'est pas un 422
|
||||||
|
* orthogonal) : un test qui se contente du code 422 passerait meme si la RG
|
||||||
|
* visee etait cassee pour une autre raison.
|
||||||
|
*
|
||||||
|
* @param array<string, mixed> $body corps decode de la reponse (toArray(false))
|
||||||
|
*
|
||||||
|
* @return array<string, string> propertyPath => message
|
||||||
|
*/
|
||||||
|
protected function violationsByPath(array $body): array
|
||||||
|
{
|
||||||
|
$byPath = [];
|
||||||
|
foreach ($body['violations'] ?? [] as $v) {
|
||||||
|
$byPath[$v['propertyPath']] = $v['message'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $byPath;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,18 +77,5 @@ final class SupplierAccountingApiTest extends AbstractSupplierApiTestCase
|
|||||||
self::assertResponseStatusCodeSame(200);
|
self::assertResponseStatusCodeSame(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// violationsByPath() : helper mutualise dans AbstractSupplierApiTestCase.
|
||||||
* @param array<string, mixed> $body
|
|
||||||
*
|
|
||||||
* @return array<string, string>
|
|
||||||
*/
|
|
||||||
private function violationsByPath(array $body): array
|
|
||||||
{
|
|
||||||
$byPath = [];
|
|
||||||
foreach ($body['violations'] ?? [] as $v) {
|
|
||||||
$byPath[$v['propertyPath']] = $v['message'];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $byPath;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -147,12 +147,15 @@ final class SupplierApiTest extends AbstractSupplierApiTestCase
|
|||||||
$seed = $this->seedSupplier('Archive Plus Field');
|
$seed = $this->seedSupplier('Archive Plus Field');
|
||||||
|
|
||||||
// RG-2.14 : une requete d'archivage ne modifie aucun autre champ.
|
// RG-2.14 : une requete d'archivage ne modifie aucun autre champ.
|
||||||
$client->request('PATCH', '/api/suppliers/'.$seed->getId(), [
|
$response = $client->request('PATCH', '/api/suppliers/'.$seed->getId(), [
|
||||||
'headers' => ['Content-Type' => self::MERGE],
|
'headers' => ['Content-Type' => self::MERGE],
|
||||||
'json' => ['isArchived' => true, 'companyName' => 'Renamed While Archiving'],
|
'json' => ['isArchived' => true, 'companyName' => 'Renamed While Archiving'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
self::assertResponseStatusCodeSame(422);
|
self::assertResponseStatusCodeSame(422);
|
||||||
|
// Le 422 doit etre celui de RG-2.14 (archivage exclusif) et non un 422
|
||||||
|
// orthogonal : on verifie le message porte par l'exception.
|
||||||
|
self::assertStringContainsString('archivage', $response->getContent(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRestoreSetsArchivedAtNull(): void
|
public function testRestoreSetsArchivedAtNull(): void
|
||||||
|
|||||||
@@ -131,7 +131,14 @@ final class SupplierRBACMatrixTest extends AbstractSupplierApiTestCase
|
|||||||
|
|
||||||
$data = $client->request('GET', '/api/suppliers/'.$supplier->getId(), ['headers' => ['Accept' => self::LD]])->toArray();
|
$data = $client->request('GET', '/api/suppliers/'.$supplier->getId(), ['headers' => ['Accept' => self::LD]])->toArray();
|
||||||
|
|
||||||
|
// Gating par omission sur l'ensemble des champs comptables (pas seulement
|
||||||
|
// siren/ribs) : une regression reintroduisant accountNumber/nTva/tvaMode/
|
||||||
|
// paymentType dans le groupe bureau serait sinon invisible.
|
||||||
self::assertArrayNotHasKey('siren', $data);
|
self::assertArrayNotHasKey('siren', $data);
|
||||||
|
self::assertArrayNotHasKey('accountNumber', $data);
|
||||||
|
self::assertArrayNotHasKey('nTva', $data);
|
||||||
|
self::assertArrayNotHasKey('tvaMode', $data);
|
||||||
|
self::assertArrayNotHasKey('paymentType', $data);
|
||||||
self::assertArrayNotHasKey('ribs', $data);
|
self::assertArrayNotHasKey('ribs', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,11 +212,14 @@ final class SupplierRBACMatrixTest extends AbstractSupplierApiTestCase
|
|||||||
|
|
||||||
// manage : la creation passe la security d'operation (pas un 403 comme
|
// manage : la creation passe la security d'operation (pas un 403 comme
|
||||||
// Compta) mais bute sur RG-2.03 (onglet Information incomplet) -> 422.
|
// Compta) mais bute sur RG-2.03 (onglet Information incomplet) -> 422.
|
||||||
$client->request('POST', '/api/suppliers', [
|
$response = $client->request('POST', '/api/suppliers', [
|
||||||
'headers' => ['Content-Type' => self::LD],
|
'headers' => ['Content-Type' => self::LD],
|
||||||
'json' => $this->validMainPayload('Commerciale Post'),
|
'json' => $this->validMainPayload('Commerciale Post'),
|
||||||
]);
|
]);
|
||||||
self::assertResponseStatusCodeSame(422);
|
self::assertResponseStatusCodeSame(422);
|
||||||
|
// Le 422 doit bien etre celui de RG-2.03 (onglet Information) et non un
|
||||||
|
// 422 orthogonal : on exige une violation sur un champ de completude.
|
||||||
|
self::assertArrayHasKey('description', $this->violationsByPath($response->toArray(false)));
|
||||||
|
|
||||||
// PAS accounting : edition onglet Comptabilite refusee
|
// PAS accounting : edition onglet Comptabilite refusee
|
||||||
$client->request('PATCH', '/api/suppliers/'.$seed->getId(), [
|
$client->request('PATCH', '/api/suppliers/'.$seed->getId(), [
|
||||||
@@ -234,8 +244,11 @@ final class SupplierRBACMatrixTest extends AbstractSupplierApiTestCase
|
|||||||
$data = $client->request('GET', '/api/suppliers/'.$supplier->getId(), ['headers' => ['Accept' => self::LD]])->toArray();
|
$data = $client->request('GET', '/api/suppliers/'.$supplier->getId(), ['headers' => ['Accept' => self::LD]])->toArray();
|
||||||
|
|
||||||
self::assertArrayNotHasKey('siren', $data);
|
self::assertArrayNotHasKey('siren', $data);
|
||||||
self::assertArrayNotHasKey('ribs', $data);
|
self::assertArrayNotHasKey('accountNumber', $data);
|
||||||
|
self::assertArrayNotHasKey('nTva', $data);
|
||||||
|
self::assertArrayNotHasKey('tvaMode', $data);
|
||||||
self::assertArrayNotHasKey('paymentType', $data);
|
self::assertArrayNotHasKey('paymentType', $data);
|
||||||
|
self::assertArrayNotHasKey('ribs', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRG203CommercialePostIncompleteIs422AdminIs201(): void
|
public function testRG203CommercialePostIncompleteIs422AdminIs201(): void
|
||||||
@@ -244,11 +257,12 @@ final class SupplierRBACMatrixTest extends AbstractSupplierApiTestCase
|
|||||||
|
|
||||||
// RG-2.03 : Commerciale POST sans onglet Information complet -> 422.
|
// RG-2.03 : Commerciale POST sans onglet Information complet -> 422.
|
||||||
$commerciale = $this->authAs('commerciale');
|
$commerciale = $this->authAs('commerciale');
|
||||||
$commerciale->request('POST', '/api/suppliers', [
|
$response = $commerciale->request('POST', '/api/suppliers', [
|
||||||
'headers' => ['Content-Type' => self::LD],
|
'headers' => ['Content-Type' => self::LD],
|
||||||
'json' => $this->validMainPayload('RG203 Commerciale', $cat->getId()),
|
'json' => $this->validMainPayload('RG203 Commerciale', $cat->getId()),
|
||||||
]);
|
]);
|
||||||
self::assertResponseStatusCodeSame(422);
|
self::assertResponseStatusCodeSame(422);
|
||||||
|
self::assertArrayHasKey('description', $this->violationsByPath($response->toArray(false)));
|
||||||
|
|
||||||
// Meme payload par un Admin (non gate par RG-2.03) -> 201.
|
// Meme payload par un Admin (non gate par RG-2.03) -> 201.
|
||||||
$admin = $this->createAdminClient();
|
$admin = $this->createAdminClient();
|
||||||
@@ -266,11 +280,12 @@ final class SupplierRBACMatrixTest extends AbstractSupplierApiTestCase
|
|||||||
$seed = $this->seedSupplier('Commerciale Patch Incomplete');
|
$seed = $this->seedSupplier('Commerciale Patch Incomplete');
|
||||||
$commerciale = $this->authAs('commerciale');
|
$commerciale = $this->authAs('commerciale');
|
||||||
|
|
||||||
$commerciale->request('PATCH', '/api/suppliers/'.$seed->getId(), [
|
$response = $commerciale->request('PATCH', '/api/suppliers/'.$seed->getId(), [
|
||||||
'headers' => ['Content-Type' => self::MERGE],
|
'headers' => ['Content-Type' => self::MERGE],
|
||||||
'json' => ['companyName' => 'Commerciale Renamed'],
|
'json' => ['companyName' => 'Commerciale Renamed'],
|
||||||
]);
|
]);
|
||||||
self::assertResponseStatusCodeSame(422);
|
self::assertResponseStatusCodeSame(422);
|
||||||
|
self::assertArrayHasKey('description', $this->violationsByPath($response->toArray(false)));
|
||||||
|
|
||||||
// Le meme PATCH par un Admin passe (non gate par RG-2.03) -> 200.
|
// Le meme PATCH par un Admin passe (non gate par RG-2.03) -> 200.
|
||||||
$admin = $this->createAdminClient();
|
$admin = $this->createAdminClient();
|
||||||
|
|||||||
@@ -345,20 +345,7 @@ final class SupplierSubResourceApiTest extends AbstractSupplierApiTestCase
|
|||||||
|
|
||||||
// === Helpers ===
|
// === Helpers ===
|
||||||
|
|
||||||
/**
|
// violationsByPath() : helper mutualise dans AbstractSupplierApiTestCase.
|
||||||
* @param array<string, mixed> $body
|
|
||||||
*
|
|
||||||
* @return array<string, string> propertyPath => message
|
|
||||||
*/
|
|
||||||
private function violationsByPath(array $body): array
|
|
||||||
{
|
|
||||||
$byPath = [];
|
|
||||||
foreach ($body['violations'] ?? [] as $v) {
|
|
||||||
$byPath[$v['propertyPath']] = $v['message'];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $byPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function firstSiteIri(): string
|
private function firstSiteIri(): string
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user