diff --git a/tests/Feature/Auth/AuthenticationTest.php b/tests/Feature/Auth/AuthenticationTest.php index c59d166a8..a53c560a8 100644 --- a/tests/Feature/Auth/AuthenticationTest.php +++ b/tests/Feature/Auth/AuthenticationTest.php @@ -51,4 +51,29 @@ public function test_users_can_logout() $this->assertGuest(); $response->assertRedirect('/'); } + + public function test_users_are_rate_limited() + { + $user = User::factory()->create(); + + for ($i = 0; $i < 5; $i++) { + $this->post('/login', [ + 'email' => $user->email, + 'password' => 'wrong-password', + ])->assertStatus(302)->assertSessionHasErrors([ + 'email' => 'These credentials do not match our records.', + ]); + } + + $response = $this->post('/login', [ + 'email' => $user->email, + 'password' => 'wrong-password', + ]); + + $response->assertSessionHasErrors('email'); + + $errors = session('errors'); + + $this->assertStringContainsString('Too many login attempts', $errors->first('email')); + } } diff --git a/tests/Feature/Auth/EmailVerificationTest.php b/tests/Feature/Auth/EmailVerificationTest.php index 627fe709d..0ce64e02a 100644 --- a/tests/Feature/Auth/EmailVerificationTest.php +++ b/tests/Feature/Auth/EmailVerificationTest.php @@ -55,4 +55,53 @@ public function test_email_is_not_verified_with_invalid_hash() $this->assertFalse($user->fresh()->hasVerifiedEmail()); } + + public function test_email_is_not_verified_with_invalid_user_id(): void + { + $user = User::factory()->create([ + 'email_verified_at' => null, + ]); + + $verificationUrl = URL::temporarySignedRoute( + 'verification.verify', + now()->addMinutes(60), + ['id' => 123, 'hash' => sha1($user->email)] + ); + + $this->actingAs($user)->get($verificationUrl); + + $this->assertFalse($user->fresh()->hasVerifiedEmail()); + } + + public function test_verified_user_is_redirected_to_dashboard_from_verification_prompt(): void + { + $user = User::factory()->create([ + 'email_verified_at' => now(), + ]); + + $response = $this->actingAs($user)->get('/verify-email'); + + $response->assertRedirect(route('dashboard', absolute: false)); + } + + public function test_already_verified_user_visiting_verification_link_is_redirected_without_firing_event_again(): void + { + $user = User::factory()->create([ + 'email_verified_at' => now(), + ]); + + Event::fake(); + + $verificationUrl = URL::temporarySignedRoute( + 'verification.verify', + now()->addMinutes(60), + ['id' => $user->id, 'hash' => sha1($user->email)] + ); + + $this->actingAs($user)->get($verificationUrl) + ->assertRedirect(route('dashboard', absolute: false).'?verified=1'); + + $this->assertTrue($user->fresh()->hasVerifiedEmail()); + Event::assertNotDispatched(Verified::class); + } } diff --git a/tests/Feature/Auth/PasswordResetTest.php b/tests/Feature/Auth/PasswordResetTest.php index 3c7441f78..71c6ef1e2 100644 --- a/tests/Feature/Auth/PasswordResetTest.php +++ b/tests/Feature/Auth/PasswordResetTest.php @@ -70,4 +70,18 @@ public function test_password_can_be_reset_with_valid_token() return true; }); } + + public function test_password_cannot_be_reset_with_invalid_token(): void + { + $user = User::factory()->create(); + + $response = $this->post('/reset-password', [ + 'token' => 'invalid-token', + 'email' => $user->email, + 'password' => 'newpassword123', + 'password_confirmation' => 'newpassword123', + ]); + + $response->assertSessionHasErrors('email'); + } } diff --git a/tests/Feature/Auth/VerificationNotificationTest.php b/tests/Feature/Auth/VerificationNotificationTest.php new file mode 100644 index 000000000..ccf3c07f3 --- /dev/null +++ b/tests/Feature/Auth/VerificationNotificationTest.php @@ -0,0 +1,44 @@ +create([ + 'email_verified_at' => null, + ]); + + $this->actingAs($user) + ->post('email/verification-notification') + ->assertRedirect('/'); + + Notification::assertSentTo($user, VerifyEmail::class); + } + + public function test_does_not_send_verification_notification_if_email_is_verified(): void + { + Notification::fake(); + + $user = User::factory()->create([ + 'email_verified_at' => now(), + ]); + + $this->actingAs($user) + ->post('email/verification-notification') + ->assertRedirect(route('dashboard', absolute: false)); + + Notification::assertNothingSent(); + } +} diff --git a/tests/Feature/Settings/PasswordUpdateTest.php b/tests/Feature/Settings/PasswordUpdateTest.php index 64e9189b3..ae1ce618d 100644 --- a/tests/Feature/Settings/PasswordUpdateTest.php +++ b/tests/Feature/Settings/PasswordUpdateTest.php @@ -11,6 +11,17 @@ class PasswordUpdateTest extends TestCase { use RefreshDatabase; + public function test_password_update_page_is_displayed() + { + $user = User::factory()->create(); + + $response = $this + ->actingAs($user) + ->get('/settings/password'); + + $response->assertStatus(200); + } + public function test_password_can_be_updated() { $user = User::factory()->create();