1

What's the secret of testing a mailable was sent from a notification?

Testing the notification:

it('does send notification when model is deleted', function() {
    Notification::fake();
    $this->model->delete();
    Notification::assertSentTo($this->model->user, MyModelDeletedNotification::class);
});

Passes.

Testing the mailable:

it('does send email when model is deleted', function() {
    Mail::fake();
    $this->model->delete();
    Mail::assertQueued(MyModelDeletedMail::class, 1);
});

Fails. No mails queued.

When a model is deleted a observer method is triggered:

public function deleted(MyModel $model)
{
    if ($model->isForceDeleting()) {
        return;
    }

    $model->user->notify(new MyModelDeletedNotification($model));
}

Notification:

class MyModelDeleted extends Notification implements ShouldQueue
{
    use Queueable;

    ...

    public function via($notifiable)
    {
        return ['mail', 'database'];
    }

    public function toMail($notifiable)
    {
        return (new MyModelDeletedMail($this->model))->to($notifiable->email);
    }

    ...
}

Mailable:

class ConsultationDeleted extends Mailable
{
    use Queueable, SerializesModels;

    ...

    public function build()
    {
        ...
    }
}

When I dump("foobar") inside the mailables constructor or build method, the message is appearing in the log. However the test fails. What am I missing here?

DarkLeafyGreen
  • 69,338
  • 131
  • 383
  • 601
  • 1
    Does this answer help you out? https://laracasts.com/discuss/channels/testing/testing-if-email-was-sent-with-out-sending-it?page=1&replyId=402801 – Aless55 Jan 06 '22 at 07:22
  • Since you're asserting the `Mail` is queued and not sent, are you also running `Queue::fake()`? – miken32 Jan 06 '22 at 19:47

1 Answers1

1

Regarding using Mail:fake in the context of notifications:

It is not a very good way to test because it catches only mails sent using the Mail facade (doesn't intercept mails sent through a notification or using a mailer retrieved via dependency injection).

Make sure you have set

<server name="MAIL_MAILER" value="array"/>

phpunit.xml. In your test:

it('does send email', function() {

    // business logic

    $emails = app()->make('mailer')->getSwiftMailer()->getTransport()->messages();

    assertCount(1, $emails);
    assertEquals([$this->user->email], array_keys($emails[0]->getTo()));
});

This worked for me using laravel 8.

Reference: https://laracasts.com/discuss/channels/testing/testing-if-email-was-sent-with-out-sending-it?page=1&replyId=402801

DarkLeafyGreen
  • 69,338
  • 131
  • 383
  • 601