createStub(EntityManagerInterface::class); $meilisearch ??= $this->createStub(MeilisearchService::class); $controller = new FactureController($em, $meilisearch); $session = new Session(new MockArraySessionStorage()); $stack = $this->createStub(RequestStack::class); $stack->method('getSession')->willReturn($session); $twig = $this->createStub(Environment::class); $twig->method('render')->willReturn(''); $router = $this->createStub(RouterInterface::class); $router->method('generate')->willReturn('/redirect'); $container = $this->createStub(ContainerInterface::class); $container->method('has')->willReturnMap([ ['twig', true], ['router', true], ['security.authorization_checker', true], ['security.token_storage', true], ['request_stack', true], ['parameter_bag', true], ['serializer', false], ]); $container->method('get')->willReturnMap([ ['twig', $twig], ['router', $router], ['security.authorization_checker', $this->createStub(AuthorizationCheckerInterface::class)], ['security.token_storage', $this->createStub(TokenStorageInterface::class)], ['request_stack', $stack], ['parameter_bag', $this->createStub(ParameterBagInterface::class)], ]); $controller->setContainer($container); return $controller; } // --------------------------------------------------------------- // search // --------------------------------------------------------------- public function testSearchReturnsEmptyWhenQueryBlank(): void { $controller = $this->buildController(); $request = new Request(['q' => '']); $response = $controller->search(1, $request); $this->assertInstanceOf(JsonResponse::class, $response); $this->assertSame(200, $response->getStatusCode()); $this->assertSame('[]', $response->getContent()); } public function testSearchReturnsMeilisearchResults(): void { $hits = [['id' => 1, 'invoiceNumber' => 'F-2026-001']]; $meilisearch = $this->createStub(MeilisearchService::class); $meilisearch->method('searchFactures')->willReturn($hits); $controller = $this->buildController(null, $meilisearch); $request = new Request(['q' => 'F-2026']); $response = $controller->search(1, $request); $this->assertInstanceOf(JsonResponse::class, $response); $this->assertSame(200, $response->getStatusCode()); $data = json_decode($response->getContent(), true); $this->assertCount(1, $data); $this->assertSame('F-2026-001', $data[0]['invoiceNumber']); } public function testSearchPassesCustomerIdFilter(): void { $meilisearch = $this->createMock(MeilisearchService::class); $meilisearch->expects($this->once()) ->method('searchFactures') ->with('test', 20, 42) ->willReturn([]); $controller = $this->buildController(null, $meilisearch); $request = new Request(['q' => 'test']); $response = $controller->search(42, $request); $this->assertInstanceOf(JsonResponse::class, $response); } // --------------------------------------------------------------- // send — facture with no PDF // --------------------------------------------------------------- public function testSendRedirectsWhenNoPdfGenerated(): void { $customer = $this->createStub(Customer::class); $customer->method('getId')->willReturn(5); $facture = $this->createStub(Facture::class); $facture->method('getFacturePdf')->willReturn(null); $facture->method('getCustomer')->willReturn($customer); $factureRepo = $this->createStub(EntityRepository::class); $factureRepo->method('find')->willReturn($facture); $em = $this->createStub(EntityManagerInterface::class); $em->method('getRepository')->willReturn($factureRepo); $controller = $this->buildController($em); $mailer = $this->createStub(\App\Service\MailerService::class); $twig = $this->createStub(Environment::class); $urlGenerator = $this->createStub(\Symfony\Component\Routing\Generator\UrlGeneratorInterface::class); $urlGenerator->method('generate')->willReturn('http://localhost/facture/verify/1/abc'); $response = $controller->send(1, $mailer, $twig, $urlGenerator, '/tmp'); $this->assertSame(302, $response->getStatusCode()); } public function testSendThrows404WhenFactureNotFound(): void { $factureRepo = $this->createStub(EntityRepository::class); $factureRepo->method('find')->willReturn(null); $em = $this->createStub(EntityManagerInterface::class); $em->method('getRepository')->willReturn($factureRepo); $controller = $this->buildController($em); $mailer = $this->createStub(\App\Service\MailerService::class); $twig = $this->createStub(Environment::class); $urlGenerator = $this->createStub(\Symfony\Component\Routing\Generator\UrlGeneratorInterface::class); $this->expectException(\Symfony\Component\HttpKernel\Exception\NotFoundHttpException::class); $controller->send(999, $mailer, $twig, $urlGenerator, '/tmp'); } // --------------------------------------------------------------- // generatePdf — 404 when facture not found // --------------------------------------------------------------- public function testGeneratePdfThrows404WhenFactureNotFound(): void { $factureRepo = $this->createStub(EntityRepository::class); $factureRepo->method('find')->willReturn(null); $em = $this->createStub(EntityManagerInterface::class); $em->method('getRepository')->willReturn($factureRepo); $controller = $this->buildController($em); $this->expectException(\Symfony\Component\HttpKernel\Exception\NotFoundHttpException::class); $controller->generatePdf( 999, $this->createStub(\Symfony\Component\HttpKernel\KernelInterface::class), $this->createStub(\Symfony\Component\Routing\Generator\UrlGeneratorInterface::class), $this->createStub(\Twig\Environment::class), ); } // --------------------------------------------------------------- // send — successful full path (pdf exists, customer has email) // --------------------------------------------------------------- public function testSendSuccessfully(): void { $customer = $this->createStub(\App\Entity\Customer::class); $customer->method('getId')->willReturn(5); $customer->method('getEmail')->willReturn('client@test.com'); $facture = $this->createStub(\App\Entity\Facture::class); $facture->method('getFacturePdf')->willReturn('facture-test.pdf'); $facture->method('getCustomer')->willReturn($customer); $facture->method('getInvoiceNumber')->willReturn('F-2026-001'); $facture->method('getId')->willReturn(1); $facture->method('getHmac')->willReturn('abc123'); $factureRepo = $this->createStub(EntityRepository::class); $factureRepo->method('find')->willReturn($facture); $em = $this->createMock(EntityManagerInterface::class); $em->method('getRepository')->willReturn($factureRepo); $em->expects($this->once())->method('flush'); $controller = $this->buildController($em); $mailer = $this->createStub(\App\Service\MailerService::class); $twig = $this->createStub(\Twig\Environment::class); $twig->method('render')->willReturn(''); $urlGenerator = $this->createStub(\Symfony\Component\Routing\Generator\UrlGeneratorInterface::class); $urlGenerator->method('generate')->willReturn('http://localhost/facture/verify/1/abc'); // projectDir points to a tmp dir where factures/ path won't exist (no attachment) $response = $controller->send(1, $mailer, $twig, $urlGenerator, sys_get_temp_dir()); $this->assertSame(302, $response->getStatusCode()); } public function testSendRedirectsWhenCustomerHasNoEmail(): void { $customer = $this->createStub(Customer::class); $customer->method('getId')->willReturn(5); $customer->method('getEmail')->willReturn(null); $facture = $this->createStub(Facture::class); $facture->method('getFacturePdf')->willReturn('facture.pdf'); $facture->method('getCustomer')->willReturn($customer); $factureRepo = $this->createStub(EntityRepository::class); $factureRepo->method('find')->willReturn($facture); $em = $this->createStub(EntityManagerInterface::class); $em->method('getRepository')->willReturn($factureRepo); $controller = $this->buildController($em); $mailer = $this->createStub(\App\Service\MailerService::class); $twig = $this->createStub(Environment::class); $urlGenerator = $this->createStub(\Symfony\Component\Routing\Generator\UrlGeneratorInterface::class); $response = $controller->send(1, $mailer, $twig, $urlGenerator, '/tmp'); $this->assertSame(302, $response->getStatusCode()); } }