Files
KanbanGit/tests/Feature/Projects/ProjectRepositorySettingsControllerTest.php
T
Twyco ff796aa10a
linter / quality (pull_request) Successful in 1m28s
tests / ci (8.4) (pull_request) Successful in 1m47s
feat: overhaul project workspace navigation
2026-07-18 17:52:25 +02:00

235 lines
9.2 KiB
PHP

<?php
namespace Tests\Feature\Projects;
use App\Actions\Git\GitProviderKey;
use App\Actions\Projects\DuplicateProjectConfiguration;
use App\Models\Project;
use App\Models\ProjectTemplate;
use App\Models\RepositoryConnection;
use App\Models\User;
use App\Models\UserGitConnection;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Http;
use Inertia\Testing\AssertableInertia as Assert;
use Tests\TestCase;
class ProjectRepositorySettingsControllerTest extends TestCase
{
use RefreshDatabase;
/**
* Ensure users with edit permission can view repository settings.
*/
public function test_users_with_edit_permission_can_view_repository_settings(): void
{
$user = User::factory()->create();
$project = Project::factory()->create([
'key' => 'CORE',
]);
RepositoryConnection::factory()->for($project)->create([
'base_url' => 'https://git.example.test',
'owner_name' => 'core-team',
'provider' => GitProviderKey::Gitea,
'provider_repository_id' => '501',
'repository_full_name' => 'core-team/kanbangit',
'repository_name' => 'kanbangit',
'repository_url' => 'https://git.example.test/core-team/kanbangit',
]);
$template = ProjectTemplate::factory()->create([
'configuration_snapshot' => app(DuplicateProjectConfiguration::class)->export($project, [
DuplicateProjectConfiguration::COPY_REPOSITORY_CONNECTIONS,
]),
'copy_areas' => [DuplicateProjectConfiguration::COPY_REPOSITORY_CONNECTIONS],
'name' => 'Connected Template',
]);
$project->update(['project_template_id' => $template->id]);
$this->syncProjectPermissions($project, $user, ['edit']);
$this->actingAs($user)
->get(route('projects.settings.index', [
'project' => $project,
'section' => 'repositories',
]))
->assertOk()
->assertInertia(fn (Assert $page) => $page
->component('projects/Settings')
->where('activeSection', 'repositories')
->where('project.id', $project->id)
->where('sectionData.repositoryConnections.0.repository_full_name', 'core-team/kanbangit')
->where('sectionData.repositoryConnections.0.has_personal_access', false)
->where('sectionData.availableRepositorySources', [])
->where('sectionData.templateState.templateName', 'Connected Template')
->where('sectionData.templateState.inheritedAreas.0.value', DuplicateProjectConfiguration::COPY_REPOSITORY_CONNECTIONS),
);
}
/**
* Ensure users without edit permission cannot manage repository settings.
*/
public function test_users_without_edit_permission_cannot_view_repository_settings(): void
{
$user = User::factory()->create();
$project = Project::factory()->create();
$this->actingAs($user)
->get(route('projects.settings.repositories', $project))
->assertForbidden();
}
/**
* Ensure authorized users can link a repository through their own Git connection.
*/
public function test_users_with_edit_permission_can_link_project_repositories(): void
{
Http::preventStrayRequests();
Http::fake([
'https://git.example.test/api/v1/user/repos*' => Http::response([
[
'id' => 501,
'name' => 'kanbangit',
'full_name' => 'core-team/kanbangit',
'html_url' => 'https://git.example.test/core-team/kanbangit',
'owner' => [
'login' => 'core-team',
],
'private' => true,
],
]),
]);
$user = User::factory()->create();
$project = Project::factory()->create();
$userGitConnection = UserGitConnection::factory()->for($user)->create([
'base_url' => 'https://git.example.test',
'provider' => GitProviderKey::Gitea,
]);
$this->syncProjectPermissions($project, $user, ['edit']);
$this->actingAs($user)
->post(route('projects.settings.repositories.store', $project), [
'provider_repository_id' => '501',
'user_git_connection_id' => $userGitConnection->id,
])
->assertRedirect(route('projects.settings.index', ['project' => $project, 'section' => 'repositories']))
->assertSessionHas('status', 'core-team/kanbangit was linked to '.$project->name.'.');
$this->assertDatabaseHas('repository_connections', [
'project_id' => $project->id,
'provider' => GitProviderKey::Gitea->value,
'base_url' => 'https://git.example.test',
'provider_repository_id' => '501',
'owner_name' => 'core-team',
'repository_name' => 'kanbangit',
'repository_full_name' => 'core-team/kanbangit',
]);
}
/**
* Ensure users cannot link repositories through another user's Git connection.
*/
public function test_users_cannot_link_repositories_through_foreign_git_connections(): void
{
Http::preventStrayRequests();
Http::fake();
$user = User::factory()->create();
$otherUser = User::factory()->create();
$project = Project::factory()->create();
$foreignGitConnection = UserGitConnection::factory()->for($otherUser)->create();
$this->syncProjectPermissions($project, $user, ['edit']);
$this->actingAs($user)
->post(route('projects.settings.repositories.store', $project), [
'provider_repository_id' => '501',
'user_git_connection_id' => $foreignGitConnection->id,
])
->assertForbidden();
}
/**
* Ensure authorized users can relink an existing project repository.
*/
public function test_users_with_edit_permission_can_update_repository_connections(): void
{
Http::preventStrayRequests();
Http::fake([
'https://git.internal.test/api/v1/user/repos*' => Http::response([
[
'id' => 902,
'name' => 'platform',
'full_name' => 'infra/platform',
'html_url' => 'https://git.internal.test/infra/platform',
'owner' => [
'login' => 'infra',
],
'private' => false,
],
]),
]);
$user = User::factory()->create();
$project = Project::factory()->create();
$repositoryConnection = RepositoryConnection::factory()->for($project)->create([
'base_url' => 'https://git.example.test',
'owner_name' => 'core-team',
'provider' => GitProviderKey::Gitea,
'provider_repository_id' => '501',
'repository_full_name' => 'core-team/kanbangit',
'repository_name' => 'kanbangit',
'repository_url' => 'https://git.example.test/core-team/kanbangit',
]);
$userGitConnection = UserGitConnection::factory()->for($user)->create([
'base_url' => 'https://git.internal.test',
'provider' => GitProviderKey::Gitea,
]);
$this->syncProjectPermissions($project, $user, ['edit']);
$this->actingAs($user)
->patch(route('projects.settings.repositories.update', [$project, $repositoryConnection]), [
'provider_repository_id' => '902',
'user_git_connection_id' => $userGitConnection->id,
])
->assertRedirect(route('projects.settings.index', ['project' => $project, 'section' => 'repositories']))
->assertSessionHas('status', 'infra/platform connection was updated.');
$this->assertDatabaseHas('repository_connections', [
'id' => $repositoryConnection->id,
'base_url' => 'https://git.internal.test',
'provider_repository_id' => '902',
'owner_name' => 'infra',
'repository_name' => 'platform',
'repository_full_name' => 'infra/platform',
]);
}
/**
* Ensure authorized users can remove project repository links.
*/
public function test_users_with_edit_permission_can_delete_repository_connections(): void
{
$user = User::factory()->create();
$project = Project::factory()->create();
$repositoryConnection = RepositoryConnection::factory()->for($project)->create([
'repository_full_name' => 'core-team/kanbangit',
]);
$this->syncProjectPermissions($project, $user, ['edit']);
$this->actingAs($user)
->delete(route('projects.settings.repositories.destroy', [$project, $repositoryConnection]))
->assertRedirect(route('projects.settings.index', ['project' => $project, 'section' => 'repositories']))
->assertSessionHas('status', 'core-team/kanbangit was removed from the project.');
$this->assertDatabaseMissing('repository_connections', [
'id' => $repositoryConnection->id,
]);
}
}