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")); }