Skip to content

Commit

Permalink
feat: allow asserting on Signed emails (#24)
Browse files Browse the repository at this point in the history
  • Loading branch information
kbond committed Feb 3, 2023
1 parent fbb32ae commit bb45289
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 4 deletions.
51 changes: 49 additions & 2 deletions src/SentEmails.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@
use Symfony\Component\Mailer\Event\MessageEvents;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Email;
use Symfony\Component\Mime\Message;
use Symfony\Component\Mime\Part\AbstractMultipartPart;
use Symfony\Component\Mime\Part\AbstractPart;
use Symfony\Component\Mime\Part\DataPart;
use Symfony\Component\Mime\Part\TextPart;
use Symfony\Component\Mime\RawMessage;
use Zenstruck\Assert;

Expand Down Expand Up @@ -55,10 +60,10 @@ public static function fromEvents(MessageEvents $events): self
$messages = \array_map(static fn(MessageEvent $event) => $event->getMessage(), $events);

// remove non Email messages
$messages = \array_filter($messages, static fn(RawMessage $message) => $message instanceof Email);
$messages = \array_filter($messages, static fn(RawMessage $message) => $message instanceof Message);

// convert to TestEmails
$messages = \array_map(static fn(Email $email) => new TestEmail($email), $messages);
$messages = \array_map([self::class, 'convertMessageToEmail'], $messages);

return new self(...$messages);
}
Expand Down Expand Up @@ -243,4 +248,46 @@ private static function emailsContain(array $addresses, string $needle): bool

return false;
}

private static function convertMessageToEmail(Message $message): TestEmail
{
if ($message instanceof Email) {
return new TestEmail($message);
}

$email = new Email($message->getHeaders());

if (!$body = $message->getBody()) {
return new TestEmail($email);
}

foreach (self::textParts($body) as $part) {
match (true) {
$part instanceof DataPart => \method_exists($email, 'addPart') ? $email->addPart($part) : $email->attachPart($part),
'plain' === $part->getMediaSubtype() => $email->text($part->getBody()),
'html' === $part->getMediaSubtype() => $email->html($part->getBody()),
default => null,
};
}

return new TestEmail($email);
}

