create([ 'email' => 'admin@clusev.local', 'two_factor_secret' => (new Google2FA)->generateSecretKey(), 'two_factor_confirmed_at' => now(), ]); } public function test_totp_resets_password_and_rotates_remember_token(): void { $user = $this->user(); $user->forceFill(['remember_token' => 'stale-cookie-token'])->save(); $otp = (new Google2FA)->getCurrentOtp($user->two_factor_secret); Livewire::test(ForgotPassword::class) ->set('email', $user->email)->set('code', $otp) ->set('password', 'NewPassw0rd123')->set('password_confirmation', 'NewPassw0rd123') ->call('resetPassword')->assertHasNoErrors(); $this->assertTrue(Hash::check('NewPassw0rd123', $user->fresh()->password)); // a stolen remember-me cookie must not survive the reset $this->assertNotSame('stale-cookie-token', $user->fresh()->remember_token); } public function test_backup_code_resets_and_is_consumed(): void { $user = $this->user(); $code = $user->replaceRecoveryCodes()[0]; Livewire::test(ForgotPassword::class) ->set('email', $user->email)->set('code', $code) ->set('password', 'NewPassw0rd123')->set('password_confirmation', 'NewPassw0rd123') ->call('resetPassword')->assertHasNoErrors(); $this->assertTrue(Hash::check('NewPassw0rd123', $user->fresh()->password)); $this->assertFalse($user->fresh()->useRecoveryCode($code)); } public function test_wrong_code_does_not_reset(): void { $user = $this->user(); $old = $user->password; Livewire::test(ForgotPassword::class) ->set('email', $user->email)->set('code', '000000') ->set('password', 'NewPassw0rd123')->set('password_confirmation', 'NewPassw0rd123') ->call('resetPassword')->assertHasErrors('code'); $this->assertSame($old, $user->fresh()->password); } public function test_weak_password_rejected(): void { $user = $this->user(); $otp = (new Google2FA)->getCurrentOtp($user->two_factor_secret); Livewire::test(ForgotPassword::class) ->set('email', $user->email)->set('code', $otp) ->set('password', 'short')->set('password_confirmation', 'short') ->call('resetPassword')->assertHasErrors('password'); } }