kirschbaum-development / mail-intercept

A testing package for intercepting mail sent from Laravel
MIT License
104 stars 7 forks source link

assert attachments #13

Open jamesj2 opened 2 years ago

jamesj2 commented 2 years ago

Is there a way to assert attachments? I tried accessing them via intercepted mail collection but it's values are private.

brandonferens commented 1 year ago

That is a great question and sorry I missed this question earlier. I'll look into that. That would be a good addition.

rabol commented 11 months ago

Any news on this ?

brandonferens commented 11 months ago

No news. I haven't been able to make time to make this addition. A PR is welcome, however ;)

OrkhanAlikhanov commented 2 months ago

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 */ 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; } } ```
brandonferens commented 1 month ago

Thank you for this! Hopefully I can get some extra time in the very near future to implement this.