From 8fb9843d29b931fc085c97782b803ba8cf5852e4 Mon Sep 17 00:00:00 2001 From: Kevin Bond Date: Thu, 30 Sep 2021 17:52:38 -0400 Subject: [PATCH] [feature] add TestEmail tag/metadata access/assertions --- README.md | 5 ++ src/TestEmail.php | 74 ++++++++++++++++++++++++++++ tests/Fixture/Email1.php | 9 ++++ tests/TestEmailTest.php | 101 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 189 insertions(+) create mode 100644 tests/TestEmailTest.php diff --git a/README.md b/README.md index 8cc5f0b..f1edc33 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,11 @@ class MyTest extends KernelTestCase // or WebTestCase ->assertHtmlContains('some text') ->assertContains('some text') // asserts text and html both contain a value ->assertHasFile('file.txt', 'text/plain', 'Hello there!') + + // tag/meta data assertions (https://symfony.com/doc/current/mailer.html#adding-tags-and-metadata-to-emails) + ->assertHasTag('password-reset') + ->assertHasMetadata('Color') + ->assertHasMetadata('Color', 'blue') ; // Any \Symfony\Component\Mime\Email methods can be used diff --git a/src/TestEmail.php b/src/TestEmail.php index 044349d..c6c10ed 100644 --- a/src/TestEmail.php +++ b/src/TestEmail.php @@ -2,6 +2,8 @@ namespace Zenstruck\Mailer\Test; +use Symfony\Component\Mailer\Header\MetadataHeader; +use Symfony\Component\Mailer\Header\TagHeader; use Symfony\Component\Mime\Email; use Zenstruck\Assert; @@ -24,6 +26,54 @@ final public function __call($name, $arguments) return $this->email->{$name}(...$arguments); } + /** + * @return string|null The first {@see TagHeader} value found or null if none + */ + final public function tag(): ?string + { + return $this->tags()[0] ?? null; + } + + /** + * @return string[] The {@see TagHeader} values + */ + final public function tags(): array + { + if (!\class_exists(TagHeader::class)) { + throw new \BadMethodCallException('Tags can only be used in symfony/mailer 5.1+.'); + } + + $tags = []; + + foreach ($this->getHeaders()->all() as $header) { + if ($header instanceof TagHeader) { + $tags[] = $header->getValue(); + } + } + + return $tags; + } + + /** + * @return array The {@see MetadataHeader} keys/values + */ + final public function metadata(): array + { + if (!\class_exists(MetadataHeader::class)) { + throw new \BadMethodCallException('Metadata can only be used in symfony/mailer 5.1+.'); + } + + $metadata = []; + + foreach ($this->getHeaders()->all() as $header) { + if ($header instanceof MetadataHeader) { + $metadata[$header->getKey()] = $header->getValue(); + } + } + + return $metadata; + } + final public function assertSubject(string $expected): self { Assert::that($this->email->getSubject())->is($expected); @@ -157,4 +207,28 @@ final public function assertHasFile(string $expectedFilename, string $expectedCo Assert::fail("Message does not include file with filename [{$expectedFilename}]"); } + + final public function assertHasTag(string $expected): self + { + Assert::that($this->tags()) + ->isNotEmpty('No tags found.') + ->contains($expected, 'Expected to have tag "{needle}".') + ; + + return $this; + } + + final public function assertHasMetadata(string $expectedKey, ?string $expectedValue = null): self + { + Assert::that($metadata = $this->metadata())->isNotEmpty('No metadata found.'); + Assert::that(\array_keys($metadata))->contains($expectedKey, 'Expected to have metadata key "{needle}".'); + + if (null !== $expectedValue) { + Assert::that($metadata[$expectedKey])->is($expectedValue, 'Expected metadata "{key}" to be "{expected}".', [ + 'key' => $expectedKey, + ]); + } + + return $this; + } } diff --git a/tests/Fixture/Email1.php b/tests/Fixture/Email1.php index 91a1226..66dd10c 100644 --- a/tests/Fixture/Email1.php +++ b/tests/Fixture/Email1.php @@ -2,6 +2,8 @@ namespace Zenstruck\Mailer\Test\Tests\Fixture; +use Symfony\Component\Mailer\Header\MetadataHeader; +use Symfony\Component\Mailer\Header\TagHeader; use Symfony\Component\Mime\Address; use Symfony\Component\Mime\Email; @@ -25,5 +27,12 @@ public function __construct() ->html('html body') ->text('text body') ; + + $this->getHeaders() + ->add(new TagHeader('foo')) + ->add(new TagHeader('bar')) + ->add(new MetadataHeader('color', 'blue')) + ->add(new MetadataHeader('id', '5')) + ; } } diff --git a/tests/TestEmailTest.php b/tests/TestEmailTest.php new file mode 100644 index 0000000..fda7f60 --- /dev/null +++ b/tests/TestEmailTest.php @@ -0,0 +1,101 @@ + + */ +final class TestEmailTest extends TestCase +{ + /** + * @test + */ + public function can_access_tags(): void + { + $this->requiresMailer51(); + + $noTags = new TestEmail(new Email()); + + $this->assertNull($noTags->tag()); + $this->assertSame([], $noTags->tags()); + + $withTags = new TestEmail(new Email1()); + + $this->assertSame('foo', $withTags->tag()); + $this->assertSame(['foo', 'bar'], $withTags->tags()); + } + + /** + * @test + */ + public function can_access_metadata(): void + { + $this->requiresMailer51(); + + $noMetadata = new TestEmail(new Email()); + + $this->assertSame([], $noMetadata->metadata()); + + $withMetadata = new TestEmail(new Email1()); + + $this->assertSame(['color' => 'blue', 'id' => '5'], $withMetadata->metadata()); + } + + /** + * @test + */ + public function can_assert_has_tag(): void + { + $this->requiresMailer51(); + + $withTags = new TestEmail(new Email1()); + + $withTags->assertHasTag('foo'); + $withTags->assertHasTag('bar'); + + Assert::that(fn() => $withTags->assertHasTag('baz'))->throws( + AssertionFailedError::class, 'Expected to have tag "baz".' + ); + Assert::that(fn() => (new TestEmail(new Email()))->assertHasTag('foo'))->throws( + AssertionFailedError::class, 'No tags found.' + ); + } + + /** + * @test + */ + public function can_assert_has_metadata(): void + { + $this->requiresMailer51(); + + $withMetadata = new TestEmail(new Email1()); + + $withMetadata->assertHasMetadata('color'); + $withMetadata->assertHasMetadata('color', 'blue'); + + Assert::that(fn() => $withMetadata->assertHasMetadata('color', 'red'))->throws( + AssertionFailedError::class, 'Expected metadata "color" to be "red".' + ); + Assert::that(fn() => $withMetadata->assertHasMetadata('foo'))->throws( + AssertionFailedError::class, 'Expected to have metadata key "foo"' + ); + Assert::that(fn() => (new TestEmail(new Email()))->assertHasMetadata('foo'))->throws( + AssertionFailedError::class, 'No metadata found.' + ); + } + + private function requiresMailer51(): void + { + if (!\class_exists(TagHeader::class)) { + $this->markTestSkipped('Requires symfony/mailer 5.1+'); + } + } +}