294 lines
11 KiB
PHP
294 lines
11 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Tests\Controller\Booking\Create;
|
|
|
|
use App\BusProNet\ApiClient;
|
|
use App\BusProNet\Constants;
|
|
use App\BusProNet\Model\BookingResponse;
|
|
use App\BusProNet\Model\Hotel;
|
|
use App\BusProNet\Model\Travel;
|
|
use App\Entity\User;
|
|
use App\Form\Model\BookingCreateContext;
|
|
use App\Form\Model\BookingDto;
|
|
use App\Form\Model\BookingSummaryDto;
|
|
use App\Form\Model\BookingSummaryPricingDto;
|
|
use App\Form\Model\BookingSummaryVoucherDto;
|
|
use App\Form\Model\ParticipantDto;
|
|
use App\Form\Model\RoomGroupsDto;
|
|
use App\Repository\UserRepository;
|
|
use App\Service\BookingConfigurator;
|
|
use App\Service\BookingCreateContextFactory;
|
|
use App\Service\BookingGuestAccountManager;
|
|
use App\Service\BookingSessionManager;
|
|
use App\Service\NewsletterManager;
|
|
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
|
use Symfony\Bundle\SecurityBundle\Security;
|
|
|
|
class Step4ControllerTest extends WebTestCase
|
|
{
|
|
protected function tearDown(): void
|
|
{
|
|
self::ensureKernelShutdown();
|
|
parent::tearDown();
|
|
}
|
|
|
|
public function testStep4RendersCheckboxAndProvisionsGuestAccountAfterSuccessfulBooking(): void
|
|
{
|
|
$client = self::createClient([], ['HTTPS' => 'on']);
|
|
$client->disableReboot();
|
|
|
|
$bookingDto = $this->createBookingDto();
|
|
$context = $this->createBookingContext($bookingDto);
|
|
|
|
$bookingSessionManager = $this->createMock(BookingSessionManager::class);
|
|
$bookingSessionManager
|
|
->expects(self::exactly(2))
|
|
->method('getOrCreateBookingCreateDto')
|
|
->willReturn($bookingDto);
|
|
|
|
$contextFactory = $this->createMock(BookingCreateContextFactory::class);
|
|
$contextFactory
|
|
->expects(self::exactly(2))
|
|
->method('createWithParticipantPrices')
|
|
->with($bookingDto)
|
|
->willReturn($context);
|
|
|
|
$userRepository = $this->createMock(UserRepository::class);
|
|
$userRepository
|
|
->expects(self::exactly(2))
|
|
->method('findOneByNormalizedEmail')
|
|
->with('[email protected]')
|
|
->willReturn(null);
|
|
|
|
$guestAccountManager = $this->createMock(BookingGuestAccountManager::class);
|
|
$guestAccountManager
|
|
->expects(self::once())
|
|
->method('provisionGuestAccountForBooking')
|
|
->with('[email protected]', 123, 'Alice', 'Example')
|
|
->willReturn(true);
|
|
|
|
$bookingConfigurator = $this->createMock(BookingConfigurator::class);
|
|
$bookingConfigurator
|
|
->expects(self::once())
|
|
->method('applyCreateBookingStatusRules');
|
|
|
|
$apiClient = $this->createMock(ApiClient::class);
|
|
$apiClient
|
|
->expects(self::once())
|
|
->method('createBooking')
|
|
->with($bookingDto)
|
|
->willReturn(new BookingResponse(BookingResponse::BOOKING_PROCESSED, 123));
|
|
|
|
$newsletterManager = $this->createMock(NewsletterManager::class);
|
|
$newsletterManager->expects(self::never())->method('requestConfirmation');
|
|
|
|
self::getContainer()->set(BookingSessionManager::class, $bookingSessionManager);
|
|
self::getContainer()->set(BookingCreateContextFactory::class, $contextFactory);
|
|
self::getContainer()->set(UserRepository::class, $userRepository);
|
|
self::getContainer()->set(BookingGuestAccountManager::class, $guestAccountManager);
|
|
self::getContainer()->set(BookingConfigurator::class, $bookingConfigurator);
|
|
self::getContainer()->set(ApiClient::class, $apiClient);
|
|
self::getContainer()->set(NewsletterManager::class, $newsletterManager);
|
|
|
|
$crawler = $client->request('GET', '/bookings/create/confirmation');
|
|
self::assertResponseIsSuccessful();
|
|
self::assertStringContainsString('Benutzeraccount in MyE&P anlegen', $client->getResponse()->getContent());
|
|
|
|
$form = $crawler->selectButton('Verbindlich buchen')->form([
|
|
'booking_create_step4[confirmationAccepted]' => '1',
|
|
'booking_create_step4[termsAccepted]' => '1',
|
|
'booking_create_step4[guestAccountOptIn]' => '1',
|
|
]);
|
|
$client->submit($form);
|
|
|
|
self::assertResponseRedirects('/bookings/create/success');
|
|
}
|
|
|
|
public function testStep4HidesGuestAccountCheckboxForAuthenticatedUsers(): void
|
|
{
|
|
$bookingDto = $this->createBookingDto();
|
|
$userRepository = $this->createMock(UserRepository::class);
|
|
$userRepository->expects(self::never())->method('findOneByNormalizedEmail');
|
|
|
|
$controller = $this->createAuthenticatedController(
|
|
user: new User('[email protected]'),
|
|
userRepository: $userRepository,
|
|
);
|
|
|
|
self::assertNull($controller->exposeGuestAccountTargetEmail($bookingDto));
|
|
}
|
|
|
|
public function testStep4HidesGuestAccountCheckboxWhenLocalUserAlreadyExists(): void
|
|
{
|
|
$client = self::createClient([], ['HTTPS' => 'on']);
|
|
$client->disableReboot();
|
|
|
|
$bookingDto = $this->createBookingDto();
|
|
$context = $this->createBookingContext($bookingDto);
|
|
|
|
$bookingSessionManager = $this->createMock(BookingSessionManager::class);
|
|
$bookingSessionManager
|
|
->expects(self::once())
|
|
->method('getOrCreateBookingCreateDto')
|
|
->willReturn($bookingDto);
|
|
|
|
$contextFactory = $this->createMock(BookingCreateContextFactory::class);
|
|
$contextFactory
|
|
->expects(self::once())
|
|
->method('createWithParticipantPrices')
|
|
->with($bookingDto)
|
|
->willReturn($context);
|
|
|
|
$userRepository = $this->createMock(UserRepository::class);
|
|
$userRepository
|
|
->expects(self::once())
|
|
->method('findOneByNormalizedEmail')
|
|
->with('[email protected]')
|
|
->willReturn(new User('[email protected]'));
|
|
|
|
$guestAccountManager = $this->createMock(BookingGuestAccountManager::class);
|
|
$guestAccountManager->expects(self::never())->method('provisionGuestAccount');
|
|
|
|
self::getContainer()->set(BookingSessionManager::class, $bookingSessionManager);
|
|
self::getContainer()->set(BookingCreateContextFactory::class, $contextFactory);
|
|
self::getContainer()->set(UserRepository::class, $userRepository);
|
|
self::getContainer()->set(BookingGuestAccountManager::class, $guestAccountManager);
|
|
|
|
$client->request('GET', '/bookings/create/confirmation');
|
|
|
|
self::assertResponseIsSuccessful();
|
|
self::assertStringNotContainsString('Benutzeraccount in MyE&P anlegen', $client->getResponse()->getContent());
|
|
}
|
|
|
|
public function testGuestAccountActivationRedirectsToPersonalDataAndForcesPasswordChange(): void
|
|
{
|
|
$client = self::createClient([], ['HTTPS' => 'on']);
|
|
$client->disableReboot();
|
|
|
|
$guestAccountManager = $this->createMock(BookingGuestAccountManager::class);
|
|
$guestAccountManager
|
|
->expects(self::once())
|
|
->method('validateActivationRequest')
|
|
->with(self::isInstanceOf(\Symfony\Component\HttpFoundation\Request::class))
|
|
->willReturn(new User('[email protected]'));
|
|
$guestAccountManager
|
|
->expects(self::never())
|
|
->method('consumeActivation');
|
|
|
|
$security = $this->createMock(Security::class);
|
|
$security
|
|
->expects(self::once())
|
|
->method('login')
|
|
->with(self::isInstanceOf(User::class), null, 'main')
|
|
->willReturn(null);
|
|
|
|
self::getContainer()->set(BookingGuestAccountManager::class, $guestAccountManager);
|
|
self::getContainer()->set(Security::class, $security);
|
|
|
|
$client->request('GET', '/welcome/[email protected]&nonce=current-nonce&expires=9999999999&_hash=signature');
|
|
|
|
self::assertResponseRedirects('/personal-data');
|
|
self::assertTrue($client->getRequest()->getSession()->get(\App\Controller\Account\PersonalDataController::SESSION_FORCE_PASSWORD_CHANGE_KEY));
|
|
}
|
|
|
|
private function createBookingDto(): BookingDto
|
|
{
|
|
$travel = new Travel();
|
|
$travel->id = 123;
|
|
$travel->label = 'Winterreise';
|
|
$travel->productCode = 'PROD-1';
|
|
$travel->dateFrom = new \DateTimeImmutable('2026-01-01');
|
|
$travel->dateTo = new \DateTimeImmutable('2026-01-08');
|
|
$hotel = new Hotel();
|
|
$hotel->name = 'Hotel Test';
|
|
$travel->hotel = $hotel;
|
|
|
|
$bookingDto = new BookingDto($travel, 77);
|
|
$bookingDto->currentStep = 4;
|
|
$bookingDto->bookingStatus = 'F';
|
|
$bookingDto->paymentMethod = Constants::PAYMENT_METHOD_TRANSFER;
|
|
|
|
$participant = new ParticipantDto();
|
|
$participant->index = 0;
|
|
$participant->firstName = 'Alice';
|
|
$participant->lastName = 'Example';
|
|
$participant->email = '[email protected]';
|
|
$participant->gender = 'M';
|
|
$participant->nationality = 'DE';
|
|
$participant->dateOfBirth = new \DateTimeImmutable('1990-01-01');
|
|
$bookingDto->participants = [$participant];
|
|
|
|
return $bookingDto;
|
|
}
|
|
|
|
private function createBookingContext(BookingDto $bookingDto): BookingCreateContext
|
|
{
|
|
$pricing = new BookingSummaryPricingDto([], [], null, [], 0.0);
|
|
$vouchers = new BookingSummaryVoucherDto(null, 0.0);
|
|
$summary = new BookingSummaryDto([], 1, $pricing, $vouchers, null);
|
|
|
|
return new BookingCreateContext(
|
|
bookingDto: $bookingDto,
|
|
summaryData: $summary,
|
|
groupedRooms: new RoomGroupsDto([], []),
|
|
participantPrices: [0.0],
|
|
);
|
|
}
|
|
|
|
private function createAuthenticatedController(User $user, UserRepository $userRepository): TestableStep4Controller
|
|
{
|
|
return new TestableStep4Controller(
|
|
$this->createMock(BookingConfigurator::class),
|
|
$this->createMock(BookingSessionManager::class),
|
|
$this->createMock(BookingCreateContextFactory::class),
|
|
$this->createMock(BookingGuestAccountManager::class),
|
|
$this->createMock(ApiClient::class),
|
|
$this->createMock(\Symfony\Contracts\Cache\CacheInterface::class),
|
|
$this->createMock(NewsletterManager::class),
|
|
$userRepository,
|
|
$this->createMock(\Psr\Log\LoggerInterface::class),
|
|
$user,
|
|
);
|
|
}
|
|
}
|
|
|
|
final class TestableStep4Controller extends \App\Controller\Booking\Create\Step4Controller
|
|
{
|
|
public function __construct(
|
|
BookingConfigurator $bookingService,
|
|
BookingSessionManager $bookingSessionService,
|
|
BookingCreateContextFactory $createContextFactory,
|
|
BookingGuestAccountManager $guestAccountManager,
|
|
ApiClient $apiClient,
|
|
\Symfony\Contracts\Cache\CacheInterface $cache,
|
|
NewsletterManager $doubleOptInService,
|
|
UserRepository $userRepository,
|
|
\Psr\Log\LoggerInterface $logger,
|
|
private readonly User $user,
|
|
) {
|
|
parent::__construct(
|
|
$bookingService,
|
|
$bookingSessionService,
|
|
$createContextFactory,
|
|
$guestAccountManager,
|
|
$apiClient,
|
|
$cache,
|
|
$doubleOptInService,
|
|
$userRepository,
|
|
$logger,
|
|
);
|
|
}
|
|
|
|
public function exposeGuestAccountTargetEmail(BookingDto $bookingDto): ?string
|
|
{
|
|
return $this->resolveGuestAccountTargetEmail($bookingDto);
|
|
}
|
|
|
|
protected function getUser(): \Symfony\Component\Security\Core\User\UserInterface|null
|
|
{
|
|
return $this->user;
|
|
}
|
|
}
|