createBookingDto([ ['applicant@example.com', 30], ['child@example.com', 12], ]); $companions = $this->createService($this->createStub(NewsletterManager::class)) ->resolveCompanions($bookingDto, 'applicant@example.com'); self::assertSame([], $companions); } public function testApplicantAddressIsNotOfferedAsACompanion(): void { $bookingDto = $this->createBookingDto([ ['applicant@example.com', 30], ['Applicant@Example.com ', 25], ]); $companions = $this->createService($this->createStub(NewsletterManager::class)) ->resolveCompanions($bookingDto, 'applicant@example.com'); self::assertSame([], $companions); } public function testDuplicateAndInvalidCompanionAddressesAreCollapsed(): void { $bookingDto = $this->createBookingDto([ ['applicant@example.com', 30], ['companion@example.com', 25], ['COMPANION@example.com', 26], ['not-an-email', 27], [null, 28], ]); $companions = $this->createService($this->createStub(NewsletterManager::class)) ->resolveCompanions($bookingDto, 'applicant@example.com'); self::assertCount(1, $companions); self::assertSame('companion@example.com', $companions[0]->email); } public function testConfirmedAndPendingCompanionsAreSkipped(): void { $companions = $this->createCompanions([ 'confirmed@example.com', 'pending@example.com', 'fresh@example.com', ]); $newsletterManager = $this->createMock(NewsletterManager::class); $newsletterManager ->method('hasConfirmedOptIn') ->willReturnCallback(static fn (string $email): bool => 'confirmed@example.com' === $email); $newsletterManager ->method('hasPendingConfirmation') ->willReturnCallback(static fn (string $email): bool => 'pending@example.com' === $email); $newsletterManager ->expects(self::once()) ->method('requestConfirmation') ->with('fresh@example.com', 'Tim', 'Teiler', NewsletterOptInContext::Companion, 'Mia Muster'); $this->createService($newsletterManager)->subscribeCompanions($companions, 'Mia Muster'); } public function testOneFailingCompanionDoesNotStopTheOthers(): void { $companions = $this->createCompanions([ 'broken@example.com', 'fine@example.com', ]); $newsletterManager = $this->createMock(NewsletterManager::class); $newsletterManager->method('hasConfirmedOptIn')->willReturn(false); $newsletterManager->method('hasPendingConfirmation')->willReturn(false); $requestedEmails = []; $newsletterManager ->expects(self::exactly(2)) ->method('requestConfirmation') ->willReturnCallback(static function (string $email) use (&$requestedEmails): void { $requestedEmails[] = $email; if ('broken@example.com' === $email) { throw new NewsletterProviderException('Mailer down.'); } }); $this->createService($newsletterManager)->subscribeCompanions($companions, 'Mia Muster'); self::assertSame(['broken@example.com', 'fine@example.com'], $requestedEmails); } public function testApplicantOptInUsesTheOwnWording(): void { $bookingDto = $this->createBookingDto([['applicant@example.com', 30]]); $applicant = $bookingDto->participants[0]; $newsletterManager = $this->createMock(NewsletterManager::class); $newsletterManager ->expects(self::once()) ->method('requestConfirmation') ->with('applicant@example.com', 'Mia', 'Muster'); $this->createService($newsletterManager)->subscribeApplicant('applicant@example.com', $applicant); } public function testRequestedByNameIsTheApplicantsFullName(): void { $bookingDto = $this->createBookingDto([['applicant@example.com', 30]]); self::assertSame( 'Mia Muster', $this->createService($this->createStub(NewsletterManager::class))->resolveRequestedByName($bookingDto) ); } private function createService(NewsletterManager $newsletterManager): BookingNewsletterOptIn { return new BookingNewsletterOptIn($newsletterManager, new NullLogger()); } /** * @param list $participants email and age, applicant first */ private function createBookingDto(array $participants): BookingDto { $bookingDto = new BookingDto(new Travel(), 1); foreach ($participants as $index => [$email, $age]) { $participant = new ParticipantDto(); $participant->index = $index; $participant->firstName = 0 === $index ? 'Mia' : 'Tim'; $participant->lastName = 0 === $index ? 'Muster' : 'Teiler'; $participant->email = $email; $participant->dateOfBirth = new \DateTimeImmutable(sprintf('-%d years', $age)); $bookingDto->participants[] = $participant; } return $bookingDto; } /** * @param list $emails * * @return list */ private function createCompanions(array $emails): array { $companions = []; foreach ($emails as $offset => $email) { $participant = new ParticipantDto(); $participant->index = $offset + 1; $participant->firstName = 'Tim'; $participant->lastName = 'Teiler'; $participant->email = $email; $participant->dateOfBirth = new \DateTimeImmutable('-25 years'); $companions[] = $participant; } return $companions; } }