refactor(test) : RBAC #344 - AbstractApiTestCase pour mutualiser auth JWT

Extrait l'helper authenticatedClient(), $alwaysBootKernel et getEm() dans
une classe de base commune aux tests fonctionnels API Platform du module
Core. Supprime la duplication entre PermissionApiTest et RoleApiTest
(flaggee en code review de la Task 2). Prepare le terrain pour le nouveau
UserRbacApiTest introduit avec la Task 4.
This commit is contained in:
Matthieu
2026-04-15 12:14:20 +02:00
parent 87aa1d0b04
commit 168a47f2b8
3 changed files with 68 additions and 87 deletions

View File

@@ -0,0 +1,66 @@
<?php
declare(strict_types=1);
namespace App\Tests\Module\Core\Api;
use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;
use ApiPlatform\Symfony\Bundle\Test\Client;
use Doctrine\ORM\EntityManagerInterface;
/**
* Classe de base pour les tests fonctionnels API Platform du module Core.
*
* Mutualise :
* - `$alwaysBootKernel = true` : bascule le nouveau comportement API Platform 5
* et evite la deprecation emise a la creation du client de test.
* - `authenticatedClient()` : cree un client authentifie via `/login_check`
* (cookie BEARER HTTP-only pose par lexik_jwt_authentication).
* - `getEm()` : recupere l'EntityManager depuis le container courant.
* A rappeler apres chaque createClient() car le kernel est reboote.
*
* @internal
*/
abstract class AbstractApiTestCase extends ApiTestCase
{
// Bascule explicite sur le nouveau comportement API Platform 5 pour
// eviter la deprecation emise a la creation du client de test.
protected static ?bool $alwaysBootKernel = true;
/**
* Recupere l'EntityManager depuis le container courant. A utiliser a
* chaque appel : apres un createClient(), le kernel est reboote et tout
* EM precedemment capture est invalide.
*/
protected function getEm(): EntityManagerInterface
{
if (!self::$kernel) {
self::bootKernel();
}
return self::getContainer()->get('doctrine')->getManager();
}
/**
* Cree un client authentifie via /login_check. La configuration du projet
* pose le JWT dans un cookie HTTP-only `BEARER` (cf. lexik_jwt_authentication.yaml)
* et retire le token du body de reponse ; le client BrowserKit persiste
* automatiquement le cookie pour les requetes suivantes.
*/
protected function authenticatedClient(string $username, string $password): Client
{
$client = self::createClient();
$response = $client->request('POST', '/login_check', [
'headers' => ['Content-Type' => 'application/json'],
'json' => ['username' => $username, 'password' => $password],
]);
self::assertContains(
$response->getStatusCode(),
[200, 204],
'Login failed for '.$username.': '.$response->getStatusCode(),
);
return $client;
}
}

View File

@@ -4,10 +4,7 @@ declare(strict_types=1);
namespace App\Tests\Module\Core\Api;
use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;
use ApiPlatform\Symfony\Bundle\Test\Client;
use App\Module\Core\Domain\Entity\Permission;
use Doctrine\ORM\EntityManagerInterface;
/**
* Tests fonctionnels de l'exposition API Platform de l'entite Permission.
@@ -20,12 +17,9 @@ use Doctrine\ORM\EntityManagerInterface;
*
* @internal
*/
final class PermissionApiTest extends ApiTestCase
final class PermissionApiTest extends AbstractApiTestCase
{
private const TEST_CODE_PREFIX = 'test.';
// Bascule explicite sur le nouveau comportement API Platform 5 pour
// eviter la deprecation emise a la creation du client de test.
protected static ?bool $alwaysBootKernel = true;
protected function setUp(): void
{
@@ -178,47 +172,10 @@ final class PermissionApiTest extends ApiTestCase
self::assertResponseStatusCodeSame(403);
}
/**
* Recupere l'EntityManager depuis le container courant. A utiliser a
* chaque appel : apres un createClient(), le kernel est reboote et tout
* EM precedemment capture est invalide.
*/
private function getEm(): EntityManagerInterface
{
if (!self::$kernel) {
self::bootKernel();
}
return self::getContainer()->get('doctrine')->getManager();
}
private function cleanupTestPermissions(): void
{
$this->getEm()->createQuery(
'DELETE FROM '.Permission::class.' p WHERE p.code LIKE :prefix'
)->setParameter('prefix', self::TEST_CODE_PREFIX.'%')->execute();
}
/**
* Cree un client authentifie via /login_check. La configuration du projet
* pose le JWT dans un cookie HTTP-only `BEARER` (cf. lexik_jwt_authentication.yaml)
* et retire le token du body de reponse ; le client BrowserKit persiste
* automatiquement le cookie pour les requetes suivantes.
*/
private function authenticatedClient(string $username, string $password): Client
{
$client = self::createClient();
$response = $client->request('POST', '/login_check', [
'headers' => ['Content-Type' => 'application/json'],
'json' => ['username' => $username, 'password' => $password],
]);
self::assertContains(
$response->getStatusCode(),
[200, 204],
'Login failed for '.$username.': '.$response->getStatusCode(),
);
return $client;
}
}

