4jZW7jVSdS4U6PC's avatar

Help figuring out how to test on demand notification

Hello Everyone.

I have a slack notification class that sends a message inside our company slack, in a specific channel, every time an user performs the activation process.

The system works, but it's manually tested and that's not cool.

The notification is sent by a listener attached to an UserHasBeenActivated event, the listener is the following:

    public function handle(UserHasBeenActivated $event)
    {
        Notification::route("slack", config("services.slack.user.url"))
            ->notify(new UserActivated($event->user));
    }

Pretty straight forward. The problem here is that the notification is on demand thus it's difficult to test... because there isn't any sort of documentation on how to test on demand notification ??

At the moment I'm stuck here:

    public function it_sends_a_notification_when_an_user_is_activated()
    {
        Notification::fake();
        
        $user = factory(User::class)->states("deleted")->create();
        $user->activate();
        
        Notification::assertSentTo(
            $user,
            UserActivated::class
        );
    }

Of course this fails, the activate() method is what triggers the Event UserHasBeenActivated and sequentially all the listeners, and one of them sends the corresponding notification.

Do you know how to test on demand Notifications? Is there any hidden API that am I missing?

0 likes
5 replies
4jZW7jVSdS4U6PC's avatar

@AdrianHernandezLopez it does not. The problem is that every assertion expect a Notifiable model, but in a case of a on demand notification there's no such thing as a notifiable.

dash's avatar

The notification is not sent to the user. It is sent to the anonymous On-Demand-Notification created in your handle-method.

Try this:

Notification::assertSentTo(
            Notification::route("slack", config("services.slack.user.url")),
            UserActivated::class
        );
1 like
ohffs's avatar
ohffs
Best Answer
Level 50

As I ran into this myself today - looks like the facility has been added to the framework (and this question was one of the top google results) :

https://github.com/laravel/framework/pull/21379

So in your test class have something like :

<?php

// ...
use Illuminate\Notifications\AnonymousNotifiable;

// ...

  public function test_the_thing()
  {
    Notification::fake();

    // ... do whatever

    Notification::assertSentTo(
            new AnonymousNotifiable(),
            MyNotification::class,
            function ($notification, $channels, $notifiable) {
                return $notifiable->routes['mail'] == '[email protected]';
            }
        );
  }
12 likes
rkallenkoot's avatar

Just came across this: testing this has been made easier since Laravel 8.65:

github.com/illuminate/support/commit/a8f4336594fc46aaf3c1517e520a324a54ec936c

Notification::assertSentOnDemand(
		OrderShipped::class,
		function ($notification, $channels, $notifiable) {
				// $notification OrderShipped::class
				// $channels:
				//  array:1 [
  				//		0 => "mail"
				// ]
				// $notifiable: 
				// Illuminate\Notifications\AnonymousNotifiable {#2183
				//	  +routes: array:1 [
 				//	   "mail" => "[email protected]"
				//	  ]
				return $notifiable->routes['mail'] == '[email protected]';
		}
 })
4 likes

Please or to participate in this conversation.