I am developing a Laravel application. I am doing unit testing to my application. Now I am having a trouble with testing the verification process.
What I am trying to do now is that I am registering a user, then test if the verification email is sent, then I will get the verification link for that registration, then I will do something with that link.
This is my test
public function test_user_can_be_verified_and_redirected_based_on_role()
{
Notification::fake();
$user = $this->registerUser();
Notification::assertSentTo($user, SendEmailVerificationNotification::class);
}
protected function registerUser()
{
$user = factory(User::class)->make();
$this->post(route('register'), [
'name' => $user->name,
'email' => $user->email,
'password' => 'testing',
'password_confirmation' => 'testing',
])->assertRedirect();
return User::whereEmail($user->email)->first();
}
But the issue is that the notification is not sent even if it is sent when I register from the browser. I also like to retrieve the verification link and do something. How can I do that?
First, a route will be needed to display a notice to the user that they should click the email verification link in the verification email that Laravel sent them after registration. Second, a route will be needed to handle requests generated when the user clicks the email verification link in the email.
Not a perfect solution but it does the trick, if somebody breaks this functionality somehow I'll know about it. :)
First overwrite the protected method verificationUri
of the VerifyEmail
notification and make it public
class EmailVerificationNotification extends VerifyEmail
{
public function verificationUrl($notifiable) {
return parent::verificationUrl($notifiable);
}
}
Then use it to generate a link and assert against it..
/** @test */
public function an_user_can_verify_his_email_address()
{
$notification = new EmailVerificationNotification();
$user = factory(User::class)->create(['email_verified_at' => null]);
$uri = $notification->verificationUrl($user);
$this->assertSame(null, $user->email_verified_at);
$this->actingAs($user)->get($uri);
$this->assertNotNull($user->email_verified_at);
}
A verification URL can be generated outside of the VerifyEmail notification easily by simply running:
$verificationUrl = URL::temporarySignedRoute(
'verification.verify',
now()->addMinutes(60),
['id' => $user->id, 'hash' => sha1($user->email)]
);
No need to make the verificationUrl()
method public.
Here is my solution:
public function testVerifyEmailValidatesUser(): void
{
// VerifyEmail extends Illuminate\Auth\Notifications\VerifyEmail in this example
$notification = new VerifyEmail();
$user = factory(User::class)->create();
// New user should not has verified their email yet
$this->assertFalse($user->hasVerifiedEmail());
$mail = $notification->toMail($user);
$uri = $mail->actionUrl;
// Simulate clicking on the validation link
$this->actingAs($user)
->get($uri);
// User should have verified their email
$this->assertTrue(User::find($user->id)->hasVerifiedEmail());
}
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