refactor(central-ui): contextual errors, parallel recipient load, delete-path test for Notification Lists
This commit is contained in:
@@ -104,14 +104,18 @@
|
|||||||
{
|
{
|
||||||
_lists = (await NotificationRepository.GetAllNotificationListsAsync()).ToList();
|
_lists = (await NotificationRepository.GetAllNotificationListsAsync()).ToList();
|
||||||
_recipients.Clear();
|
_recipients.Clear();
|
||||||
foreach (var list in _lists)
|
var recipientTasks = _lists.ToDictionary(
|
||||||
|
list => list.Id,
|
||||||
|
list => NotificationRepository.GetRecipientsByListIdAsync(list.Id));
|
||||||
|
await Task.WhenAll(recipientTasks.Values);
|
||||||
|
foreach (var (id, task) in recipientTasks)
|
||||||
{
|
{
|
||||||
_recipients[list.Id] = await NotificationRepository.GetRecipientsByListIdAsync(list.Id);
|
_recipients[id] = task.Result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_errorMessage = ex.Message;
|
_errorMessage = $"Failed to load notification lists: {ex.Message}";
|
||||||
}
|
}
|
||||||
_loading = false;
|
_loading = false;
|
||||||
}
|
}
|
||||||
@@ -131,7 +135,7 @@
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_toast.ShowError(ex.Message);
|
_toast.ShowError($"Failed to delete notification list: {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,8 +44,11 @@ public class NotificationListsPageTests : BunitContext
|
|||||||
|
|
||||||
var cut = Render<NotificationListsPage>();
|
var cut = Render<NotificationListsPage>();
|
||||||
|
|
||||||
Assert.Contains("Ops On-Call", cut.Markup);
|
cut.WaitForAssertion(() =>
|
||||||
Assert.Contains("jane@example.com", cut.Markup);
|
{
|
||||||
|
Assert.Contains("Ops On-Call", cut.Markup);
|
||||||
|
Assert.Contains("jane@example.com", cut.Markup);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -60,7 +63,38 @@ public class NotificationListsPageTests : BunitContext
|
|||||||
|
|
||||||
var cut = Render<NotificationListsPage>();
|
var cut = Render<NotificationListsPage>();
|
||||||
|
|
||||||
Assert.Contains("No notification lists", cut.Markup);
|
cut.WaitForAssertion(() =>
|
||||||
|
Assert.Contains("No notification lists", cut.Markup));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void DeleteList_ConfirmsThenDeletesAndReloads()
|
||||||
|
{
|
||||||
|
var repo = Substitute.For<INotificationRepository>();
|
||||||
|
repo.GetAllNotificationListsAsync()
|
||||||
|
.Returns(Task.FromResult<IReadOnlyList<NotificationList>>(
|
||||||
|
new List<NotificationList> { new("Ops On-Call") { Id = 1 } }));
|
||||||
|
repo.GetRecipientsByListIdAsync(1)
|
||||||
|
.Returns(Task.FromResult<IReadOnlyList<NotificationRecipient>>(
|
||||||
|
new List<NotificationRecipient>()));
|
||||||
|
Services.AddSingleton(repo);
|
||||||
|
WireAuthAndDialog();
|
||||||
|
|
||||||
|
var cut = Render<NotificationListsPage>();
|
||||||
|
|
||||||
|
cut.WaitForState(() => cut.Markup.Contains("Ops On-Call"));
|
||||||
|
|
||||||
|
var deleteButton = cut.FindAll("tbody tr button")
|
||||||
|
.First(b => b.TextContent.Contains("Delete"));
|
||||||
|
deleteButton.Click();
|
||||||
|
|
||||||
|
cut.WaitForAssertion(() =>
|
||||||
|
{
|
||||||
|
repo.Received().DeleteNotificationListAsync(1);
|
||||||
|
repo.Received().SaveChangesAsync();
|
||||||
|
// Reload re-invokes the list query (once on init, once after delete).
|
||||||
|
repo.Received(2).GetAllNotificationListsAsync();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>A dialog service that auto-confirms, so action paths run end-to-end.</summary>
|
/// <summary>A dialog service that auto-confirms, so action paths run end-to-end.</summary>
|
||||||
|
|||||||
Reference in New Issue
Block a user