create(); UserGitConnection::factory()->for($user)->create([ 'account_login' => 'nico', 'base_url' => 'https://git.example.test', ]); UserGitConnection::factory()->create(); $this->actingAs($user) ->get(route('git-connections.edit')) ->assertOk() ->assertInertia(fn (Assert $page) => $page ->component('settings/GitConnections') ->has('gitConnections', 1) ->missing('gitConnections.0.api_token') ->where('gitConnections.0.account_login', 'nico') ->where('gitConnections.0.base_url', 'https://git.example.test') ->where('gitConnections.0.provider', GitProviderKey::Gitea->value), ); } /** * Ensure a user can add a verified Gitea connection from settings. */ public function test_users_can_store_verified_gitea_connections(): void { Http::preventStrayRequests(); Http::fake([ 'https://git.example.test/api/v1/user' => Http::response([ 'id' => 101, 'login' => 'nico', 'full_name' => 'Nico Example', ]), ]); $user = User::factory()->create(); $this->actingAs($user) ->post(route('git-connections.store'), [ 'provider' => 'gitea', 'base_url' => 'https://git.example.test/api/v1', 'api_token' => 'super-secret-token', ]) ->assertRedirect(route('git-connections.edit')) ->assertSessionHas('status', 'Git connection was added.'); $this->assertDatabaseHas('user_git_connections', [ 'user_id' => $user->id, 'provider' => GitProviderKey::Gitea->value, 'base_url' => 'https://git.example.test', 'provider_user_id' => '101', 'account_login' => 'nico', 'account_name' => 'Nico Example', ]); } /** * Ensure invalid provider credentials are rejected with a validation error. */ public function test_invalid_provider_credentials_are_rejected(): void { Http::preventStrayRequests(); Http::fake([ 'https://git.example.test/api/v1/user' => Http::response([ 'message' => 'Unauthorized', ], 401), ]); $user = User::factory()->create(); $this->actingAs($user) ->from(route('git-connections.edit')) ->post(route('git-connections.store'), [ 'provider' => 'gitea', 'base_url' => 'https://git.example.test', 'api_token' => 'wrong-token', ]) ->assertRedirect(route('git-connections.edit')) ->assertSessionHasErrors('api_token') ->assertSessionMissing('_old_input.api_token'); } /** * Ensure a user can update only their own Git connection. */ public function test_users_can_update_their_own_git_connections(): void { Http::preventStrayRequests(); Http::fake([ 'https://git.internal.test/api/v1/user' => Http::response([ 'id' => 202, 'login' => 'updated-user', 'full_name' => 'Updated User', ]), ]); $user = User::factory()->create(); $gitConnection = UserGitConnection::factory()->for($user)->create([ 'account_login' => 'old-user', 'account_name' => 'Old User', 'base_url' => 'https://git.example.test', 'provider' => GitProviderKey::Gitea, 'provider_user_id' => '100', ]); $this->actingAs($user) ->patch(route('git-connections.update', $gitConnection), [ 'provider' => 'gitea', 'base_url' => 'https://git.internal.test', 'api_token' => 'fresh-token', ]) ->assertRedirect(route('git-connections.edit')) ->assertSessionHas('status', 'Git connection was updated.'); $this->assertDatabaseHas('user_git_connections', [ 'id' => $gitConnection->id, 'base_url' => 'https://git.internal.test', 'provider_user_id' => '202', 'account_login' => 'updated-user', 'account_name' => 'Updated User', ]); } /** * Ensure users cannot update another user's Git connection. */ public function test_users_cannot_update_foreign_git_connections(): void { Http::preventStrayRequests(); Http::fake(); $owner = User::factory()->create(); $otherUser = User::factory()->create(); $gitConnection = UserGitConnection::factory()->for($owner)->create(); $this->actingAs($otherUser) ->patch(route('git-connections.update', $gitConnection), [ 'provider' => 'gitea', 'base_url' => 'https://git.example.test', 'api_token' => 'fresh-token', ]) ->assertForbidden(); } /** * Ensure users can remove their own Git connections. */ public function test_users_can_delete_their_own_git_connections(): void { $user = User::factory()->create(); $gitConnection = UserGitConnection::factory()->for($user)->create([ 'account_login' => 'nico', 'base_url' => 'https://git.example.test', ]); $this->actingAs($user) ->delete(route('git-connections.destroy', $gitConnection)) ->assertRedirect(route('git-connections.edit')) ->assertSessionHas( 'status', 'nico @ https://git.example.test was removed.', ); $this->assertDatabaseMissing('user_git_connections', [ 'id' => $gitConnection->id, ]); } public function test_empty_personal_connections_are_displayed(): void { UserGitConnection::factory()->create(); $this->actingAs(User::factory()->create()) ->get(route('git-connections.edit')) ->assertOk() ->assertInertia(fn (Assert $page) => $page ->component('settings/GitConnections') ->where('gitConnections', []), ); } public function test_guests_cannot_access_git_connections(): void { $this->get(route('git-connections.edit'))->assertRedirect(route('login')); } public function test_users_cannot_delete_foreign_connections(): void { $connection = UserGitConnection::factory()->create(); $this->actingAs(User::factory()->create()) ->delete(route('git-connections.destroy', $connection)) ->assertForbidden(); $this->assertModelExists($connection); } public function test_failed_provider_update_preserves_connection_and_does_not_flash_token(): void { Http::preventStrayRequests(); Http::fake(['https://git.changed.test/api/v1/user' => Http::response([], 503)]); $user = User::factory()->create(); $connection = UserGitConnection::factory()->for($user)->create([ 'base_url' => 'https://git.original.test', 'api_token' => 'original-secret', ]); $original = $connection->fresh()->getAttributes(); $this->actingAs($user) ->from(route('git-connections.edit')) ->patch(route('git-connections.update', $connection), [ 'provider' => 'gitea', 'base_url' => 'https://git.changed.test', 'api_token' => 'replacement-secret', ]) ->assertRedirect(route('git-connections.edit')) ->assertSessionHasErrors('api_token') ->assertSessionMissing('_old_input.api_token'); $this->assertSame($original, $connection->fresh()->getAttributes()); $this->assertSame('original-secret', $connection->fresh()->api_token); } }