From dd6a9efecb44a03993fe248a4bc553408bbb4eca Mon Sep 17 00:00:00 2001 From: "MSI\\niranjankagri" Date: Thu, 22 Oct 2026 16:57:49 +0530 Subject: [PATCH] Fix the flaky admin user search scenario The scenario "Search users by username and status" sometimes saw all 28 users instead of only Admin (main run 39758065455). The filters were typed while the System Users page was still loading its table, and the page then re-rendered and cleared the username; Search ran unfiltered. - isDisplayed() now also waits for the loader and the record counter, so the filters are only typed into a fully loaded page. - filterByUsername() waits until the field really holds the text. - search() waits until the old table is replaced or the counter changes, so the assertion never reads the rows from before the search. - The assertion message now shows the filter value, the counter and all usernames, so a future failure explains itself. Locally: admin scenarios 8/8 and the full suite 4/4 in a row (one earlier batch failed while the public demo site was unreachable). Co-Authored-By: Claude Opus 5.5 --- .../automation/ui/pages/SystemUsersPage.java | 41 ++++++++++++++++++- .../com/automation/ui/steps/AdminSteps.java | 4 +- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/automation/ui/pages/SystemUsersPage.java b/src/main/java/com/automation/ui/pages/SystemUsersPage.java index f059dca..1db27ea 100644 --- a/src/main/java/com/automation/ui/pages/SystemUsersPage.java +++ b/src/main/java/com/automation/ui/pages/SystemUsersPage.java @@ -3,8 +3,11 @@ import java.util.List; import org.openqa.selenium.By; +import org.openqa.selenium.StaleElementReferenceException; +import org.openqa.selenium.TimeoutException; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.ui.ExpectedConditions; /** * Admin → User Management → System Users ({@value #PATH}): a filter form @@ -36,10 +39,16 @@ public SystemUsersPage(WebDriver driver) { } /** - * @return boolean true once the page URL and the filter form are shown. + * @return boolean true once the page URL, the filter form and the loaded + * user table are shown. Filters typed while the table is still + * loading can be cleared when the page finishes rendering. */ public boolean isDisplayed() { - return waitForUrl(PATH) && isVisible(filterInput("Username")); + if (!waitForUrl(PATH) || !isVisible(filterInput("Username"))) { + return false; + } + waitForLoader(); + return isVisible(recordCount); } /** @@ -49,6 +58,7 @@ public boolean isDisplayed() { */ public void filterByUsername(String username) { type(filterInput("Username"), username); + wait.until(d -> username.equals(usernameFilter())); } /** @@ -63,13 +73,40 @@ public void filterByStatus(String status) { /** * Clicks Search and waits for the table to reload. + *

+ * The unfiltered table and its counter are already on screen, so waiting + * for them alone can read the old rows when the spinner is missed. This + * also waits until the old first row is replaced or the counter changes. + * If neither happens, the search returned the rows already shown. */ public void search() { + List oldRows = findAll(rows); + String oldCount = currentCount(); click(searchButton); waitForLoader(); + if (!oldRows.isEmpty()) { + try { + wait.until(d -> { + String count = currentCount(); + return ExpectedConditions.stalenessOf(oldRows.get(0)).apply(d) + || (!count.isEmpty() && !count.equals(oldCount)); + }); + } catch (TimeoutException e) { + // Same rows and counter as before: the table already shows the result + } + } waitVisible(recordCount); } + // Counter text without waiting; "" while it is absent or being re-rendered + private String currentCount() { + try { + return findAll(recordCount).stream().findFirst().map(e -> e.getText().trim()).orElse(""); + } catch (StaleElementReferenceException e) { + return ""; + } + } + /** * Clicks Reset and waits for the table to reload. */ diff --git a/src/test/java/com/automation/ui/steps/AdminSteps.java b/src/test/java/com/automation/ui/steps/AdminSteps.java index 5eb40db..654a0fe 100644 --- a/src/test/java/com/automation/ui/steps/AdminSteps.java +++ b/src/test/java/com/automation/ui/steps/AdminSteps.java @@ -109,7 +109,9 @@ public void theAdminResetsTheFilters() { public void onlyMatchingUsersAreListed(String username, String status) { List usernames = page().usernames(); assertFalse(usernames.isEmpty(), "No users found, counter shows: " + page().recordCount()); - usernames.forEach(name -> assertTrue(name.equalsIgnoreCase(username), "Unexpected username in results: " + name)); + usernames.forEach(name -> assertTrue(name.equalsIgnoreCase(username), + "Unexpected username in results: " + name + " (filter \"" + page().usernameFilter() + "\", " + + page().recordCount() + ": " + usernames + ")")); page().statuses().forEach(value -> assertEquals(status, value, "Status in results")); }