From 014038fbbd372f358d282760ed9080bb29e1013d Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Sat, 15 Aug 2026 03:33:51 -0400 Subject: [PATCH] test(playwright): repair 14 selector-drift failures from two Central UI refactors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All 14 pre-existing Playwright failures triage to selector drift, not rig data, timing, or application defects — every one is a test-side assumption that two merged UI refactors invalidated without updating this suite. `9e243493` (2026-08-11 density sweep + Theme 0.4.1) regrouped page/dialog action buttons into `btn-group btn-group-sm`, moving the size class off the button and onto the group. Twelve selectors still pinned `.btn-sm` on the button itself: ConfigurationAuditLog's Search (4 tests), the Topology Create/Move dialog footers (3), the Notification Lists row Edit/Delete (2), and the Notification Report row Retry/Discard (2). The same sweep re-cast SiteForm's per-node subsections from bare `
` headings to Bootstrap cards, so `h6:has-text('Node A')` matches nothing (1). Note the swept surfaces are a subset — the recipient table on the notification-list edit form, OffsetPager, DiffDialog and friends still carry `.btn-sm` on the button, so the selectors are deliberately asymmetric; the remaining `.btn-sm` selectors in this suite were each re-verified against current markup rather than swept along. `a506b19d` moved TemplateEdit's page-embedded modals onto the DialogService host. The attribute modal is now the DialogHost modal (`modal fade show d-block`, title in an h5), so the `:not(.fade)` guard written to exclude DialogHost — plus the `h6.modal-title` assertion — excluded the very modal under test (2). TemplateEdit renders no page-local modal any more, so the guard has nothing left to guard. Comments at each site record why the size class is absent, so a future reader does not "fix" the selectors back. Verified: 14 failed / 158 passed baseline -> the 36 tests in the seven affected classes all green; solution build 0 warnings / 0 errors. --- .../Audit/AuditConfigurationTests.cs | 13 ++++++----- .../Deployment/TopologyAreaTests.cs | 9 +++++--- .../Design/TemplateCrudTests.cs | 22 +++++++++++-------- .../Notifications/NotificationActionTests.cs | 12 ++++++---- .../NotificationListCrudTests.cs | 8 +++++-- .../Notifications/SmsNotificationE2ETests.cs | 4 +++- .../SiteCrudTests.cs | 7 ++++-- 7 files changed, 49 insertions(+), 26 deletions(-) diff --git a/tests/ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests/Audit/AuditConfigurationTests.cs b/tests/ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests/Audit/AuditConfigurationTests.cs index e6747284..38c4e435 100644 --- a/tests/ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests/Audit/AuditConfigurationTests.cs +++ b/tests/ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests/Audit/AuditConfigurationTests.cs @@ -82,9 +82,12 @@ public class AuditConfigurationTests await Assertions.Expect(page.Locator("#audit-filter-entity-type")).ToBeVisibleAsync(); // Filter by the unique marker so only this run's 3 rows remain, then - // Search to load the grid. + // Search to load the grid. The Search/Clear pair sits in a + // `btn-group btn-group-sm` since the 2026-08-11 UI density sweep, so the + // size class lives on the group and NOT on the button — do not re-add + // `.btn-sm` to this selector. await page.Locator("#audit-filter-entity-type").FillAsync(marker); - await page.Locator("button.btn.btn-primary.btn-sm:has-text('Search')").ClickAsync(); + await page.Locator("button.btn.btn-primary:has-text('Search')").ClickAsync(); await page.WaitForLoadStateAsync(LoadState.NetworkIdle); // Seeded rows are isolated: a known row is visible AND the footer total @@ -116,7 +119,7 @@ public class AuditConfigurationTests // Filter by the marker so the totals/page-count reflect only this run. await page.Locator("#audit-filter-entity-type").FillAsync(marker); - await page.Locator("button.btn.btn-primary.btn-sm:has-text('Search')").ClickAsync(); + await page.Locator("button.btn.btn-primary:has-text('Search')").ClickAsync(); await page.WaitForLoadStateAsync(LoadState.NetworkIdle); // Page 1 of 2: Previous disabled, Next enabled. (M10 OffsetPager summary: @@ -161,7 +164,7 @@ public class AuditConfigurationTests // Filter by the unique marker and Search so only this run's single // large-state row populates the grid. await page.Locator("#audit-filter-entity-type").FillAsync(marker); - await page.Locator("button.btn.btn-primary.btn-sm:has-text('Search')").ClickAsync(); + await page.Locator("button.btn.btn-primary:has-text('Search')").ClickAsync(); await page.WaitForLoadStateAsync(LoadState.NetworkIdle); // Open the modal from the seeded large-state row. The marker is unique, @@ -198,7 +201,7 @@ public class AuditConfigurationTests await page.WaitForLoadStateAsync(LoadState.NetworkIdle); await page.Locator("#audit-filter-entity-type").FillAsync(marker); - await page.Locator("button.btn.btn-primary.btn-sm:has-text('Search')").ClickAsync(); + await page.Locator("button.btn.btn-primary:has-text('Search')").ClickAsync(); await page.WaitForLoadStateAsync(LoadState.NetworkIdle); // Click the copy-entity-ID button on the (only) seeded row. diff --git a/tests/ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests/Deployment/TopologyAreaTests.cs b/tests/ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests/Deployment/TopologyAreaTests.cs index b7d36afb..768bbc3c 100644 --- a/tests/ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests/Deployment/TopologyAreaTests.cs +++ b/tests/ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests/Deployment/TopologyAreaTests.cs @@ -92,10 +92,13 @@ public class TopologyAreaTests : IClassFixture await Assertions.Expect(dialog).ToBeVisibleAsync(); // First select = Site (option value = site.Id); then the name; then Create. + // The dialog footer pair sits in a `btn-group btn-group-sm` since the + // 2026-08-11 UI density sweep, so the size class lives on the group and NOT + // on the button — do not re-add `.btn-sm` to the footer selectors here. await dialog.Locator("select").First.SelectOptionAsync( new SelectOptionValue { Value = _cluster.SiteAId.ToString() }); await dialog.Locator("input[placeholder='Area name']").FillAsync(areaName); - await dialog.Locator("button.btn.btn-primary.btn-sm:has-text('Create')").ClickAsync(); + await dialog.Locator("button.btn.btn-primary:has-text('Create')").ClickAsync(); await Assertions.Expect(page.Locator(".toast")).ToHaveCountAsync(1, new() { Timeout = 15_000 }); await Assertions.Expect(page.Locator($"span.tv-label:has-text('{areaName}')")) @@ -207,7 +210,7 @@ public class TopologyAreaTests : IClassFixture // the option's exact visible text. A