fix(test): give Ui.Tests task seeds a unique Number

The task-numbers slice added a UNIQUE index on tasks.number. Ui.Tests seed
TaskEntity rows directly instead of going through TaskRepository, so every row
kept the default Number = 0 and 31 tests failed with
'UNIQUE constraint failed: tasks.number'.
This commit is contained in:
mika kuns
2026-08-11 11:32:01 +02:00
parent 5ab5a6c0a8
commit 8da1a12389
14 changed files with 57 additions and 21 deletions
@@ -0,0 +1,13 @@
namespace ClaudeDo.Ui.Tests;
/// <summary>
/// Tests seed <see cref="ClaudeDo.Data.Models.TaskEntity"/> rows directly instead of going through
/// TaskRepository, so nothing allocates their Number — and every row would default to 0, colliding
/// on the unique index. Hand out a process-wide unique number instead.
/// </summary>
internal static class TestTaskNumbers
{
private static int _next;
public static int Next() => Interlocked.Increment(ref _next);
}
@@ -81,6 +81,7 @@ public class DetailsIslandHandlerRangeTests : IDisposable
ctx.Lists.Add(new ListEntity { Id = listId, Name = "L", WorkingDir = @"C:\repo", CreatedAt = DateTime.UtcNow });
ctx.Tasks.Add(new TaskEntity
{
Number = TestTaskNumbers.Next(),
Id = taskId, ListId = listId, Title = "List handler: L",
Status = TaskStatus.WaitingForReview, IsManual = true,
HandlerBaseCommit = "base123", HandlerHeadCommit = "head456",
@@ -108,12 +108,14 @@ public class DetailsIslandPlanningTests : IDisposable
ctx.Lists.Add(new ListEntity { Id = listId, Name = "L", CreatedAt = DateTime.UtcNow });
ctx.Tasks.Add(new TaskEntity
{
Number = TestTaskNumbers.Next(),
Id = parentId, ListId = listId, Title = "Parent",
Status = TaskStatus.Idle, PlanningPhase = PlanningPhase.Active,
CreatedAt = DateTime.UtcNow,
});
ctx.Tasks.Add(new TaskEntity
{
Number = TestTaskNumbers.Next(),
Id = childId, ListId = listId, Title = "Child",
Status = TaskStatus.Done, ParentTaskId = parentId, CreatedAt = DateTime.UtcNow,
});
@@ -69,6 +69,7 @@ public class DetailsIslandTaskUpdatedTests : IDisposable
db.Lists.Add(new ListEntity { Id = "L1", Name = "Work", CreatedAt = DateTime.UtcNow });
db.Tasks.Add(new TaskEntity
{
Number = TestTaskNumbers.Next(),
Id = id, ListId = "L1", Title = "Task", Status = status, CreatedAt = DateTime.UtcNow,
});
await db.SaveChangesAsync();
@@ -53,6 +53,7 @@ public class MergeHelperSelectionModalViewModelTests : IDisposable
void Add(string id, string listId, TaskStatus status) =>
db.Tasks.Add(new TaskEntity
{
Number = TestTaskNumbers.Next(),
Id = id, ListId = listId, Title = $"task {id}",
Status = status, CreatedAt = DateTime.UtcNow, SortOrder = order++,
});
@@ -105,6 +106,7 @@ public class MergeHelperSelectionModalViewModelTests : IDisposable
{
db.Tasks.Add(new TaskEntity
{
Number = TestTaskNumbers.Next(),
Id = "t-new", ListId = "L1", Title = "arrived later",
Status = TaskStatus.Idle, CreatedAt = DateTime.UtcNow, SortOrder = 99,
});
@@ -127,16 +129,19 @@ public class MergeHelperSelectionModalViewModelTests : IDisposable
db.Lists.Add(new ListEntity { Id = "L1", Name = "Work", CreatedAt = DateTime.UtcNow });
db.Tasks.Add(new TaskEntity
{
Number = TestTaskNumbers.Next(),
Id = "parent", ListId = "L1", Title = "parent",
Status = TaskStatus.Idle, CreatedAt = DateTime.UtcNow, SortOrder = 0,
});
db.Tasks.Add(new TaskEntity
{
Number = TestTaskNumbers.Next(),
Id = "child1", ListId = "L1", Title = "child1", ParentTaskId = "parent",
Status = TaskStatus.Idle, CreatedAt = DateTime.UtcNow, SortOrder = 1,
});
db.Tasks.Add(new TaskEntity
{
Number = TestTaskNumbers.Next(),
Id = "child2", ListId = "L1", Title = "child2", ParentTaskId = "parent",
Status = TaskStatus.Idle, CreatedAt = DateTime.UtcNow, SortOrder = 2,
});
@@ -235,9 +240,9 @@ public class MergeHelperSelectionModalViewModelTests : IDisposable
await using (var db = NewContext())
{
db.Lists.Add(new ListEntity { Id = "L1", Name = "Work", CreatedAt = DateTime.UtcNow });
db.Tasks.Add(new TaskEntity { Id = "parent", ListId = "L1", Title = "parent", Status = TaskStatus.Idle, CreatedAt = DateTime.UtcNow, SortOrder = 0 });
db.Tasks.Add(new TaskEntity { Id = "sibling", ListId = "L1", Title = "sibling", Status = TaskStatus.Idle, CreatedAt = DateTime.UtcNow, SortOrder = 1 });
db.Tasks.Add(new TaskEntity { Id = "child", ListId = "L1", Title = "child", Status = TaskStatus.Idle, CreatedAt = DateTime.UtcNow, SortOrder = 2, ParentTaskId = "parent" });
db.Tasks.Add(new TaskEntity { Number = TestTaskNumbers.Next(), Id = "parent", ListId = "L1", Title = "parent", Status = TaskStatus.Idle, CreatedAt = DateTime.UtcNow, SortOrder = 0 });
db.Tasks.Add(new TaskEntity { Number = TestTaskNumbers.Next(), Id = "sibling", ListId = "L1", Title = "sibling", Status = TaskStatus.Idle, CreatedAt = DateTime.UtcNow, SortOrder = 1 });
db.Tasks.Add(new TaskEntity { Number = TestTaskNumbers.Next(), Id = "child", ListId = "L1", Title = "child", Status = TaskStatus.Idle, CreatedAt = DateTime.UtcNow, SortOrder = 2, ParentTaskId = "parent" });
await db.SaveChangesAsync();
}
@@ -258,8 +263,8 @@ public class MergeHelperSelectionModalViewModelTests : IDisposable
await using (var db = NewContext())
{
db.Lists.Add(new ListEntity { Id = "L1", Name = "Work", CreatedAt = DateTime.UtcNow });
db.Tasks.Add(new TaskEntity { Id = "parent-done", ListId = "L1", Title = "parent", Status = TaskStatus.Done, CreatedAt = DateTime.UtcNow, SortOrder = 0 });
db.Tasks.Add(new TaskEntity { Id = "child", ListId = "L1", Title = "child", Status = TaskStatus.Idle, CreatedAt = DateTime.UtcNow, SortOrder = 1, ParentTaskId = "parent-done" });
db.Tasks.Add(new TaskEntity { Number = TestTaskNumbers.Next(), Id = "parent-done", ListId = "L1", Title = "parent", Status = TaskStatus.Done, CreatedAt = DateTime.UtcNow, SortOrder = 0 });
db.Tasks.Add(new TaskEntity { Number = TestTaskNumbers.Next(), Id = "child", ListId = "L1", Title = "child", Status = TaskStatus.Idle, CreatedAt = DateTime.UtcNow, SortOrder = 1, ParentTaskId = "parent-done" });
await db.SaveChangesAsync();
}
@@ -282,9 +287,9 @@ public class MergeHelperSelectionModalViewModelTests : IDisposable
await using (var db = NewContext())
{
db.Lists.Add(new ListEntity { Id = "L1", Name = "Work", CreatedAt = DateTime.UtcNow });
db.Tasks.Add(new TaskEntity { Id = "parent", ListId = "L1", Title = "parent", Status = TaskStatus.Idle, CreatedAt = DateTime.UtcNow, SortOrder = 0 });
db.Tasks.Add(new TaskEntity { Id = "child1", ListId = "L1", Title = "child1", Status = TaskStatus.Idle, CreatedAt = DateTime.UtcNow, SortOrder = 1, ParentTaskId = "parent" });
db.Tasks.Add(new TaskEntity { Id = "child2", ListId = "L1", Title = "child2", Status = TaskStatus.Idle, CreatedAt = DateTime.UtcNow, SortOrder = 2, ParentTaskId = "parent" });
db.Tasks.Add(new TaskEntity { Number = TestTaskNumbers.Next(), Id = "parent", ListId = "L1", Title = "parent", Status = TaskStatus.Idle, CreatedAt = DateTime.UtcNow, SortOrder = 0 });
db.Tasks.Add(new TaskEntity { Number = TestTaskNumbers.Next(), Id = "child1", ListId = "L1", Title = "child1", Status = TaskStatus.Idle, CreatedAt = DateTime.UtcNow, SortOrder = 1, ParentTaskId = "parent" });
db.Tasks.Add(new TaskEntity { Number = TestTaskNumbers.Next(), Id = "child2", ListId = "L1", Title = "child2", Status = TaskStatus.Idle, CreatedAt = DateTime.UtcNow, SortOrder = 2, ParentTaskId = "parent" });
await db.SaveChangesAsync();
}
@@ -314,8 +319,8 @@ public class MergeHelperSelectionModalViewModelTests : IDisposable
await using (var db = NewContext())
{
db.Lists.Add(new ListEntity { Id = "L1", Name = "Work", CreatedAt = DateTime.UtcNow });
db.Tasks.Add(new TaskEntity { Id = "parent", ListId = "L1", Title = "parent", Status = TaskStatus.Idle, CreatedAt = DateTime.UtcNow, SortOrder = 0 });
db.Tasks.Add(new TaskEntity { Id = "child", ListId = "L1", Title = "child", Status = TaskStatus.Idle, CreatedAt = DateTime.UtcNow, SortOrder = 1, ParentTaskId = "parent" });
db.Tasks.Add(new TaskEntity { Number = TestTaskNumbers.Next(), Id = "parent", ListId = "L1", Title = "parent", Status = TaskStatus.Idle, CreatedAt = DateTime.UtcNow, SortOrder = 0 });
db.Tasks.Add(new TaskEntity { Number = TestTaskNumbers.Next(), Id = "child", ListId = "L1", Title = "child", Status = TaskStatus.Idle, CreatedAt = DateTime.UtcNow, SortOrder = 1, ParentTaskId = "parent" });
await db.SaveChangesAsync();
}
@@ -334,7 +339,7 @@ public class MergeHelperSelectionModalViewModelTests : IDisposable
await using (var db = NewContext())
{
db.Lists.Add(new ListEntity { Id = "L1", Name = "Work", CreatedAt = DateTime.UtcNow });
db.Tasks.Add(new TaskEntity { Id = "t-done", ListId = "L1", Title = "done", Status = TaskStatus.Done, CreatedAt = DateTime.UtcNow });
db.Tasks.Add(new TaskEntity { Number = TestTaskNumbers.Next(), Id = "t-done", ListId = "L1", Title = "done", Status = TaskStatus.Done, CreatedAt = DateTime.UtcNow });
await db.SaveChangesAsync();
}
@@ -113,8 +113,8 @@ public class MissionControlViewModelTests : IDisposable
{
db.Lists.Add(new ListEntity { Id = "L1", Name = "Work", CreatedAt = DateTime.UtcNow });
// Running task has higher SortOrder — must still appear first
db.Tasks.Add(new TaskEntity { Id = "r1", ListId = "L1", Title = "running-task", Status = TaskStatus.Running, CreatedAt = DateTime.UtcNow, SortOrder = 10 });
db.Tasks.Add(new TaskEntity { Id = "q1", ListId = "L1", Title = "queued-task", Status = TaskStatus.Queued, CreatedAt = DateTime.UtcNow, SortOrder = 0 });
db.Tasks.Add(new TaskEntity { Number = TestTaskNumbers.Next(), Id = "r1", ListId = "L1", Title = "running-task", Status = TaskStatus.Running, CreatedAt = DateTime.UtcNow, SortOrder = 10 });
db.Tasks.Add(new TaskEntity { Number = TestTaskNumbers.Next(), Id = "q1", ListId = "L1", Title = "queued-task", Status = TaskStatus.Queued, CreatedAt = DateTime.UtcNow, SortOrder = 0 });
await db.SaveChangesAsync();
}
@@ -139,7 +139,7 @@ public class MissionControlViewModelTests : IDisposable
await using (var db = NewContext())
{
db.Lists.Add(new ListEntity { Id = "L1", Name = "Work", CreatedAt = DateTime.UtcNow });
db.Tasks.Add(new TaskEntity { Id = "r1", ListId = "L1", Title = "running", Status = TaskStatus.Running, CreatedAt = DateTime.UtcNow, SortOrder = 0 });
db.Tasks.Add(new TaskEntity { Number = TestTaskNumbers.Next(), Id = "r1", ListId = "L1", Title = "running", Status = TaskStatus.Running, CreatedAt = DateTime.UtcNow, SortOrder = 0 });
await db.SaveChangesAsync();
}
@@ -159,7 +159,7 @@ public class MissionControlViewModelTests : IDisposable
await using (var db = NewContext())
{
db.Lists.Add(new ListEntity { Id = "L1", Name = "Work", CreatedAt = DateTime.UtcNow });
db.Tasks.Add(new TaskEntity { Id = "q1", ListId = "L1", Title = "clickable", Status = TaskStatus.Queued, CreatedAt = DateTime.UtcNow, SortOrder = 0 });
db.Tasks.Add(new TaskEntity { Number = TestTaskNumbers.Next(), Id = "q1", ListId = "L1", Title = "clickable", Status = TaskStatus.Queued, CreatedAt = DateTime.UtcNow, SortOrder = 0 });
await db.SaveChangesAsync();
}
@@ -180,7 +180,7 @@ public class MissionControlViewModelTests : IDisposable
await using (var db = NewContext())
{
db.Lists.Add(new ListEntity { Id = "L1", Name = "Work", CreatedAt = DateTime.UtcNow });
db.Tasks.Add(new TaskEntity { Id = "r1", ListId = "L1", Title = "running", Status = TaskStatus.Running, CreatedAt = DateTime.UtcNow, SortOrder = 0 });
db.Tasks.Add(new TaskEntity { Number = TestTaskNumbers.Next(), Id = "r1", ListId = "L1", Title = "running", Status = TaskStatus.Running, CreatedAt = DateTime.UtcNow, SortOrder = 0 });
await db.SaveChangesAsync();
}
@@ -212,9 +212,9 @@ public class MissionControlViewModelTests : IDisposable
{
await using var db = NewContext();
db.Lists.Add(new ListEntity { Id = "L1", Name = "Work", CreatedAt = DateTime.UtcNow });
db.Tasks.Add(new TaskEntity { Id = "q2", ListId = "L1", Title = "second", Status = TaskStatus.Queued, CreatedAt = DateTime.UtcNow, SortOrder = 1 });
db.Tasks.Add(new TaskEntity { Id = "q1", ListId = "L1", Title = "first", Status = TaskStatus.Queued, CreatedAt = DateTime.UtcNow, SortOrder = 0 });
db.Tasks.Add(new TaskEntity { Id = "idle1", ListId = "L1", Title = "idle", Status = TaskStatus.Idle, CreatedAt = DateTime.UtcNow, SortOrder = 2 });
db.Tasks.Add(new TaskEntity { Number = TestTaskNumbers.Next(), Id = "q2", ListId = "L1", Title = "second", Status = TaskStatus.Queued, CreatedAt = DateTime.UtcNow, SortOrder = 1 });
db.Tasks.Add(new TaskEntity { Number = TestTaskNumbers.Next(), Id = "q1", ListId = "L1", Title = "first", Status = TaskStatus.Queued, CreatedAt = DateTime.UtcNow, SortOrder = 0 });
db.Tasks.Add(new TaskEntity { Number = TestTaskNumbers.Next(), Id = "idle1", ListId = "L1", Title = "idle", Status = TaskStatus.Idle, CreatedAt = DateTime.UtcNow, SortOrder = 2 });
await db.SaveChangesAsync();
}
@@ -246,7 +246,7 @@ public class MissionControlViewModelTests : IDisposable
await using (var db = NewContext())
{
db.Lists.Add(new ListEntity { Id = "L1", Name = "Work", CreatedAt = DateTime.UtcNow });
db.Tasks.Add(new TaskEntity { Id = "idleTask", ListId = "L1", Title = "Do the thing", Status = TaskStatus.Idle, CreatedAt = DateTime.UtcNow, SortOrder = 0 });
db.Tasks.Add(new TaskEntity { Number = TestTaskNumbers.Next(), Id = "idleTask", ListId = "L1", Title = "Do the thing", Status = TaskStatus.Idle, CreatedAt = DateTime.UtcNow, SortOrder = 0 });
await db.SaveChangesAsync();
}
@@ -270,7 +270,7 @@ public class MissionControlViewModelTests : IDisposable
await using (var db = NewContext())
{
db.Lists.Add(new ListEntity { Id = "L1", Name = "Work", CreatedAt = DateTime.UtcNow });
db.Tasks.Add(new TaskEntity { Id = "t1", ListId = "L1", Title = "Do the thing", Status = TaskStatus.Idle, CreatedAt = DateTime.UtcNow, SortOrder = 0 });
db.Tasks.Add(new TaskEntity { Number = TestTaskNumbers.Next(), Id = "t1", ListId = "L1", Title = "Do the thing", Status = TaskStatus.Idle, CreatedAt = DateTime.UtcNow, SortOrder = 0 });
await db.SaveChangesAsync();
}
@@ -90,6 +90,7 @@ public class TasksIslandDeltaResilienceTests : IDisposable
db.Lists.Add(new ListEntity { Id = "L1", Name = "Work", CreatedAt = DateTime.UtcNow });
db.Tasks.Add(new TaskEntity
{
Number = TestTaskNumbers.Next(),
Id = "T1", ListId = "L1", Title = "Task one",
Status = TaskStatus.Queued, CreatedAt = DateTime.UtcNow, SortOrder = 0,
});
@@ -53,12 +53,14 @@ public class TasksIslandFullReloadSelectionTests : IDisposable
db.Lists.Add(new ListEntity { Id = "L1", Name = "Work", CreatedAt = DateTime.UtcNow });
db.Tasks.Add(new TaskEntity
{
Number = TestTaskNumbers.Next(),
Id = "P1", ListId = "L1", Title = "Parent",
Status = TaskStatus.WaitingForChildren, PlanningPhase = PlanningPhase.Finalized,
CreatedAt = DateTime.UtcNow, SortOrder = 0,
});
db.Tasks.Add(new TaskEntity
{
Number = TestTaskNumbers.Next(),
Id = "C1", ListId = "L1", ParentTaskId = "P1", Title = "Child",
Status = TaskStatus.Running, CreatedAt = DateTime.UtcNow, SortOrder = 1,
});
@@ -48,11 +48,13 @@ public class TasksIslandListSwitchSelectionTests : IDisposable
db.Lists.Add(new ListEntity { Id = "L2", Name = "Home", CreatedAt = DateTime.UtcNow });
db.Tasks.Add(new TaskEntity
{
Number = TestTaskNumbers.Next(),
Id = "T1", ListId = "L1", Title = "Task one",
Status = TaskStatus.Idle, CreatedAt = DateTime.UtcNow, SortOrder = 0,
});
db.Tasks.Add(new TaskEntity
{
Number = TestTaskNumbers.Next(),
Id = "T2", ListId = "L2", Title = "Task two",
Status = TaskStatus.Idle, CreatedAt = DateTime.UtcNow, SortOrder = 0,
});
@@ -86,6 +86,7 @@ public class TasksIslandMoveToListTests : IDisposable
await using var db = NewContext();
db.Tasks.Add(new TaskEntity
{
Number = TestTaskNumbers.Next(),
Id = id, ListId = listId, Title = id, CreatedAt = DateTime.UtcNow,
Status = status, ParentTaskId = parentTaskId, SortOrder = 0,
});
@@ -75,6 +75,7 @@ public class TasksIslandReconcileTickTests : IDisposable
await using var db = NewContext();
db.Tasks.Add(new TaskEntity
{
Number = TestTaskNumbers.Next(),
Id = id, ListId = "L1", Title = title,
Status = status, CreatedAt = DateTime.UtcNow, SortOrder = sortOrder,
});
@@ -64,6 +64,7 @@ public class TasksIslandRegroupTests : IDisposable
db.Tasks.Add(new TaskEntity
{
Number = TestTaskNumbers.Next(),
Id = parentId,
ListId = list.Id,
Title = "Parent",
@@ -74,6 +75,7 @@ public class TasksIslandRegroupTests : IDisposable
});
db.Tasks.Add(new TaskEntity
{
Number = TestTaskNumbers.Next(),
Id = childId,
ListId = list.Id,
Title = "Child",
@@ -116,6 +118,7 @@ public class TasksIslandRegroupTests : IDisposable
{
db.Tasks.Add(new TaskEntity
{
Number = TestTaskNumbers.Next(),
Id = t.Id,
ListId = "list1",
Title = t.Id,
@@ -56,6 +56,7 @@ public class TasksIslandRemoveFromQueueTests : IDisposable
});
db.Tasks.Add(new TaskEntity
{
Number = TestTaskNumbers.Next(),
Id = parentId,
ListId = "list1",
Title = "Parent",
@@ -69,6 +70,7 @@ public class TasksIslandRemoveFromQueueTests : IDisposable
var c = children[i];
db.Tasks.Add(new TaskEntity
{
Number = TestTaskNumbers.Next(),
Id = c.Id,
ListId = "list1",
Title = $"Child {i}",
@@ -143,6 +145,7 @@ public class TasksIslandRemoveFromQueueTests : IDisposable
});
db.Tasks.Add(new TaskEntity
{
Number = TestTaskNumbers.Next(),
Id = "solo",
ListId = "list1",
Title = "Solo",
@@ -50,6 +50,7 @@ public class TasksIslandSelectByIdTests : IDisposable
});
db.Tasks.Add(new TaskEntity
{
Number = TestTaskNumbers.Next(),
Id = "T1",
ListId = "L1",
Title = "My task",