DEV Community

Peter Fox
Peter Fox

Posted on • Originally published at Medium on

Laravel Tip: Testing your emails contents

Photo by CDC on Unsplash

One of the things I originally found difficult in the Laravel framework is testing emails. As someone who’s worked on a package to perform unsubscribes in Laravel I’ve had to deal with testing quite a few emails for their final rendered content and it’s not as obvious as it seems. You might be thinking, wait a minute there’s a Mail fake and Notifications fake, and these work? But actually they do not allow you to test the final rendered email because they only allow you to test if a notification or mailable has been ‘sent’ but this happens before the email is rendered. This can be difficult if you need to test that something was actually rendered in your email. For instance, when I made my unsubscribe package I needed to test that the links for unsubscribing made it into the email body and that particular headers were added to the email. It’s not immediately obvious how to test that from the Laravel documentation so I thought I’d share how I’ve accomplished this.

Test email contents using the Event Fake

If you didn’t know, the Event fake is actually pretty useful. This is because no matter what way you’re sending an email, either by notification or by mailable, events are fired giving you the final email content as a \Swift_Message object.

To do this first you need to use the Event fake() method of the facade to catch the MessageSending event. What this means is every time an email is attempted to be sent, the event will be caught by the Event fake.

<?php
namespace Tests\Feature;
use Illuminate\Mail\Events\MessageSending;
use Illuminate\Support\Facades\Event;
class ExampleTest extends TestCase
{
public function testEmailContainsString()
{
// Swapping out the event dispatcher for a fake
Event::fake([MessageSending::class]);
}
}
view raw ExampleTest.php hosted with ❤ by GitHub

Once we have this in a test we can trigger our code to send an email and perform an assertion on the event.

<?php
namespace Tests\Feature;
use Illuminate\Mail\Events\MessageSending;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Mail;
use App\Mail\ExampleMailable;
class ExampleTest extends TestCase
{
public function testEmailContainsString()
{
// Swapping out the event dispatcher for a fake
Event::fake([MessageSending::class]);
$mailable = new ExampleMailable();
Mail::send($mailable);
}
}
view raw ExampleTest.php hosted with ❤ by GitHub

Below is an example of what one of these completed tests might look like. The beauty of this system is you can also test for things like the to, cc and bcc addresses are correct or that a special header you’ve added has been applied to the message instance.

<?php
namespace Tests\Feature;
use Illuminate\Mail\Events\MessageSending;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Mail;
use App\Mail\ExampleMailable;
class ExampleTest extends TestCase
{
public function testEmailContainsString()
{
// Swapping out the event dispatcher for a fake
Event::fake([MessageSending::class]);
$mailable = new ExampleMailable();
Mail::send($mailable);
Event::assertDispatched(MessageSending::class, function (MessageSending $event) {
$this->assertStringContainsString('Hello', $event->message->getBody());
return true; // always make sure it returns true or it will result in a failed assertion;
});
}
}
view raw ExampleTest.php hosted with ❤ by GitHub

If you’d like to take this even further you could use Laravel Mojito. By installing the package you can pass the HTML content to a new ViewAssertion instance which then lets you make more structured assertions against the email content.

<?php
namespace Tests\Feature;
use Illuminate\Mail\Events\MessageSending;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Mail;
use App\Mail\ExampleMailable;
use NunoMaduro\LaravelMojito\ViewAssertion;
class ExampleTest extends TestCase
{
public function testEmailContainsString()
{
// Swapping out the event dispatcher for a fake
Event::fake([MessageSending::class]);
$mailable = new ExampleMailable();
Mail::send($mailable);
Event::assertDispatched(MessageSending::class, function (MessageSending $event) {
(new ViewAssertion($event->message->getBody()))->contains('Hello');
return true; // always make sure it returns true or it will result in a failed assertion;
});
}
}

Conclusion

Not a lot more to say to this one. It you find yourself needing to test that your blade views are rendering correctly into HTML emails etc then this is a fairly quick and easy way to test it. Good luck!

I’m Peter Fox, a software developer in the UK who works with Laravel among other things. Thank you for reading my article. I’ve got several more on both medium and dev.to that. If you want to know more about me, head over to https://www.peterfox.me. Also feel free to follow me @SlyFireFox on twitter for more Laravel tips and tutorials in the future.

Image of Docusign

🛠️ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

AWS Security LIVE!

Hosted by security experts, AWS Security LIVE! showcases AWS Partners tackling real-world security challenges. Join live and get your security questions answered.

Tune in to the full event

DEV is partnering to bring live events to the community. Join us or dismiss this billboard if you're not interested. ❤️