provider = new CreateFieldStateProvider(new ParticipantEligibilityChecker( new ServiceAgeEvaluator(), new ServiceAvailabilityCalculator() )); } public function testDependentInsuranceFieldHidesWhenApplicantSelectsFamilyInsuranceThenReappearsAfterSwitch(): void { $travel = new Travel(); $travel->dateFrom = new \DateTimeImmutable('+30 days'); $travel->dateTo = new \DateTimeImmutable('+37 days'); $applicant = new ParticipantDto(); $applicant->index = 0; // Baby age (0-2 years at travel date) is always eligible regardless of skipass availability $applicant->dateOfBirth = $travel->dateFrom->modify('-1 year'); $dependent = new ParticipantDto(); $dependent->index = 1; $dependent->dateOfBirth = $travel->dateFrom->modify('-1 year'); $bookingDto = new BookingDto($travel, 1); $bookingDto->participants = [$applicant, $dependent]; $this->assertTrue( $this->provider->shouldIncludeField('insurance', $bookingDto, 1), 'Dependent should see their own insurance field before the applicant selects family insurance' ); $familyInsurance = new Insurance(); $familyInsurance->familyInsurance = true; $applicant->insurance = $familyInsurance; $this->assertFalse( $this->provider->shouldIncludeField('insurance', $bookingDto, 1), 'Dependent insurance field must be hidden once the applicant selects family insurance' ); $nonFamilyInsurance = new Insurance(); $nonFamilyInsurance->familyInsurance = false; $applicant->insurance = $nonFamilyInsurance; $this->assertTrue( $this->provider->shouldIncludeField('insurance', $bookingDto, 1), 'Dependent insurance field must reappear once the applicant switches away from family insurance' ); } public function testEmailIsNotRequiredForNonApplicantChild(): void { $bookingDto = $this->createBookingDtoWithApplicantAndDependent(new \DateTimeImmutable('2015-01-01')); $this->assertFalse( $this->provider->getFieldState('email', $bookingDto, 1)['required'], 'A child travelling with an applicant does not need an email address of their own' ); } public function testEmailIsRequiredForNonApplicantAdult(): void { $bookingDto = $this->createBookingDtoWithApplicantAndDependent(new \DateTimeImmutable('1990-01-01')); $this->assertTrue($this->provider->getFieldState('email', $bookingDto, 1)['required']); } public function testEmailIsRequiredForTheApplicantEvenAsAChild(): void { $bookingDto = $this->createBookingDtoWithApplicantAndDependent(new \DateTimeImmutable('2015-01-01')); $bookingDto->participants[0]->dateOfBirth = new \DateTimeImmutable('2015-01-01'); $this->assertTrue( $this->provider->getFieldState('email', $bookingDto, 0)['required'], 'The applicant is the booking contact and always has to be reachable' ); } public function testEmailIsRequiredWhenDateOfBirthIsUnknown(): void { $bookingDto = $this->createBookingDtoWithApplicantAndDependent(new \DateTimeImmutable('2015-01-01')); $bookingDto->participants[1]->dateOfBirth = null; $this->assertTrue( $this->provider->getFieldState('email', $bookingDto, 1)['required'], 'An unknown age counts as an adult' ); } public function testEmailRequirementFlipsWhenDateOfBirthChanges(): void { $bookingDto = $this->createBookingDtoWithApplicantAndDependent(new \DateTimeImmutable('2015-01-01')); $dependent = $bookingDto->participants[1]; $this->assertFalse($this->provider->getFieldState('email', $bookingDto, 1)['required']); $dependent->dateOfBirth = new \DateTimeImmutable('1990-01-01'); $this->assertTrue( $this->provider->getFieldState('email', $bookingDto, 1)['required'], 'Correcting a child date of birth to an adult one must reinstate the requirement' ); } /** * Guards the switch from add-only to toggling 'required' state: the two fields that already * used a 'required' condition must keep behaving exactly as before, now reporting false * instead of omitting the key. Both declare 'required' => false as their base in the form * type, so assigning the condition result either way is equivalent to the old add-only pass. */ public function testMobileAndAddressRemainRequiredOnlyForTheFirstParticipant(): void { $bookingDto = $this->createBookingDtoWithApplicantAndDependent(new \DateTimeImmutable('1990-01-01')); $this->assertTrue($this->provider->getFieldState('mobile', $bookingDto, 0)['required']); $this->assertFalse($this->provider->getFieldState('mobile', $bookingDto, 1)['required']); $this->assertTrue($this->provider->getFieldState('address', $bookingDto, 0)['required']); $this->assertFalse($this->provider->getFieldState('address', $bookingDto, 1)['required']); } private function createBookingDtoWithApplicantAndDependent(\DateTimeImmutable $dependentDateOfBirth): BookingDto { $travel = new Travel(); $travel->dateFrom = new \DateTimeImmutable('+30 days'); $travel->dateTo = new \DateTimeImmutable('+37 days'); $applicant = new ParticipantDto(); $applicant->index = 0; $applicant->dateOfBirth = new \DateTimeImmutable('1980-01-01'); $dependent = new ParticipantDto(); $dependent->index = 1; $dependent->dateOfBirth = $dependentDateOfBirth; $bookingDto = new BookingDto($travel, 1); $bookingDto->participants = [$applicant, $dependent]; return $bookingDto; } }