feat: offer a newsletter opt-in for the other participants
addresses #869etn6c5
This commit is contained in:
1 parent
96b7b3f451
commit
876e69e62c
10 files changed
+598
-71
No files matched your search
@@ -0,0 +1,183 @@
|
||||
<?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 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)
|
||||
);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ namespace App\Tests\Service;
|
||||
use App\Email\Mailer;
|
||||
use App\Entity\NewsletterConsent;
|
||||
use App\Entity\NewsletterOptInRequest;
|
||||
use App\Enum\NewsletterOptInContext;
|
||||
use App\Exception\NewsletterListNotAllowedException;
|
||||
use App\Mailjet\ApiClient;
|
||||
use App\Model\NewsletterConfirmationResult;
|
||||
@@ -16,7 +17,6 @@ use App\Repository\NewsletterOptInRequestRepository;
|
||||
use App\Service\NewsletterManager;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\Log\NullLogger;
|
||||
|
||||
@@ -439,14 +439,69 @@ class NewsletterManagerTest extends TestCase
|
||||
yield 'boolean' => [true];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param MockObject&NewsletterOptInRequestRepository $repository
|
||||
* @param MockObject&NewsletterConsentRepository $consents
|
||||
* @param MockObject&EntityManagerInterface $entityManager
|
||||
* @param MockObject&ApiClient $mailjet
|
||||
* @param MockObject&Mailer $mailer
|
||||
* @param array<int, string> $mailjetLists
|
||||
*/
|
||||
public function testRequestConfirmationUsesOwnWordingByDefault(): void
|
||||
{
|
||||
$repository = $this->createStub(NewsletterOptInRequestRepository::class);
|
||||
$consents = $this->createStub(NewsletterConsentRepository::class);
|
||||
$entityManager = $this->createStub(EntityManagerInterface::class);
|
||||
$mailjet = $this->createStub(ApiClient::class);
|
||||
$mailer = $this->createMock(Mailer::class);
|
||||
|
||||
$repository->method('deleteExpiredPendingByEmail')->willReturn(0);
|
||||
$repository->method('findPendingByEmail')->willReturn(null);
|
||||
$mailer
|
||||
->expects(self::once())
|
||||
->method('createAndSendEmail')
|
||||
->with(
|
||||
self::callback(static function (array $context): bool {
|
||||
self::assertNull($context['requestedByName']);
|
||||
|
||||
return true;
|
||||
}),
|
||||
self::callback(static function (array $options): bool {
|
||||
self::assertSame('Deine Anmeldung zum E&P Newsletter', $options['subject']);
|
||||
self::assertSame('email/newsletter_opt_in.html.twig', $options['template']);
|
||||
|
||||
return true;
|
||||
}),
|
||||
);
|
||||
|
||||
$this->createManager($repository, $consents, $entityManager, $mailjet, $mailer)
|
||||
->requestConfirmation('[email protected]', 'Mia', 'Muster');
|
||||
}
|
||||
|
||||
public function testRequestConfirmationUsesCompanionWordingAndNamesTheRequester(): void
|
||||
{
|
||||
$repository = $this->createStub(NewsletterOptInRequestRepository::class);
|
||||
$consents = $this->createStub(NewsletterConsentRepository::class);
|
||||
$entityManager = $this->createStub(EntityManagerInterface::class);
|
||||
$mailjet = $this->createStub(ApiClient::class);
|
||||
$mailer = $this->createMock(Mailer::class);
|
||||
|
||||
$repository->method('deleteExpiredPendingByEmail')->willReturn(0);
|
||||
$repository->method('findPendingByEmail')->willReturn(null);
|
||||
$mailer
|
||||
->expects(self::once())
|
||||
->method('createAndSendEmail')
|
||||
->with(
|
||||
self::callback(static function (array $context): bool {
|
||||
self::assertSame('Tim', $context['recipientFirstName']);
|
||||
self::assertSame('Mia Muster', $context['requestedByName']);
|
||||
|
||||
return true;
|
||||
}),
|
||||
self::callback(static function (array $options): bool {
|
||||
self::assertSame('Möchtest du den E&P Newsletter erhalten?', $options['subject']);
|
||||
self::assertSame('email/newsletter_opt_in_companion.html.twig', $options['template']);
|
||||
|
||||
return true;
|
||||
}),
|
||||
);
|
||||
|
||||
$this->createManager($repository, $consents, $entityManager, $mailjet, $mailer)
|
||||
->requestConfirmation('[email protected]', 'Tim', 'Teiler', NewsletterOptInContext::Companion, 'Mia Muster');
|
||||
}
|
||||
|
||||
private function createManager(
|
||||
NewsletterOptInRequestRepository $repository,
|
||||
NewsletterConsentRepository $consents,
|
||||
|
||||
Reference in new issue
Block a user