My users can specify if they have Notifications sent to them instantly or to be notified daily of any pending Notifications.
The below works fine with manual testing; now I'd like to write a feature test around this to ensure that an email is sent and not an SMS or nothing.
public function test_instant_notification_is_sent(): void
{
Mail::fake();
$this->user = $user = factory(User::class)->create();
$this->user->update(
[
'notification_frequency' => 'instant',
'notification_method' => 'email',
'notification_email' => $this->email,
]
);
$this->user->save();
$email = ['subject' => 'subject', 'data' => 'data'];
$sms = 'Test Notification';
$database = ['some' => 'data'];
$this->user->notify(new TestNotification($email, $sms, $database));
Mail::assertSent(MailMessage::class);
}
I've written a TestNotification
to go with it.
class TestNotification extends Notification
{
use Queueable;
public function __construct(array $email, string $sms, array $database)
{
$this->email = $email;
$this->sms = $sms;
$this->database = $database;
}
public function via($notifiable): array
{
return [$notifiable->preferredNotificationMethod()];
}
public function toDatabase($notifiable): array
{
return $this->database;
}
public function toNexmo($notifiable): array
{
return (new NexmoMessage)
->content($this->sms);
}
public function toMail($notifiable): MailMessage
{
return (new MailMessage)
->greeting($this->email['subject'])
->line('Testing Notifications!')
->line('Thank you for using our application!');
}
}
My test fails because, as I now see, MailMessage
is not a Mailable
and I think Mail::fake()
and the mail assertions only work with Mailable
. Incidentally, if I remove Mail::fake()
the email is sent fine.
How have others managed to test this please without actually sending the email?
When testing Notifications, you'll want to use Notification::fake()
and make those assertions. See the Notification Fake of the docs to see what I mean.
public function test_instant_notification_is_sent(): void
{
Notification::fake();
$this->user = $user = factory(User::class)->create();
$this->user->update(
[
'notification_frequency' => 'instant',
'notification_method' => 'email',
'notification_email' => $this->email,
]
);
$this->user->save();
$email = ['subject' => 'subject', 'data' => 'data'];
$sms = 'Test Notification';
$database = ['some' => 'data'];
$this->user->notify(new TestNotification($email, $sms, $database));
Notification::assertSentTo($this->user, TestNotification::class, function ($notification, $channels) {
// check channels or properties of $notification here
return in_array('mail', $channels);
// or maybe check for nexmo:
return in_array('nexmo', $channels);
});
}
The answer turned out to be to check the via
method as this is only set to one channel (in my case). And I didn't need to check the email was sent at all as @FatBoyXPC pointed out. Final solution:
Notification::fake();
$this->user->update(
[
'notification_frequency' => 'instant',
'notification_method' => 'email',
'notification_email' => $this->email,
]
);
$email = ['subject' => 'Test Subject', 'data' => 'data'];
$sms = 'Test Notification';
$database = ['some' => 'data'];
$notification = new TestNotification($email, $sms, $database);
$this->user->notify($notification);
$this->assertEquals(['mail'], $notification->via($this->user));
now if I change email
or instant
this test fails and passes if email
and instant
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With