Files
Starseed/tests/Module/Logistique/Api/WeighingTicketRBACMatrixTest.php
T
Matthieu b036c72615 test(logistique) : tests PHPUnit RG-5.01→5.10 + capture contrat JSON (ERP-187)
Couverture des règles de gestion du M5 (tickets de pesée) et capture de la
réponse JSON réelle (DoD § 4.0.bis) avant les écrans front.

Tests unitaires (Processor/Normalizer/Callback, sans BDD ni HTTP) :
- NetWeightTest (RG-5.05) : net = plein − vide, null si pesée manquante, recalcul PATCH.
- CounterpartyValidationTest (RG-5.03) : présence par branche (propertyPath) + exclusivité.
- ImmatriculationNormalizationTest (RG-5.01/5.10) : masque XX-000-XX, « Tout format », 422.

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 (client embarqué,
  plateFreeFormat présent, number formaté, netWeight = full − empty) + dump JSON.
- WeighingTicketRBACMatrixTest (§ 5.2) : admin/bureau/usine OK, compta/commerciale 403,
  anonyme 401.

DSD/stub/reading déjà couverts (ERP-184/185). spec-back.md § 4.0.bis : JSON réel collé.
2026-06-18 14:37:16 +02:00

122 lines
3.9 KiB
PHP

<?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);
}
}