155 lines
5.9 KiB
PHP
155 lines
5.9 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Tests\Twig;
|
|
|
|
use App\Config\QuestionnaireCatalog;
|
|
use App\Entity\Application;
|
|
use App\Entity\Assignment;
|
|
use App\Entity\Disposition;
|
|
use App\Entity\QuestionnaireResponse;
|
|
use App\Entity\Teamer;
|
|
use App\Form\QuestionnaireType;
|
|
use App\Model\Questionnaire\Definition;
|
|
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
|
use Symfony\Component\DomCrawler\Crawler;
|
|
use Symfony\Component\Form\FormFactoryInterface;
|
|
use Twig\Environment;
|
|
|
|
/**
|
|
* The questionnaire's form-theme blocks and the read-only answers partial, rendered for real:
|
|
* a misspelt block prefix silently falls back to Symfony's default markup, which would drop the
|
|
* data attributes the show/hide controller needs.
|
|
*/
|
|
class QuestionnaireTemplateTest extends KernelTestCase
|
|
{
|
|
public function testEveryQuestionRowCarriesItsKeyAndConditionalOnesTheirCondition(): void
|
|
{
|
|
$crawler = $this->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);
|
|
}
|
|
}
|