feat: order and format the pickup fields
This commit is contained in:
1 parent
8da9af46f5
commit
392e67448e
9 files changed
+746
-21
No files matched your search
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Form;
|
||||
|
||||
use App\Entity\Destination;
|
||||
use App\Service\Common\PickupOptions;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\FormFactoryInterface;
|
||||
use Twig\Environment;
|
||||
|
||||
/**
|
||||
* Renders the radio list the way the assignment form does, because the parts that break here
|
||||
* only break at render time: templates/forms.html.twig reads the departure and the street off
|
||||
* each choice, twig runs with strict_variables, and the "Keine Busbegleitung" placeholder is a
|
||||
* choice that carries neither.
|
||||
*/
|
||||
class PickupChoiceWidgetTest extends KernelTestCase
|
||||
{
|
||||
public function testEveryBoardingPointIsRenderedWithItsTimeAndStreet(): void
|
||||
{
|
||||
$html = $this->render([
|
||||
['busProId' => 74, 'city' => 'Stuttgart', 'street' => 'Flughafen (Busterminal)', 'time' => '03:15'],
|
||||
['busProId' => 673, 'city' => 'Stuttgart', 'street' => 'Schelmenwasenstr. 15', 'time' => '03:15'],
|
||||
]);
|
||||
|
||||
$this->assertSame(3, substr_count($html, 'type="radio"'), 'two boarding points plus the placeholder');
|
||||
$this->assertSame(2, substr_count($html, '>Stuttgart<'));
|
||||
$this->assertStringContainsString('Flughafen (Busterminal)', $html);
|
||||
$this->assertStringContainsString('Schelmenwasenstr. 15', $html);
|
||||
$this->assertSame(2, substr_count($html, '03:15 Uhr'));
|
||||
}
|
||||
|
||||
public function testThePlaceholderRendersWithoutADepartureOrStreet(): void
|
||||
{
|
||||
$html = $this->render([
|
||||
['busProId' => 4, 'city' => 'Karlsruhe', 'street' => 'A5 - Autohof', 'time' => '23:59'],
|
||||
]);
|
||||
|
||||
$this->assertStringContainsString('Keine Busbegleitung', $html);
|
||||
// one time only: the placeholder must not pick up the boarding point's
|
||||
$this->assertSame(1, substr_count($html, 'Uhr'));
|
||||
}
|
||||
|
||||
public function testAFullDateInTheSourceIsRenderedAsAClock(): void
|
||||
{
|
||||
$html = $this->render([
|
||||
['busProId' => 1, 'city' => 'Hannover', 'street' => 'ZOB', 'time' => '08.03.2024 20:45:00'],
|
||||
]);
|
||||
|
||||
$this->assertStringContainsString('20:45 Uhr', $html);
|
||||
$this->assertStringNotContainsString('08.03.2024', $html);
|
||||
}
|
||||
|
||||
public function testABoardingPointWithoutATimeOrStreetStillRenders(): void
|
||||
{
|
||||
$html = $this->render([
|
||||
['busProId' => 4711, 'city' => null, 'street' => null, 'time' => null],
|
||||
]);
|
||||
|
||||
$this->assertStringContainsString('Zustieg 4711', $html);
|
||||
$this->assertStringNotContainsString('Uhr', $html);
|
||||
}
|
||||
|
||||
public function testWithoutADestinationTheFieldExplainsItselfInsteadOfShowingAnEmptySelect(): void
|
||||
{
|
||||
$html = $this->render([], 'Bitte erst eine Destination wählen …');
|
||||
|
||||
$this->assertStringContainsString('Bitte erst eine Destination wählen', $html);
|
||||
$this->assertStringNotContainsString('type="radio"', $html);
|
||||
}
|
||||
|
||||
public function testADestinationWithoutBoardingPointsSaysSoInstead(): void
|
||||
{
|
||||
// 1271 of 2267 destinations carry no boarding points at all
|
||||
$html = $this->render([], 'Für diese Destination sind keine Zustiege hinterlegt.');
|
||||
|
||||
$this->assertStringContainsString('keine Zustiege hinterlegt', $html);
|
||||
$this->assertStringNotContainsString('type="radio"', $html);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<array<string, mixed>> $pickups
|
||||
*/
|
||||
private function render(array $pickups, string $emptyText = 'Keine Zustiege verfügbar.'): string
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
$options = PickupOptions::inDepartureOrder((new Destination())->setPickups($pickups));
|
||||
$labels = array_column($options, 'label', 'busProId');
|
||||
$attributes = [];
|
||||
|
||||
foreach ($options as $option) {
|
||||
$attributes[$option['busProId']] = [
|
||||
'data-departure' => $option['departure'] ?? '',
|
||||
'data-street' => $option['street'] ?? '',
|
||||
];
|
||||
}
|
||||
|
||||
/** @var FormFactoryInterface $formFactory */
|
||||
$formFactory = self::getContainer()->get('form.factory');
|
||||
$form = $formFactory->createNamed('pickup', ChoiceType::class, null, [
|
||||
'label' => 'Busbegleitung ab',
|
||||
'required' => false,
|
||||
'placeholder' => 'Keine Busbegleitung',
|
||||
'choices' => array_column($options, 'busProId'),
|
||||
'choice_label' => static fn (int $busProId): string => $labels[$busProId],
|
||||
'choice_attr' => static fn (int $busProId): array => $attributes[$busProId],
|
||||
'expanded' => true,
|
||||
'block_prefix' => 'pickup_choice',
|
||||
'attr' => ['data-empty-text' => $emptyText],
|
||||
// a bare field rendered outside a request, so there is no session to hold a token
|
||||
'csrf_protection' => false,
|
||||
]);
|
||||
|
||||
/** @var Environment $twig */
|
||||
$twig = self::getContainer()->get('twig');
|
||||
|
||||
return $twig
|
||||
->createTemplate('{{ form_widget(form) }}')
|
||||
->render(['form' => $form->createView()])
|
||||
;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user