assert attachments
Is there a way to assert attachments? I tried accessing them via intercepted mail collection but it's values are private.
That is a great question and sorry I missed this question earlier. I'll look into that. That would be a good addition.
Any news on this ?
No news. I haven't been able to make time to make this addition. A PR is welcome, however ;)
Roughly 4 years ago, I had to implement my own mail interception as I didn't come across this library. I wanted to transition to this now but it lacks attachments api that I had already written. Here is the attachment part from my implementation which can give some direction if someone wants to implement it in this library:
public function assertMailHasAttachment($name = null, $mimeType = null)
{
$email = $this->lastEmail();
$attachments = collect($email->getAttachments())->filter(function (DataPart $dataPart) use ($mimeType, $name) {
$attachmentFilename = $dataPart->getPreparedHeaders()->getHeaderParameter('Content-Disposition', 'filename');
$attachmentMimeType = $dataPart->getPreparedHeaders()->getHeaderBody('Content-Type');
$valid = true;
if ($name) {
$valid = $valid && $attachmentFilename === $name;
}
if ($mimeType) {
$valid = $valid && $attachmentMimeType === $mimeType;
}
return $valid;
});
$helpMessage = "Could not find any attachment";
if ($name || $mimeType) {
$helpMessage .= " with " . collect(['name' => $name, 'mime type' => $mimeType])
->filter()
->map(fn($v, $key) => "$key \"$v\"")
->join(' and ');
}
Assert::assertNotEmpty($attachments, $helpMessage);
return $this;
}
Here is my full implementation:
Click to expand...
<?php
namespace App\Traits;
use Illuminate\Testing\Assert;
use Illuminate\Testing\Constraints\SeeInOrder;
use Illuminate\Support\Collection;
use Symfony\Component\Mailer\SentMessage;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Email;
use Symfony\Component\Mime\Part\DataPart;
trait InteractsWithMail
{
/**
* @return Collection<int, SentMessage>
*/
public function getMessages()
{
return app('mailer')->getSymfonyTransport()->messages();
}
/** @before */
public function setUpInteractsWithMail()
{
$this->afterApplicationCreated(function () {
config()->set('mail.driver', 'array');
});
}
public function lastEmail(): Email
{
return $this->getMessages()->last()->getOriginalMessage();
}
/// Assertions
public function assertMailSent()
{
$this->assertTrue($this->getMessages()->isNotEmpty(), 'No mail has been sent');
return $this;
}
public function assertMailSentTo($mail, $name = null)
{
$email = $this->lastEmail();
$to = collect($email->getTo())
->map(fn(Address $address) => ['name' => $address->getName(), 'address' => $address->getAddress()])
->pluck('name', 'address');
$helpMessage = function ($key) use ($to) {
$v = json_encode($to);
return "Could not find the given $key in $v";
};
$this->assertArrayHasKey($mail, $to, $helpMessage($mail));
if ($name) {
$this->assertEquals($name, $to[$mail] ?? null, $helpMessage($name));
}
return $this;
}
public function assertMailSentFrom($mail, $name = null)
{
$email = $this->lastEmail();
$from = collect($email->getFrom())
->map(fn(Address $address) => ['name' => $address->getName(), 'address' => $address->getAddress()])
->pluck('name', 'address');
$helpMessage = function ($key) use ($from) {
$v = json_encode($from);
return "Could not find the given $key in $v";
};
$this->assertArrayHasKey($mail, $from, $helpMessage($mail));
if ($name) {
$this->assertEquals($name, $from[$mail] ?? null, $helpMessage($name));
}
return $this;
}
public function assertMailSubject($value)
{
$email = $this->lastEmail();
$this->assertEquals($value, $email->getSubject());
return $this;
}
public function assertMailContainsText($value)
{
$email = $this->lastEmail();
Assert::assertStringContainsString((string)$value, strip_tags($email->getHtmlBody()));
return $this;
}
public function assertMailContainsTextInOrder(array $values)
{
$email = $this->lastEmail();
Assert::assertThat($values, new SeeInOrder(strip_tags($email->getHtmlBody())));
return $this;
}
public function assertMailContainsRaw($value)
{
$email = $this->lastEmail();
Assert::assertStringContainsString((string)$value, $email->getHtmlBody());
return $this;
}
public function assertMailHasAttachment($name = null, $mimeType = null)
{
$email = $this->lastEmail();
$attachments = collect($email->getAttachments())->filter(function (DataPart $dataPart) use ($mimeType, $name) {
$attachmentFilename = $dataPart->getPreparedHeaders()->getHeaderParameter('Content-Disposition', 'filename');
$attachmentMimeType = $dataPart->getPreparedHeaders()->getHeaderBody('Content-Type');
$valid = true;
if ($name) {
$valid = $valid && $attachmentFilename === $name;
}
if ($mimeType) {
$valid = $valid && $attachmentMimeType === $mimeType;
}
return $valid;
});
$helpMessage = "Could not find any attachment";
if ($name || $mimeType) {
$helpMessage .= " with " . collect(['name' => $name, 'mime type' => $mimeType])
->filter()
->map(fn($v, $key) => "$key \"$v\"")
->join(' and ');
}
Assert::assertNotEmpty($attachments, $helpMessage);
return $this;
}
}
Thank you for this! Hopefully I can get some extra time in the very near future to implement this.