request('GET', '/admin'); self::assertResponseRedirects(); } public function testDashboardDeniedForNonRoot(): void { $client = static::createClient(); $user = $this->createUser(); $client->loginUser($user); $client->request('GET', '/admin'); self::assertResponseStatusCodeSame(403); } public function testDashboardReturnsSuccessForRoot(): void { $client = static::createClient(); $user = $this->createUser(['ROLE_ROOT']); $client->loginUser($user); $client->request('GET', '/admin'); self::assertResponseIsSuccessful(); } public function testUsersPageReturnsSuccessForRoot(): void { $client = static::createClient(); $user = $this->createUser(['ROLE_ROOT']); $client->loginUser($user); $client->request('GET', '/admin/utilisateurs'); self::assertResponseIsSuccessful(); } public function testUsersPageDeniedForNonRoot(): void { $client = static::createClient(); $user = $this->createUser(); $client->loginUser($user); $client->request('GET', '/admin/utilisateurs'); self::assertResponseStatusCodeSame(403); } public function testBuyersPageReturnsSuccessForRoot(): void { $client = static::createClient(); $user = $this->createUser(['ROLE_ROOT']); $client->loginUser($user); $client->request('GET', '/admin/acheteurs'); self::assertResponseIsSuccessful(); } public function testBuyersSearchWithQuery(): void { $client = static::createClient(); $admin = $this->createUser(['ROLE_ROOT']); $meilisearch = $this->createMock(MeilisearchService::class); $meilisearch->expects(self::once())->method('search')->willReturn([ 'hits' => [], 'estimatedTotalHits' => 0, ]); static::getContainer()->set(MeilisearchService::class, $meilisearch); $client->loginUser($admin); $client->request('GET', '/admin/acheteurs?q=test'); self::assertResponseIsSuccessful(); } public function testSyncMeilisearchWithBuyers(): void { $client = static::createClient(); $em = static::getContainer()->get(EntityManagerInterface::class); $admin = $this->createUser(['ROLE_ROOT']); $buyer = new User(); $buyer->setEmail('test-sync-'.uniqid().'@example.com'); $buyer->setFirstName('Sync'); $buyer->setLastName('Test'); $buyer->setPassword('$2y$13$hashed'); $buyer->setIsVerified(true); $em->persist($buyer); $em->flush(); $meilisearch = $this->createMock(MeilisearchService::class); $meilisearch->expects(self::exactly(2))->method('createIndexIfNotExists'); static::getContainer()->set(MeilisearchService::class, $meilisearch); $client->loginUser($admin); $client->request('POST', '/admin/sync-meilisearch'); self::assertResponseRedirects('/admin'); } public function testSyncMeilisearchWithOrganizers(): void { $client = static::createClient(); $em = static::getContainer()->get(EntityManagerInterface::class); $admin = $this->createUser(['ROLE_ROOT']); $orga = $this->createOrganizer($em); $orga->setIsApproved(true); $em->flush(); $meilisearch = $this->createMock(MeilisearchService::class); $meilisearch->expects(self::exactly(2))->method('createIndexIfNotExists'); $meilisearch->expects(self::exactly(2))->method('addDocuments'); static::getContainer()->set(MeilisearchService::class, $meilisearch); $client->loginUser($admin); $client->request('POST', '/admin/sync-meilisearch'); self::assertResponseRedirects('/admin'); } public function testBuyersSearchWithMeilisearchError(): void { $client = static::createClient(); $admin = $this->createUser(['ROLE_ROOT']); $meilisearch = $this->createMock(MeilisearchService::class); $meilisearch->method('search')->willThrowException(new \RuntimeException('Meilisearch down')); static::getContainer()->set(MeilisearchService::class, $meilisearch); $client->loginUser($admin); $client->request('GET', '/admin/acheteurs?q=test'); self::assertResponseIsSuccessful(); } public function testBuyersSearchWithResults(): void { $client = static::createClient(); $em = static::getContainer()->get(EntityManagerInterface::class); $admin = $this->createUser(['ROLE_ROOT']); $buyer = new User(); $buyer->setEmail('test-search-hit-'.uniqid().'@example.com'); $buyer->setFirstName('Found'); $buyer->setLastName('User'); $buyer->setPassword('$2y$13$hashed'); $buyer->setIsVerified(true); $em->persist($buyer); $em->flush(); $meilisearch = $this->createMock(MeilisearchService::class); $meilisearch->method('search')->willReturn([ 'hits' => [['id' => $buyer->getId()]], 'estimatedTotalHits' => 1, ]); static::getContainer()->set(MeilisearchService::class, $meilisearch); $client->loginUser($admin); $client->request('GET', '/admin/acheteurs?q=Found'); self::assertResponseIsSuccessful(); } public function testCreateBuyerWithValidData(): void { $client = static::createClient(); $admin = $this->createUser(['ROLE_ROOT']); $mailer = $this->createMock(MailerService::class); $mailer->expects(self::once())->method('sendEmail'); static::getContainer()->set(MailerService::class, $mailer); $client->loginUser($admin); $client->request('POST', '/admin/acheteurs/creer', [ 'first_name' => 'Nouveau', 'last_name' => 'Acheteur', 'email' => 'new-buyer-'.uniqid().'@example.com', ]); self::assertResponseRedirects('/admin/acheteurs'); } public function testCreateBuyerWithDuplicateEmail(): void { $client = static::createClient(); $admin = $this->createUser(['ROLE_ROOT']); $client->loginUser($admin); $client->request('POST', '/admin/acheteurs/creer', [ 'first_name' => 'Dup', 'last_name' => 'Test', 'email' => $admin->getEmail(), ]); self::assertResponseRedirects('/admin/acheteurs'); } public function testResendVerificationEmail(): void { $client = static::createClient(); $em = static::getContainer()->get(EntityManagerInterface::class); $admin = $this->createUser(['ROLE_ROOT']); $buyer = new User(); $buyer->setEmail('test-buyer-'.uniqid().'@example.com'); $buyer->setFirstName('Buyer'); $buyer->setLastName('Test'); $buyer->setPassword('$2y$13$hashed'); $em->persist($buyer); $em->flush(); $mailer = $this->createMock(MailerService::class); $mailer->expects(self::once())->method('sendEmail'); static::getContainer()->set(MailerService::class, $mailer); $client->loginUser($admin); $client->request('POST', '/admin/acheteur/'.$buyer->getId().'/renvoyer-verification'); self::assertResponseRedirects('/admin/acheteurs'); $em->refresh($buyer); self::assertNotNull($buyer->getEmailVerificationToken()); } public function testResetPasswordSendsEmail(): void { $client = static::createClient(); $em = static::getContainer()->get(EntityManagerInterface::class); $admin = $this->createUser(['ROLE_ROOT']); $buyer = new User(); $buyer->setEmail('test-reset-admin-'.uniqid().'@example.com'); $buyer->setFirstName('Reset'); $buyer->setLastName('Test'); $buyer->setPassword('$2y$13$hashed'); $buyer->setIsVerified(true); $em->persist($buyer); $em->flush(); $mailer = $this->createMock(MailerService::class); $mailer->expects(self::once())->method('sendEmail'); static::getContainer()->set(MailerService::class, $mailer); $client->loginUser($admin); $client->request('POST', '/admin/acheteur/'.$buyer->getId().'/reset-password'); self::assertResponseRedirects('/admin/acheteurs'); } public function testDeleteBuyer(): void { $client = static::createClient(); $em = static::getContainer()->get(EntityManagerInterface::class); $admin = $this->createUser(['ROLE_ROOT']); $buyer = new User(); $buyer->setEmail('test-delete-'.uniqid().'@example.com'); $buyer->setFirstName('Delete'); $buyer->setLastName('Test'); $buyer->setPassword('$2y$13$hashed'); $em->persist($buyer); $em->flush(); $buyerId = $buyer->getId(); $meilisearch = $this->createMock(MeilisearchService::class); $meilisearch->expects(self::once())->method('deleteDocument')->with('buyers', $buyerId); static::getContainer()->set(MeilisearchService::class, $meilisearch); $client->loginUser($admin); $client->request('POST', '/admin/acheteur/'.$buyerId.'/supprimer'); self::assertResponseRedirects('/admin/acheteurs'); $deleted = $em->getRepository(User::class)->find($buyerId); self::assertNull($deleted); } public function testDeleteBuyerMeilisearchFailureDoesNotBlock(): void { $client = static::createClient(); $em = static::getContainer()->get(EntityManagerInterface::class); $admin = $this->createUser(['ROLE_ROOT']); $buyer = new User(); $buyer->setEmail('test-delete-fail-'.uniqid().'@example.com'); $buyer->setFirstName('DeleteFail'); $buyer->setLastName('Test'); $buyer->setPassword('$2y$13$hashed'); $em->persist($buyer); $em->flush(); $buyerId = $buyer->getId(); $meilisearch = $this->createMock(MeilisearchService::class); $meilisearch->method('deleteDocument')->willThrowException(new \RuntimeException('Meilisearch down')); static::getContainer()->set(MeilisearchService::class, $meilisearch); $client->loginUser($admin); $client->request('POST', '/admin/acheteur/'.$buyerId.'/supprimer'); self::assertResponseRedirects('/admin/acheteurs'); } public function testForceVerification(): void { $client = static::createClient(); $em = static::getContainer()->get(EntityManagerInterface::class); $admin = $this->createUser(['ROLE_ROOT']); $buyer = new User(); $buyer->setEmail('test-force-'.uniqid().'@example.com'); $buyer->setFirstName('Force'); $buyer->setLastName('Test'); $buyer->setPassword('$2y$13$hashed'); $em->persist($buyer); $em->flush(); $client->loginUser($admin); $client->request('POST', '/admin/acheteur/'.$buyer->getId().'/forcer-verification'); self::assertResponseRedirects('/admin/acheteurs'); $em->refresh($buyer); self::assertTrue($buyer->isVerified()); self::assertNotNull($buyer->getEmailVerifiedAt()); self::assertNull($buyer->getEmailVerificationToken()); } public function testOrganizersSearchWithQuery(): void { $client = static::createClient(); $admin = $this->createUser(['ROLE_ROOT']); $meilisearch = $this->createMock(MeilisearchService::class); $meilisearch->expects(self::once())->method('search')->with('organizers')->willReturn([ 'hits' => [], 'estimatedTotalHits' => 0, ]); static::getContainer()->set(MeilisearchService::class, $meilisearch); $client->loginUser($admin); $client->request('GET', '/admin/organisateurs?q=test'); self::assertResponseIsSuccessful(); } public function testOrganizersSearchWithError(): void { $client = static::createClient(); $admin = $this->createUser(['ROLE_ROOT']); $meilisearch = $this->createMock(MeilisearchService::class); $meilisearch->method('search')->willThrowException(new \RuntimeException('Meilisearch down')); static::getContainer()->set(MeilisearchService::class, $meilisearch); $client->loginUser($admin); $client->request('GET', '/admin/organisateurs?q=test'); self::assertResponseIsSuccessful(); } public function testOrganizersPagePendingTab(): void { $client = static::createClient(); $admin = $this->createUser(['ROLE_ROOT']); $client->loginUser($admin); $client->request('GET', '/admin/organisateurs'); self::assertResponseIsSuccessful(); } public function testOrganizersPageApprovedTab(): void { $client = static::createClient(); $admin = $this->createUser(['ROLE_ROOT']); $client->loginUser($admin); $client->request('GET', '/admin/organisateurs?tab=approved'); self::assertResponseIsSuccessful(); } public function testSiretCheckPage(): void { $client = static::createClient(); $em = static::getContainer()->get(EntityManagerInterface::class); $admin = $this->createUser(['ROLE_ROOT']); $orga = $this->createOrganizer($em); $client->loginUser($admin); $client->request('GET', '/admin/organisateur/'.$orga->getId().'/siret'); self::assertResponseIsSuccessful(); } public function testSiretCheckRedirectsIfApproved(): void { $client = static::createClient(); $em = static::getContainer()->get(EntityManagerInterface::class); $admin = $this->createUser(['ROLE_ROOT']); $orga = $this->createOrganizer($em); $orga->setIsApproved(true); $em->flush(); $client->loginUser($admin); $client->request('GET', '/admin/organisateur/'.$orga->getId().'/siret'); self::assertResponseRedirects('/admin/organisateurs'); } public function testSiretCheckWithoutSiret(): void { $client = static::createClient(); $em = static::getContainer()->get(EntityManagerInterface::class); $admin = $this->createUser(['ROLE_ROOT']); $orga = new User(); $orga->setEmail('test-no-siret-'.uniqid().'@example.com'); $orga->setFirstName('No'); $orga->setLastName('Siret'); $orga->setPassword('$2y$13$hashed'); $orga->setRoles(['ROLE_ORGANIZER']); $em->persist($orga); $em->flush(); $client->loginUser($admin); $client->request('GET', '/admin/organisateur/'.$orga->getId().'/siret'); self::assertResponseRedirects('/admin/organisateurs'); } public function testSiretRefresh(): void { $client = static::createClient(); $em = static::getContainer()->get(EntityManagerInterface::class); $admin = $this->createUser(['ROLE_ROOT']); $orga = $this->createOrganizer($em); $client->loginUser($admin); $client->request('POST', '/admin/organisateur/'.$orga->getId().'/siret/refresh'); self::assertResponseRedirects('/admin/organisateur/'.$orga->getId().'/siret'); } public function testEditOrganizerPage(): void { $client = static::createClient(); $em = static::getContainer()->get(EntityManagerInterface::class); $admin = $this->createUser(['ROLE_ROOT']); $orga = $this->createOrganizer($em); $orga->setIsApproved(true); $orga->setOffer('free'); $orga->setCommissionRate(3.0); $em->flush(); $client->loginUser($admin); $client->request('GET', '/admin/organisateur/'.$orga->getId().'/modifier'); self::assertResponseIsSuccessful(); } public function testEditOrganizerSubmit(): void { $client = static::createClient(); $em = static::getContainer()->get(EntityManagerInterface::class); $admin = $this->createUser(['ROLE_ROOT']); $orga = $this->createOrganizer($em); $orga->setIsApproved(true); $orga->setOffer('free'); $orga->setCommissionRate(3.0); $em->flush(); $client->loginUser($admin); $client->request('POST', '/admin/organisateur/'.$orga->getId().'/modifier', [ 'offer' => 'custom', 'commission_rate' => '0.5', ]); self::assertResponseRedirects('/admin/organisateurs?tab=approved'); $em->refresh($orga); self::assertSame('custom', $orga->getOffer()); self::assertSame(0.5, $orga->getCommissionRate()); } public function testEditOrganizerRedirectsIfNotApproved(): void { $client = static::createClient(); $em = static::getContainer()->get(EntityManagerInterface::class); $admin = $this->createUser(['ROLE_ROOT']); $orga = $this->createOrganizer($em); $client->loginUser($admin); $client->request('GET', '/admin/organisateur/'.$orga->getId().'/modifier'); self::assertResponseRedirects('/admin/organisateurs'); } public function testApproveOrganizer(): void { $client = static::createClient(); $em = static::getContainer()->get(EntityManagerInterface::class); $admin = $this->createUser(['ROLE_ROOT']); $orga = $this->createOrganizer($em); $mailer = $this->createMock(MailerService::class); $mailer->expects(self::once())->method('sendEmail'); static::getContainer()->set(MailerService::class, $mailer); $meilisearch = $this->createMock(MeilisearchService::class); $meilisearch->expects(self::once())->method('createIndexIfNotExists')->with('organizers'); $meilisearch->expects(self::once())->method('addDocuments'); static::getContainer()->set(MeilisearchService::class, $meilisearch); $client->loginUser($admin); $client->request('POST', '/admin/organisateur/'.$orga->getId().'/approuver', [ 'offer' => 'basic', 'commission_rate' => '1.5', ]); self::assertResponseRedirects('/admin/organisateurs'); $em->refresh($orga); self::assertTrue($orga->isApproved()); self::assertSame('basic', $orga->getOffer()); self::assertSame(1.5, $orga->getCommissionRate()); } public function testRejectOrganizer(): void { $client = static::createClient(); $em = static::getContainer()->get(EntityManagerInterface::class); $admin = $this->createUser(['ROLE_ROOT']); $orga = $this->createOrganizer($em); $orgaId = $orga->getId(); $mailer = $this->createMock(MailerService::class); $mailer->expects(self::once())->method('sendEmail'); static::getContainer()->set(MailerService::class, $mailer); $client->loginUser($admin); $client->request('POST', '/admin/organisateur/'.$orgaId.'/refuser', [ 'reason' => 'SIRET invalide, activite non conforme.', ]); self::assertResponseRedirects('/admin/organisateurs'); $deleted = $em->getRepository(User::class)->find($orgaId); self::assertNull($deleted); } /** * @param list $roles */ private function createUser(array $roles = []): User { $em = static::getContainer()->get(EntityManagerInterface::class); $user = new User(); $user->setEmail('test-admin-'.uniqid().'@example.com'); $user->setFirstName('Admin'); $user->setLastName('User'); $user->setPassword('$2y$13$hashed'); $user->setRoles($roles); $em->persist($user); $em->flush(); return $user; } private function createOrganizer(EntityManagerInterface $em): User { $orga = new User(); $orga->setEmail('test-orga-'.uniqid().'@example.com'); $orga->setFirstName('Orga'); $orga->setLastName('Test'); $orga->setPassword('$2y$13$hashed'); $orga->setRoles(['ROLE_ORGANIZER']); $orga->setIsVerified(true); $orga->setCompanyName('Mon Asso'); $orga->setSiret('12345678901234'); $em->persist($orga); $em->flush(); return $orga; } }