839770d503
Add ParkedMessagesActionTests with three facts: Query disabled until site selected, Clear disabled until filter set (then re-disabled after clear), and a tolerant bulk Retry/Discard bar reveal when parked rows happen to be present. Distinct from the existing render-without-hang test — gating facts are deterministic; row-dependent fact early-returns gracefully in unseedable environments.
125 lines
5.9 KiB
C#
125 lines
5.9 KiB
C#
using Microsoft.Playwright;
|
|
using Xunit;
|
|
using ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests.Cluster;
|
|
|
|
namespace ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests.Monitoring;
|
|
|
|
/// <summary>
|
|
/// End-to-end action and filter-control gating tests for the central Parked Messages page
|
|
/// (<c>/monitoring/parked-messages</c>).
|
|
///
|
|
/// <para>
|
|
/// <b>Why this is distinct from <see cref="ParkedMessagesTests"/>:</b> the existing render
|
|
/// guard verifies that the singleton-backed cross-cluster query resolves (renders the results
|
|
/// table or the empty-state card) rather than hanging. This class targets the DETERMINISTIC
|
|
/// filter-control gating behaviour that is verifiable regardless of whether any parked rows
|
|
/// exist in the live environment:
|
|
/// <list type="bullet">
|
|
/// <item><description>The Query button is disabled until a site is selected.</description></item>
|
|
/// <item><description>The Clear button is disabled until at least one filter is active,
|
|
/// and is re-disabled after clicking Clear.</description></item>
|
|
/// </list>
|
|
/// A third, tolerant fact exercises the conditional bulk-action bar (Retry/Discard selected)
|
|
/// that appears when at least one row checkbox is checked. Parked store-and-forward rows live
|
|
/// in the SITE's local SQLite buffer — there is no central table to seed — so that fact
|
|
/// performs an early-return no-op when no rows happen to be present, which is both expected
|
|
/// and acceptable in this environment.
|
|
/// </para>
|
|
///
|
|
/// <para>
|
|
/// Gated on <see cref="ClusterAvailability"/> via <c>Skip.IfNot</c>: when the cluster is
|
|
/// unreachable the facts report as Skipped (not Failed), matching the established suite idiom.
|
|
/// </para>
|
|
/// </summary>
|
|
[Collection("Playwright")]
|
|
public class ParkedMessagesActionTests
|
|
{
|
|
private readonly PlaywrightFixture _fixture;
|
|
|
|
public ParkedMessagesActionTests(PlaywrightFixture fixture)
|
|
{
|
|
_fixture = fixture;
|
|
}
|
|
|
|
/// <summary>
|
|
/// The Query button must be disabled on page load (no site selected) and become
|
|
/// enabled once a site is selected from the site dropdown.
|
|
/// </summary>
|
|
[SkippableFact]
|
|
public async Task QueryButton_DisabledUntilSiteSelected()
|
|
{
|
|
Skip.IfNot(await ClusterAvailability.IsAvailableAsync(), ClusterAvailability.SkipReason);
|
|
|
|
var page = await _fixture.NewAuthenticatedPageAsync();
|
|
await page.GotoAsync($"{PlaywrightFixture.BaseUrl}/monitoring/parked-messages");
|
|
await page.WaitForLoadStateAsync(LoadState.NetworkIdle);
|
|
await Assertions.Expect(page.Locator("h4:has-text('Parked Messages')")).ToBeVisibleAsync();
|
|
|
|
var query = page.Locator("button.btn.btn-primary.btn-sm:has-text('Query')");
|
|
await Assertions.Expect(query).ToBeDisabledAsync();
|
|
|
|
await page.Locator("#pm-filter-site").SelectOptionAsync("site-a");
|
|
// Selecting a site enables Query (and kicks off its own search — tolerated).
|
|
await Assertions.Expect(query).ToBeEnabledAsync(new() { Timeout = 5_000 });
|
|
}
|
|
|
|
/// <summary>
|
|
/// The Clear button must be disabled on page load (no active filters) and become
|
|
/// enabled once any filter is changed. Clicking Clear must re-disable it.
|
|
/// </summary>
|
|
[SkippableFact]
|
|
public async Task ClearButton_DisabledUntilFilterSet_ThenResets()
|
|
{
|
|
Skip.IfNot(await ClusterAvailability.IsAvailableAsync(), ClusterAvailability.SkipReason);
|
|
|
|
var page = await _fixture.NewAuthenticatedPageAsync();
|
|
await page.GotoAsync($"{PlaywrightFixture.BaseUrl}/monitoring/parked-messages");
|
|
await page.WaitForLoadStateAsync(LoadState.NetworkIdle);
|
|
|
|
var clear = page.Locator("button.btn.btn-outline-secondary.btn-sm:has-text('Clear')");
|
|
await Assertions.Expect(clear).ToBeDisabledAsync();
|
|
|
|
// Setting any filter (Age) flips HasActiveFilters -> Clear enables.
|
|
await page.Locator("#pm-filter-age").SelectOptionAsync("LastHour");
|
|
await Assertions.Expect(clear).ToBeEnabledAsync(new() { Timeout = 5_000 });
|
|
|
|
await clear.ClickAsync();
|
|
await Assertions.Expect(clear).ToBeDisabledAsync(new() { Timeout = 5_000 });
|
|
}
|
|
|
|
/// <summary>
|
|
/// When at least one parked row is present, checking its row checkbox must reveal
|
|
/// the bulk action bar with Retry selected and Discard selected buttons. If no rows
|
|
/// are present (the common case in a clean test environment — parked rows are not
|
|
/// seedable from central), the test exits early as a tolerated no-op.
|
|
/// </summary>
|
|
[SkippableFact]
|
|
public async Task SelectingParkedRow_RevealsBulkRetryDiscardBar_WhenRowsPresent()
|
|
{
|
|
Skip.IfNot(await ClusterAvailability.IsAvailableAsync(), ClusterAvailability.SkipReason);
|
|
|
|
var page = await _fixture.NewAuthenticatedPageAsync();
|
|
await page.GotoAsync($"{PlaywrightFixture.BaseUrl}/monitoring/parked-messages");
|
|
await page.WaitForLoadStateAsync(LoadState.NetworkIdle);
|
|
|
|
await page.Locator("#pm-filter-site").SelectOptionAsync("site-a");
|
|
await page.Locator("button.btn.btn-primary.btn-sm:has-text('Query')").ClickAsync();
|
|
|
|
// Wait for the query to resolve (table OR empty-state card).
|
|
var resolved = page.Locator("table.parked-table, div.card-body:has-text('No parked messages')");
|
|
await Assertions.Expect(resolved.First).ToBeVisibleAsync(new() { Timeout = 20_000 });
|
|
|
|
// Parked S&F rows are not seedable, so rows may be absent in this environment. Only
|
|
// assert the action affordances when at least one row rendered.
|
|
var rows = page.Locator("tr.parked-row");
|
|
if (await rows.CountAsync() == 0)
|
|
{
|
|
return; // No parked messages at site-a — bulk-bar affordance can't be exercised.
|
|
}
|
|
|
|
await rows.First.Locator("input.form-check-input").CheckAsync();
|
|
await Assertions.Expect(page.Locator("button:has-text('Retry selected')")).ToBeVisibleAsync();
|
|
await Assertions.Expect(page.Locator("button:has-text('Discard selected')")).ToBeVisibleAsync();
|
|
}
|
|
}
|