185 lines
6.7 KiB
PHP
185 lines
6.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Tests\Controller\Admin\ApplicationFormSubmission;
|
|
|
|
use App\Entity\ApplicationFormSubmission;
|
|
use App\Entity\User;
|
|
use Doctrine\ORM\EntityManagerInterface;
|
|
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
|
|
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
|
|
/**
|
|
* Everything around the provisioning click that can be exercised without writing to BusPro.
|
|
*
|
|
* The write itself cannot: the teamer CRM selection is only changeable in the production database
|
|
* (.ddev/plans/buspro-crm-selection-write.md), and a POST that gets as far as the api client would
|
|
* open a socket to it from a test. TeamerProvisionerTest covers the flow against a mocked client;
|
|
* what is left here is the route, the confirmation and the one POST that is safe to make - a
|
|
* submission TeamerProvisioner refuses before it sends anything.
|
|
*/
|
|
class CreateTeamerControllerTest extends WebTestCase
|
|
{
|
|
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', ApplicationFormSubmission::class))->execute();
|
|
$this->entityManager->createQuery(sprintf('DELETE FROM %s', User::class))->execute();
|
|
|
|
$this->client->loginUser($this->reviewer());
|
|
}
|
|
|
|
public function testTheDetailPageOffersTheProvisioningButton(): void
|
|
{
|
|
$submission = $this->submission();
|
|
|
|
$crawler = $this->client->request(
|
|
'GET',
|
|
sprintf('/admin/application-form-submission/detail/%s', $submission->getUuid()),
|
|
['r' => rawurlencode('/admin/application-form-submission')]
|
|
);
|
|
|
|
$this->assertSame(Response::HTTP_OK, $this->client->getResponse()->getStatusCode());
|
|
|
|
$button = $crawler->filter('button[hx-get*="create-teamer"]');
|
|
|
|
$this->assertCount(1, $button);
|
|
// Like every other action on that page: it hands on the return url it was given, so "zurück"
|
|
// keeps pointing at the list.
|
|
$this->assertStringContainsString('r='.rawurlencode('/admin/application-form-submission'), (string) $button->attr('hx-get'));
|
|
}
|
|
|
|
/**
|
|
* The three writes cannot be undone from here, so the confirmation names what goes to BusPro
|
|
* rather than asking "are you sure".
|
|
*/
|
|
public function testTheConfirmationNamesWhatGoesToBusPro(): void
|
|
{
|
|
$crawler = $this->client->request('GET', $this->url($this->submission()));
|
|
|
|
$this->assertSame(Response::HTTP_OK, $this->client->getResponse()->getStatusCode());
|
|
|
|
$modal = $crawler->filter('#htmx-confirmation-modal')->text();
|
|
|
|
$this->assertStringContainsString('Anna Muster', $modal);
|
|
$this->assertStringContainsString('01.01.1990', $modal);
|
|
$this->assertStringContainsString('Musterstraße 1, 10115 Berlin', $modal);
|
|
}
|
|
|
|
/**
|
|
* A row from before the tightened endpoint contract. The confirmation says so before the
|
|
* reviewer clicks, because BusPro would answer the same thing only after the attempt.
|
|
*/
|
|
public function testTheConfirmationFlagsAnIncompleteSubmission(): void
|
|
{
|
|
$crawler = $this->client->request('GET', $this->url($this->incompleteSubmission()));
|
|
|
|
$modal = $crawler->filter('#htmx-confirmation-modal')->text();
|
|
|
|
$this->assertStringContainsString('ohne Geburtsdatum', $modal);
|
|
$this->assertStringContainsString('ohne Straße, PLZ und Ort', $modal);
|
|
}
|
|
|
|
/**
|
|
* The only POST a test may make: TeamerProvisioner refuses an unprovisionable submission before
|
|
* it touches the api client, so nothing here reaches BusPro. It covers what the reviewer
|
|
* actually sees when provisioning fails - the refusal's own wording, not "es ist ein Fehler
|
|
* aufgetreten".
|
|
*/
|
|
public function testAnUnprovisionableSubmissionFailsWithoutWritingAnything(): void
|
|
{
|
|
$submission = $this->incompleteSubmission();
|
|
|
|
$this->client->request('POST', $this->url($submission));
|
|
|
|
$response = $this->client->getResponse();
|
|
|
|
$this->assertSame(Response::HTTP_OK, $response->getStatusCode());
|
|
$this->assertStringContainsString('detail', (string) $response->headers->get('HX-Redirect'));
|
|
|
|
$flashes = $this->client->getRequest()->getSession()->getFlashBag()->peekAll();
|
|
|
|
$this->assertArrayHasKey('error', $flashes);
|
|
$this->assertStringContainsString('Geburtsdatum', $flashes['error'][0]);
|
|
|
|
$this->entityManager->clear();
|
|
$stored = $this->entityManager->getRepository(ApplicationFormSubmission::class)->find($submission->getId());
|
|
|
|
$this->assertNotNull($stored);
|
|
$this->assertFalse($stored->isProvisioned());
|
|
$this->assertNull($stored->getBusProAddressId());
|
|
$this->assertNull($stored->getUser());
|
|
}
|
|
|
|
private function url(ApplicationFormSubmission $submission): string
|
|
{
|
|
return sprintf('/admin/application-form-submission/create-teamer/%s', $submission->getUuid());
|
|
}
|
|
|
|
private function submission(): ApplicationFormSubmission
|
|
{
|
|
return $this->persist(
|
|
$this->newSubmission()
|
|
->setBirthDate('1990-01-01')
|
|
->setStreet('Musterstraße 1')
|
|
->setZipCode('10115')
|
|
->setCity('Berlin')
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Everything the contract now requires, missing - which only a row stored before it can be.
|
|
*/
|
|
private function incompleteSubmission(): ApplicationFormSubmission
|
|
{
|
|
return $this->persist($this->newSubmission()->setBirthDate('01.01.1990'));
|
|
}
|
|
|
|
private function newSubmission(): ApplicationFormSubmission
|
|
{
|
|
return (new ApplicationFormSubmission(
|
|
'applicationform',
|
|
'Bewerbungsformular',
|
|
new \DateTimeImmutable('2026-09-22T12:30:00+02:00'),
|
|
'F'
|
|
))
|
|
->setFirstName('Anna')
|
|
->setLastName('Muster')
|
|
->setEmail('[email protected]')
|
|
;
|
|
}
|
|
|
|
private function persist(ApplicationFormSubmission $submission): ApplicationFormSubmission
|
|
{
|
|
$this->entityManager->persist($submission);
|
|
$this->entityManager->flush();
|
|
|
|
return $submission;
|
|
}
|
|
|
|
private function reviewer(): User
|
|
{
|
|
$user = (new User())
|
|
->setFirstName('Rita')
|
|
->setLastName('Reviewer')
|
|
->setEmail('[email protected]')
|
|
->setRoles(['ROLE_TEAM_ADMIN'])
|
|
->setBusProAddressId(1)
|
|
->setBusProPersonId(1)
|
|
;
|
|
|
|
$this->entityManager->persist($user);
|
|
$this->entityManager->flush();
|
|
|
|
return $user;
|
|
}
|
|
}
|