243 lines
8.5 KiB
PHP
243 lines
8.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Tests\Controller\Booking\Create;
|
|
|
|
use App\BusProNet\Model\Room;
|
|
use App\BusProNet\Model\Travel;
|
|
use App\Controller\Booking\Create\Step1Controller;
|
|
use App\Form\Model\BookingCreateContext;
|
|
use App\Form\Model\BookingDto;
|
|
use App\Form\Model\BookingSummaryDto;
|
|
use App\Form\Model\RoomGroupsDto;
|
|
use App\Form\Model\RoomSelectionDto;
|
|
use App\Service\BookingAvailabilityRefreshResult;
|
|
use App\Service\BookingConfigurator;
|
|
use App\Service\BookingCreateContextFactory;
|
|
use App\Service\BookingSessionManager;
|
|
use PHPUnit\Framework\TestCase;
|
|
use Symfony\Component\Form\FormInterface;
|
|
use Symfony\Component\HttpFoundation\Request;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
use Symfony\Component\HttpFoundation\RedirectResponse;
|
|
|
|
class Step1ControllerTest extends TestCase
|
|
{
|
|
public function testIndexRefreshesBaselineAfterAutoPruningUnavailableRooms(): void
|
|
{
|
|
$request = Request::create('/bookings/create/rooms', 'GET');
|
|
$bookingDto = $this->createBookingDtoWithUnavailableSelection();
|
|
|
|
$bookingSessionService = $this->createMock(BookingSessionManager::class);
|
|
$bookingSessionService->expects($this->once())
|
|
->method('getOrCreateBookingCreateDto')
|
|
->with($request)
|
|
->willReturn($bookingDto);
|
|
$bookingSessionService->expects($this->once())
|
|
->method('getOrCreateBaselineSnapshot')
|
|
->with($request, $bookingDto)
|
|
->willReturn([[2, 1]]);
|
|
$bookingSessionService->expects($this->once())
|
|
->method('refreshCreateAvailability')
|
|
->with($request, $bookingDto)
|
|
->willReturn(new BookingAvailabilityRefreshResult(
|
|
availabilityRefreshed: true,
|
|
roomSelectionQuantityReset: true,
|
|
roomSelectionSnapshotChanged: true,
|
|
hasAvailableRooms: true,
|
|
));
|
|
$bookingSessionService->expects($this->once())
|
|
->method('saveBaselineSnapshot')
|
|
->with($request, $bookingDto);
|
|
|
|
$bookingService = $this->createMock(BookingConfigurator::class);
|
|
|
|
$form = $this->createMock(FormInterface::class);
|
|
$form->expects($this->once())
|
|
->method('handleRequest')
|
|
->with($request)
|
|
->willReturnSelf();
|
|
$form->expects($this->once())
|
|
->method('isSubmitted')
|
|
->willReturn(false);
|
|
|
|
$createContextFactory = $this->createMock(BookingCreateContextFactory::class);
|
|
$createContextFactory->expects($this->once())
|
|
->method('create')
|
|
->with($bookingDto, $this->anything())
|
|
->willReturn(new BookingCreateContext(
|
|
bookingDto: $bookingDto,
|
|
summaryData: $this->createMock(BookingSummaryDto::class),
|
|
groupedRooms: new RoomGroupsDto([], []),
|
|
));
|
|
|
|
$controller = new TestableStep1Controller(
|
|
$bookingService,
|
|
$bookingSessionService,
|
|
$createContextFactory,
|
|
$form,
|
|
);
|
|
|
|
$response = $controller->index($request);
|
|
|
|
$this->assertInstanceOf(Response::class, $response);
|
|
$this->assertSame(['warning', 'Mindestens eine Zimmerauswahl ist nicht mehr verfügbar und wurde zurückgesetzt.'], $controller->flashes[0]);
|
|
}
|
|
|
|
public function testIndexUsesPrunedBaselineBeforeSubmittingUnchangedSelections(): void
|
|
{
|
|
$request = Request::create('/bookings/create/rooms', 'POST');
|
|
$bookingDto = $this->createBookingDtoWithUnavailableSelection();
|
|
|
|
$bookingDto = $this->getMockBuilder(BookingDto::class)
|
|
->setConstructorArgs([$bookingDto->travel, $bookingDto->hotelId])
|
|
->onlyMethods(['hasRoomSelectionChanged', 'resetParticipantAssignments'])
|
|
->getMock();
|
|
|
|
$bookingDto->roomSelections = $this->createBookingDtoWithUnavailableSelection()->roomSelections;
|
|
$bookingDto->currentStep = 1;
|
|
|
|
$bookingSessionService = $this->createMock(BookingSessionManager::class);
|
|
$bookingSessionService->expects($this->once())
|
|
->method('getOrCreateBookingCreateDto')
|
|
->with($request)
|
|
->willReturn($bookingDto);
|
|
$bookingSessionService->expects($this->once())
|
|
->method('getOrCreateBaselineSnapshot')
|
|
->with($request, $bookingDto)
|
|
->willReturn([[1, 0], [2, 1]]);
|
|
$bookingSessionService->expects($this->once())
|
|
->method('refreshCreateAvailability')
|
|
->with($request, $bookingDto)
|
|
->willReturn(new BookingAvailabilityRefreshResult(
|
|
availabilityRefreshed: true,
|
|
roomSelectionQuantityReset: true,
|
|
roomSelectionSnapshotChanged: true,
|
|
hasAvailableRooms: true,
|
|
));
|
|
$bookingSessionService->expects($this->once())
|
|
->method('saveBookingDto')
|
|
->with($request, $bookingDto, BookingDto::MODE_CREATE);
|
|
$bookingSessionService->expects($this->once())
|
|
->method('saveBaselineSnapshot')
|
|
->with($request, $bookingDto)
|
|
->willReturn([[1, 0]]);
|
|
$bookingSessionService->expects($this->once())
|
|
->method('clearBaselineSnapshot')
|
|
->with($request);
|
|
|
|
$bookingService = $this->createMock(BookingConfigurator::class);
|
|
$bookingService->expects($this->once())
|
|
->method('updateBookingStatusFromRoomSelection')
|
|
->with($bookingDto);
|
|
|
|
$bookingDto->expects($this->never())
|
|
->method('resetParticipantAssignments');
|
|
$bookingDto->expects($this->once())
|
|
->method('hasRoomSelectionChanged')
|
|
->with([[1, 0]])
|
|
->willReturn(false);
|
|
|
|
$form = $this->createMock(FormInterface::class);
|
|
$form->expects($this->once())
|
|
->method('handleRequest')
|
|
->with($request)
|
|
->willReturnSelf();
|
|
$form->expects($this->once())
|
|
->method('isSubmitted')
|
|
->willReturn(true);
|
|
$form->expects($this->once())
|
|
->method('isValid')
|
|
->willReturn(true);
|
|
|
|
$createContextFactory = $this->createMock(BookingCreateContextFactory::class);
|
|
$createContextFactory->expects($this->never())
|
|
->method('create');
|
|
|
|
$controller = new TestableStep1Controller(
|
|
$bookingService,
|
|
$bookingSessionService,
|
|
$createContextFactory,
|
|
$form,
|
|
);
|
|
|
|
$response = $controller->index($request);
|
|
|
|
$this->assertInstanceOf(Response::class, $response);
|
|
}
|
|
|
|
private function createBookingDtoWithUnavailableSelection(): BookingDto
|
|
{
|
|
$travel = new Travel();
|
|
$travel->id = 1234;
|
|
|
|
$availableRoom = new Room();
|
|
$availableRoom->id = 1;
|
|
$availableRoom->label = 'Doppelzimmer';
|
|
$availableRoom->available = 2;
|
|
$availableRoom->status = 'Frei';
|
|
$travel->rooms = [$availableRoom];
|
|
|
|
$bookingDto = new BookingDto($travel, 77);
|
|
|
|
$selection = new RoomSelectionDto();
|
|
$selection->id = 2;
|
|
$selection->quantity = 1;
|
|
$bookingDto->roomSelections = [$selection];
|
|
|
|
return $bookingDto;
|
|
}
|
|
}
|
|
|
|
final class TestableStep1Controller extends Step1Controller
|
|
{
|
|
/**
|
|
* @var array<int, array{string, mixed}>
|
|
*/
|
|
public array $flashes = [];
|
|
|
|
/**
|
|
* @param FormInterface<mixed> $form
|
|
*/
|
|
public function __construct(
|
|
BookingConfigurator $bookingService,
|
|
BookingSessionManager $bookingSessionService,
|
|
BookingCreateContextFactory $createContextFactory,
|
|
private readonly FormInterface $form,
|
|
) {
|
|
parent::__construct($bookingService, $bookingSessionService, $createContextFactory);
|
|
}
|
|
|
|
/**
|
|
* @return FormInterface<mixed>
|
|
*/
|
|
protected function createForm(string $type, mixed $data = null, array $options = []): FormInterface
|
|
{
|
|
return $this->form;
|
|
}
|
|
|
|
protected function addFlash(string $type, mixed $message): void
|
|
{
|
|
$this->flashes[] = [$type, $message];
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $parameters
|
|
*/
|
|
protected function render(string $view, array $parameters = [], ?Response $response = null): Response
|
|
{
|
|
return new Response('rendered:'.$view);
|
|
}
|
|
|
|
protected function redirectToRoute(string $route, array $parameters = [], int $status = 302): RedirectResponse
|
|
{
|
|
return new RedirectResponse('redirect:'.$route, $status);
|
|
}
|
|
|
|
protected function generateUrl(string $route, array $parameters = [], int $referenceType = 0): string
|
|
{
|
|
return $route;
|
|
}
|
|
}
|