174 lines
6.4 KiB
PHP
174 lines
6.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Tests\Controller\Administrative\System\Document;
|
|
|
|
use App\Config\SeasonTask;
|
|
use App\Entity\SeasonTaskDocument;
|
|
use App\Entity\Upload;
|
|
use App\Entity\User;
|
|
use Doctrine\ORM\EntityManagerInterface;
|
|
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
|
|
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
|
|
/**
|
|
* A library document handed out for a season task is held by a NOT NULL foreign key. Deleting it
|
|
* used to end in a 500 that htmx swallowed, so the modal just stayed open; it now has to be
|
|
* refused before it reaches the database.
|
|
*/
|
|
class DeleteControllerTest extends WebTestCase
|
|
{
|
|
private const LIST_URL = '/administrative/system/document';
|
|
|
|
private KernelBrowser $client;
|
|
|
|
private EntityManagerInterface $entityManager;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
$this->client = static::createClient(server: ['HTTPS' => true]);
|
|
$this->entityManager = self::getContainer()->get(EntityManagerInterface::class);
|
|
|
|
$this->entityManager->createQuery(sprintf('DELETE FROM %s', SeasonTaskDocument::class))->execute();
|
|
$this->entityManager->createQuery(sprintf('DELETE FROM %s', Upload::class))->execute();
|
|
$this->entityManager->createQuery(sprintf('DELETE FROM %s', User::class))->execute();
|
|
|
|
$this->client->loginUser($this->administrative());
|
|
}
|
|
|
|
/**
|
|
* The mapping holds a foreign key on upload; left behind, it breaks every later test that
|
|
* clears the upload table.
|
|
*/
|
|
protected function tearDown(): void
|
|
{
|
|
$this->entityManager->createQuery(sprintf('DELETE FROM %s', SeasonTaskDocument::class))->execute();
|
|
|
|
parent::tearDown();
|
|
}
|
|
|
|
public function testTheModalOffersNoConfirmationForAnAssignedDocument(): void
|
|
{
|
|
$document = $this->assigned($this->document('Vertrag.pdf'), SeasonTask::CONTRACT);
|
|
|
|
$crawler = $this->client->request('GET', $this->deleteUrl($document));
|
|
|
|
$this->assertSame(Response::HTTP_OK, $this->client->getResponse()->getStatusCode());
|
|
$this->assertStringContainsString('kann deshalb nicht gelöscht werden', $crawler->text());
|
|
$this->assertStringContainsString('Vertrag', $crawler->text());
|
|
$this->assertCount(0, $crawler->filter('button[hx-post]'));
|
|
}
|
|
|
|
public function testDeletingAnAssignedDocumentIsRefused(): void
|
|
{
|
|
$document = $this->assigned($this->document('Vertrag.pdf'), SeasonTask::CONTRACT);
|
|
$id = $document->getId();
|
|
|
|
$this->client->request('POST', $this->deleteUrl($document));
|
|
|
|
$this->assertSame(Response::HTTP_OK, $this->client->getResponse()->getStatusCode());
|
|
$this->assertSame(self::LIST_URL, $this->client->getResponse()->headers->get('HX-Redirect'));
|
|
|
|
$this->entityManager->clear();
|
|
$this->assertNotNull($this->entityManager->find(Upload::class, $id));
|
|
}
|
|
|
|
/**
|
|
* A row whose task key no longer resolves still holds the foreign key.
|
|
*/
|
|
public function testAnAssignmentToARemovedTaskStillBlocksDeletion(): void
|
|
{
|
|
$document = $this->document('Alt.pdf');
|
|
$this->entityManager->persist((new SeasonTaskDocument())->setTaskKey('removed_task')->setDocument($document));
|
|
$this->entityManager->flush();
|
|
$id = $document->getId();
|
|
|
|
$this->client->request('POST', $this->deleteUrl($document));
|
|
|
|
// Refused by the guard, not by the database: that would be the 500.
|
|
$this->assertSame(self::LIST_URL, $this->client->getResponse()->headers->get('HX-Redirect'));
|
|
|
|
$this->entityManager->clear();
|
|
$this->assertNotNull($this->entityManager->find(Upload::class, $id));
|
|
}
|
|
|
|
public function testAnUnassignedDocumentIsDeleted(): void
|
|
{
|
|
$document = $this->document('Handbuch.pdf');
|
|
$id = $document->getId();
|
|
|
|
$crawler = $this->client->request('GET', $this->deleteUrl($document));
|
|
$this->assertCount(1, $crawler->filter('button[hx-post]'));
|
|
|
|
$this->client->request('POST', $this->deleteUrl($document));
|
|
|
|
$this->assertSame(self::LIST_URL, $this->client->getResponse()->headers->get('HX-Redirect'));
|
|
|
|
$this->entityManager->clear();
|
|
$this->assertNull($this->entityManager->find(Upload::class, $id));
|
|
}
|
|
|
|
public function testTheListMarksAnAssignedDocumentAndOffersNoDelete(): void
|
|
{
|
|
$assigned = $this->assigned($this->document('Vertrag.pdf'), SeasonTask::CONTRACT);
|
|
$free = $this->document('Handbuch.pdf');
|
|
|
|
$crawler = $this->client->request('GET', self::LIST_URL);
|
|
|
|
$this->assertSame(Response::HTTP_OK, $this->client->getResponse()->getStatusCode());
|
|
$this->assertStringContainsString('Saisonteam: Vertrag', $crawler->text());
|
|
$this->assertCount(0, $crawler->filter(sprintf('button[hx-get="%s"]', $this->deleteUrl($assigned))));
|
|
$this->assertCount(1, $crawler->filter(sprintf('button[hx-get="%s"]', $this->deleteUrl($free))));
|
|
}
|
|
|
|
private function deleteUrl(Upload $document): string
|
|
{
|
|
return sprintf('/administrative/system/document/delete/%s', $document->getUuid());
|
|
}
|
|
|
|
private function assigned(Upload $document, SeasonTask $task): Upload
|
|
{
|
|
$this->entityManager->persist((new SeasonTaskDocument())->setTaskKey($task->value)->setDocument($document));
|
|
$this->entityManager->flush();
|
|
|
|
return $document;
|
|
}
|
|
|
|
private function document(string $filename): Upload
|
|
{
|
|
// No file on disk: neither the guard nor the list reads it, and deleting a missing file
|
|
// is a no-op for UploadHandler::removeUploadedFile().
|
|
$upload = (new Upload())
|
|
->setType(Upload::TYPE_DOCUMENT)
|
|
->setFilename(sprintf('test-%s-%s', bin2hex(random_bytes(4)), $filename))
|
|
->setOriginalFilename($filename)
|
|
->setMimeType('application/pdf')
|
|
->setSize(1024)
|
|
;
|
|
|
|
$this->entityManager->persist($upload);
|
|
$this->entityManager->flush();
|
|
|
|
return $upload;
|
|
}
|
|
|
|
private function administrative(): User
|
|
{
|
|
$user = (new User())
|
|
->setFirstName('Anna')
|
|
->setLastName('Administrative')
|
|
->setEmail('[email protected]')
|
|
->setRoles(['ROLE_ADMINISTRATIVE'])
|
|
->setBusProAddressId(1)
|
|
->setBusProPersonId(1)
|
|
;
|
|
|
|
$this->entityManager->persist($user);
|
|
$this->entityManager->flush();
|
|
|
|
return $user;
|
|
}
|
|
}
|