test(e2e): row-scope API-key kebab dropdown selectors + visibility-gate items (review fix)
This commit is contained in:
@@ -172,20 +172,30 @@ public sealed class ApiKeyCrudTests : IClassFixture<ApiSurfaceFixture>
|
||||
var row = page.Locator("tr").Filter(new() { HasText = keyName });
|
||||
await Assertions.Expect(row).ToBeVisibleAsync(new() { Timeout = 15_000 });
|
||||
|
||||
var kebab = page.Locator($"button[aria-label=\"More actions for {keyName}\"]");
|
||||
// Scope ALL dropdown interactions to THIS row's .dropdown container so the kebab and
|
||||
// its menu items can never multi-match against another row's (hidden) menu under
|
||||
// Playwright strict mode (e.g. when the list has test residue / multiple keys).
|
||||
var rowDropdown = row.Locator(".dropdown");
|
||||
var kebab = rowDropdown.Locator("button[aria-label^='More actions']");
|
||||
var disabledBadge = row.Locator("span.badge.bg-secondary");
|
||||
|
||||
// Open the kebab (Bootstrap dropdown) and click Disable. The dropdown item is only
|
||||
// visible/clickable once the menu is .show; Playwright auto-waits for it.
|
||||
// Open the kebab (Bootstrap dropdown) and click Disable. Gate the click on the item's
|
||||
// visibility so we don't race the Bootstrap open-transition before the menu is .show.
|
||||
await kebab.ClickAsync();
|
||||
await page.Locator("button.dropdown-item").Filter(new() { HasText = "Disable" }).ClickAsync();
|
||||
var disableItem = rowDropdown.Locator(".dropdown-menu button.dropdown-item")
|
||||
.Filter(new() { HasText = "Disable" });
|
||||
await Assertions.Expect(disableItem).ToBeVisibleAsync();
|
||||
await disableItem.ClickAsync();
|
||||
|
||||
// Authoritative: the "Disabled" badge appears on the row's name cell.
|
||||
await Assertions.Expect(disabledBadge).ToBeVisibleAsync(new() { Timeout = 10_000 });
|
||||
|
||||
// Re-open the kebab and click Enable; the badge must disappear from this row.
|
||||
await kebab.ClickAsync();
|
||||
await page.Locator("button.dropdown-item").Filter(new() { HasText = "Enable" }).ClickAsync();
|
||||
var enableItem = rowDropdown.Locator(".dropdown-menu button.dropdown-item")
|
||||
.Filter(new() { HasText = "Enable" });
|
||||
await Assertions.Expect(enableItem).ToBeVisibleAsync();
|
||||
await enableItem.ClickAsync();
|
||||
|
||||
await Assertions.Expect(disabledBadge).ToHaveCountAsync(0, new() { Timeout = 10_000 });
|
||||
}
|
||||
@@ -219,9 +229,19 @@ public sealed class ApiKeyCrudTests : IClassFixture<ApiSurfaceFixture>
|
||||
var row = page.Locator("tr").Filter(new() { HasText = keyName });
|
||||
await Assertions.Expect(row).ToBeVisibleAsync(new() { Timeout = 15_000 });
|
||||
|
||||
// Open the kebab and click the danger "Delete" item.
|
||||
await page.Locator($"button[aria-label=\"More actions for {keyName}\"]").ClickAsync();
|
||||
await page.Locator(".dropdown-item.text-danger").Filter(new() { HasText = "Delete" }).ClickAsync();
|
||||
// Scope ALL dropdown interactions to THIS row's .dropdown container so the kebab and
|
||||
// its menu items can never multi-match against another row's (hidden) menu under
|
||||
// Playwright strict mode (e.g. when the list has test residue / multiple keys).
|
||||
var rowDropdown = row.Locator(".dropdown");
|
||||
var kebab = rowDropdown.Locator("button[aria-label^='More actions']");
|
||||
|
||||
// Open the kebab and click the danger "Delete" item. Gate the click on the item's
|
||||
// visibility so we don't race the Bootstrap open-transition before the menu is .show.
|
||||
await kebab.ClickAsync();
|
||||
var deleteItem = rowDropdown.Locator(".dropdown-menu button.dropdown-item")
|
||||
.Filter(new() { HasText = "Delete" });
|
||||
await Assertions.Expect(deleteItem).ToBeVisibleAsync();
|
||||
await deleteItem.ClickAsync();
|
||||
|
||||
// The confirm dialog must appear before we confirm.
|
||||
await Assertions.Expect(page.Locator(".modal-title").Filter(new() { HasText = "Delete API Key" }))
|
||||
|
||||
Reference in New Issue
Block a user