feat(KAN-40): rebuild workflow column and status settings
CI/CD / test_and_check_app (pull_request) Canceled after 0s
CI/CD / Publish immutable image (pull_request) Canceled after 0s
CI/CD / preconditions (pull_request) Canceled after 36s

This commit is contained in:
2026-09-15 16:04:05 +02:00
parent 3eea473336
commit f461439ce6
11 changed files with 1412 additions and 640 deletions
@@ -372,4 +372,51 @@ class ProjectBoardSettingsControllerTest extends TestCase
'id' => $backlogStatus->id,
]);
}
public function test_deleting_a_used_column_preserves_statuses_tickets_and_backlog_order(): void
{
$user = User::factory()->create();
$project = Project::factory()->create();
$this->syncProjectPermissions($project, $user, ['edit']);
$backlog = TicketStatus::factory()->for($project)->create(['position' => 1]);
$column = BoardColumn::factory()->for($project)->create(['position' => 1]);
$statuses = TicketStatus::factory()->for($project)->for($column)->count(2)
->sequence(['position' => 1], ['position' => 2])->create();
$ticket = Ticket::factory()->for($project)->create(['ticket_status_id' => $statuses[1]->id]);
$statuses[0]->allowedTargetStatuses()->sync([$statuses[1]->id]);
$this->actingAs($user)
->delete(route('projects.settings.board.columns.destroy', [$project, $column]))
->assertRedirect(route('projects.settings.board', $project))
->assertSessionHasNoErrors();
$this->assertModelMissing($column);
$this->assertSame($statuses[1]->id, $ticket->fresh()->ticket_status_id);
$this->assertSame([$backlog->id, ...$statuses->modelKeys()], $project->ticketStatuses()->pluck('id')->all());
$this->assertSame([1, 2, 3], $project->ticketStatuses()->pluck('position')->all());
$this->assertTrue($project->ticketStatuses()->get()->every(fn (TicketStatus $status): bool => $status->board_column_id === null));
$this->assertSame([$statuses[1]->id], $statuses[0]->allowedTargetStatuses()->pluck('ticket_statuses.id')->all());
}
public function test_last_column_status_is_protected_and_invalid_position_preserves_order(): void
{
$user = User::factory()->create();
$project = Project::factory()->create();
$this->syncProjectPermissions($project, $user, ['edit']);
$column = BoardColumn::factory()->for($project)->create(['position' => 1]);
$status = TicketStatus::factory()->for($project)->for($column)->create();
$ticket = Ticket::factory()->for($project)->create(['ticket_status_id' => $status->id]);
$this->actingAs($user)->from(route('projects.settings.board', $project))
->delete(route('projects.settings.board.statuses.destroy', [$project, $status]))
->assertSessionHasErrors('ticket_status_id');
$this->assertModelExists($status);
$this->assertSame($status->id, $ticket->fresh()->ticket_status_id);
$this->actingAs($user)->from(route('projects.settings.board', $project))
->patch(route('projects.settings.board.columns.update', [$project, $column]), ['name' => 'Invalid move', 'position' => 0])
->assertSessionHasErrors('position');
$this->assertSame(1, $column->fresh()->position);
$this->assertSame($column->name, $column->fresh()->name);
}
}
@@ -0,0 +1,18 @@
<?php
namespace Tests\Feature\Projects;
use Symfony\Component\Process\Process;
use Tests\TestCase;
class ProjectBoardSettingsUiTest extends TestCase
{
public function test_workflow_renders_ordered_groups_deletion_protection_and_localization(): void
{
$process = new Process(['node', 'tests/Fixtures/project-board-settings.mjs'], base_path());
$process->setTimeout(60);
$process->run();
$this->assertTrue($process->isSuccessful(), $process->getOutput().$process->getErrorOutput());
$this->assertStringContainsString('Project board settings rendering checks passed.', $process->getOutput());
}
}