Files
myep/tests/Form/Service/ParticipantFieldOptionsProviderMandatoryServiceTest.php
T
2026-03-16 20:24:58 +01:00

153 lines
5.7 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Tests\Form\Service;
use App\BusProNet\Constants;
use App\BusProNet\Model\Service;
use App\BusProNet\Model\Travel;
use App\Form\Model\BookingDto;
use App\Form\Model\ParticipantDto;
use App\Form\Service\ParticipantFieldOptionsProvider;
use App\Service\BookingPriceCalculatorService;
use App\Service\InsuranceService;
use App\Service\ServiceAvailabilityCalculator;
use PHPUnit\Framework\TestCase;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* Tests that mandatory services in choice_attr are only locked (readonly)
* when actually selected in the participant's DTO, preventing incorrect
* force-locking after age-related service changes.
*/
class ParticipantFieldOptionsProviderMandatoryServiceTest extends TestCase
{
private ParticipantFieldOptionsProvider $provider;
protected function setUp(): void
{
$serviceAvailabilityCalculator = $this->createMock(ServiceAvailabilityCalculator::class);
$insuranceService = $this->createMock(InsuranceService::class);
$priceCalculatorService = $this->createMock(BookingPriceCalculatorService::class);
$translator = $this->createMock(TranslatorInterface::class);
$this->provider = new ParticipantFieldOptionsProvider(
$serviceAvailabilityCalculator,
$insuranceService,
$priceCalculatorService,
$translator
);
}
public function testMandatoryServiceSelectedHasReadonlyAndTooltip(): void
{
$mandatoryService = $this->createMandatoryService(1, 'Ortstaxe');
$travel = $this->createTravelWithAdditionalServices([$mandatoryService]);
$bookingDto = new BookingDto($travel, 1);
$participant = new ParticipantDto();
$participant->index = 0;
$participant->dateOfBirth = $travel->dateFrom->modify('-25 years');
$participant->additionalServices = [$mandatoryService];
$bookingDto->participants[0] = $participant;
$options = $this->provider->getFieldOptions('additionalServices', $bookingDto, 0);
$choiceAttr = $options['choice_attr'];
$attributes = $choiceAttr($mandatoryService);
$this->assertTrue($attributes['readonly']);
$this->assertSame('Diese Leistung ist nicht abwählbar', $attributes['data-tooltip']);
$this->assertArrayNotHasKey('checked', $attributes);
}
public function testMandatoryServiceNotSelectedHasNoReadonlyOrChecked(): void
{
$mandatoryService = $this->createMandatoryService(1, 'Ortstaxe');
$travel = $this->createTravelWithAdditionalServices([$mandatoryService]);
$bookingDto = new BookingDto($travel, 1);
$participant = new ParticipantDto();
$participant->index = 0;
$participant->dateOfBirth = $travel->dateFrom->modify('-25 years');
$participant->additionalServices = [];
$bookingDto->participants[0] = $participant;
$options = $this->provider->getFieldOptions('additionalServices', $bookingDto, 0);
$choiceAttr = $options['choice_attr'];
$attributes = $choiceAttr($mandatoryService);
$this->assertArrayNotHasKey('readonly', $attributes);
$this->assertArrayNotHasKey('checked', $attributes);
$this->assertArrayNotHasKey('data-tooltip', $attributes);
}
public function testNonMandatoryServiceUnaffected(): void
{
$nonMandatoryService = new Service();
$nonMandatoryService->id = 2;
$nonMandatoryService->label = 'Keycard-Pfand';
$nonMandatoryService->subType = Constants::TOKEN_ADDITIONAL;
$nonMandatoryService->available = 10;
$nonMandatoryService->price = 10.0;
$nonMandatoryService->mandatory = false;
$nonMandatoryService->autoBook = true;
$travel = $this->createTravelWithAdditionalServices([$nonMandatoryService]);
$bookingDto = new BookingDto($travel, 1);
$participant = new ParticipantDto();
$participant->index = 0;
$participant->dateOfBirth = $travel->dateFrom->modify('-25 years');
$participant->additionalServices = [$nonMandatoryService];
$bookingDto->participants[0] = $participant;
$options = $this->provider->getFieldOptions('additionalServices', $bookingDto, 0);
$choiceAttr = $options['choice_attr'];
$attributes = $choiceAttr($nonMandatoryService);
$this->assertArrayNotHasKey('readonly', $attributes);
$this->assertArrayNotHasKey('checked', $attributes);
}
public function testNullParticipantReturnsEmptyOptions(): void
{
$mandatoryService = $this->createMandatoryService(1, 'Ortstaxe');
$travel = $this->createTravelWithAdditionalServices([$mandatoryService]);
$bookingDto = new BookingDto($travel, 1);
// Do not set participant — age filtering cannot determine choices, returns empty
$options = $this->provider->getFieldOptions('additionalServices', $bookingDto, 0);
$this->assertEmpty($options);
}
private function createMandatoryService(int $id, string $label): Service
{
$service = new Service();
$service->id = $id;
$service->label = $label;
$service->subType = Constants::TOKEN_ADDITIONAL;
$service->available = 10;
$service->price = 5.0;
$service->mandatory = true;
return $service;
}
private function createTravelWithAdditionalServices(array $services): Travel
{
$travel = new Travel();
$travel->dateFrom = new \DateTimeImmutable('+30 days');
$travel->dateTo = new \DateTimeImmutable('+37 days');
$indexed = [];
foreach ($services as $service) {
$indexed[$service->id] = $service;
}
$travel->additionalServices = $indexed;
return $travel;
}
}