How to test that a mailable was sent from a notification? - laravel

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?

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

Related

Laravel Notification Markdown - Undefined variable

I am getting the following error when trying to pass data to a markdown mailable
Undefined variable: claim
I have the following code for a notification
class ChequeDiscrepancy extends Notification
{
use Queueable;
public $data;
public function __construct($data)
{
$this->data = $data;
}
public function via($notifiable)
{
return ['mail'];
}
public function toMail($notifiable)
{
return (new MailMessage)
->subject('Subject')
->markdown('emails.admin.banking.cheque_discrepancy');
}
public function toArray($notifiable)
{
return [
//
];
}
}
In my markdown template, I have
#component('mail::message')
# Cheque No: {{$data->id}}
#endcomponent
According to https://laravel.com/docs/8.x/mail#view-data I should be able to pass the data via public properties or via The with Method. This works for regular mail but doesn't seem to work for notifications.
Am I doing something wrong?
Thanks
Passing data is different between Notifications & Mailable classes.
In notifications you need to pass the data explicitly, like this
public function toMail($notifiable)
{
return (new MailMessage)
->subject('Subject')
->markdown('emails.admin.banking.cheque_discrepancy', ['data'=>$this->data]);
}
You may read further here : Laravel Notifications

Sending Data to Pusher in laravel broadcast

I am having issues with sending data object to pusher, after saving data to db. When I send the request to to db , it saved to db then initialize the event but it does not send with the specified object.
event(new NotifyResponderEvent($emergencyRequest));
Here is my code for the event file
class NotifyResponderEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $emergencyRequest;
public function __construct($emergencyRequest)
{
$this->$emergencyRequest = $emergencyRequest;
}
public function broadcastOn()
{
return new Channel('request');
}
public function broadcastAs()
{
return 'emergencyRequest';
}
public function broadcastWith()
{
return [
'data' => [
$this->emergencyRequest
],
];
}
}
This is what I get in pusher after when the event is fired
{
"emergencyRequest": null
}
Even when I log the data before sending its still giving me the same issue, but it is saving on the db and sending to another api that sends sms and some object data as well.
Regards
Sorted ... Not sure what was the problem, I had to delete node_module folder, remove any pusher related packages and reinstall.

Laravel how to capture event with Server Sent Events

The Laravel SSE(server sent event) is a great solution to push the changes to frontend, however, on the server side, we need to have an efficient way to keep track of the updated record(s) before sending notification to frontend. however, the SSE requires a controller to work with, problem is how can the controller capture the Laravel events?
class HomeController extends Controller
{
public function sse(SSE $sse)
{
// how to add the Laravel event listener here?
return $sse->createResponse();
}
}
Laravel provides with events, listeners, broadcasting and channels to communicate with front end via events. You don't need to do that in controllers. You can define broadcast routes in
routes/channels.php
you can then define events that by default include broadcast method in scaffolding.
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
Bind listeners to event and implement "shouldque" interface to that these run as async jobs. You can also use laravel notifications to provide live notification. laravel broadcasting
If you still want to grab event in controller you can specify in EventServiceProvider as
class EventServiceProvider extends ServiceProvider
{
protected $listen = [
DownloadFile::class => [
CompanyDashboardController::class,
],
];
public function boot()
{
parent::boot();
}
}
your event will look like
class DownloadFile
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $process_id;
public function __construct($process_id)
{
$this->process_id = $file;
}
}
Finally you can grab this event in you controller as like:
class CompanyDashboardController extends Controller
{
public function __construct()
{
//constructor
}
public function handle(DownloadFile $event)
{
if($event->process_id == 1)
{
return "something";
}
}
}
If you meant to some Javascript event instead of Laravel read
Use Server-Sent Events to push messages to browser

Laravel Bulk Send Mail with Notification

I read in laravel documentation :
Once the ShouldQueue interface has been added to your notification, you may send the notification like normal. Laravel will detect the ShouldQueue interface on the class and automatically queue the delivery of the notification:
Because of in notification do automatically queue,
if I use in my controller:
public function store(Request $request)
{
$users = User::all()
Notification::send($users, new MyFirstNotification());
}
and in my notification:
public function toMail($notifiable)
{
return new custome-emailTo("emails.welcome",$notifiable);
}
and in custom-mailTo, (it is a mailable class) :
public function __construct($view2,User $user)
{
$this->user = $user;
$this->view = $view2;
}
public function build()
{
$this->to($this->user->email);
return $this->view('emails.welcome');
}
for me, it work and send to many users,
but my questions are:
As stated in the documentation of Laravel,
1. Do it really do queuing for send notification?
2. Do I need queue in mailable laravel class for send bulk email?

Send email in background : Laravel 5.4

I am using an inbuilt code in Laravel to send Email Notification. Code is below. I am using smtp to send email
class RegisterNotification extends Notification
{
use Queueable;
public function __construct($token)
{
$this->token = $token;
}
public function via($notifiable)
{
return ['mail'];
}
public function toMail($notifiable)
{
return (new MailMessage)
->line('hi');
}
public function toArray($notifiable)
{
return [
//
];
}
}
Here the problem is, it takes around 5 seconds to complete the process and control does not come back. I am assuming that if it come back and do the email sending work in background...it would save a lot of time.
Is there any inbuilt work to do the same? I meant, control should come back and should say email sent...and then it should do the work in background.
Email Sending code in Controller
class apiRegisterController extends Controller
{
public function Register(RegisterRequest $request) {
$RegisterNotification = new RegisterNotification($Token);
$User->notify($RegisterNotification);
}
}
Code for Queue
Controller Code
$job = (new SendForgotPasswordEmail($Data))->onConnection('database');
dispatch($job);
Job
class SendForgotPasswordEmail implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $Data;
public $tries = 5;
public function __construct($Data)
{
$this->Data = $Data;
}
public function handle()
{
$Token = $this->Data["Token"];
$User = $this->Data["User"];
$RegisterNotification = new RegisterNotification($Token);
$User->notify($RegisterNotification);
}
}
Step 1: Change class RegisterNotification extends Notification to class RegisterNotification extends Notification implements ShouldQueue
Step 2: Implement a queue driver. In your config/queue.php make sure your driver is not set to sync like so: 'default' => env('QUEUE_DRIVER', 'sync'), and make sure your .env doesnt have QUEUE_DRIVER=sync. You can look at the Laravel documentation for queues to choose an appropriate queue driver
You can use the build-in API.
$user = User::findOrFail($id);
Mail::queue('emails.welcome', $data, function ($message) use ($user){
$message->from('hello#app.com', 'Your Application');
$message->to($user->email, $user->name)->subject('Your Reminder!');
});
But first you have to configure the queues.
Add in your .env file the line QUEUE_DRIVER=sync and then write on the terminal php artisan queue:listen.
If you want the queue to run forever on the server use Supervisor. Queues documentation explains how you can use it.
you can use laravel job queue https://laravel.com/docs/5.4/queues
Mail::queue(

Resources