Files
myep-team/tests/Config/QuestionnaireCompletenessTest.php
T

138 lines
6.9 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Tests\Config;
use App\Config\QuestionnaireCatalog;
use App\Entity\Application;
use App\Entity\Assignment;
use App\Entity\Disposition;
use App\Entity\Teamer;
use App\Service\Questionnaire\DispositionContext;
use PHPUnit\Framework\TestCase;
/**
* Every question of the two Google forms the questionnaires replace ("RL-Feedback 25-26" and
* "Bus-Feedback 25-26") is either asked or answered from the placement - none may get lost when
* a definition is edited.
*
* The lists below are the Google forms' questions in their order, with what each became:
* "question:<key>" is asked, "context:<field>" is taken from the disposition and snapshotted into
* the response (DispositionContext::build()). Google's "Bitte ankreuzen:" checkbox list was split
* into five single-choice questions, so it maps to five.
*/
class QuestionnaireCompletenessTest extends TestCase
{
private const array TEAMER_FEEDBACK = [
'Name' => ['context:teamerName'],
'Jobprofil' => ['context:jobProfileName'],
'Haus' => ['context:hotel'],
'Einsatzzeitraum (Anreisetag)' => ['context:dateFrom'],
'Wie gut hast du dich vorab vom Büro gebrieft gefühlt?' => ['question:office_briefing_rating'],
'Wenn 1 - 3 Sterne Bewertung, warum?' => ['question:office_briefing_low_reason'],
'War das Wochenteam-Seminar hilfreich für dich? Warst du bzw. wurdest du gut vorbereitet?' => ['question:team_week_seminar'],
'Wie gut lief die Reiseorganisation vor Ort?' => ['question:onsite_organisation_rating'],
'Gab es organisatorische Probleme?' => ['question:had_organisational_problems'],
'Wenn ja, welche?' => ['question:organisational_problems'],
'Wie lief die Kommunikation & Zusammenarbeit mit den E&P Teamer:innen vor Ort während der Reise?' => ['question:teamer_collaboration_rating'],
'Welche Unterstützung hättest du dir zusätzlich gewünscht?' => ['question:support_wished'],
'Wie ist deine Hausleitung mit Problemen vor Ort umgegangen?' => ['question:house_manager_problem_handling'],
'Gab es Momente, in denen du dich überfordert gefühlt hast?' => ['question:felt_overwhelmed'],
'Wenn ja, wodurch?' => ['question:overwhelmed_reason'],
'Was hättest du dir anders oder besser gewünscht?' => ['question:wished_differently'],
'Würdest du wieder als Reiseleitung für E&P arbeiten?' => ['question:would_work_again'],
'Wenn nein, warum nicht?' => ['question:would_not_work_again_reason'],
'Du hast nun schon vieles beantwortet, aber nirgendwo konntest du folgende Aspekte loswerden:' => ['question:anything_else'],
];
private const array BUS_FEEDBACK = [
'(Datum, ohne Titel)' => ['context:escortPickupDate', 'context:dateTo'],
'Hin- oder Rückfahrt' => ['question:direction'],
'Reiseziel:' => ['context:destinationProduct'],
'Bus-Unternehmen:' => ['question:bus_company'],
'Name des Busunternehmens:' => ['question:bus_company_other'],
'Busfahrer-Namen:' => ['question:driver_names'],
'Reiseleitung:' => ['context:teamerName'],
'1. Abfahrtsort' => ['context:escortPickup', 'context:hotel'],
'Bus pünktlich am 1. Abfahrtsort?' => ['question:on_time_at_first_pickup'],
'Wieviel Verspätung hatte der Bus am 1. Abfahrtsort?' => ['question:delay_at_first_pickup'],
'Gesamteindruck des Busses' => ['question:overall_impression'],
'Alter des Fahrzeugs' => ['question:vehicle_age'],
'Sitzkomfort im Bus' => ['question:seating_comfort'],
'Freundlichkeit der Fahrer' => ['question:driver_friendliness'],
'Pausenzeiten' => ['question:breaks'],
'Temperatur im Bus' => ['question:temperature'],
'Verhalten der Gäste im Bus' => ['question:guest_behaviour'],
'Waren den Fahrern alle Abfahrtsorte bekannt?' => ['question:drivers_knew_pickups'],
'Welche Abfahrtsorte waren nicht bekannt? Gab es dadurch Probleme?' => ['question:unknown_pickups'],
'War den Busfahrern der Zielort und die Ausladestelle bekannt?' => ['question:drivers_knew_destination'],
'Bitte ankreuzen:' => ['question:video', 'question:wc', 'question:luggage', 'question:smoking', 'question:snow_chains'],
'Entstanden während der Fahrt Schäden am Bus?' => ['question:bus_damage'],
'Was ist passiert?' => ['question:damage_description'],
'Das ging gar nicht / ist besonders hervorzuheben:' => ['question:bus_remarks'],
];
public function testEveryTeamerFeedbackQuestionIsAskedOrDerived(): void
{
$this->assertComplete(QuestionnaireCatalog::TEAMER_FEEDBACK, self::TEAMER_FEEDBACK);
}
public function testEveryBusFeedbackQuestionIsAskedOrDerived(): void
{
$this->assertComplete(QuestionnaireCatalog::BUS_FEEDBACK, self::BUS_FEEDBACK);
}
/**
* The Google forms had 19 and 24 questions; with the checkbox list split there are 43 places
* an answer comes from.
*/
public function testTheMappingCoversBothGoogleForms(): void
{
$this->assertCount(19, self::TEAMER_FEEDBACK);
$this->assertCount(24, self::BUS_FEEDBACK);
}
/**
* A bus escort answers every question of both forms; anyone else every question of the
* teamer form.
*/
public function testABusEscortGetsBothQuestionnairesAndEveryoneTheTeamerOne(): void
{
$this->assertSame(
[QuestionnaireCatalog::TEAMER_FEEDBACK, QuestionnaireCatalog::BUS_FEEDBACK],
DispositionContext::questionnaires((new Assignment())->setPickup(4711)),
);
$this->assertSame(
[QuestionnaireCatalog::TEAMER_FEEDBACK],
DispositionContext::questionnaires((new Assignment())->setPickup(0)),
);
}
/**
* @param array<string, list<string>> $googleQuestions
*/
private function assertComplete(string $questionnaire, array $googleQuestions): void
{
$definition = new QuestionnaireCatalog(__DIR__.'/../../config/questionnaires')->get($questionnaire);
$contextFields = array_keys(DispositionContext::build(new Disposition(new Application(new Assignment(), new Teamer()))));
$mapped = [];
foreach ($googleQuestions as $label => $targets) {
foreach ($targets as $target) {
[$kind, $key] = explode(':', $target);
if ('question' === $kind) {
$this->assertNotNull($definition->getQuestion($key), sprintf('"%s" is not asked as "%s"', $label, $key));
$mapped[] = $key;
} else {
$this->assertContains($key, $contextFields, sprintf('"%s" is not snapshotted as "%s"', $label, $key));
}
}
}
// and nothing is asked that the Google form did not ask
$this->assertSame([], array_values(array_diff(array_keys($definition->getQuestions()), $mapped)));
}
}