assertSubmissionResultFlashes( new BookingEditSubmissionResult( BookingEditSubmissionResult::STATUS_SUCCESS, null, true ), [ ['info', 'Einige Änderungen wurden verworfen, da sie aktuell nicht mehr änderbar sind.'], ['success', 'Buchung erfolgreich aktualisiert'], ['booking_edit_notice', 'Bitte ladet euch eine aktualisierte Rechnung herunter, damit ihr stets den aktuellen Stand eurer Buchung vorliegen habt.'], ], ); } /** * @dataProvider submissionResultProvider * * @param array $expectedFlashes * @phpstan-param array $expectedFlashes */ public function testIndexAppliesErrorSubmissionResultFlashesAndRedirectsBackToEditPage( BookingEditSubmissionResult $submissionResult, array $expectedFlashes, ): void { $this->assertSubmissionResultFlashes($submissionResult, $expectedFlashes); } /** * @return array}> */ public static function submissionResultProvider(): array { return [ 'notification error' => [ new BookingEditSubmissionResult( BookingEditSubmissionResult::STATUS_NOTIFICATION_ERROR, 'BPN-FAIL', false ), [ ['error', 'BPN-FAIL'], ], ], 'timeout' => [ new BookingEditSubmissionResult( BookingEditSubmissionResult::STATUS_TIMEOUT, null, false ), [ ['error', 'Die Anfrage hat zu lange gedauert. Bitte versuche es erneut.'], ], ], 'reload failed' => [ new BookingEditSubmissionResult( BookingEditSubmissionResult::STATUS_BOOKING_DATA_RELOAD_FAILED, null, false ), [ ['error', 'Buchungsdaten konnten vor dem Speichern nicht neu geladen werden'], ], ], ]; } private function createUser(): User { return new User('tester@example.com'); } private function createBookingDto(): BookingDto { $travel = new Travel(); $travel->id = 1234; $bookingDto = new BookingDto($travel, 77); $bookingDto->booking = new Booking(); $bookingDto->booking->id = 42; return $bookingDto; } private function createBooking(): Booking { $booking = new Booking(); $booking->id = 42; $booking->dateId = 1234; return $booking; } /** * @param array $expectedFlashes */ private function assertSubmissionResultFlashes( BookingEditSubmissionResult $submissionResult, array $expectedFlashes, ): void { $request = Request::create('/bookings/42/edit', 'POST'); $user = $this->createUser(); $bookingDto = $this->createBookingDto(); $bookingData = $this->createBooking(); $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); $dataLoader = $this->createMock(BookingEditDataLoader::class); $dataLoader->expects($this->once()) ->method('loadFormData') ->with($request, 42, $user) ->willReturn($bookingDto); $dataLoader->expects($this->once()) ->method('fetchBookingData') ->with(42, $user) ->willReturn($bookingData); $dataLoader->expects($this->once()) ->method('isDraftRestored'); $submitter = $this->createMock(BookingEditSubmitter::class); $submitter->expects($this->once()) ->method('handleSubmission') ->with($request, $bookingDto, 42, $user) ->willReturn($submissionResult); $controller = new TestableIndexController( $dataLoader, $this->createMock(BookingEditDraftManager::class), $this->createMock(BookingSessionManager::class), $this->createMock(BookingChangeTracker::class), $this->createMock(BookingEditContextFactory::class), $submitter, $user, $form, ); $response = $controller->index(42, $request); $this->assertInstanceOf(RedirectResponse::class, $response); $this->assertSame('/bookings/42/edit', $response->headers->get('Location')); $this->assertSame($expectedFlashes, $controller->flashes); } } final class TestableIndexController extends IndexController { /** * @var array */ public array $flashes = []; /** * @var FormInterface */ private readonly FormInterface $form; /** * @param FormInterface $form */ public function __construct( BookingEditDataLoader $dataLoader, BookingEditDraftManager $draftService, BookingSessionManager $bookingSessionService, BookingChangeTracker $fingerprintService, BookingEditContextFactory $editContextFactory, BookingEditSubmitter $formSubmitter, private readonly User $user, FormInterface $form, ) { $this->form = $form; parent::__construct( $dataLoader, $draftService, $bookingSessionService, $fingerprintService, $editContextFactory, $formSubmitter, ); } protected function getUser(): UserInterface { return $this->user; } /** * @return FormInterface */ 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 $parameters */ protected function redirectToRoute(string $route, array $parameters = [], int $status = 302): RedirectResponse { $location = match ($route) { 'app_booking_edit' => '/bookings/'.$parameters['bookingId'].'/edit', default => '/'.$route, }; return new RedirectResponse($location, $status); } /** * @param array $parameters */ protected function render(string $view, array $parameters = [], ?Response $response = null): Response { throw new \LogicException('Render should not be called in this test.'); } }