createBookingDto(); $bookingSessionService = $this->createMock(BookingSessionManager::class); $bookingSessionService->expects($this->once()) ->method('getBookingDto') ->with($request, BookingDto::MODE_CREATE) ->willReturn($bookingDto); $bookingSessionService->expects($this->once()) ->method('refreshCreateAvailability') ->with($request, $bookingDto, false) ->willReturn(new BookingAvailabilityRefreshResult( availabilityRefreshed: true, roomSelectionQuantityReset: false, roomSelectionSnapshotChanged: false, hasAvailableRooms: true, )); $bookingSessionService->expects($this->once()) ->method('saveBookingDto') ->with($request, $bookingDto, BookingDto::MODE_CREATE); $bookingService = $this->createMock(BookingConfigurator::class); $bookingService->expects($this->once()) ->method('updateBookingStatusFromRoomSelection') ->with($bookingDto); $participantFormSupportService = $this->createMock(ParticipantFormSupport::class); $participantFormSupportService->method('ensureParticipantExists')->willReturn(new ParticipantDto()); $participantFormSupportService->method('createParticipantEditDto')->willReturn($this->createMock(\App\Form\Model\ParticipantEditDto::class)); $participantFormSupportService->method('getParticipantFormOptions')->willReturn([]); $participantFormSupportService->method('collectAndClearNotifications')->willReturn([]); $prepopulationService = $this->createMock(ParticipantDataPrefiller::class); $prepopulationService->method('isDummyDataFillRequested')->willReturn(false); $form = $this->createMock(FormInterface::class); $form->expects($this->once())->method('handleRequest')->with($request)->willReturnSelf(); $form->expects($this->once())->method('isSubmitted')->willReturn(false); $bookingDto->participants[0] = new ParticipantDto(); $createContextFactory = $this->createMock(BookingCreateContextFactory::class); $createContextFactory->method('create')->willReturn(new \App\Form\Model\BookingCreateContext( bookingDto: $bookingDto, summaryData: $this->createMock(\App\Form\Model\BookingSummaryDto::class), groupedRooms: new \App\Form\Model\RoomGroupsDto([], []), )); $controller = new TestableStep2ParticipantController( $bookingService, $bookingSessionService, $createContextFactory, $prepopulationService, $participantFormSupportService, ); $controller->form = $form; $response = $controller->editParticipant(0, $request); $this->assertSame('rendered', $response->getContent()); } public function testRefreshParticipantFormReturnsHxRedirectForHtmxRequestWhenSelectionStale(): void { $request = Request::create('/bookings/create/participants/0/refresh', 'POST'); $request->headers->set('HX-Request', 'true'); $response = $this->invokeRefreshWithStaleSelection($request); $this->assertInstanceOf(HxRedirectResponse::class, $response); $this->assertSame('app_booking_create_step_1', $response->headers->get('HX-Redirect')); } public function testRefreshParticipantFormReturnsPlainRedirectForNonHtmxRequestWhenSelectionStale(): void { $request = Request::create('/bookings/create/participants/0/refresh', 'POST'); $response = $this->invokeRefreshWithStaleSelection($request); $this->assertInstanceOf(RedirectResponse::class, $response); $this->assertNotInstanceOf(HxRedirectResponse::class, $response); $this->assertSame('app_booking_create_step_1', $response->getTargetUrl()); } private function invokeRefreshWithStaleSelection(Request $request): \Symfony\Component\HttpFoundation\Response { $bookingDto = $this->createBookingDto(); $bookingSessionService = $this->createMock(BookingSessionManager::class); $bookingSessionService->expects($this->once()) ->method('getBookingDto') ->with($request, BookingDto::MODE_CREATE) ->willReturn($bookingDto); $bookingSessionService->expects($this->once()) ->method('refreshCreateAvailability') ->with($request, $bookingDto, false) ->willReturn(new BookingAvailabilityRefreshResult( availabilityRefreshed: true, roomSelectionQuantityReset: true, roomSelectionSnapshotChanged: true, hasAvailableRooms: true, )); $bookingService = $this->createMock(BookingConfigurator::class); $bookingService->expects($this->never())->method('updateBookingStatusFromRoomSelection'); $controller = new TestableStep2ParticipantController( $bookingService, $bookingSessionService, $this->createMock(BookingCreateContextFactory::class), $this->createMock(ParticipantDataPrefiller::class), $this->createMock(ParticipantFormSupport::class), ); return $controller->refreshParticipantForm(0, $request); } private function createBookingDto(): BookingDto { $travel = new Travel(); $travel->id = 1234; $travel->hotelId = 77; $room = new Room(); $room->id = 1; $room->label = 'Doppelzimmer'; $room->available = 2; $room->status = 'Frei'; $travel->rooms = [$room]; $bookingDto = new BookingDto($travel, 77); $bookingDto->currentStep = 2; $selection = new RoomSelectionDto(); $selection->id = 1; $selection->quantity = 1; $bookingDto->roomSelections = [$selection]; return $bookingDto; } } final class TestableStep2ParticipantController extends Step2ParticipantController { /** * @var array */ public array $flashes = []; public ?FormInterface $form = null; protected function addFlash(string $type, mixed $message): void { $this->flashes[] = [$type, $message]; } protected function generateUrl(string $route, array $parameters = [], int $referenceType = 0): string { return $route; } protected function createForm(string $type, mixed $data = null, array $options = []): FormInterface { return $this->form; } protected function render(string $view, array $parameters = [], ?\Symfony\Component\HttpFoundation\Response $response = null): \Symfony\Component\HttpFoundation\Response { return new \Symfony\Component\HttpFoundation\Response('rendered'); } }