test(e2e): SiteCalls Discard click-through on a Parked row surfaces a relay outcome toast

This commit is contained in:
Joseph Doherty
2026-06-06 13:33:48 -04:00
parent 839770d503
commit d80737978d
@@ -30,6 +30,9 @@ namespace ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests.SiteCalls;
/// rows, never on Failed (or other) rows.</item>
/// <item><c>RetryClickThrough</c> — clicking Retry on a Parked row confirms
/// the dialog, relays to the owning site, and surfaces an outcome toast.</item>
/// <item><c>DiscardClickThrough</c> — clicking Discard on a Parked row confirms
/// the danger dialog ("Delete"), relays to the owning site, and surfaces an
/// outcome toast.</item>
/// </list>
/// </para>
///
@@ -328,4 +331,60 @@ public class SiteCallsPageTests
await SiteCallDataSeeder.DeleteByTargetPrefixAsync(targetPrefix);
}
}
/// <summary>
/// Mirrors <see cref="RetryClickThrough_OnParkedRow_ConfirmsRelayAndShowsOutcomeToast"/>
/// but exercises the Discard path: clicking Discard opens a <em>danger</em>
/// confirm modal (Dialog.ConfirmAsync with <c>danger: true</c>), whose footer
/// button is labelled "Delete" (not "Confirm"). Confirming relays a discard to
/// the owning site and <c>ShowRelayOutcome</c> surfaces exactly one outcome toast.
/// </summary>
[SkippableFact]
public async Task DiscardClickThrough_OnParkedRow_ConfirmsRelayAndShowsOutcomeToast()
{
Skip.IfNot(await SiteCallDataSeeder.IsAvailableAsync(), DbUnavailableSkipReason);
var runId = Guid.NewGuid().ToString("N");
var targetPrefix = $"playwright-test/sc-discard-click/{runId}/";
var parkedId = Guid.NewGuid();
var now = DateTime.UtcNow;
try
{
// Parked + real site-a so the discard relay resolves fast (NotParked ack for this
// freshly-seeded GUID), surfacing a toast.
await SiteCallDataSeeder.InsertSiteCallAsync(
trackedOperationId: parkedId, channel: "ApiOutbound", target: targetPrefix + "parked",
sourceSite: "site-a", status: "Parked", retryCount: 3,
lastError: "HTTP 503 from ERP", httpStatus: 503,
createdAtUtc: now, updatedAtUtc: now);
var page = await _fixture.NewAuthenticatedPageAsync();
await page.GotoAsync($"{PlaywrightFixture.BaseUrl}{SiteCallsUrl}");
await page.WaitForLoadStateAsync(LoadState.NetworkIdle);
await SetSearchKeywordAsync(page, targetPrefix + "parked");
await page.Locator("[data-test='site-calls-query']").ClickAsync();
await page.WaitForLoadStateAsync(LoadState.NetworkIdle);
var parkedRow = page.Locator("tbody tr", new() { HasText = targetPrefix + "parked" });
await Assertions.Expect(parkedRow).ToBeVisibleAsync();
// Discard opens the danger confirm modal.
await parkedRow.Locator("button:has-text('Discard')").ClickAsync();
// Danger confirm — labelled "Delete" (Dialog.ConfirmAsync(..., danger: true)).
var deleteButton = page.Locator(".modal-footer .btn-danger");
await Assertions.Expect(deleteButton).ToBeVisibleAsync();
await Assertions.Expect(deleteButton).ToHaveTextAsync("Delete");
await deleteButton.ClickAsync();
// One outcome toast (Applied / NotParked / SiteUnreachable — tolerant).
await Assertions.Expect(page.Locator(".toast")).ToHaveCountAsync(1, new() { Timeout = 15_000 });
}
finally
{
await SiteCallDataSeeder.DeleteByTargetPrefixAsync(targetPrefix);
}
}
}