Laravel Mailable Testing Tips

Intro

According to Laravel News: Testing Mailable Content in Laravel 8 few additional methods for testing mailable were added to Laravel 8.18.0.

Those are:

1.  assertSeeInHtml;
2.  assertDontSeeInHtml;
3.  assertSeeInText;
4.  assertDontSeeInText;

And here is an example of how you can use them:

public function test_mailable_content()
{
    $user = User::factory()->create();

    $mailable = new UserRegisteredMail($user);

    $mailable->assertSeeInText($user->email);
    $mailable->assertSeeInHtml('<b>Welcome</b>');

    $mailable->assertDontSeeInText($user->password);
    $mailable->assertDontSeeInHtml($user->password);
}

Let's do some testing

My approach for testing mailable is divided into 2 steps:

- make sure email is sent in a feature test;
- unit test mailable;

Feature Test

Let's first look at the feature test. As you can see here, I only make sure that the mail is either sent or queued. As you can see, there is also a callback where you can add an additional condition. If the condition fails, the mail won't' be sent.

// test/Feature/UserRegistrationTest.php

/** @test */
public function email_is_sent()
{
    $user = User::factory()->create();

    $this->actingAs($user)
        ->post('register');

    Mail::assertQueued(WelcomeMail::class, function ($mail) use ($user) {
        // some available methods here are: hasTo, hasBcc, hasCc, hasReplayTo, hasRecipient
        return $mail->hasTo($user->email);
    });
}

Unit Test

Bellow is the mailable unit test where I assert that the mail:

1. has specific text;
2. has subject;
3. has sender;
// test/Unit/PasswordChangedMailTest.php

<?php

namespace Tests\Unit\Mail;

use App\Mail\PasswordChangedMail;
use Tests\TestCase;

/** @see \App\Mail\PasswordChangedMail */
class PasswordChangedMailTest extends TestCase
{
    /** @test */
    public function email_contains_password_changed_text()
    {
        $mail = new PasswordChangedMail();
        $mail->assertSeeInText('your password has been changed');
    }

    /** @test */
    public function email_has_a_subject()
    {
        $mail = new PasswordChangedMail();
        $this->assertEquals('Security notification regarding your password', $mail->build()->subject);
    }

    /** @test */
    public function email_has_a_sender()
    {
        $mail = new PasswordChangedMail();
        $this->assertTrue($mail->build()->hasFrom('[email protected]', 'laravellte'));
    }
}

If you are interested in how those 4 methods simplified testing mailable, you can check one my commits for an open-source project of mine.

Final thoughts

Even though this seems like a small improvement, a pile of small improvements lead to one big one.

And finally, here is the list of all available Mailable methods.