View File

@@ -4,12 +4,9 @@ declare(strict_types=1);
namespace App\Tests\Module\Core\Api;
use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;
use ApiPlatform\Symfony\Bundle\Test\Client;
use App\Module\Core\Domain\Entity\Permission;
use App\Module\Core\Domain\Entity\Role;
use App\Module\Core\Domain\Security\SystemRoles;
use Doctrine\ORM\EntityManagerInterface;
/**
* Tests fonctionnels de l'exposition API Platform de l'entite Role (CRUD nominal).
@@ -24,7 +21,7 @@ use Doctrine\ORM\EntityManagerInterface;
*
* @internal
*/
final class RoleApiTest extends ApiTestCase
final class RoleApiTest extends AbstractApiTestCase
{
// Prefixe pour les roles de test : `test_` (underscore) parce que les
// codes de role doivent matcher `/^[a-z][a-z0-9_]*$/` (pas de point
@@ -36,10 +33,6 @@ final class RoleApiTest extends ApiTestCase
// module.resource.action validee dans le constructeur Permission).
private const TEST_PERMISSION_PREFIX = 'test.';
// Bascule explicite sur le nouveau comportement API Platform 5 pour
// eviter la deprecation emise a la creation du client de test.
protected static ?bool $alwaysBootKernel = true;
protected function setUp(): void
{
parent::setUp();
@@ -332,20 +325,6 @@ final class RoleApiTest extends ApiTestCase
self::assertResponseStatusCodeSame(403);
}
/**
* Recupere l'EntityManager depuis le container courant. A utiliser a
* chaque appel : apres un createClient(), le kernel est reboote et tout
* EM precedemment capture est invalide.
*/
private function getEm(): EntityManagerInterface
{
if (!self::$kernel) {
self::bootKernel();
}
return self::getContainer()->get('doctrine')->getManager();
}
/**
* Purge les donnees de test (roles et permissions prefixees `test.`).
* Ne touche JAMAIS aux roles systeme `admin` et `user` charges par les
@@ -369,25 +348,4 @@ final class RoleApiTest extends ApiTestCase
'DELETE FROM '.Permission::class.' p WHERE p.code LIKE :prefix'
)->setParameter('prefix', self::TEST_PERMISSION_PREFIX.'%')->execute();
}
/**
* Cree un client authentifie via /login_check (cookie BEARER pose par
* lexik_jwt_authentication et persiste automatiquement par BrowserKit).
*/
private function authenticatedClient(string $username, string $password): Client
{
$client = self::createClient();
$response = $client->request('POST', '/login_check', [
'headers' => ['Content-Type' => 'application/json'],
'json' => ['username' => $username, 'password' => $password],
]);
self::assertContains(
$response->getStatusCode(),
[200, 204],
'Login failed for '.$username.': '.$response->getStatusCode(),
);
return $client;
}
}