test(logistique) : tests PHPUnit RG-5.01→5.10 + capture contrat JSON (ERP-187) (#137)
Auto Tag Develop / tag (push) Successful in 8s
Auto Tag Develop / tag (push) Successful in 8s
## ERP-187 (1.7) — Tests PHPUnit RG-5.01→5.10 + capture contrat JSON
Couvre les règles de gestion du M5 (tickets de pesée) par des tests PHPUnit et capture la **réponse JSON réelle** (DoD § 4.0.bis) collée dans `spec-back.md` avant les écrans front.
### Tests unitaires (Processor / Normalizer / Callback — sans BDD ni HTTP)
- **NetWeightTest** (RG-5.05) : net = plein − vide, `null` si une pesée manque, recalcul au PATCH.
- **CounterpartyValidationTest** (RG-5.03) : présence du champ requis par branche (propertyPath `client`/`supplier`/`otherLabel`) + exclusivité (null-ification hors-branche).
- **ImmatriculationNormalizationTest** (RG-5.01/5.10) : masque `XX-000-XX`, « Tout format », mapping 422 sur `immatriculation`.
### Tests fonctionnels (API réelle)
- **WeighingTicketNumberingTest** (RG-5.02/5.09) : format `{siteCode}-TP-{NNNN}`, séquence par site, isolation inter-sites, immuabilité numéro/site au PATCH.
- **WeighingTicketSerializationContractTest** (DoD § 4.0.bis) : 4 pièges verts (client embarqué, `plateFreeFormat` présent, `number` formaté, `netWeight` = full − empty) + dump JSON via `WEIGHING_TICKET_DOD_DUMP`.
- **WeighingTicketRBACMatrixTest** (§ 5.2) : admin/bureau/usine OK, compta/commerciale 403, anonyme 401.
> DSD / stub pont bascule / endpoint pesée déjà couverts (ERP-184/185).
### DoD
- `spec-back.md § 4.0.bis` : **JSON réel** (liste + détail) collé, 4 pièges marqués ✅ — feu vert front.
### Vérifications
- `make test` complet **vert** : 848 tests, 6302 assertions (0 échec ; deprecations/notices PHPUnit seuls).
- `make php-cs-fixer-allow-risky` : 0 correction.
Empilée sur ERP-186 (stack M5).
---------
Co-authored-by: Matthieu <contact@malio.fr>
Reviewed-on: #137
This commit was merged in pull request #137.
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Module\Logistique\Api;
|
||||
|
||||
use App\Module\Core\Infrastructure\DataFixtures\RbacDemoFixtures;
|
||||
use Symfony\Bundle\FrameworkBundle\Console\Application;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
use Symfony\Component\Console\Output\NullOutput;
|
||||
|
||||
/**
|
||||
* Matrice RBAC du ticket de pesee par role metier (spec-back M5 § 5.2). Jumeau de
|
||||
* {@see \App\Tests\Module\Transport\Api\CarrierRBACMatrixTest}.
|
||||
*
|
||||
* Matrice § 5.2 (V0.2) :
|
||||
* - admin / bureau / usine : view + manage (200 lecture, 201 creation)
|
||||
* - compta / commerciale : AUCUN acces (403 sur view ET manage)
|
||||
* - anonyme : 401
|
||||
*
|
||||
* La creation (POST -> 201) suppose un site courant (numerotation + cloisonnement,
|
||||
* § 2.3) : on le positionne pour chaque role autorise a ecrire.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final class WeighingTicketRBACMatrixTest extends AbstractWeighingTicketApiTestCase
|
||||
{
|
||||
private const string PWD = RbacDemoFixtures::DEMO_PASSWORD;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
// Seed idempotent des roles metier + matrice § 5.2 + comptes demo (meme
|
||||
// chemin qu'en recette).
|
||||
self::bootKernel();
|
||||
$application = new Application(self::$kernel);
|
||||
$application->setAutoExit(false);
|
||||
$exit = $application->run(
|
||||
new ArrayInput([
|
||||
'command' => 'app:seed-rbac',
|
||||
'--with-demo-users' => true,
|
||||
'--password' => self::PWD,
|
||||
]),
|
||||
new NullOutput(),
|
||||
);
|
||||
self::assertSame(
|
||||
0,
|
||||
$exit,
|
||||
'app:seed-rbac a echoue : les permissions logistique.weighing_tickets.* sont-elles synchronisees (app:sync-permissions) ?',
|
||||
);
|
||||
|
||||
self::ensureKernelShutdown();
|
||||
}
|
||||
|
||||
public function testAdminCanViewAndManage(): void
|
||||
{
|
||||
$this->assertCanViewAndManage('admin', 'admin');
|
||||
}
|
||||
|
||||
public function testBureauCanViewAndManage(): void
|
||||
{
|
||||
$this->assertCanViewAndManage('bureau', self::PWD);
|
||||
}
|
||||
|
||||
public function testUsineCanViewAndManage(): void
|
||||
{
|
||||
$this->assertCanViewAndManage('usine', self::PWD);
|
||||
}
|
||||
|
||||
public function testComptaHasNoAccess(): void
|
||||
{
|
||||
$this->assertHasNoAccess('compta');
|
||||
}
|
||||
|
||||
public function testCommercialeHasNoAccess(): void
|
||||
{
|
||||
$this->assertHasNoAccess('commerciale');
|
||||
}
|
||||
|
||||
public function testAnonymousIsUnauthorized(): void
|
||||
{
|
||||
$client = self::createClient();
|
||||
$client->request('GET', '/api/weighing_tickets', ['headers' => ['Accept' => self::LD]]);
|
||||
self::assertResponseStatusCodeSame(401);
|
||||
}
|
||||
|
||||
/**
|
||||
* Role autorise : GET 200 (view) + POST 201 (manage). Le site courant est
|
||||
* positionne avant le POST pour permettre la numerotation.
|
||||
*/
|
||||
private function assertCanViewAndManage(string $username, string $password): void
|
||||
{
|
||||
$site = $this->firstSite();
|
||||
$this->setCurrentSite($username, $site);
|
||||
|
||||
$clientEntity = $this->seedTestClient('Rbac '.$username);
|
||||
$http = $this->authenticatedClient($username, $password);
|
||||
|
||||
$http->request('GET', '/api/weighing_tickets', ['headers' => ['Accept' => self::LD]]);
|
||||
self::assertResponseStatusCodeSame(200);
|
||||
|
||||
$this->postTicket($http, $this->validClientTicketPayload($clientEntity));
|
||||
self::assertResponseStatusCodeSame(201);
|
||||
}
|
||||
|
||||
/**
|
||||
* Role sans acces : 403 en lecture (view absent) ET en ecriture (manage absent).
|
||||
*/
|
||||
private function assertHasNoAccess(string $username): void
|
||||
{
|
||||
$clientEntity = $this->seedTestClient('Rbac '.$username);
|
||||
$http = $this->authenticatedClient($username, self::PWD);
|
||||
|
||||
$http->request('GET', '/api/weighing_tickets', ['headers' => ['Accept' => self::LD]]);
|
||||
self::assertResponseStatusCodeSame(403);
|
||||
|
||||
$this->postTicket($http, $this->validClientTicketPayload($clientEntity));
|
||||
self::assertResponseStatusCodeSame(403);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user