using ClaudeDo.Data; using ClaudeDo.Data.Models; using ClaudeDo.Ui.ViewModels.Islands; using Microsoft.EntityFrameworkCore; using TaskStatus = ClaudeDo.Data.Models.TaskStatus; namespace ClaudeDo.Ui.Tests.ViewModels; // Switching lists must drop the previous list's selection; reloading the SAME list (worker // refresh / reconnect) must keep it, so a live update never yanks the detail pane away. public class TasksIslandListSwitchSelectionTests : IDisposable { private readonly string _dbPath; public TasksIslandListSwitchSelectionTests() { _dbPath = Path.Combine(Path.GetTempPath(), $"claudedo_ui_listswitch_{Guid.NewGuid():N}.db"); using var ctx = NewContext(); ctx.Database.EnsureCreated(); } public void Dispose() { try { File.Delete(_dbPath); } catch { } try { File.Delete(_dbPath + "-wal"); } catch { } try { File.Delete(_dbPath + "-shm"); } catch { } } private ClaudeDoDbContext NewContext() { var opts = new DbContextOptionsBuilder() .UseSqlite($"Data Source={_dbPath}") .Options; return new ClaudeDoDbContext(opts); } private sealed class TestDbFactory : IDbContextFactory { private readonly Func _create; public TestDbFactory(Func create) => _create = create; public ClaudeDoDbContext CreateDbContext() => _create(); } private async Task SeedTwoListsAsync() { await using var db = NewContext(); db.Lists.Add(new ListEntity { Id = "L1", Name = "Work", CreatedAt = DateTime.UtcNow }); db.Lists.Add(new ListEntity { Id = "L2", Name = "Home", CreatedAt = DateTime.UtcNow }); db.Tasks.Add(new TaskEntity { Id = "T1", ListId = "L1", Title = "Task one", Status = TaskStatus.Idle, CreatedAt = DateTime.UtcNow, SortOrder = 0, }); db.Tasks.Add(new TaskEntity { Id = "T2", ListId = "L2", Title = "Task two", Status = TaskStatus.Idle, CreatedAt = DateTime.UtcNow, SortOrder = 0, }); await db.SaveChangesAsync(); } private static ListNavItemViewModel Nav(string listId, string name) => new() { Id = $"user:{listId}", Name = name, Kind = ListKind.User }; [Fact] public async Task LoadForList_OtherList_ClearsSelectedTask_AndRaisesSelectionChanged() { await SeedTwoListsAsync(); var vm = new TasksIslandViewModel(new TestDbFactory(NewContext), worker: null); vm.LoadForList(Nav("L1", "Work")); Assert.True(await vm.SelectByIdAsync("T1")); var selectionChanges = 0; vm.SelectionChanged += (_, _) => selectionChanges++; vm.LoadForList(Nav("L2", "Home")); if (vm.LoadTask is { } load) await load; Assert.Null(vm.SelectedTask); Assert.Equal(1, selectionChanges); } [Fact] public async Task LoadForList_NullList_ClearsSelectedTask() { await SeedTwoListsAsync(); var vm = new TasksIslandViewModel(new TestDbFactory(NewContext), worker: null); vm.LoadForList(Nav("L1", "Work")); Assert.True(await vm.SelectByIdAsync("T1")); vm.LoadForList(null); Assert.Null(vm.SelectedTask); } [Fact] public async Task LoadForList_SameList_KeepsSelectedTask() { await SeedTwoListsAsync(); var vm = new TasksIslandViewModel(new TestDbFactory(NewContext), worker: null); vm.LoadForList(Nav("L1", "Work")); Assert.True(await vm.SelectByIdAsync("T1")); vm.LoadForList(Nav("L1", "Work")); if (vm.LoadTask is { } load) await load; Assert.Equal("T1", vm.SelectedTask?.Id); } }