diff --git a/tests/ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests/Design/ApiMethodFormTests.cs b/tests/ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests/Design/ApiMethodFormTests.cs index 9c20142c..a80a5ed4 100644 --- a/tests/ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests/Design/ApiMethodFormTests.cs +++ b/tests/ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests/Design/ApiMethodFormTests.cs @@ -32,10 +32,12 @@ public class ApiMethodFormTests await page.WaitForLoadStateAsync(LoadState.NetworkIdle); await Assertions.Expect(page.Locator("h4:has-text('Add API Method')")).ToBeVisibleAsync(); - // The form has several text inputs (Name + SchemaBuilder/parameter rows), so anchor - // the Name input to its label wrapper to stay unambiguous. - var nameInput = page.Locator("div.mb-3:has(label:has-text('Name')) input[type=text]"); - await Assertions.Expect(nameInput).ToBeVisibleAsync(); + // The form has several text inputs (Name + SchemaBuilder/parameter rows that also + // carry .form-control), so anchor the Name input to its labelled mb-3 wrapper and + // require .form-control (the peer ExternalSystemCrudTests pattern). The count guard + // makes any future selector ambiguity fail loudly instead of filling the wrong field. + var nameInput = page.Locator("div.mb-3:has(label:has-text('Name')) input[type=text].form-control"); + await Assertions.Expect(nameInput).ToHaveCountAsync(1); await nameInput.FillAsync("zzapimethod"); // Leave the Monaco script empty and submit — the gate should reject it. @@ -71,7 +73,10 @@ public class ApiMethodFormTests // Switch to the Inbound API Methods tab; only its panel renders, so the card // locator below stays unambiguous against External System / DB Connection cards. + // The tab switch is a Blazor SignalR re-render (@if (_tab == "inbound")), so let + // the circuit settle before querying the freshly-rendered panel. await page.Locator("button.nav-link:has-text('Inbound API Methods')").ClickAsync(); + await page.WaitForLoadStateAsync(LoadState.NetworkIdle); var card = page.Locator("div.card").Filter(new() { HasText = name }); await Assertions.Expect(card).ToHaveCountAsync(1, new() { Timeout = 10_000 }); @@ -82,7 +87,9 @@ public class ApiMethodFormTests await dropdown.Locator("button[aria-label^='More actions']").ClickAsync(); await dropdown.Locator(".dropdown-menu button.dropdown-item.text-danger").ClickAsync(); - await Assertions.Expect(page.Locator(".modal-footer .btn-danger")).ToBeVisibleAsync(); + // Confirm we are on the right dialog before clicking danger. The api-method delete + // uses the generic "Delete" title (ConfirmAsync("Delete", "Delete API method '{name}'?")). + await Assertions.Expect(page.Locator(".modal-title:has-text('Delete')")).ToBeVisibleAsync(); await page.Locator(".modal-footer .btn-danger").ClickAsync(); // Single web-first assertion on the success toast — toasts auto-dismiss, so we