Files
ClaudeDo/tests/ClaudeDo.Ui.Tests/ViewModels/TaskRowContextMenuTests.cs
T
mika kuns 51dc7bd61b feat(ui): Task-Zeile entdichten und Kontextmenü gruppieren (UX-Struktur A)
Gruppe 1 (Send to queue, Remove from queue, Cancel execution, Open quick
session, Refine task) ist jetzt fix sichtbar und gated per IsEnabled + Grund
statt komplett auszublenden. Planning/Schedule wandern in Untermenüs (Mark as
existierte bereits); der Planning-Kopf zeigt einen Grund, wenn er sonst leer
wäre. Refine-Button, ungesetzter Star und Dequeue-X erscheinen nur bei
Hover-oder-Selektion (TaskRowViewModel.ShowRowActions); ein gesetzter Star und
der Refining-Spinner bleiben immer sichtbar. Der Branch-Chip wandert aus der
Zeile in eine Meta-Zeile in TaskHeaderBar.

A3 headless verifiziert: Avalonia 12 zeigt ToolTips auf IsEnabled=false
Controls nur mit ToolTip.ShowOnDisabled="True" (Default ist false) — dieses
Attached Property existiert bereits und wird für die neuen Disabled-Reason-
Tooltips genutzt.
2026-08-21 14:34:14 +02:00

163 lines
4.6 KiB
C#

using ClaudeDo.Data.Models;
using ClaudeDo.Ui.ViewModels.Islands;
using Xunit;
using TaskStatus = ClaudeDo.Data.Models.TaskStatus;
namespace ClaudeDo.Ui.Tests.ViewModels;
/// <summary>
/// [UX-Struktur A2/A4] Group 1's disabled-reason properties (grayed out with an explanation
/// instead of hidden — see task A1) and the hover-or-selected gate for the optional row actions.
/// </summary>
public class TaskRowContextMenuTests
{
private static TaskRowViewModel MakeRow() => new() { Id = "t1" };
[Fact]
public void SendToQueueDisabledReason_Null_When_Sendable()
{
var row = MakeRow();
row.Status = TaskStatus.Idle;
Assert.True(row.CanSendToQueue);
Assert.Null(row.SendToQueueDisabledReason);
}
[Fact]
public void SendToQueueDisabledReason_Set_When_AlreadyQueued()
{
var row = MakeRow();
row.Status = TaskStatus.Queued;
Assert.False(row.CanSendToQueue);
Assert.NotNull(row.SendToQueueDisabledReason);
}
[Fact]
public void SendToQueueDisabledReason_Set_When_Manual()
{
var row = MakeRow();
row.Status = TaskStatus.Idle;
row.IsManual = true;
Assert.False(row.CanSendToQueue);
Assert.NotNull(row.SendToQueueDisabledReason);
}
[Fact]
public void CancelDisabledReason_Null_While_Running()
{
var row = MakeRow();
row.Status = TaskStatus.Running;
Assert.Null(row.CancelDisabledReason);
}
[Fact]
public void CancelDisabledReason_Set_When_NotRunning()
{
var row = MakeRow();
row.Status = TaskStatus.Idle;
Assert.NotNull(row.CancelDisabledReason);
}
[Theory]
[InlineData(TaskStatus.Idle)]
[InlineData(TaskStatus.Running)]
[InlineData(TaskStatus.Done)]
public void QuickSessionDisabledReason_Is_Always_Null(TaskStatus status)
{
var row = MakeRow();
row.Status = status;
row.IsManual = true;
Assert.Null(row.QuickSessionDisabledReason);
}
[Fact]
public void RefineDisabledReason_Null_When_Refinable()
{
var row = MakeRow();
row.Status = TaskStatus.Idle;
Assert.True(row.CanRefine);
Assert.Null(row.RefineDisabledReason);
}
[Fact]
public void RefineDisabledReason_Set_When_Manual()
{
var row = MakeRow();
row.Status = TaskStatus.Idle;
row.IsManual = true;
Assert.False(row.CanRefine);
Assert.NotNull(row.RefineDisabledReason);
}
[Fact]
public void RefineDisabledReason_Set_When_Refining()
{
var row = MakeRow();
row.Status = TaskStatus.Idle;
row.IsRefining = true;
Assert.False(row.CanRefine);
Assert.NotNull(row.RefineDisabledReason);
}
[Fact]
public void RefineDisabledReason_Set_When_NotIdle()
{
var row = MakeRow();
row.Status = TaskStatus.Running;
Assert.False(row.CanRefine);
Assert.NotNull(row.RefineDisabledReason);
}
[Fact]
public void PlanningDisabledReason_Null_When_OpenAvailable()
{
var row = MakeRow();
row.Status = TaskStatus.Idle;
Assert.True(row.CanOpenPlanningSession);
Assert.Null(row.PlanningDisabledReason);
}
[Fact]
public void PlanningDisabledReason_Null_When_PlanningActive()
{
var row = MakeRow();
row.Status = TaskStatus.Idle;
row.PlanningPhase = PlanningPhase.Active;
Assert.True(row.CanResumeOrDiscardPlanning);
Assert.Null(row.PlanningDisabledReason);
}
[Fact]
public void PlanningDisabledReason_Set_When_Finalized()
{
var row = MakeRow();
row.Status = TaskStatus.Idle;
row.PlanningPhase = PlanningPhase.Finalized;
Assert.False(row.CanOpenPlanningSession);
Assert.False(row.CanResumeOrDiscardPlanning);
Assert.False(row.CanFinalizePlanning);
Assert.NotNull(row.PlanningDisabledReason);
}
[Fact]
public void PlanningDisabledReason_Set_When_Manual()
{
var row = MakeRow();
row.Status = TaskStatus.Idle;
row.IsManual = true;
Assert.NotNull(row.PlanningDisabledReason);
}
[Theory]
[InlineData(false, false, false)]
[InlineData(true, false, true)]
[InlineData(false, true, true)]
[InlineData(true, true, true)]
public void ShowRowActions_Follows_Hover_Or_Selection(bool isHovered, bool isSelected, bool expected)
{
var row = MakeRow();
row.IsHovered = isHovered;
row.IsSelected = isSelected;
Assert.Equal(expected, row.ShowRowActions);
}
}