How to test Laravel notification e-mail contents

Ralph J. Smit Laravel Software Engineer

In this tutorial I'll show you how to test the content of notifications in Laravel. This is particularly handy for testing whether certain data (like a confirmation number or certain credentials) is visible in the notification, similar to how you test 'regular' view.

For this tutorial I'll assume you already know how to make notifications in Laravel.

How test whether a Laravel notification has been sent

First, let's start with a simple example of testing whether a notification with subscription information was sent to a user. That could look something like this:

$user = User::factory();
 
$subscriptionData = [
'start_date' => now()->toDateString(),
'end_date' => null,
];
 
$user->notify(new \App\Notifications\Order\PaymentComplete($data));
 
Notification::assertSentTo($user, \App\Notifications\Order\PaymentComplete::class);

This will work nicely and it will correctly test whether this user has indeed received a notification.

As a small note, usually, the above piece of code will be part of (in most cases) a feature test. This means that the $subscriptionData and the $user->notify() will in most tests not be present here, but it will be part of your application logic.

How to test notification content

There are two ways you can use to test the email contents of a Laravel notification. The first way is to ensure that the notification was actually sent. After sending it, you can inspect the contents of the email that was sent.

The second way would be to write a unit Test for this specific notification.

I'll show you both approaches below, though I personally prefer the second approach.

Test Laravel notification content after sending the email

The first approach is to send the email and then inspect its contents. Verifying that an email was sent can be done by using helpers like the Notification::assertSentTo() and Notification::assertSentToTimes().

A less commonly known feature of those functions is that you can also pass a callback to these helpers. Inside those callbacks, you can make additional assertions. You could use those assertions to verify things like the subject or attachments. In this case, we'll use it as a way to add a custom notification assertion:

// Prepare
$user = User::factory();
 
$subscriptionData = [
'start_date' => now()->toDateString(),
'end_date' => null,
];
 
// Act
$user->notify((new \App\Notifications\Order\PaymentComplete($data)));
 
// Assert
Notification::assertSentTo($user, \App\Notifications\Order\PaymentComplete::class, function ($notification, $channels) use ($user, $subscriptionData) {
$mailData = $notification->toMail($user);
 
$this->assertStringContainsString("Start date: {$subscriptionData['start_date']}", $mailData->render());
 
return true;
});

One important thing here is that the callback should return true, because if it returns false, the whole assertSentTo() will fail. However, you could also use that to your own benefit, to clean up the test a little bit:

Notification::assertSentTo($user, \App\Notifications\Order\PaymentComplete::class, function ($notification, $channels) use ($user, $subscriptionData) {
return $notification->toMail($user)->subject === 'Your subscription information';
});

Test Laravel notification content without sending the email

The second method consists of not sending the email, but only rendering it. It is somewhat easier and cleaner on the eye, but in core it is still the same method as above:

// Prepare
$user = User::factory();
 
$subscriptionData = [
'start_date' => now()->toDateString(),
'end_date' => null,
];
 
// 'Act'
$notification = new \App\Notifications\Order\PaymentComplete($response);
$rendered = $notification->toMail($user)->render();
 
// Assert
$this->assertStringContainsString("Start date: {$subscriptionData['start_date']}", $rendered);

This method allows for less 'overhead' and serves to keep your feature tests more clean. What I mean by that is that your feature tests are not responsible anymore for testing the content of the email, but only that it was sent. As soon as we verify in the feature tests that the notification was sent and we have a unit test that is responsible for testing the notification itself, we can be pretty sure that everything works correctly.

Conclusion

As you've seen, testing Laravel notification content is not difficult, you only need to know the right tricks. I hope this was useful for you!

As a last tip, I'd recommend to dump() the $notification->toMail($notifiable). You'll then get all the available content of the notification and you can do some cool assertions on almost everything (subject, attachments, etc).

You can also checkout my previous article and learn how to test whether a notification has actually been sent a certain number of times (e.g. only once and not accidentally twice🙀).

Published by Ralph J. Smit on in Laravel . Last updated on 11 March 2022 .