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> $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()]) ; } }