em = self::getContainer()->get('doctrine')->getManager(); // Nettoyage defensif au cas ou un run precedent aurait laisse des restes. $this->cleanupTestPermissions(); // Donnees de test : deux permissions "core" dont une orpheline, // plus une permission d'un autre module pour verifier le filtre. $p1 = new Permission('test.core.users.view', 'View users (test)', 'core'); $p2 = new Permission('test.core.users.manage', 'Manage users (test)', 'core'); $p3 = new Permission('test.commercial.clients.view', 'View clients (test)', 'commercial'); $p2->markOrphan(); $this->em->persist($p1); $this->em->persist($p2); $this->em->persist($p3); $this->em->flush(); $this->em->clear(); } protected function tearDown(): void { $this->cleanupTestPermissions(); parent::tearDown(); } public function testGetCollectionAsAdminReturns200(): void { $client = $this->authenticatedClient('admin', 'admin'); $response = $client->request('GET', '/api/permissions'); self::assertResponseIsSuccessful(); $data = $response->toArray(); self::assertArrayHasKey('member', $data); self::assertGreaterThanOrEqual(3, $data['totalItems']); } public function testCollectionFilterByModule(): void { $client = $this->authenticatedClient('admin', 'admin'); $response = $client->request('GET', '/api/permissions', [ 'query' => ['module' => 'core'], ]); self::assertResponseIsSuccessful(); $data = $response->toArray(); foreach ($data['member'] as $item) { self::assertSame('core', $item['module']); } // Doit contenir au moins nos deux permissions core de test. $codes = array_column($data['member'], 'code'); self::assertContains('test.core.users.view', $codes); self::assertContains('test.core.users.manage', $codes); self::assertNotContains('test.commercial.clients.view', $codes); } public function testCollectionFilterByOrphanFalse(): void { $client = $this->authenticatedClient('admin', 'admin'); $response = $client->request('GET', '/api/permissions', [ 'query' => ['orphan' => 'false'], ]); self::assertResponseIsSuccessful(); $data = $response->toArray(); foreach ($data['member'] as $item) { self::assertFalse($item['orphan']); } $codes = array_column($data['member'], 'code'); self::assertContains('test.core.users.view', $codes); self::assertNotContains('test.core.users.manage', $codes); } public function testGetItemAsAdminReturnsAllReadFields(): void { /** @var null|Permission $permission */ $permission = $this->em->getRepository(Permission::class) ->findOneBy(['code' => 'test.core.users.view']) ; self::assertNotNull($permission); $client = $this->authenticatedClient('admin', 'admin'); $response = $client->request('GET', '/api/permissions/'.$permission->getId()); self::assertResponseIsSuccessful(); $data = $response->toArray(); self::assertSame($permission->getId(), $data['id']); self::assertSame('test.core.users.view', $data['code']); self::assertSame('View users (test)', $data['label']); self::assertSame('core', $data['module']); self::assertFalse($data['orphan']); } public function testPostIsMethodNotAllowed(): void { $client = $this->authenticatedClient('admin', 'admin'); $client->request('POST', '/api/permissions', [ 'headers' => ['Content-Type' => 'application/ld+json'], 'json' => ['code' => 'test.foo.bar.baz', 'label' => 'Foo', 'module' => 'foo'], ]); self::assertResponseStatusCodeSame(405); } public function testUnauthenticatedReturns401(): void { $client = self::createClient(); $client->request('GET', '/api/permissions'); self::assertResponseStatusCodeSame(401); } public function testNonAdminReturns403(): void { $client = $this->authenticatedClient('alice', 'alice'); $client->request('GET', '/api/permissions'); self::assertResponseStatusCodeSame(403); } private function cleanupTestPermissions(): void { $this->em->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; } }