/**
* @return TextPart[]
*/
private static function textParts(AbstractPart $part): iterable
{
if ($part instanceof TextPart) {
yield $part;
}

if (!$part instanceof AbstractMultipartPart) {
return;
}

foreach ($part->getParts() as $subPart) {
yield from self::textParts($subPart);
}
}
}
4 changes: 2 additions & 2 deletions src/TestEmail.php
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ final public function assertContains(string $expected): self
final public function assertHtmlContains(string $expected): self
{
Assert::that($this->email->getHtmlBody())
->contains($expected, 'The [text/html] part does not contain "{expected}".')
->contains($expected, 'The [text/html] part does not contain "{needle}".')
;

return $this;
Expand All @@ -227,7 +227,7 @@ final public function assertHtmlContains(string $expected): self
final public function assertTextContains(string $expected): self
{
Assert::that($this->email->getTextBody())
->contains($expected, 'The [text/plain] part does not contain "{expected}".')
->contains($expected, 'The [text/plain] part does not contain "{needle}".')
;

return $this;
Expand Down
72 changes: 72 additions & 0 deletions tests/InteractsWithMailerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

use PHPUnit\Framework\AssertionFailedError;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\Mime\Crypto\DkimSigner;
use Symfony\Component\Mime\Email;
use Zenstruck\Mailer\Test\InteractsWithMailer;
use Zenstruck\Mailer\Test\TestEmail;
Expand All @@ -27,6 +28,24 @@ final class InteractsWithMailerTest extends KernelTestCase
{
use EnvironmentProvider, InteractsWithMailer;

private const PRIVATE_KEY = <<<EOF
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQC6lQYNOMaboSOE/c2KNl8Rwk61zoMXrEmXC926an3/jHrtj9wB
ndP2DY2nUyz0vpmJlcDOjDwTGs8U/C7zn7PDdZ8EuuxlAa7oNo/38YYV+5Oki93m
io6rGV8zLMGLLygAB1sJaJVP5W9wm0RLY776YFL4V/nekA5ZTnA4+KaIYwIDAQAB
AoGAJLhjgoKkA8kI1omkxAjDWRlmqD1Ga4hKy2FYd/GxbnPVVZ+0atUG/Cvarw2d
kWVZjkxcr8nFoPTrwHOJQgUyOXWLuIuirznoTtDKzC+4JlDsZJd8hkVohqwKfdPA
v4iYceN6V0YRQpsLVwKJinr5k6oHpCGs3sNffpHQzrXc24ECQQDb0JLiMm5OZoYZ
G3739DsYVycUmYmYJtXuUBHTIwBAaOyo0yEmeQ8Li4H5dSSWqeOO0XrfP7cQ3TOm
6LuSrIXDAkEA2Uv2PuteQXGSzOEuQbDbYeR0Le0drDUFJkXBM4oS3XB3wx2+umD+
WqpfLEIXWV3/hkuottTmlsQuuAP3Xv+o4QJAf5FyTRfbcGCLnnKYoyn4Sc36fjgE
5GpVaXLKhXAgq0C5Z9jvujYzhw21pqJXU6DQ0Ye8+WcuxPi7Czix8xNwpQJBAMm1
vexCSMivSPpuvaW1KrEAhOhtB/JndVRFxEa3kTOFx2aUIgyZJQO8y4QmBc6rdxuO
+BpgH30st8GRzPuej4ECQAsLon/QgsyhkfquBMLDC1uhO027K59C/aYRlufPyHkq
HIyrMg2pQ46h2ybEuB50Cs+xF19KwBuGafBtRjkvXdU=
-----END RSA PRIVATE KEY-----
EOF;

/**
* @test
* @dataProvider environmentProvider
Expand Down Expand Up @@ -252,4 +271,57 @@ public function bundle_must_be_enabled(): void

$this->mailer();
}

/**
* @test
* @dataProvider environmentProvider
*/
public function can_get_signed_emails(string $environment): void
{
self::bootKernel(['environment' => $environment]);

$signer = new DkimSigner(self::PRIVATE_KEY, 'testdkim.symfony.net', 'sf');
$email1 = $signer->sign(new Email1());
$email2 = $signer->sign((new Email())->from('kevin@example.com')->to('html@example.com')->html('some html'));
$email3 = $signer->sign((new Email())->from('kevin@example.com')->to('text@example.com')->text('some text'));

self::getContainer()->get('mailer')->send($email1);
self::getContainer()->get('mailer')->send($email2);
self::getContainer()->get('mailer')->send($email3);

$this->mailer()->sentEmails()->assertCount(3);
$this->mailer()
->assertEmailSentTo('kevin@example.com', 'email subject')
->assertEmailSentTo('kevin@example.com', function(TestEmail $email) {
$email
->assertTo('kevin@example.com', 'Kevin')
->assertFrom('webmaster@example.com')
->assertCc('cc@example.com')
// ->assertBcc('bcc@example.com') // BCC is removed - see https://github.com/symfony/symfony/issues/48566
->assertReplyTo('reply@example.com')
->assertSubjectContains('sub')
->assertHtmlContains('html body')
->assertTextContains('text body')
->assertContains('body')
->assertHasFile('attachment.txt')
->assertHasFile('attachment.txt', 'text/plain')
->assertHasFile('attachment.txt', 'text/plain', "attachment contents\n")
->assertHasFile('name with space.txt', 'text/plain', "attachment contents\n")
;

// TestEmail can call underlying Symfony\Component\Mime\Email methods
$this->assertSame('Kevin', $email->getTo()[0]->getName());
})
->assertEmailSentTo('text@example.com', function(TestEmail $email) {
$email
->assertTextContains('some text')
;
})
->assertEmailSentTo('html@example.com', function(TestEmail $email) {
$email
->assertHtmlContains('some html')
;
})
;
}
}

0 comments on commit bb45289

Please sign in to comment.