renderForm(); $this->assertCount( count($this->definition()->getQuestions()) + count($this->busDefinition()->getQuestions()), $crawler->filter('[data-question-key]'), ); $this->assertSame( '{"question":"bus_feedback.bus_company","operator":"equals","value":"other"}', $crawler->filter('[data-question-key="bus_feedback.bus_company_other"]')->attr('data-show-if'), ); } public function testSectionsAreFieldsetsWithTheirTitle(): void { $crawler = $this->renderForm(); $this->assertSame('Organisation & Ablauf', trim($crawler->filter('fieldset legend')->first()->text())); $this->assertCount( count($this->definition()->sections) + count($this->busDefinition()->sections), $crawler->filter('fieldset'), ); } /** * On one page, each questionnaire keeps its own heading. */ public function testEachQuestionnaireHasItsHeading(): void { $headings = $this->renderForm()->filter('section > h2')->each(static fn (Crawler $h2): string => trim($h2->text())); $this->assertSame([$this->definition()->title, $this->busDefinition()->title], $headings); } /** * Long scales are selects, starting empty; Ja/Nein stays radios, each answer a clickable row. */ public function testLongScalesAreSelectsAndYesNoAreClickableRows(): void { $crawler = $this->renderForm(); $seminar = $crawler->filter('[data-question-key="teamer_feedback.team_week_seminar"] select'); $this->assertCount(1, $seminar); $this->assertSame('', $seminar->filter('option')->first()->attr('value')); $this->assertCount(1, $crawler->filter('[data-question-key="bus_feedback.wc"] select')); // the labels wrapping a radio: the whole row is the click target $rows = $crawler ->filter('[data-question-key="teamer_feedback.had_organisational_problems"] label') ->reduce(static fn (Crawler $label): bool => 1 === $label->filter('input[type="radio"]')->count()) ; $this->assertCount(2, $rows); $this->assertStringContainsString('hover:', $rows->first()->attr('class')); } public function testRatingIsFiveRadiosInARadioGroup(): void { $group = $this->renderForm()->filter('[data-question-key="teamer_feedback.office_briefing_rating"] [role="radiogroup"]'); $this->assertCount(5, $group->filter('input[type="radio"]')); } public function testAnswersShowLabelsNotKeysAndSkipHiddenQuestions(): void { $definition = $this->definition(); $response = QuestionnaireResponse::forDisposition($definition, new Disposition(new Application(new Assignment(), new Teamer()))) ->submit($definition, [ 'office_briefing_rating' => 2, 'office_briefing_low_reason' => 'Briefing kam zu spät', 'had_organisational_problems' => 'no', 'organisational_problems' => 'hidden, so dropped', ], [], new \DateTimeImmutable()) ; $html = $this->renderAnswers($definition, $response->getAnswers()); $this->assertStringContainsString('2 von 5', $html); $this->assertStringContainsString('Briefing kam zu spät', $html); $this->assertStringContainsString('Nein', $html); $this->assertStringNotContainsString('hidden, so dropped', $html); // nothing was answered there, so the section is left out $this->assertStringNotContainsString('Kommunikation & Zusammenarbeit', $html); $html = $this->renderAnswers($this->busDefinition(), ['bus_company' => 'heess']); $this->assertStringContainsString('Heeß', $html); $this->assertStringNotContainsString('heess', $html); } private function renderForm(): Crawler { self::bootKernel(); $container = self::getContainer(); $form = $container->get(FormFactoryInterface::class)->create(QuestionnaireType::class, [], [ 'definitions' => [$this->definition(), $this->busDefinition()], 'csrf_protection' => false, ]); $html = $container->get(Environment::class) ->createTemplate('{{ form(form) }}') ->render(['form' => $form->createView()]) ; return new Crawler($html); } private function renderAnswers(Definition $definition, array $answers): string { self::bootKernel(); return self::getContainer()->get(Environment::class)->render('questionnaire/_answers.html.twig', [ 'definition' => $definition, 'answers' => $answers, ]); } private function definition(): Definition { return new QuestionnaireCatalog(__DIR__.'/../../config/questionnaires')->get(QuestionnaireCatalog::TEAMER_FEEDBACK); } private function busDefinition(): Definition { return new QuestionnaireCatalog(__DIR__.'/../../config/questionnaires')->get(QuestionnaireCatalog::BUS_FEEDBACK); } }