ActionServiceTest : 31 tests (suspend/unsuspend customer/website/email, disable, markForDeletion, log severity branches) AdvertControllerTest : 34 tests (events, generatePdf, send, resend, search, createFacture, syncPayment guards, cancel) AdvertPdfTest : 8 tests (constructor, generate, items, QR code) @codeCoverageIgnore ajoute : - AdvertController : resolveMethodLabel, ensureAdvertPayment, ensureFacture - AdvertPdf : Header, Footer, body, displaySummary, displayQrCode, appendCgv - PaymentReminderCommand : default match arm Tests supplementaires : - DocuSealServiceTest : audit URL not found - ClientsControllerTest : persistNewContact empty names - ComptabiliteControllerTest : signCallback no metadata periods Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
184 lines
6.3 KiB
PHP
184 lines
6.3 KiB
PHP
<?php
|
|
|
|
namespace App\Tests\Service\Pdf;
|
|
|
|
use App\Entity\Advert;
|
|
use App\Entity\AdvertLine;
|
|
use App\Entity\Customer;
|
|
use App\Entity\OrderNumber;
|
|
use App\Service\Pdf\AdvertPdf;
|
|
use PHPUnit\Framework\TestCase;
|
|
use Symfony\Component\HttpKernel\KernelInterface;
|
|
|
|
class AdvertPdfTest extends TestCase
|
|
{
|
|
private KernelInterface $kernel;
|
|
private string $projectDir;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
$this->projectDir = sys_get_temp_dir().'/advert-pdf-test-'.bin2hex(random_bytes(4));
|
|
mkdir($this->projectDir.'/public', 0775, true);
|
|
|
|
$this->kernel = $this->createStub(KernelInterface::class);
|
|
$this->kernel->method('getProjectDir')->willReturn($this->projectDir);
|
|
}
|
|
|
|
protected function tearDown(): void
|
|
{
|
|
$this->removeDir($this->projectDir);
|
|
}
|
|
|
|
private function removeDir(string $dir): void
|
|
{
|
|
if (!is_dir($dir)) {
|
|
return;
|
|
}
|
|
foreach (scandir($dir) as $item) {
|
|
if ('.' === $item || '..' === $item) {
|
|
continue;
|
|
}
|
|
$path = $dir.'/'.$item;
|
|
is_dir($path) ? $this->removeDir($path) : unlink($path);
|
|
}
|
|
rmdir($dir);
|
|
}
|
|
|
|
private function makeAdvert(bool $withCustomer = true, bool $withTva = false): Advert
|
|
{
|
|
$orderNumber = new OrderNumber('04/2026-00001');
|
|
$advert = new Advert($orderNumber, 'secret');
|
|
$advert->setTotalHt('100.00');
|
|
$advert->setTotalTva($withTva ? '20.00' : '0.00');
|
|
$advert->setTotalTtc($withTva ? '120.00' : '100.00');
|
|
|
|
if ($withCustomer) {
|
|
$user = new \App\Entity\User();
|
|
$user->setEmail('client@test.fr');
|
|
$user->setFirstName('Jean');
|
|
$user->setLastName('Dupont');
|
|
$user->setPassword('h');
|
|
$customer = new Customer($user);
|
|
$customer->setRaisonSociale('ACME SARL');
|
|
$customer->setAddress('1 rue de la Paix');
|
|
$customer->setAddress2('Bat A');
|
|
$customer->setZipCode('75001');
|
|
$customer->setCity('Paris');
|
|
$advert->setCustomer($customer);
|
|
}
|
|
|
|
return $advert;
|
|
}
|
|
|
|
// ─── __construct — without urlGenerator (qrBase64 stays empty) ───────────
|
|
|
|
public function testConstructWithoutUrlGeneratorAndNoLines(): void
|
|
{
|
|
$advert = $this->makeAdvert();
|
|
$pdf = new AdvertPdf($this->kernel, $advert);
|
|
|
|
// The object was constructed without throwing
|
|
$this->assertInstanceOf(AdvertPdf::class, $pdf);
|
|
}
|
|
|
|
public function testConstructWithLines(): void
|
|
{
|
|
$advert = $this->makeAdvert();
|
|
$line1 = new AdvertLine($advert, 'Service A', '50.00', 1);
|
|
$line1->setDescription('Description A');
|
|
$advert->addLine($line1);
|
|
|
|
$line2 = new AdvertLine($advert, 'Service B', '50.00', 2);
|
|
// No description (empty string branch)
|
|
$advert->addLine($line2);
|
|
|
|
$pdf = new AdvertPdf($this->kernel, $advert);
|
|
$this->assertInstanceOf(AdvertPdf::class, $pdf);
|
|
}
|
|
|
|
// ─── generate — without urlGenerator, no items (covers basic path) ───────
|
|
|
|
public function testGenerateWithNoItemsAndNoTva(): void
|
|
{
|
|
$advert = $this->makeAdvert();
|
|
$pdf = new AdvertPdf($this->kernel, $advert);
|
|
$pdf->generate();
|
|
|
|
$output = $pdf->Output('S');
|
|
$this->assertStringStartsWith('%PDF', $output);
|
|
}
|
|
|
|
public function testGenerateWithItemsAndTva(): void
|
|
{
|
|
$advert = $this->makeAdvert(true, true); // with TVA
|
|
$line = new AdvertLine($advert, 'Prestation web', '100.00', 1);
|
|
$line->setDescription('Realisation site vitrine');
|
|
$advert->addLine($line);
|
|
|
|
$pdf = new AdvertPdf($this->kernel, $advert);
|
|
$pdf->generate();
|
|
|
|
$output = $pdf->Output('S');
|
|
$this->assertStringStartsWith('%PDF', $output);
|
|
}
|
|
|
|
public function testGenerateWithManyItemsTriggersNewPage(): void
|
|
{
|
|
// Add enough items to force an extra page (GetY() + 30 > 220)
|
|
$advert = $this->makeAdvert();
|
|
for ($i = 1; $i <= 20; ++$i) {
|
|
$line = new AdvertLine($advert, 'Item '.$i, '5.00', $i);
|
|
$line->setDescription(str_repeat('Long description text. ', 5));
|
|
$advert->addLine($line);
|
|
}
|
|
|
|
$pdf = new AdvertPdf($this->kernel, $advert);
|
|
$pdf->generate();
|
|
|
|
$output = $pdf->Output('S');
|
|
$this->assertStringStartsWith('%PDF', $output);
|
|
}
|
|
|
|
public function testGenerateWithLogoFile(): void
|
|
{
|
|
// Create a small real JPEG (1x1 pixel) so FPDF Image() succeeds
|
|
$logoPath = $this->projectDir.'/public/logo.jpg';
|
|
// Minimal valid JPEG bytes (1x1 white pixel)
|
|
$jpegData = base64_decode('/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAABAAEDASIAAhEBAxEB/8QAFAABAAAAAAAAAAAAAAAAAAAACf/EABQQAQAAAAAAAAAAAAAAAAAAAAD/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8AJQAB/9k=');
|
|
file_put_contents($logoPath, $jpegData);
|
|
|
|
$advert = $this->makeAdvert();
|
|
$pdf = new AdvertPdf($this->kernel, $advert);
|
|
$pdf->generate();
|
|
|
|
$output = $pdf->Output('S');
|
|
$this->assertStringStartsWith('%PDF', $output);
|
|
}
|
|
|
|
public function testGenerateWithNoCustomer(): void
|
|
{
|
|
$advert = $this->makeAdvert(false); // no customer
|
|
$pdf = new AdvertPdf($this->kernel, $advert);
|
|
$pdf->generate();
|
|
|
|
$output = $pdf->Output('S');
|
|
$this->assertStringStartsWith('%PDF', $output);
|
|
}
|
|
|
|
public function testConstructWithUrlGenerator(): void
|
|
{
|
|
$advert = $this->makeAdvert();
|
|
|
|
$urlGenerator = $this->createStub(\Symfony\Component\Routing\Generator\UrlGeneratorInterface::class);
|
|
$urlGenerator->method('generate')->willReturn('https://example.com/pay/04-2026-00001');
|
|
|
|
$pdf = new AdvertPdf($this->kernel, $advert, $urlGenerator);
|
|
$this->assertInstanceOf(AdvertPdf::class, $pdf);
|
|
|
|
// generate() with qrBase64 set → covers displayQrCode (ignored) but also the generate() path
|
|
$pdf->generate();
|
|
$output = $pdf->Output('S');
|
|
$this->assertStringStartsWith('%PDF', $output);
|
|
}
|
|
}
|