104 lines
3.7 KiB
PHP
104 lines
3.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Tests\Email;
|
|
|
|
use App\Email\Mailer;
|
|
use Monolog\Handler\TestHandler;
|
|
use Monolog\Logger;
|
|
use PHPUnit\Framework\TestCase;
|
|
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
|
|
use Symfony\Component\Mailer\Envelope;
|
|
use Symfony\Component\Mailer\Exception\TransportException;
|
|
use Symfony\Component\Mailer\MailerInterface;
|
|
use Symfony\Component\Mime\Address;
|
|
use Symfony\Component\Mime\RawMessage;
|
|
|
|
/**
|
|
* The two promises every caller relies on: one mail per recipient, addressed to them alone, and
|
|
* a failure that costs only its own recipient and is never thrown.
|
|
*/
|
|
class MailerTest extends TestCase
|
|
{
|
|
public function testEveryRecipientGetsTheirOwnMail(): void
|
|
{
|
|
$transport = $this->transport();
|
|
$mailer = new Mailer($transport, new Logger('test'), '[email protected]');
|
|
|
|
$report = $mailer->send(
|
|
['[email protected]', new Address('[email protected]', 'B')],
|
|
'Betreff',
|
|
'email/some',
|
|
['key' => 'value'],
|
|
);
|
|
|
|
self::assertSame(2, $report->sent);
|
|
self::assertSame(0, $report->failed);
|
|
self::assertCount(2, $transport->sent);
|
|
|
|
foreach ($transport->sent as $i => $email) {
|
|
self::assertCount(1, $email->getTo());
|
|
self::assertSame(['[email protected]', '[email protected]'][$i], $email->getTo()[0]->getAddress());
|
|
self::assertSame('[email protected]', $email->getFrom()[0]->getAddress());
|
|
self::assertSame('E&P Platz', $email->getFrom()[0]->getName());
|
|
self::assertSame('Betreff', $email->getSubject());
|
|
self::assertSame('email/some.html.twig', $email->getHtmlTemplate());
|
|
self::assertSame('email/some.txt.twig', $email->getTextTemplate());
|
|
self::assertSame(['key' => 'value'], $email->getContext());
|
|
}
|
|
}
|
|
|
|
public function testAFailedRecipientIsLoggedAndTheOthersStillGetTheirs(): void
|
|
{
|
|
$transport = $this->transport(failFor: '[email protected]');
|
|
$log = new TestHandler();
|
|
$mailer = new Mailer($transport, new Logger('test', [$log]), '[email protected]');
|
|
|
|
$report = $mailer->send(['[email protected]', '[email protected]', '[email protected]'], 'Betreff', 'email/some');
|
|
|
|
self::assertSame(2, $report->sent);
|
|
self::assertSame(1, $report->failed);
|
|
self::assertCount(2, $transport->sent);
|
|
self::assertTrue($log->hasErrorThatContains('Email could not be sent.'));
|
|
self::assertSame('[email protected]', $log->getRecords()[0]->context['recipient']);
|
|
}
|
|
|
|
public function testNoRecipientsSendsNothing(): void
|
|
{
|
|
$transport = $this->transport();
|
|
$mailer = new Mailer($transport, new Logger('test'), '[email protected]');
|
|
|
|
$report = $mailer->send([], 'Betreff', 'email/some');
|
|
|
|
self::assertSame(0, $report->sent);
|
|
self::assertSame([], $transport->sent);
|
|
}
|
|
|
|
/**
|
|
* @return MailerInterface&object{sent: list<TemplatedEmail>}
|
|
*/
|
|
private function transport(?string $failFor = null): MailerInterface
|
|
{
|
|
return new class($failFor) implements MailerInterface {
|
|
/** @var list<TemplatedEmail> */
|
|
public array $sent = [];
|
|
|
|
public function __construct(private readonly ?string $failFor)
|
|
{
|
|
}
|
|
|
|
public function send(RawMessage $message, ?Envelope $envelope = null): void
|
|
{
|
|
\assert($message instanceof TemplatedEmail);
|
|
|
|
if ($message->getTo()[0]->getAddress() === $this->failFor) {
|
|
throw new TransportException('550 mailbox unavailable');
|
|
}
|
|
|
|
$this->sent[] = $message;
|
|
}
|
|
};
|
|
}
|
|
}
|