Framework: Can't make Notification::assertSentTo($user, UserSubscribed::class) work.

Created on 5 Feb 2017  路  7Comments  路  Source: laravel/framework

  • Laravel Version: 5.4.9
  • PHP Version: 7.0.8
  • Database Driver & Version: MySQL 5.7.17

Description:

Not able to test the sending of a notification in the RegisterController. Though the application is working just fine, I can't make the test asserting OK...

In my app, I modified the RegisterController so a new users gets a mail notification when he registers.

Here is my RegisterController's create function:

/**
     * Create a new user instance after a valid registration.
     *
     * @param  array $data
     * @return User
     */
    protected function create(array $data)
    {
        $user = User::create(
            [
            'firstname' => $data['firstname'],
            'lastname' => $data['lastname'],
            'email' => $data['email'],
            'password' => bcrypt($data['password']),
            ]
        );

        Notification::send($user, new UserSubscribed());

        return $user;
    }

Then, my notification class is

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;

class UserSubscribed extends Notification
{
    use Queueable;

    /**
     * Create a new notification instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Get the notification's delivery channels.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    public function via($notifiable)
    {
        return ['mail'];
    }

    /**
     * Get the mail representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return \Illuminate\Notifications\Messages\MailMessage
     */
    public function toMail($notifiable)
    {
        return (new MailMessage)
                    ->subject('Welcome')
                    ->line('Welcome')
                    ->line('Update your profile')
                    ->action('some action link')
                    ->line('Thank you');
    }
}

The application works fine and everything is going well... But when I want to test it:

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

        // Check email adress is unique in DB by deleting whoever would already have this email.
        $email = '[email protected]';
        $test = User::where(['email' => $email])->delete();

        // Make a user
        $user = factory(User::class)->make(['email' => '[email protected]']);

        // Make Request
        $response = $this->post('/register', [
            'firstname' => $user->firstname,
            'lastname' => $user->lastname,
            'email' => $user->email,
            'password' => 'testing',
        ]);

        // Assert a notification was sent to the user
        Notification::assertSentTo($user, UserSubscribed::class);

        $response->assertStatus(302);
        $response->assertRedirect('/');

        // Tear Down
        // Delete created user
        User::where(['email' => $email])->delete();
    }

Then I get the error message:

1) Tests\Feature\RegisterTest::testUserCanRegister
The expected [App\Notifications\UserSubscribed] notification was not sent.
Failed asserting that false is true.

/home/lucius/womyjob/wmj-code/vendor/laravel/framework/src/Illuminate/Support/Testing/Fakes/NotificationFake.php:39
/home/lucius/womyjob/wmj-code/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php:221
/home/lucius/womyjob/wmj-code/tests/Feature/RegisterTest.php:42

Steps To Reproduce:

If you start with the test

    public function testUserCanRegister()
    {
        // Check email adress is unique in DB by deleting whoever would already have this email.
        $email = '[email protected]';
        $test = User::where(['email' => $email])->delete();

        // Make a user
        $user = factory(User::class)->make(['email' => '[email protected]']);

        // Make Request
        $response = $this->post('/register', [
            'firstname' => $user->firstname,
            'lastname' => $user->lastname,
            'email' => $user->email,
            'password' => 'testing',
        ]);

        $response->assertStatus(302);
        $response->assertRedirect('/');

        // Tear Down
        // Delete created user
        User::where(['email' => $email])->delete();
    }

Then the test passes and the Notification is actually sent.

Next, add

Notification::fake()

The test still passes and the notification is no more sent. Which is good.

Finally, add the line

 Notification::assertSentTo($user, UserSubscribed::class);

And I get the error...

If I replace by

 Notification::assertNotSentTo($user, UserSubscribed::class);

Then the test passes again...

For info: I started my app in Laravel 5.2 about a year ago, then I migrated progressively to 5.4... I never had any other problems since now...

Most helpful comment

The $user you are putting in your test is not the $user used in your register method - because in your register method you are creating a new $user

You need to do something like:

    Notification::assertSentTo(User::latest()->first(), UserSubscribed::class);

to get the latest user from the DB table and use that. I havent tested the code - you get the general idea.

But it is not a bug in the framework - so this issue should be closed.

All 7 comments

I don't think it's an issue with the core, please try to replicate in a fresh laravel installation.

The $user you are putting in your test is not the $user used in your register method - because in your register method you are creating a new $user

You need to do something like:

    Notification::assertSentTo(User::latest()->first(), UserSubscribed::class);

to get the latest user from the DB table and use that. I havent tested the code - you get the general idea.

But it is not a bug in the framework - so this issue should be closed.

Thank you so much! It works now...

Thank you so much! It works now...
@LuciusCaesar

How did you solved this issue I have the issue but no luck with any solution ?

Thank you so much! It works now...
@LuciusCaesar

How did you solved this issue I have the issue but no luck with any solution ?

Hi im at same situation

@laurencei after changing my code to ur solution is also asserting that the expected notification was not sent
in my case this function in the core which in NotificationFake class

/**
     * Get all of the notifications for a notifiable entity by type.
     *
     * @param  mixed  $notifiable
     * @param  string  $notification
     * @return array
     */
    protected function notificationsFor($notifiable, $notification)
    {
        return $this->notifications[get_class($notifiable)][$notifiable->getKey()][$notification] ?? [];
    }

is always says un-defined index \App\Models\User
what i have missed ?

@mohammedabdallah Have you tried following solution?

The $user you are putting in your test is _not_ the $user used in your register method - because in your register method you are creating a new $user

You need to do something like:

    Notification::assertSentTo(User::latest()->first(), UserSubscribed::class);

to get the latest user from the DB table and use that. I havent tested the code - you get the general idea.

But it is not a bug in the framework - so this issue should be closed.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

felixsanz picture felixsanz  路  3Comments

lzp819739483 picture lzp819739483  路  3Comments

iivanov2 picture iivanov2  路  3Comments

jackmu95 picture jackmu95  路  3Comments

SachinAgarwal1337 picture SachinAgarwal1337  路  3Comments