I was hoping to figure this out without having to post but I'm what my wits end.
I've googled, checked stack overflow, and laracasts for an answer, but none of the posts I've found have a solution for my use case.
Very simply, I have a job that sends an email. I am trying to test that this email is being sent. What's puzzling me is that the email is going out (I am getting a copy in mailtrap, and logs when I switch the driver). For some reason, Mail::assertSent() refuses to return true.
Here's some code:
SendEmail job:
public function handle()
{
$emailTemplate = EmailTemplate::find($this->template);
$storeArgument = isset($emailTemplate->arguments) ? $emailTemplate->arguments : [];
$arguments = array_merge($this->arguments, $storeArgument, array("root_url" => URL::to('/')));
$email = new EmailForQueuing(
$emailTemplate->subject,
$arguments,
$emailTemplate->email_view,
$this->category,
$this->variables
);
Mail::to($this->to)->send($email);
}
EmailTest class:
public function test_user_without_profile_receives_an_email_to_create_profile_instead_of_reset_password()
{
Queue::fake();
Mail::fake();
$user = User::factory()->create([
'status' => 0
]);
$response = $this->post('/password/email', [
'email' => $user->email,
]);
Queue::assertPushed(SendEmail::class);
// Assert a message was sent to the given user...
Mail::assertSent(EmailForQueuing::class);
}
The failing test:
The expected [App\Mail\EmailForQueuing] mailable was not sent.
Failed asserting that false is true.
I can place a dd() in the job before or after the Mail::to() call and see it in my terminal when I run my tests, so I know the code is being ran. Also, as I mentioned, the email is landing in Mailtrap.
I can not for the life of me figure out why the test is failing. Any feedback is greatly appreciated! Thank you :)
UPDATE
I setup a very simple route to test:
Route::get('/email', function () {
$mail = new \App\Mail\EmailForQueuing(
'test',
[],
'emails.default',
'',
[]
);
Mail::send($mail);
});
and then updated my test:
{
$this->get('/email')
Mail:assertSent(EmailForQueuing::class)
}
Which passes. Out of curiosity, I swapped out the logic in the route for the same logic I'm using in my controller to queue the email;
$data = [
'to' => $user->email,
'arguments' => [
'link' => $this->userService->getLoginLink($user),
],
'template' => 'MustCreateProfileBeforePasswordReset'
];
SendEmail::dispatch($data);
And now the test is failing again. So it seems that there is some disconnect between using a custom job to queue the mail.
P.S. I know there is no need to have a job to queue the email; the project I'm working on has many opportunities for refactoring and improvement, we're just not there yet.
P.S.S. I've watched this video https://laracasts.com/series/phpunit-testing-in-laravel/episodes/12 but haven't tried this approach as I'm hoping to avoid such a custom implementation and would prefer to use functionality available by default.