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 testEditOrganizerWithLogo(): void { $client = static::createClient(); $em = static::getContainer()->get(EntityManagerInterface::class); $admin = $this->createUser(['ROLE_ROOT']); $orga = $this->createOrganizer($em); $orga->setIsApproved(true); $orga->setOffer('basic'); $orga->setCommissionRate(3.0); $em->flush(); $logo = new \Symfony\Component\HttpFoundation\File\UploadedFile( __DIR__.'/../fixtures/logo.png', 'logo.png', 'image/png', null, true, ); $client->loginUser($admin); $client->request('POST', '/admin/organisateur/'.$orga->getId().'/modifier', [ 'first_name' => $orga->getFirstName(), 'last_name' => $orga->getLastName(), 'email' => $orga->getEmail(), 'company_name' => $orga->getCompanyName(), 'siret' => $orga->getSiret(), 'offer' => 'basic', 'commission_rate' => '3', ], ['logo' => $logo]); self::assertResponseRedirects('/admin/organisateurs?tab=approved'); $em->refresh($orga); self::assertNotNull($orga->getLogoName()); } 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; } public function testEventsPageReturnsSuccess(): void { $client = static::createClient(); $admin = $this->createUser(['ROLE_ROOT']); $client->loginUser($admin); $client->request('GET', '/admin/evenements'); self::assertResponseIsSuccessful(); } public function testEventsPageWithSearch(): void { $client = static::createClient(); $admin = $this->createUser(['ROLE_ROOT']); $client->loginUser($admin); $client->request('GET', '/admin/evenements?q=brocante'); self::assertResponseIsSuccessful(); } public function testEventsPageDeniedForNonRoot(): void { $client = static::createClient(); $user = $this->createUser(); $client->loginUser($user); $client->request('GET', '/admin/evenements'); self::assertResponseStatusCodeSame(403); } 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; } public function testSuspendOrganizer(): 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('POST', '/admin/organisateur/'.$orga->getId().'/suspendre'); self::assertResponseRedirects('/admin/organisateurs?tab=approved'); $em->refresh($orga); self::assertTrue($orga->isSuspended()); } public function testReactivateOrganizer(): void { $client = static::createClient(); $em = static::getContainer()->get(EntityManagerInterface::class); $admin = $this->createUser(['ROLE_ROOT']); $orga = $this->createOrganizer($em); $orga->setIsApproved(true); $orga->setIsSuspended(true); $em->flush(); $client->loginUser($admin); $client->request('POST', '/admin/organisateur/'.$orga->getId().'/suspendre'); self::assertResponseRedirects('/admin/organisateurs?tab=approved'); $em->refresh($orga); self::assertNull($orga->isSuspended()); } public function testOrdersPage(): void { $client = static::createClient(); $admin = $this->createUser(['ROLE_ROOT']); $client->loginUser($admin); $client->request('GET', '/admin/commandes'); self::assertResponseIsSuccessful(); } public function testOrdersPageWithFilters(): void { $client = static::createClient(); $admin = $this->createUser(['ROLE_ROOT']); $client->loginUser($admin); $client->request('GET', '/admin/commandes?status=paid&q=test'); self::assertResponseIsSuccessful(); } public function testForceValidateOrderPending(): void { $client = static::createClient(); $admin = $this->createUser(['ROLE_ROOT']); $em = static::getContainer()->get(EntityManagerInterface::class); $organizer = $this->createUser(['ROLE_ORGANIZER']); $event = new Event(); $event->setTitle('Test Event Force'); $event->setAccount($organizer); $event->setStartAt(new \DateTimeImmutable('+1 day')); $event->setEndAt(new \DateTimeImmutable('+2 days')); $event->setAddress('1 rue test'); $event->setZipcode('75001'); $event->setCity('Paris'); $em->persist($event); $order = new BilletBuyer(); $order->setEvent($event); $order->setEmail('buyer@test.fr'); $order->setFirstName('Jean'); $order->setLastName('Test'); $order->setStatus(BilletBuyer::STATUS_PENDING); $em->persist($order); $em->flush(); $billetOrderService = $this->createMock(BilletOrderService::class); $billetOrderService->expects(self::once())->method('generateOrderTickets'); $billetOrderService->expects(self::once())->method('generateAndSendTickets'); $billetOrderService->expects(self::once())->method('notifyOrganizer'); static::getContainer()->set(BilletOrderService::class, $billetOrderService); $client->loginUser($admin); $client->request('POST', '/admin/commandes/'.$order->getId().'/forcer-validation'); self::assertResponseRedirects('/admin/commandes'); } public function testForceValidateOrderNonPendingFails(): void { $client = static::createClient(); $admin = $this->createUser(['ROLE_ROOT']); $em = static::getContainer()->get(EntityManagerInterface::class); $organizer = $this->createUser(['ROLE_ORGANIZER']); $event = new Event(); $event->setTitle('Test Event Paid'); $event->setAccount($organizer); $event->setStartAt(new \DateTimeImmutable('+1 day')); $event->setEndAt(new \DateTimeImmutable('+2 days')); $event->setAddress('1 rue test'); $event->setZipcode('75001'); $event->setCity('Paris'); $em->persist($event); $order = new BilletBuyer(); $order->setEvent($event); $order->setEmail('buyer2@test.fr'); $order->setFirstName('Pierre'); $order->setLastName('Test'); $order->setStatus(BilletBuyer::STATUS_PAID); $em->persist($order); $em->flush(); $client->loginUser($admin); $client->request('POST', '/admin/commandes/'.$order->getId().'/forcer-validation'); self::assertResponseRedirects('/admin/commandes'); } public function testForceValidateOrderNotFound(): void { $client = static::createClient(); $admin = $this->createUser(['ROLE_ROOT']); $client->loginUser($admin); $client->request('POST', '/admin/commandes/999999/forcer-validation'); self::assertResponseStatusCodeSame(404); } public function testLogsPage(): void { $client = static::createClient(); $admin = $this->createUser(['ROLE_ROOT']); $client->loginUser($admin); $client->request('GET', '/admin/logs'); self::assertResponseIsSuccessful(); } public function testInfraPage(): void { $client = static::createClient(); $admin = $this->createUser(['ROLE_ROOT']); $client->loginUser($admin); $client->request('GET', '/admin/infra'); self::assertResponseIsSuccessful(); } public function testInfraPageWithSnapshotData(): void { $client = static::createClient(); $admin = $this->createUser(['ROLE_ROOT']); $projectDir = static::getContainer()->getParameter('kernel.project_dir'); $path = $projectDir.'/var/infra.json'; $existed = file_exists($path); $originalContent = $existed ? file_get_contents($path) : null; file_put_contents($path, json_encode([ 'server' => [ 'hostname' => 'test', 'os' => 'Linux', 'uptime' => '1d', 'cpu_model' => 'Test CPU', 'cpu_cores' => '4', 'load_1m' => '0.5', 'load_5m' => '0.3', 'load_15m' => '0.1', 'load_percent' => '12', 'ram_total' => '8G', 'ram_used' => '4G', 'ram_free' => '4G', 'ram_percent' => '50', 'disk_total' => '100G', 'disk_used' => '50G', 'disk_free' => '50G', 'disk_percent' => '50', 'caddy' => ['status' => 'ok', 'info' => 'running'], 'docker' => ['status' => 'ok', 'info' => 'running'], 'ssl' => ['domain' => 'test.fr', 'issuer' => 'LE', 'valid_until' => '2027-01-01', 'days_left' => '270', 'status' => 'ok'], ], 'containers' => [], 'redis_global' => ['connected' => false, 'error' => 'Test'], 'redis_dbs' => [], 'postgres' => ['connected' => false, 'error' => 'Test'], 'pgbouncer' => ['connected' => false, 'error' => 'Test'], 'generated_at' => '2026-04-01 10:00:00', ])); $client->loginUser($admin); $client->request('GET', '/admin/infra'); self::assertResponseIsSuccessful(); if ($existed) { file_put_contents($path, $originalContent); } else { unlink($path); } } public function testInfraPageDeniedForNonRoot(): void { $client = static::createClient(); $user = $this->createUser(); $client->loginUser($user); $client->request('GET', '/admin/infra'); self::assertResponseStatusCodeSame(403); } public function testInviteOrganizerPage(): void { $client = static::createClient(); $admin = $this->createUser(['ROLE_ROOT']); $mailer = $this->createMock(MailerService::class); static::getContainer()->set(MailerService::class, $mailer); $client->loginUser($admin); $client->request('GET', '/admin/organisateurs/inviter'); self::assertResponseIsSuccessful(); } public function testInviteOrganizerSubmit(): 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/organisateurs/inviter', [ 'company_name' => 'New Asso', 'first_name' => 'Jean', 'last_name' => 'Invite', 'email' => 'invite-admin-'.uniqid().'@example.com', 'offer' => 'basic', 'commission_rate' => '2.5', ]); self::assertResponseRedirects('/admin/organisateurs/inviter'); } public function testInviteOrganizerEmptyFields(): void { $client = static::createClient(); $admin = $this->createUser(['ROLE_ROOT']); $client->loginUser($admin); $client->request('POST', '/admin/organisateurs/inviter', [ 'company_name' => '', 'first_name' => '', 'last_name' => '', 'email' => '', ]); self::assertResponseRedirects('/admin/organisateurs/inviter'); } public function testDeleteInvitation(): void { $client = static::createClient(); $em = static::getContainer()->get(EntityManagerInterface::class); $admin = $this->createUser(['ROLE_ROOT']); $invitation = new \App\Entity\OrganizerInvitation(); $invitation->setCompanyName('Del Asso'); $invitation->setFirstName('Del'); $invitation->setLastName('Test'); $invitation->setEmail('del-'.uniqid().'@example.com'); $em->persist($invitation); $em->flush(); $client->loginUser($admin); $client->request('POST', '/admin/organisateurs/invitation/'.$invitation->getId().'/supprimer'); self::assertResponseRedirects('/admin/organisateurs/inviter'); } public function testResendInvitation(): void { $client = static::createClient(); $em = static::getContainer()->get(EntityManagerInterface::class); $admin = $this->createUser(['ROLE_ROOT']); $mailer = $this->createMock(MailerService::class); $mailer->expects(self::once())->method('sendEmail'); static::getContainer()->set(MailerService::class, $mailer); $invitation = new \App\Entity\OrganizerInvitation(); $invitation->setCompanyName('Resend Asso'); $invitation->setFirstName('Resend'); $invitation->setLastName('Test'); $invitation->setEmail('resend-'.uniqid().'@example.com'); $invitation->setStatus(\App\Entity\OrganizerInvitation::STATUS_ACCEPTED); $em->persist($invitation); $em->flush(); $client->loginUser($admin); $client->request('POST', '/admin/organisateurs/invitation/'.$invitation->getId().'/renvoyer'); self::assertResponseRedirects('/admin/organisateurs/inviter'); $freshEm = static::getContainer()->get(EntityManagerInterface::class); $updated = $freshEm->getRepository(\App\Entity\OrganizerInvitation::class)->find($invitation->getId()); self::assertSame(\App\Entity\OrganizerInvitation::STATUS_SENT, $updated->getStatus()); } public function testDeleteInvitationNotFound(): void { $client = static::createClient(); $admin = $this->createUser(['ROLE_ROOT']); $client->loginUser($admin); $client->request('POST', '/admin/organisateurs/invitation/999999/supprimer'); self::assertResponseStatusCodeSame(404); } public function testResendInvitationNotFound(): void { $client = static::createClient(); $admin = $this->createUser(['ROLE_ROOT']); $client->loginUser($admin); $client->request('POST', '/admin/organisateurs/invitation/999999/renvoyer'); self::assertResponseStatusCodeSame(404); } public function testExportCsv(): void { $client = static::createClient(); $admin = $this->createUser(['ROLE_ROOT']); $client->loginUser($admin); $client->request('GET', '/admin/export/2026/3'); self::assertResponseIsSuccessful(); self::assertStringContainsString('text/csv', $client->getResponse()->headers->get('Content-Type')); } public function testExportPdf(): void { $client = static::createClient(); $admin = $this->createUser(['ROLE_ROOT']); $client->loginUser($admin); $client->request('GET', '/admin/export/2026/3/pdf'); self::assertResponseIsSuccessful(); self::assertStringContainsString('application/pdf', $client->getResponse()->headers->get('Content-Type')); } private function createEvent(EntityManagerInterface $em, User $organizer): Event { $event = new Event(); $event->setAccount($organizer); $event->setTitle('Test Event '.uniqid()); $event->setStartAt(new \DateTimeImmutable('2026-08-01 10:00')); $event->setEndAt(new \DateTimeImmutable('2026-08-01 18:00')); $event->setAddress('1 rue de la Paix'); $event->setZipcode('75001'); $event->setCity('Paris'); $em->persist($event); $em->flush(); return $event; } public function testToggleEventOnline(): void { $client = static::createClient(); $em = static::getContainer()->get(EntityManagerInterface::class); $admin = $this->createUser(['ROLE_ROOT']); $orga = $this->createOrganizer($em); $event = $this->createEvent($em, $orga); $eventIndex = $this->createMock(EventIndexService::class); $eventIndex->expects(self::once())->method('indexEvent'); static::getContainer()->set(EventIndexService::class, $eventIndex); self::assertFalse($event->isOnline()); $client->loginUser($admin); $client->request('POST', '/admin/evenement/'.$event->getId().'/en-ligne'); self::assertResponseRedirects('/admin/evenements'); $em->refresh($event); self::assertTrue($event->isOnline()); } public function testToggleEventOffline(): void { $client = static::createClient(); $em = static::getContainer()->get(EntityManagerInterface::class); $admin = $this->createUser(['ROLE_ROOT']); $orga = $this->createOrganizer($em); $event = $this->createEvent($em, $orga); $event->setIsOnline(true); $em->flush(); $eventIndex = $this->createMock(EventIndexService::class); $eventIndex->expects(self::once())->method('indexEvent'); static::getContainer()->set(EventIndexService::class, $eventIndex); $client->loginUser($admin); $client->request('POST', '/admin/evenement/'.$event->getId().'/en-ligne'); self::assertResponseRedirects('/admin/evenements'); $em->refresh($event); self::assertFalse($event->isOnline()); } public function testDeleteEvent(): void { $client = static::createClient(); $em = static::getContainer()->get(EntityManagerInterface::class); $admin = $this->createUser(['ROLE_ROOT']); $orga = $this->createOrganizer($em); $event = $this->createEvent($em, $orga); $eventId = $event->getId(); $eventIndex = $this->createMock(EventIndexService::class); $eventIndex->expects(self::once())->method('removeEvent'); static::getContainer()->set(EventIndexService::class, $eventIndex); $client->loginUser($admin); $client->request('POST', '/admin/evenement/'.$eventId.'/supprimer'); self::assertResponseRedirects('/admin/evenements'); $deleted = $em->getRepository(Event::class)->find($eventId); self::assertNull($deleted); } public function testToggleEventOnlineDeniedForNonRoot(): void { $client = static::createClient(); $em = static::getContainer()->get(EntityManagerInterface::class); $user = $this->createUser(); $orga = $this->createOrganizer($em); $event = $this->createEvent($em, $orga); $client->loginUser($user); $client->request('POST', '/admin/evenement/'.$event->getId().'/en-ligne'); self::assertResponseStatusCodeSame(403); } public function testDeleteEventDeniedForNonRoot(): void { $client = static::createClient(); $em = static::getContainer()->get(EntityManagerInterface::class); $user = $this->createUser(); $orga = $this->createOrganizer($em); $event = $this->createEvent($em, $orga); $client->loginUser($user); $client->request('POST', '/admin/evenement/'.$event->getId().'/supprimer'); self::assertResponseStatusCodeSame(403); } public function testAnalyticsDefaultPeriod(): void { $client = static::createClient(); $admin = $this->createUser(['ROLE_ROOT']); $client->loginUser($admin); $client->request('GET', '/admin/analytics'); self::assertResponseIsSuccessful(); } public function testAnalyticsPeriodToday(): void { $client = static::createClient(); $admin = $this->createUser(['ROLE_ROOT']); $client->loginUser($admin); $client->request('GET', '/admin/analytics?period=today'); self::assertResponseIsSuccessful(); } public function testAnalyticsPeriod30d(): void { $client = static::createClient(); $admin = $this->createUser(['ROLE_ROOT']); $client->loginUser($admin); $client->request('GET', '/admin/analytics?period=30d'); self::assertResponseIsSuccessful(); } public function testAnalyticsPeriodAll(): void { $client = static::createClient(); $admin = $this->createUser(['ROLE_ROOT']); $client->loginUser($admin); $client->request('GET', '/admin/analytics?period=all'); self::assertResponseIsSuccessful(); } public function testAnalyticsWithData(): void { $client = static::createClient(); $em = static::getContainer()->get(EntityManagerInterface::class); $admin = $this->createUser(['ROLE_ROOT']); $visitor = new \App\Entity\AnalyticsUniqId(); $visitor->setUid('test-'.uniqid()); $visitor->setHash(hash('sha256', 'test')); $visitor->setIpHash(hash('sha256', '127.0.0.1')); $visitor->setUserAgent('PHPUnit Test Browser'); $visitor->setDeviceType('desktop'); $visitor->setOs('Linux'); $visitor->setBrowser('Chrome'); $em->persist($visitor); $event = new \App\Entity\AnalyticsEvent(); $event->setVisitor($visitor); $event->setUrl('/test-page'); $event->setTitle('Test Page'); $event->setReferrer('https://google.com'); $em->persist($event); $event2 = new \App\Entity\AnalyticsEvent(); $event2->setVisitor($visitor); $event2->setUrl('/another-page'); $em->persist($event2); $em->flush(); $client->loginUser($admin); $client->request('GET', '/admin/analytics?period=7d'); self::assertResponseIsSuccessful(); } public function testAnalyticsDeniedForNonRoot(): void { $client = static::createClient(); $user = $this->createUser(); $client->loginUser($user); $client->request('GET', '/admin/analytics'); self::assertResponseStatusCodeSame(403); } public function testOrderTicketsSingleTicketReturnsPdf(): void { $client = static::createClient(); $em = static::getContainer()->get(EntityManagerInterface::class); $admin = $this->createUser(['ROLE_ROOT']); $orga = $this->createOrganizer($em); $event = $this->createEvent($em, $orga); $category = new Category(); $category->setName('Test'); $category->setEvent($event); $category->setPosition(0); $category->setStartAt(new \DateTimeImmutable('2026-08-01 10:00')); $category->setEndAt(new \DateTimeImmutable('2026-08-01 18:00')); $em->persist($category); $billet = new Billet(); $billet->setName('Test'); $billet->setCategory($category); $billet->setPriceHT(1000); $em->persist($billet); $order = new BilletBuyer(); $order->setEvent($event); $order->setFirstName('Jean'); $order->setLastName('Test'); $order->setEmail('jean@test.fr'); $order->setOrderNumber('2026-'.uniqid()); $order->setTotalHT(1000); $order->setStatus(BilletBuyer::STATUS_PAID); $em->persist($order); $item = new BilletBuyerItem(); $item->setBillet($billet); $item->setBilletName('Test'); $item->setQuantity(1); $item->setUnitPriceHT(1000); $order->addItem($item); $em->persist($item); $ticket = new BilletOrder(); $ticket->setBilletBuyer($order); $ticket->setBillet($billet); $ticket->setBilletName('Test'); $ticket->setUnitPriceHT(1000); $em->persist($ticket); $em->flush(); $billetOrderService = $this->createMock(BilletOrderService::class); $billetOrderService->expects(self::once())->method('generatePdf')->willReturn('%PDF-1.4 dummy'); static::getContainer()->set(BilletOrderService::class, $billetOrderService); $client->loginUser($admin); $client->request('GET', '/admin/commandes/'.$order->getId().'/billets'); self::assertResponseIsSuccessful(); self::assertStringContainsString('application/pdf', $client->getResponse()->headers->get('Content-Type')); } public function testOrderTicketsMultipleTicketsReturnsZip(): void { $client = static::createClient(); $em = static::getContainer()->get(EntityManagerInterface::class); $admin = $this->createUser(['ROLE_ROOT']); $orga = $this->createOrganizer($em); $event = $this->createEvent($em, $orga); $category = new Category(); $category->setName('Test'); $category->setEvent($event); $category->setPosition(0); $category->setStartAt(new \DateTimeImmutable('2026-08-01 10:00')); $category->setEndAt(new \DateTimeImmutable('2026-08-01 18:00')); $em->persist($category); $billet = new Billet(); $billet->setName('Test'); $billet->setCategory($category); $billet->setPriceHT(1000); $em->persist($billet); $order = new BilletBuyer(); $order->setEvent($event); $order->setFirstName('Jean'); $order->setLastName('Test'); $order->setEmail('jean@test.fr'); $order->setOrderNumber('2026-'.uniqid()); $order->setTotalHT(2000); $order->setStatus(BilletBuyer::STATUS_PAID); $em->persist($order); $item = new BilletBuyerItem(); $item->setBillet($billet); $item->setBilletName('Test'); $item->setQuantity(2); $item->setUnitPriceHT(1000); $order->addItem($item); $em->persist($item); $ticket1 = new BilletOrder(); $ticket1->setBilletBuyer($order); $ticket1->setBillet($billet); $ticket1->setBilletName('Test'); $ticket1->setUnitPriceHT(1000); $em->persist($ticket1); $ticket2 = new BilletOrder(); $ticket2->setBilletBuyer($order); $ticket2->setBillet($billet); $ticket2->setBilletName('Test'); $ticket2->setUnitPriceHT(1000); $em->persist($ticket2); $em->flush(); $billetOrderService = $this->createMock(BilletOrderService::class); $billetOrderService->expects(self::exactly(2))->method('generatePdf')->willReturn('%PDF-1.4 dummy'); static::getContainer()->set(BilletOrderService::class, $billetOrderService); $client->loginUser($admin); $client->request('GET', '/admin/commandes/'.$order->getId().'/billets'); self::assertResponseIsSuccessful(); self::assertStringContainsString('application/zip', $client->getResponse()->headers->get('Content-Type')); } public function testOrderTicketsNotFound(): void { $client = static::createClient(); $admin = $this->createUser(['ROLE_ROOT']); $client->loginUser($admin); $client->request('GET', '/admin/commandes/999999/billets'); self::assertResponseStatusCodeSame(404); } public function testOrderTicketsNoTickets(): void { $client = static::createClient(); $em = static::getContainer()->get(EntityManagerInterface::class); $admin = $this->createUser(['ROLE_ROOT']); $orga = $this->createOrganizer($em); $event = $this->createEvent($em, $orga); $order = new BilletBuyer(); $order->setEvent($event); $order->setFirstName('Jean'); $order->setLastName('Test'); $order->setEmail('jean@test.fr'); $order->setOrderNumber('2026-'.uniqid()); $order->setTotalHT(1000); $order->setStatus(BilletBuyer::STATUS_PAID); $em->persist($order); $em->flush(); $client->loginUser($admin); $client->request('GET', '/admin/commandes/'.$order->getId().'/billets'); self::assertResponseStatusCodeSame(404); } }