diff --git a/README.md b/README.md
index fa1dc02..23457c6 100644
--- a/README.md
+++ b/README.md
@@ -151,6 +151,17 @@ This should be called after `Mail` has been sent, but before your assertions, ot
| `$intercepted->assertPriorityIsLowest();` | |
| `$intercepted->assertPriorityIsLowest();` | |
+| Attachment Assertions | Parameters |
+|:-------------------------------------------------------|:-------------------|
+| `$intercepted->assertHasAttachment($filename);` | `$filename` string |
+| `$intercepted->assertHasAttachments();` | |
+| `$intercepted->assertMissingAttachment($filename);` | `$filename` string |
+| `$intercepted->assertMissingAttachments();` | |
+| `$intercepted->assertHasEmbeddedImage($filename);` | `$filename` string |
+| `$intercepted->assertHasEmbeddedImages();` | |
+| `$intercepted->assertMissingEmbeddedImage($filename);` | `$filename` string |
+| `$intercepted->assertMissingEmbeddedImages();` | |
+
#### Assertion Methods
| Assertions | Parameters |
@@ -211,6 +222,17 @@ This should be called after `Mail` has been sent, but before your assertions, ot
| `$this->assertMailPriorityIsLowest($mail);` | `$mail` AssertableMessage, Email |
| `$this->assertMailPriorityIsLowest($mail);` | `$mail` AssertableMessage, Email |
+| Attachment Assertions | Parameters |
+|:---------------------------------------------------|:--------------------------------------------------------|
+| `this->assertMailHasAttachment($filename);` | `$filename` string
`$mail` AssertableMessage, Email |
+| `this->assertMailHasAttachments();` | `$mail` AssertableMessage, Email |
+| `this->assertMailMissingAttachment($filename);` | `$filename` string
`$mail` AssertableMessage, Email |
+| `this->assertMailMissingAttachments();` | `$mail` AssertableMessage, Email |
+| `this->assertMailHasEmbeddedImage($filename);` | `$filename` string
`$mail` AssertableMessage, Email |
+| `this->assertMailHasEmbeddedImages();` | `$mail` AssertableMessage, Email |
+| `this->assertMailMissingEmbeddedImage($filename);` | `$filename` string
`$mail` AssertableMessage, Email |
+| `this->assertMailMissingEmbeddedImages();` | `$mail` AssertableMessage, Email |
+
You should use each item of the `interceptedMail()` collection as the mail object for all assertions.
If you are injecting your own headers or need access to other headers in the email, use this assertion to verify they exist and are set properly. These assertions require the header name and the compiled email.
diff --git a/src/AssertableMessage.php b/src/AssertableMessage.php
index 7388c1e..cc51adb 100644
--- a/src/AssertableMessage.php
+++ b/src/AssertableMessage.php
@@ -54,6 +54,14 @@
* @method assertMissingHeader(string $expected)
* @method assertHeaderIs(string $expected, string $expectedValue)
* @method assertHeaderIsNot(string $expected, string $expectedValue)
+ * @method assertHasAttachment(string $filename)
+ * @method assertHasAttachments()
+ * @method assertMissingAttachment(string $filename)
+ * @method assertMissingAttachments()
+ * @method assertHasEmbeddedImage(string $filename)
+ * @method assertHasEmbeddedImages()
+ * @method assertMissingEmbeddedImage(string $filename)
+ * @method assertMissingEmbeddedImages()
*/
class AssertableMessage extends Assert
{
diff --git a/src/Assertions/AttachmentAssertions.php b/src/Assertions/AttachmentAssertions.php
new file mode 100644
index 0000000..8be8471
--- /dev/null
+++ b/src/Assertions/AttachmentAssertions.php
@@ -0,0 +1,147 @@
+assertNotEmpty(
+ $mail->getAttachments(),
+ 'Mail missing expected attachments.'
+ );
+ }
+
+ /**
+ * Assert mail missing attachments.
+ */
+ public function assertMailMissingAttachments(AssertableMessage|Email $mail): void
+ {
+ $this->assertEmpty(
+ $mail->getAttachments(),
+ 'Mail has expected attachments.'
+ );
+ }
+
+ /**
+ * Assert mail has attachment.
+ */
+ public function assertMailHasAttachment(string $expected, AssertableMessage|Email $mail): void
+ {
+ $hasAttachment = collect($mail->getAttachments())
+ ->contains(fn (DataPart $attachment) => $expected === $attachment->getFilename());
+
+ $this->assertTrue(
+ $hasAttachment,
+ 'Mail missing expected attachment.'
+ );
+ }
+
+ /**
+ * Assert mail missing attachment.
+ */
+ public function assertMailMissingAttachment(string $expected, AssertableMessage|Email $mail): void
+ {
+ $missingAttachment = ! collect($mail->getAttachments())
+ ->contains(fn (DataPart $attachment) => $expected === $attachment->getFilename());
+
+ $this->assertTrue(
+ $missingAttachment,
+ 'Mail has expected attachment.'
+ );
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | Embedded Images
+ |--------------------------------------------------------------------------
+ */
+
+ /**
+ * Assert mail has attachments.
+ */
+ public function assertMailHasEmbeddedImages(AssertableMessage|Email $mail): void
+ {
+ $hasEmbedded = collect($mail->getAttachments())
+ ->contains(fn (DataPart $attachment) => $attachment->getDisposition() === 'inline');
+
+ $this->assertTrue(
+ $hasEmbedded,
+ 'Mail missing embedded images.'
+ );
+ }
+
+ /**
+ * Assert mail missing attachments.
+ */
+ public function assertMailMissingEmbeddedImages(AssertableMessage|Email $mail): void
+ {
+ $missingEmbedded = ! collect($mail->getAttachments())
+ ->contains(fn (DataPart $attachment) => $attachment->getDisposition() === 'inline');
+
+ $this->assertTrue(
+ $missingEmbedded,
+ 'Mail has embedded images.'
+ );
+ }
+
+ /**
+ * Assert mail has attachment.
+ */
+ public function assertMailHasEmbeddedImage(string $expected, AssertableMessage|Email $mail): void
+ {
+ /**
+ * @var DataPart|null $embed
+ */
+ $embed = collect($mail->getAttachments())
+ ->firstWhere(fn (DataPart $attachment) => $expected === $attachment->getFilename());
+
+ if ($embed) {
+ $this->assertTrue(
+ $embed->getDisposition() === 'inline',
+ 'Mail has expected attachment but is not embedded.'
+ );
+
+ return;
+ }
+
+ throw new ExpectationFailedException('Mail missing expected embedded image.');
+ }
+
+ /**
+ * Assert mail missing attachment.
+ */
+ public function assertMailMissingEmbeddedImage(string $expected, AssertableMessage|Email $mail): void
+ {
+ /**
+ * @var DataPart|null $embed
+ */
+ $embed = collect($mail->getAttachments())
+ ->firstWhere(fn (DataPart $attachment) => $expected === $attachment->getFilename());
+
+ if (! $embed) {
+ $this->assertNull($embed);
+
+ return;
+ }
+
+ $this->assertTrue(
+ $embed->getDisposition() !== 'inline',
+ 'Mail has expected embedded image.'
+ );
+ }
+}
diff --git a/src/WithMailInterceptor.php b/src/WithMailInterceptor.php
index c22cd61..057b4db 100644
--- a/src/WithMailInterceptor.php
+++ b/src/WithMailInterceptor.php
@@ -4,6 +4,7 @@
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Config;
+use KirschbaumDevelopment\MailIntercept\Assertions\AttachmentAssertions;
use KirschbaumDevelopment\MailIntercept\Assertions\BccAssertions;
use KirschbaumDevelopment\MailIntercept\Assertions\CcAssertions;
use KirschbaumDevelopment\MailIntercept\Assertions\ContentAssertions;
@@ -21,6 +22,7 @@
trait WithMailInterceptor
{
+ use AttachmentAssertions;
use BccAssertions;
use CcAssertions;
use ContentAssertions;
diff --git a/tests/AttachmentAssertionsTest.php b/tests/AttachmentAssertionsTest.php
new file mode 100644
index 0000000..cd0770f
--- /dev/null
+++ b/tests/AttachmentAssertionsTest.php
@@ -0,0 +1,213 @@
+addPart(new DataPart(new File(__DIR__ . '/../Fixtures/f-18.jpg')));
+
+ $this->assertMailHasAttachments($mail);
+ }
+
+ public function testMailHasAttachmentsThrowsProperExpectationFailedException()
+ {
+ $mail = (new Email());
+
+ $this->expectException(ExpectationFailedException::class);
+ $this->expectExceptionMessage('Mail missing expected attachments.');
+
+ $this->assertMailHasAttachments($mail);
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | assertMailMissingAttachments
+ |--------------------------------------------------------------------------
+ */
+
+ public function testMailMissingAttachments()
+ {
+ $mail = (new Email());
+
+ $this->assertMailMissingAttachments($mail);
+ }
+
+ public function testMailMissingAttachmentsThrowsProperExpectationFailedException()
+ {
+ $mail = (new Email())->addPart(new DataPart(new File(__DIR__ . '/../Fixtures/f-18.jpg')));
+
+ $this->expectException(ExpectationFailedException::class);
+ $this->expectExceptionMessage('Mail has expected attachments.');
+
+ $this->assertMailMissingAttachments($mail);
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | testMailHasAttachment
+ |--------------------------------------------------------------------------
+ */
+
+ public function testMailHasAttachment()
+ {
+ $mail = (new Email())->addPart(new DataPart(new File(__DIR__ . '/../Fixtures/f-18.jpg')));
+
+ $this->assertMailHasAttachment('f-18.jpg', $mail);
+ }
+
+ public function testMailHasAttachmentThrowsProperExpectationFailedException()
+ {
+ $mail = (new Email());
+
+ $this->expectException(ExpectationFailedException::class);
+ $this->expectExceptionMessage('Mail missing expected attachment.');
+
+ $this->assertMailHasAttachment('f-18.jpg', $mail);
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | testMailMissingAttachment
+ |--------------------------------------------------------------------------
+ */
+
+ public function testMailMissingAttachment()
+ {
+ $mail = (new Email());
+
+ $this->assertMailMissingAttachment('f-18.jpg', $mail);
+ }
+
+ public function testMailMissingAttachmentThrowsProperExpectationFailedException()
+ {
+ $mail = (new Email())->addPart(new DataPart(new File(__DIR__ . '/../Fixtures/f-18.jpg')));
+
+ $this->expectException(ExpectationFailedException::class);
+ $this->expectExceptionMessage('Mail has expected attachment.');
+
+ $this->assertMailMissingAttachment('f-18.jpg', $mail);
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | assertMailHasEmbeddedImages
+ |--------------------------------------------------------------------------
+ */
+
+ public function testMailHasEmbeddedImages()
+ {
+ $mail = (new Email())->addPart((new DataPart(new File(__DIR__ . '/../Fixtures/f-18.jpg')))->asInline());
+
+ $this->assertMailHasEmbeddedImages($mail);
+ }
+
+ public function testMailHasEmbeddedImagesThrowsProperExpectationFailedException()
+ {
+ $mail = (new Email());
+
+ $this->expectException(ExpectationFailedException::class);
+ $this->expectExceptionMessage('Mail missing embedded images.');
+
+ $this->assertMailHasEmbeddedImages($mail);
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | assertMailMissingEmbeddedImages
+ |--------------------------------------------------------------------------
+ */
+
+ public function testMailMissingEmbeddedImages()
+ {
+ $mail = (new Email());
+
+ $this->assertMailMissingEmbeddedImages($mail);
+ }
+
+ public function testMailMissingEmbeddedImagesThrowsProperExpectationFailedException()
+ {
+ $mail = (new Email())->addPart((new DataPart(new File(__DIR__ . '/../Fixtures/f-18.jpg')))->asInline());
+
+ $this->expectException(ExpectationFailedException::class);
+ $this->expectExceptionMessage('Mail has embedded images.');
+
+ $this->assertMailMissingEmbeddedImages($mail);
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | testMailHasEmbeddedImage
+ |--------------------------------------------------------------------------
+ */
+
+ public function testMailHasEmbeddedImage()
+ {
+ $mail = (new Email())->addPart((new DataPart(new File(__DIR__ . '/../Fixtures/f-18.jpg')))->asInline());
+
+ $this->assertMailHasEmbeddedImage('f-18.jpg', $mail);
+ }
+
+ public function testMailHasEmbeddedImageThrowsProperExpectationFailedException()
+ {
+ $mail = (new Email());
+
+ $this->expectException(ExpectationFailedException::class);
+ $this->expectExceptionMessage('Mail missing expected embedded image.');
+
+ $this->assertMailHasEmbeddedImage('f-18.jpg', $mail);
+ }
+
+ public function testMailHasEmbeddedImageButCheckingForWrongImageThrowsProperExpectationFailedException()
+ {
+ $mail = (new Email());
+
+ $this->expectException(ExpectationFailedException::class);
+ $this->expectExceptionMessage('Mail missing expected embedded image.');
+
+ $this->assertMailHasEmbeddedImage('f-22.jpg', $mail);
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | testMailMissingEmbeddedImage
+ |--------------------------------------------------------------------------
+ */
+
+ public function testMailMissingEmbeddedImage()
+ {
+ $mail = (new Email());
+
+ $this->assertMailMissingEmbeddedImage('f-18.jpg', $mail);
+ }
+
+ public function testMailMissingEmbeddedImageThrowsProperExpectationFailedException()
+ {
+ $mail = (new Email())->addPart((new DataPart(new File(__DIR__ . '/../Fixtures/f-18.jpg')))->asInline());
+
+ $this->expectException(ExpectationFailedException::class);
+ $this->expectExceptionMessage('Mail has expected embedded image.');
+
+ $this->assertMailMissingEmbeddedImage('f-18.jpg', $mail);
+ }
+
+ public function testMailHasEmbeddedImageButCheckingForDifferentImage()
+ {
+ $mail = (new Email())->addPart((new DataPart(new File(__DIR__ . '/../Fixtures/f-18.jpg')))->asInline());
+
+ $this->assertMailMissingEmbeddedImage('f-22.jpg', $mail);
+ }
+}
diff --git a/tests/Fixtures/f-18.jpg b/tests/Fixtures/f-18.jpg
new file mode 100644
index 0000000..cfab7de
Binary files /dev/null and b/tests/Fixtures/f-18.jpg differ
diff --git a/tests/Fluent/AttachmentAssertionsTest.php b/tests/Fluent/AttachmentAssertionsTest.php
new file mode 100644
index 0000000..69303d4
--- /dev/null
+++ b/tests/Fluent/AttachmentAssertionsTest.php
@@ -0,0 +1,250 @@
+addPart(new DataPart(new File(__DIR__ . '/../Fixtures/f-18.jpg')))
+ );
+
+ $mail->assertHasAttachments($mail);
+ }
+
+ public function testMailHasAttachmentsThrowsProperExpectationFailedException()
+ {
+ $mail = new AssertableMessage(
+ new Email()
+ );
+
+ $this->expectException(ExpectationFailedException::class);
+ $this->expectExceptionMessage('Mail missing expected attachments.');
+
+ $mail->assertHasAttachments($mail);
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | assertMailMissingAttachments
+ |--------------------------------------------------------------------------
+ */
+
+ public function testMailMissingAttachments()
+ {
+ $mail = new AssertableMessage(
+ new Email()
+ );
+
+ $mail->assertMissingAttachments($mail);
+ }
+
+ public function testMailMissingAttachmentsThrowsProperExpectationFailedException()
+ {
+ $mail = new AssertableMessage(
+ (new Email())->addPart(new DataPart(new File(__DIR__ . '/../Fixtures/f-18.jpg')))
+ );
+
+ $this->expectException(ExpectationFailedException::class);
+ $this->expectExceptionMessage('Mail has expected attachments.');
+
+ $mail->assertMissingAttachments($mail);
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | testMailHasAttachment
+ |--------------------------------------------------------------------------
+ */
+
+ public function testMailHasAttachment()
+ {
+ $mail = new AssertableMessage(
+ (new Email())->addPart(new DataPart(new File(__DIR__ . '/../Fixtures/f-18.jpg')))
+ );
+
+ $mail->assertHasAttachment('f-18.jpg', $mail);
+ }
+
+ public function testMailHasAttachmentThrowsProperExpectationFailedException()
+ {
+ $mail = new AssertableMessage(
+ new Email()
+ );
+
+ $this->expectException(ExpectationFailedException::class);
+ $this->expectExceptionMessage('Mail missing expected attachment.');
+
+ $mail->assertHasAttachment('f-18.jpg', $mail);
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | testMailMissingAttachment
+ |--------------------------------------------------------------------------
+ */
+
+ public function testMailMissingAttachment()
+ {
+ $mail = new AssertableMessage(
+ new Email()
+ );
+
+ $mail->assertMissingAttachment('f-18.jpg', $mail);
+ }
+
+ public function testMailMissingAttachmentThrowsProperExpectationFailedException()
+ {
+ $mail = new AssertableMessage(
+ (new Email())->addPart(new DataPart(new File(__DIR__ . '/../Fixtures/f-18.jpg')))
+ );
+
+ $this->expectException(ExpectationFailedException::class);
+ $this->expectExceptionMessage('Mail has expected attachment.');
+
+ $mail->assertMissingAttachment('f-18.jpg', $mail);
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | assertMailHasEmbeddedImages
+ |--------------------------------------------------------------------------
+ */
+
+ public function testMailHasEmbeddedImages()
+ {
+ $mail = new AssertableMessage(
+ (new Email())->addPart((new DataPart(new File(__DIR__ . '/../Fixtures/f-18.jpg')))->asInline())
+ );
+
+ $mail->assertHasEmbeddedImages($mail);
+ }
+
+ public function testMailHasEmbeddedImagesThrowsProperExpectationFailedException()
+ {
+ $mail = new AssertableMessage(
+ new Email()
+ );
+
+ $this->expectException(ExpectationFailedException::class);
+ $this->expectExceptionMessage('Mail missing embedded images.');
+
+ $mail->assertHasEmbeddedImages($mail);
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | assertMailMissingEmbeddedImages
+ |--------------------------------------------------------------------------
+ */
+
+ public function testMailMissingEmbeddedImages()
+ {
+ $mail = new AssertableMessage(
+ new Email()
+ );
+
+ $mail->assertMissingEmbeddedImages($mail);
+ }
+
+ public function testMailMissingEmbeddedImagesThrowsProperExpectationFailedException()
+ {
+ $mail = new AssertableMessage(
+ (new Email())->addPart((new DataPart(new File(__DIR__ . '/../Fixtures/f-18.jpg')))->asInline())
+ );
+
+ $this->expectException(ExpectationFailedException::class);
+ $this->expectExceptionMessage('Mail has embedded images.');
+
+ $mail->assertMissingEmbeddedImages($mail);
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | testMailHasEmbeddedImage
+ |--------------------------------------------------------------------------
+ */
+
+ public function testMailHasEmbeddedImage()
+ {
+ $mail = new AssertableMessage(
+ (new Email())->addPart((new DataPart(new File(__DIR__ . '/../Fixtures/f-18.jpg')))->asInline())
+ );
+
+ $mail->assertHasEmbeddedImage('f-18.jpg', $mail);
+ }
+
+ public function testMailHasEmbeddedImageThrowsProperExpectationFailedException()
+ {
+ $mail = new AssertableMessage(
+ new Email()
+ );
+
+ $this->expectException(ExpectationFailedException::class);
+ $this->expectExceptionMessage('Mail missing expected embedded image.');
+
+ $mail->assertHasEmbeddedImage('f-18.jpg', $mail);
+ }
+
+ public function testMailHasEmbeddedImageButCheckingForWrongImageThrowsProperExpectationFailedException()
+ {
+ $mail = new AssertableMessage(
+ new Email()
+ );
+
+ $this->expectException(ExpectationFailedException::class);
+ $this->expectExceptionMessage('Mail missing expected embedded image.');
+
+ $mail->assertHasEmbeddedImage('f-22.jpg', $mail);
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | testMailMissingEmbeddedImage
+ |--------------------------------------------------------------------------
+ */
+
+ public function testMailMissingEmbeddedImage()
+ {
+ $mail = new AssertableMessage(
+ new Email()
+ );
+
+ $mail->assertMissingEmbeddedImage('f-18.jpg', $mail);
+ }
+
+ public function testMailMissingEmbeddedImageThrowsProperExpectationFailedException()
+ {
+ $mail = new AssertableMessage(
+ (new Email())->addPart((new DataPart(new File(__DIR__ . '/../Fixtures/f-18.jpg')))->asInline())
+ );
+
+ $this->expectException(ExpectationFailedException::class);
+ $this->expectExceptionMessage('Mail has expected embedded image.');
+
+ $mail->assertMissingEmbeddedImage('f-18.jpg', $mail);
+ }
+
+ public function testMailHasEmbeddedImageButCheckingForDifferentImage()
+ {
+ $mail = new AssertableMessage(
+ (new Email())->addPart((new DataPart(new File(__DIR__ . '/../Fixtures/f-18.jpg')))->asInline())
+ );
+
+ $mail->assertMissingEmbeddedImage('f-22.jpg', $mail);
+ }
+}