seed(RolesAndPermissionsSeeder::class); }); function fakeGoogleUser(string $id, string $email, string $name): void { $socialiteUser = (new SocialiteUser)->map([ 'id' => $id, 'email' => $email, 'name' => $name, ]); $provider = Mockery::mock(Provider::class); $provider->shouldReceive('user')->andReturn($socialiteUser); Socialite::shouldReceive('driver')->with('google')->andReturn($provider); } test('a new google user is created active, verified and as customer', function () { /** @var TestCase $this */ fakeGoogleUser('g-new-1', 'new-google@example.test', 'Neu Google'); $this->get(route('oauth.google.callback')) ->assertRedirect(route('me.dashboard', absolute: false)); $user = User::query()->where('email', 'new-google@example.test')->firstOrFail(); expect($user->is_active)->toBeTrue(); expect($user->hasVerifiedEmail())->toBeTrue(); expect($user->hasRole('customer'))->toBeTrue(); expect($user->oauth_provider)->toBe('google'); expect($user->oauth_provider_id)->toBe('g-new-1'); $this->assertAuthenticatedAs($user); }); test('an existing user is linked by email without creating a duplicate', function () { /** @var TestCase $this */ $existing = User::factory()->create(['email' => 'existing-google@example.test', 'is_active' => true]); $existing->assignRole('customer'); fakeGoogleUser('g-existing-1', 'Existing-Google@example.test', 'Existing'); $this->get(route('oauth.google.callback')) ->assertRedirect(route('me.dashboard', absolute: false)); expect(User::query()->where('email', 'existing-google@example.test')->count())->toBe(1); $existing->refresh(); expect($existing->oauth_provider)->toBe('google'); expect($existing->oauth_provider_id)->toBe('g-existing-1'); $this->assertAuthenticatedAs($existing); }); test('a deactivated verified account is not reactivated by google login', function () { /** @var TestCase $this */ $existing = User::factory()->create(['email' => 'deactivated@example.test', 'is_active' => false]); $existing->assignRole('customer'); fakeGoogleUser('g-deact-1', 'deactivated@example.test', 'Deactivated'); $this->get(route('oauth.google.callback')) ->assertRedirect(route('login')); expect($existing->fresh()->is_active)->toBeFalse(); $this->assertGuest(); }); test('a pending unverified registrant is onboarded via google', function () { /** @var TestCase $this */ $pending = User::factory()->unverified()->create([ 'email' => 'pending@example.test', 'is_active' => false, ]); fakeGoogleUser('g-pending-1', 'pending@example.test', 'Pending'); $this->get(route('oauth.google.callback')) ->assertRedirect(route('me.dashboard', absolute: false)); $pending->refresh(); expect($pending->is_active)->toBeTrue(); expect($pending->hasVerifiedEmail())->toBeTrue(); expect($pending->hasRole('customer'))->toBeTrue(); }); test('a failed google callback redirects back to login with an error', function () { /** @var TestCase $this */ $provider = Mockery::mock(Provider::class); $provider->shouldReceive('user')->andThrow(new RuntimeException('invalid state')); Socialite::shouldReceive('driver')->with('google')->andReturn($provider); $this->get(route('oauth.google.callback')) ->assertRedirect(route('login')); $this->assertGuest(); });