fix(centralui): single relay toast, paging/skip polish, extra Site Calls tests
This commit is contained in:
@@ -329,6 +329,88 @@ public class SiteCallsReportPageTests : BunitContext
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Paging_PrevButton_PopsBackStackAndRefetchesPriorCursor()
|
||||
{
|
||||
// The keyset back-stack is the trickiest paging path: Next pushes the
|
||||
// current cursor, Prev pops it and refetches that prior page. Page 1 is
|
||||
// opened with the empty (null, null) cursor, so after Next→Previous the
|
||||
// follow-up query must carry (null, null) again.
|
||||
var firstPage = new List<SiteCallSummary>();
|
||||
for (var i = 0; i < 50; i++)
|
||||
{
|
||||
firstPage.Add(new SiteCallSummary(
|
||||
Guid.NewGuid(), "plant-a", "ApiOutbound", $"ERP.Op{i}", "Delivered",
|
||||
RetryCount: 0, LastError: null, HttpStatus: 200,
|
||||
CreatedAtUtc: DateTime.UtcNow.AddMinutes(-i), UpdatedAtUtc: DateTime.UtcNow.AddMinutes(-i),
|
||||
TerminalAtUtc: DateTime.UtcNow.AddMinutes(-i), IsStuck: false));
|
||||
}
|
||||
|
||||
var cursorCreated = new DateTime(2026, 5, 20, 12, 0, 0, DateTimeKind.Utc);
|
||||
var cursorId = Guid.Parse("99999999-9999-9999-9999-999999999999");
|
||||
_queryReply = new SiteCallQueryResponse(
|
||||
"q", true, null, firstPage,
|
||||
NextAfterCreatedAtUtc: cursorCreated,
|
||||
NextAfterId: cursorId);
|
||||
|
||||
var cut = Render<SiteCallsReportPage>();
|
||||
cut.WaitForState(() => cut.Markup.Contains("ERP.Op0"));
|
||||
|
||||
// Step forward — query 2 carries the keyset cursor.
|
||||
var next = cut.Find("[data-test='site-calls-next']");
|
||||
next.Click();
|
||||
cut.WaitForAssertion(() =>
|
||||
{
|
||||
Assert.Equal(2, _queryRequests.Count);
|
||||
Assert.Equal(cursorCreated, _queryRequests[1].AfterCreatedAtUtc);
|
||||
});
|
||||
|
||||
// Previous is now live (the back-stack has one entry); click it.
|
||||
var prev = cut.Find("[data-test='site-calls-prev']");
|
||||
Assert.False(prev.HasAttribute("disabled"));
|
||||
prev.Click();
|
||||
|
||||
cut.WaitForAssertion(() =>
|
||||
{
|
||||
// Query 3 is the Previous refetch — the back-stack popped the page-1
|
||||
// cursor, which is the empty (null, null) first-page cursor.
|
||||
Assert.Equal(3, _queryRequests.Count);
|
||||
Assert.Null(_queryRequests[2].AfterCreatedAtUtc);
|
||||
Assert.Null(_queryRequests[2].AfterId);
|
||||
// Back on page 1, the back-stack is empty again so Previous re-disables.
|
||||
Assert.True(cut.Find("[data-test='site-calls-prev']").HasAttribute("disabled"));
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RetryRelay_NotParked_ShowsInfoMessage_AndExactlyOneToast()
|
||||
{
|
||||
// NotParked is a definitive answer from the site (nothing to do), not a
|
||||
// failure — it surfaces as a single info toast, never an error. This
|
||||
// also guards the single-toast contract: a non-Applied outcome must
|
||||
// produce exactly one toast.
|
||||
_retryReply = new RetrySiteCallResponse(
|
||||
"q", SiteCallRelayOutcome.NotParked, Success: false, SiteReachable: true,
|
||||
ErrorMessage: "The cached call is no longer parked.");
|
||||
|
||||
var cut = Render<SiteCallsReportPage>();
|
||||
cut.WaitForState(() => cut.Markup.Contains("ERP.GetOrder"));
|
||||
|
||||
var parkedRow = cut.FindAll("tbody tr")
|
||||
.First(r => r.TextContent.Contains("ERP.GetOrder"));
|
||||
parkedRow.QuerySelectorAll("button")
|
||||
.First(b => b.TextContent.Contains("Retry"))
|
||||
.Click();
|
||||
|
||||
cut.WaitForAssertion(() =>
|
||||
{
|
||||
Assert.Contains("no longer parked", cut.Markup);
|
||||
// Exactly one toast — the ShowRelayOutcome switch owns the single
|
||||
// toast; no second (error) toast piggybacks on the same response.
|
||||
Assert.Single(cut.FindAll(".toast"));
|
||||
});
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
|
||||
Reference in New Issue
Block a user