create(); $g = new Google2FA; $secret = $g->generateSecretKey(); Livewire::actingAs($user)->test(TwoFactorSetup::class) ->set('secret', $secret) ->set('code', $g->getCurrentOtp($secret)) ->call('confirm') ->assertRedirect(route('settings')); $this->assertTrue($user->fresh()->hasRecoveryCodes()); $this->assertTrue(session('open_recovery_modal')); } public function test_first_key_register_generates_codes_and_opens_modal(): void { $user = User::factory()->create(); $svc = Mockery::mock(WebauthnService::class); $svc->shouldReceive('available')->andReturnTrue(); $svc->shouldReceive('verifyRegistration')->andReturnUsing(fn ($u, $a, $name) => WebauthnCredential::create([ 'user_id' => $u->id, 'name' => $name, 'credential_id' => 'cid', 'public_key' => '{}', 'sign_count' => 0, ])); app()->instance(WebauthnService::class, $svc); Livewire::actingAs($user)->test(WebauthnKeys::class) ->set('newName', 'YubiKey 5C') ->call('register', ['dummy' => true], $svc) ->assertDispatched('openModal'); $this->assertTrue($user->fresh()->hasRecoveryCodes()); } public function test_malformed_setup_secret_yields_validation_error_not_500(): void { $user = User::factory()->create(); Livewire::actingAs($user)->test(TwoFactorSetup::class) ->set('secret', 'x') // client-tampered, too short for Google2FA ->set('code', '123456') ->call('confirm') ->assertHasErrors('code'); $this->assertFalse($user->fresh()->hasTotp()); } }