get('/'); $response->assertRedirect('/login'); }); it('shows login page with OAuth button', function () { $response = $this->get('/login'); $response->assertStatus(200); $response->assertInertia( fn ($page) => $page ->component('Auth/Login') ); }); it('login page has no email or password inputs', function () { $response = $this->get('/login'); $response->assertStatus(200); // The Login.vue should NOT contain email/password form fields // This is verified by checking the component renders correctly $response->assertInertia( fn ($page) => $page ->component('Auth/Login') ); }); it('redirects to ChurchTools OAuth on auth initiation', function () { $providerMock = Mockery::mock(\Laravel\Socialite\Two\AbstractProvider::class); $providerMock->shouldReceive('redirect') ->once() ->andReturn(redirect('https://churchtools.example.com/oauth/authorize')); Socialite::shouldReceive('driver') ->with('churchtools') ->once() ->andReturn($providerMock); $response = $this->get('/auth/churchtools'); $response->assertRedirect(); $response->assertRedirectContains('churchtools.example.com/oauth/authorize'); }); it('creates a new user from OAuth callback', function () { $socialiteUser = new SocialiteUser; $socialiteUser->map([ 'id' => '42', 'name' => 'Max Mustermann', 'email' => 'max@example.com', 'avatar' => 'https://churchtools.example.com/avatar/42.jpg', ]); $socialiteUser->user = [ 'id' => 42, 'firstName' => 'Max', 'lastName' => 'Mustermann', 'displayName' => 'Max Mustermann', 'email' => 'max@example.com', 'imageUrl' => 'https://churchtools.example.com/avatar/42.jpg', 'groups' => [['id' => 1, 'name' => 'Worship']], 'roles' => [['id' => 2, 'name' => 'Admin']], ]; $providerMock = Mockery::mock(\Laravel\Socialite\Two\AbstractProvider::class); $providerMock->shouldReceive('user') ->once() ->andReturn($socialiteUser); Socialite::shouldReceive('driver') ->with('churchtools') ->once() ->andReturn($providerMock); $response = $this->get('/auth/churchtools/callback'); $response->assertRedirect(route('dashboard')); $this->assertDatabaseHas('users', [ 'email' => 'max@example.com', 'name' => 'Max Mustermann', 'churchtools_id' => 42, 'avatar' => 'https://churchtools.example.com/avatar/42.jpg', ]); $user = User::where('email', 'max@example.com')->first(); expect($user)->not->toBeNull(); expect((int) $user->churchtools_id)->toBe(42); expect($user->churchtools_groups)->toBe([['id' => 1, 'name' => 'Worship']]); expect($user->churchtools_roles)->toBe([['id' => 2, 'name' => 'Admin']]); $this->assertAuthenticatedAs($user); }); it('updates existing user on OAuth callback', function () { $existingUser = User::factory()->create([ 'email' => 'max@example.com', 'name' => 'Old Name', 'churchtools_id' => 42, ]); $socialiteUser = new SocialiteUser; $socialiteUser->map([ 'id' => '42', 'name' => 'Max Mustermann', 'email' => 'max@example.com', 'avatar' => 'https://churchtools.example.com/avatar/42.jpg', ]); $socialiteUser->user = [ 'id' => 42, 'firstName' => 'Max', 'lastName' => 'Mustermann', 'displayName' => 'Max Mustermann', 'email' => 'max@example.com', 'imageUrl' => 'https://churchtools.example.com/avatar/42.jpg', 'groups' => [['id' => 1, 'name' => 'Worship']], 'roles' => [['id' => 2, 'name' => 'Admin']], ]; $providerMock = Mockery::mock(\Laravel\Socialite\Two\AbstractProvider::class); $providerMock->shouldReceive('user') ->once() ->andReturn($socialiteUser); Socialite::shouldReceive('driver') ->with('churchtools') ->once() ->andReturn($providerMock); $response = $this->get('/auth/churchtools/callback'); $response->assertRedirect(route('dashboard')); $existingUser->refresh(); expect($existingUser->name)->toBe('Max Mustermann'); expect($existingUser->avatar)->toBe('https://churchtools.example.com/avatar/42.jpg'); expect(User::count())->toBe(1); $this->assertAuthenticatedAs($existingUser); }); it('logs out user and redirects to login', function () { $user = User::factory()->create(); $response = $this->actingAs($user)->post('/logout'); $response->assertRedirect('/login'); $this->assertGuest(); }); it('does not have register routes', function () { $response = $this->get('/register'); $response->assertStatus(404); }); it('authenticated user can access dashboard', function () { $user = User::factory()->create(); $response = $this->actingAs($user)->get('/dashboard'); $response->assertStatus(200); });