275 lines
9.8 KiB
PHP
275 lines
9.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Tests\Service;
|
|
|
|
use App\BusProNet\Model\Travel;
|
|
use App\Enum\NewsletterOptInContext;
|
|
use App\Exception\NewsletterProviderException;
|
|
use App\Form\Model\BookingDto;
|
|
use App\Form\Model\ParticipantDto;
|
|
use App\Service\BookingNewsletterOptIn;
|
|
use App\Service\NewsletterManager;
|
|
use PHPUnit\Framework\TestCase;
|
|
use Psr\Log\NullLogger;
|
|
|
|
class BookingNewsletterOptInTest extends TestCase
|
|
{
|
|
public function testChildrenAreNotOfferedACompanionOptIn(): void
|
|
{
|
|
$bookingDto = $this->createBookingDto([
|
|
['[email protected]', 30],
|
|
['[email protected]', 12],
|
|
]);
|
|
|
|
$companions = $this->createService($this->createStub(NewsletterManager::class))
|
|
->resolveCompanions($bookingDto, '[email protected]');
|
|
|
|
self::assertSame([], $companions);
|
|
}
|
|
|
|
public function testApplicantAddressIsNotOfferedAsACompanion(): void
|
|
{
|
|
$bookingDto = $this->createBookingDto([
|
|
['[email protected]', 30],
|
|
['[email protected] ', 25],
|
|
]);
|
|
|
|
$companions = $this->createService($this->createStub(NewsletterManager::class))
|
|
->resolveCompanions($bookingDto, '[email protected]');
|
|
|
|
self::assertSame([], $companions);
|
|
}
|
|
|
|
public function testDuplicateAndInvalidCompanionAddressesAreCollapsed(): void
|
|
{
|
|
$bookingDto = $this->createBookingDto([
|
|
['[email protected]', 30],
|
|
['[email protected]', 25],
|
|
['[email protected]', 26],
|
|
['not-an-email', 27],
|
|
[null, 28],
|
|
]);
|
|
|
|
$companions = $this->createService($this->createStub(NewsletterManager::class))
|
|
->resolveCompanions($bookingDto, '[email protected]');
|
|
|
|
self::assertCount(1, $companions);
|
|
self::assertSame('[email protected]', $companions[0]->email);
|
|
}
|
|
|
|
public function testConfirmedAndPendingCompanionsAreSkipped(): void
|
|
{
|
|
$companions = $this->createCompanions([
|
|
'[email protected]',
|
|
'[email protected]',
|
|
'[email protected]',
|
|
]);
|
|
|
|
$newsletterManager = $this->createMock(NewsletterManager::class);
|
|
$newsletterManager
|
|
->method('hasConfirmedOptIn')
|
|
->willReturnCallback(static fn (string $email): bool => '[email protected]' === $email);
|
|
$newsletterManager
|
|
->method('hasPendingConfirmation')
|
|
->willReturnCallback(static fn (string $email): bool => '[email protected]' === $email);
|
|
$newsletterManager
|
|
->expects(self::once())
|
|
->method('requestConfirmation')
|
|
->with('[email protected]', 'Tim', 'Teiler', NewsletterOptInContext::Companion, 'Mia Muster');
|
|
|
|
$this->createService($newsletterManager)->subscribeCompanions($companions, 'Mia Muster');
|
|
}
|
|
|
|
public function testOneFailingCompanionDoesNotStopTheOthers(): void
|
|
{
|
|
$companions = $this->createCompanions([
|
|
'[email protected]',
|
|
'[email protected]',
|
|
]);
|
|
|
|
$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 ('[email protected]' === $email) {
|
|
throw new NewsletterProviderException('Mailer down.');
|
|
}
|
|
});
|
|
|
|
$this->createService($newsletterManager)->subscribeCompanions($companions, 'Mia Muster');
|
|
|
|
self::assertSame(['[email protected]', '[email protected]'], $requestedEmails);
|
|
}
|
|
|
|
public function testAFailingConsentLookupDoesNotEscapeToTheCaller(): void
|
|
{
|
|
$companions = $this->createCompanions([
|
|
'[email protected]',
|
|
'[email protected]',
|
|
]);
|
|
|
|
$newsletterManager = $this->createMock(NewsletterManager::class);
|
|
$newsletterManager
|
|
->method('hasConfirmedOptIn')
|
|
->willReturnCallback(static function (string $email): bool {
|
|
if ('[email protected]' === $email) {
|
|
throw new \RuntimeException('Database gone.');
|
|
}
|
|
|
|
return false;
|
|
});
|
|
$newsletterManager->method('hasPendingConfirmation')->willReturn(false);
|
|
$newsletterManager
|
|
->expects(self::once())
|
|
->method('requestConfirmation')
|
|
->with('[email protected]');
|
|
|
|
$this->createService($newsletterManager)->subscribeCompanions($companions, 'Mia Muster');
|
|
}
|
|
|
|
public function testApplicantOptInFailureDoesNotEscapeToTheCaller(): void
|
|
{
|
|
$newsletterManager = $this->createStub(NewsletterManager::class);
|
|
$newsletterManager
|
|
->method('requestConfirmation')
|
|
->willThrowException(new \RuntimeException('Database gone.'));
|
|
|
|
$this->createService($newsletterManager)->subscribeApplicant('[email protected]', null);
|
|
|
|
$this->expectNotToPerformAssertions();
|
|
}
|
|
|
|
public function testApplicantOptInUsesTheOwnWording(): void
|
|
{
|
|
$bookingDto = $this->createBookingDto([['[email protected]', 30]]);
|
|
$applicant = $bookingDto->participants[0];
|
|
|
|
$newsletterManager = $this->createMock(NewsletterManager::class);
|
|
$newsletterManager
|
|
->expects(self::once())
|
|
->method('requestConfirmation')
|
|
->with('[email protected]', 'Mia', 'Muster');
|
|
|
|
$this->createService($newsletterManager)->subscribeApplicant('[email protected]', $applicant);
|
|
}
|
|
|
|
public function testRequestedByNameIsTheApplicantsFullName(): void
|
|
{
|
|
$bookingDto = $this->createBookingDto([['[email protected]', 30]]);
|
|
|
|
self::assertSame(
|
|
'Mia Muster',
|
|
$this->createService($this->createStub(NewsletterManager::class))->resolveRequestedByName($bookingDto)
|
|
);
|
|
}
|
|
|
|
public function testApplicantIsTheSeparateRecordWhenTheyDoNotTravel(): void
|
|
{
|
|
$bookingDto = $this->createBookingDto([['[email protected]', 12]]);
|
|
$bookingDto->applicantTravels = false;
|
|
|
|
$applicant = new ParticipantDto();
|
|
$applicant->firstName = 'Probe';
|
|
$applicant->lastName = 'Elternteil';
|
|
$applicant->email = '[email protected]';
|
|
$bookingDto->applicant = $applicant;
|
|
|
|
$service = $this->createService($this->createStub(NewsletterManager::class));
|
|
|
|
$this->assertSame('[email protected]', $service->resolveApplicantEmail($bookingDto, null));
|
|
$this->assertSame($applicant, $service->resolveApplicantParticipant($bookingDto));
|
|
$this->assertSame('Probe Elternteil', $service->resolveRequestedByName($bookingDto));
|
|
}
|
|
|
|
public function testAdultAtIndexZeroIsOfferedACompanionOptInOnASplitBooking(): void
|
|
{
|
|
$bookingDto = $this->createBookingDto([['[email protected]', 25]]);
|
|
$bookingDto->applicantTravels = false;
|
|
|
|
$applicant = new ParticipantDto();
|
|
$applicant->firstName = 'Probe';
|
|
$applicant->lastName = 'Elternteil';
|
|
$applicant->email = '[email protected]';
|
|
$bookingDto->applicant = $applicant;
|
|
|
|
$service = $this->createService($this->createStub(NewsletterManager::class));
|
|
$companions = $service->resolveCompanions($bookingDto, '[email protected]');
|
|
|
|
$this->assertCount(
|
|
1,
|
|
$companions,
|
|
'participant[0] is an ordinary companion once the applicant stays home'
|
|
);
|
|
$this->assertSame('[email protected]', $companions[0]->email);
|
|
}
|
|
|
|
public function testChildCarryingTheApplicantAddressIsNotOfferedACompanionOptIn(): void
|
|
{
|
|
$bookingDto = $this->createBookingDto([
|
|
['[email protected]', 40],
|
|
['[email protected]', 12],
|
|
]);
|
|
|
|
$service = $this->createService($this->createStub(NewsletterManager::class));
|
|
$companions = $service->resolveCompanions($bookingDto, '[email protected]');
|
|
|
|
$this->assertSame([], $companions);
|
|
}
|
|
|
|
private function createService(NewsletterManager $newsletterManager): BookingNewsletterOptIn
|
|
{
|
|
return new BookingNewsletterOptIn($newsletterManager, new NullLogger());
|
|
}
|
|
|
|
/**
|
|
* @param list<array{0: string|null, 1: int}> $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<string> $emails
|
|
*
|
|
* @return list<ParticipantDto>
|
|
*/
|
|
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;
|
|
}
|
|
}
|