From 45e2a1d7255736b4f9f5bed54711d0fc978909b4 Mon Sep 17 00:00:00 2001 From: alanv Date: Tue, 13 Feb 2024 10:58:21 -0600 Subject: [PATCH 1/5] AppsMenu: Refactor to account for new DOM layout --- .../ui/navigation/apps/AppsMenu.java | 72 ++++++++++++++++--- 1 file changed, 63 insertions(+), 9 deletions(-) diff --git a/src/org/labkey/test/components/ui/navigation/apps/AppsMenu.java b/src/org/labkey/test/components/ui/navigation/apps/AppsMenu.java index 91d3ddad91..14d1e86a4e 100644 --- a/src/org/labkey/test/components/ui/navigation/apps/AppsMenu.java +++ b/src/org/labkey/test/components/ui/navigation/apps/AppsMenu.java @@ -1,22 +1,67 @@ package org.labkey.test.components.ui.navigation.apps; import org.labkey.test.Locator; +import org.labkey.test.WebDriverWrapper; +import org.labkey.test.components.Component; import org.labkey.test.components.WebDriverComponent; -import org.labkey.test.components.html.BootstrapMenu; import org.labkey.test.components.react.BaseBootstrapMenu; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; +import java.util.Optional; + /** * Wraps the expand/collapse toggle piece of the Apps menu in Biologics and SampleManager. * In LKS views, LKAppsMenu is the analog of this component */ -public class AppsMenu extends BaseBootstrapMenu +public class AppsMenu extends WebDriverComponent { + private final WebElement _componentElement; + private final WebDriver _driver; protected AppsMenu(WebElement element, WebDriver driver) { - super(element, driver); + _componentElement = element; + _driver = driver; + } + + @Override + protected WebDriver getDriver() + { + return _driver; + } + + @Override + public WebElement getComponentElement() + { + return _componentElement; + } + + protected boolean isExpanded() + { + return "true".equals(elementCache().toggle.getAttribute("aria-expanded")); + } + + protected boolean isLoaded() + { + return elementCache().getList().isPresent(); + } + + public void expand() + { + if (!isExpanded()) + { + elementCache().toggle.click(); + WebDriverWrapper.waitFor(this::isLoaded, "AppsMenu did not expand as expected", WebDriverWrapper.WAIT_FOR_JAVASCRIPT); + } + } + + public void collapse() + { + if (isExpanded()) + { + elementCache().toggle.click(); + } } /** @@ -26,6 +71,7 @@ protected AppsMenu(WebElement element, WebDriver driver) public ProductsNavContainer showProductsPanel() { expand(); + return new ProductsNavContainer.ProductNavContainerFinder(getDriver()).withTitle("Applications") .waitFor(); } @@ -50,19 +96,27 @@ public void navigateToLabKey(String project) .clickProject(project); } - @Override - protected Locator getToggleLocator() + protected AppsMenu.ElementCache newElementCache() + { + return new AppsMenu.ElementCache(); + } + + protected class ElementCache extends Component.ElementCache { - return BootstrapMenu.Locators.dropdownToggle(); + public final WebElement rootElement = Locator.byClass("product-navigation-menu").findWhenNeeded(getDriver()); + public final WebElement toggle = Locator.byClass("navbar-menu-button").findWhenNeeded(rootElement); + + public Optional getList() + { + return Locator.byClass("product-navigation-listing").findOptionalElement(rootElement); + } } public static class AppsMenuFinder extends WebDriverComponent.WebDriverComponentFinder { - private Locator _locator = Locator.XPathLocator.union( - Locator.id("product-navigation-button").parent(), //lksm/bio - Locator.id("headerProductDropdown")); //lks + private Locator _locator = Locator.byClass("product-navigation-menu"); public AppsMenuFinder(WebDriver driver) { From 28457412af0eb8cc3ad9e4e9b04e0514c2c5778d Mon Sep 17 00:00:00 2001 From: alanv Date: Tue, 13 Feb 2024 11:45:40 -0600 Subject: [PATCH 2/5] AppsMenu: Fix LKS usages --- .../ui/navigation/apps/AppsMenu.java | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/org/labkey/test/components/ui/navigation/apps/AppsMenu.java b/src/org/labkey/test/components/ui/navigation/apps/AppsMenu.java index 14d1e86a4e..4d9520f753 100644 --- a/src/org/labkey/test/components/ui/navigation/apps/AppsMenu.java +++ b/src/org/labkey/test/components/ui/navigation/apps/AppsMenu.java @@ -89,12 +89,9 @@ public void navigateTo(ProductsNavContainer.Product product, String node) .clickItem(node); } - public void navigateToLabKey(String project) - { - showProductsPanel() - .clickLabkey() - .clickProject(project); - } + public static Locator rootLocator = Locator.XPathLocator.union( + Locator.byClass("product-navigation-menu"), // Bio/FM/SM + Locator.id("headerProductDropdown")); // LKS @Override protected AppsMenu.ElementCache newElementCache() @@ -104,8 +101,13 @@ protected AppsMenu.ElementCache newElementCache() protected class ElementCache extends Component.ElementCache { - public final WebElement rootElement = Locator.byClass("product-navigation-menu").findWhenNeeded(getDriver()); - public final WebElement toggle = Locator.byClass("navbar-menu-button").findWhenNeeded(rootElement); + public final WebElement rootElement = rootLocator.findWhenNeeded(getDriver()); + + private final Locator _toggleLocator = Locator.XPathLocator.union( + Locator.byClass("navbar-menu-button"), // Bio/FM/SM + Locator.byClass("dropdown-toggle") // LKS + ); + public final WebElement toggle = _toggleLocator.findWhenNeeded(rootElement); public Optional getList() { @@ -113,10 +115,12 @@ public Optional getList() } } - public static class AppsMenuFinder extends WebDriverComponent.WebDriverComponentFinder { - private Locator _locator = Locator.byClass("product-navigation-menu"); + private final Locator _locator = Locator.XPathLocator.union( + Locator.byClass("product-navigation-menu"), // Bio/FM/SM + Locator.id("headerProductDropdown") // LKS + ); public AppsMenuFinder(WebDriver driver) { @@ -126,7 +130,7 @@ public AppsMenuFinder(WebDriver driver) @Override protected Locator locator() { - return _locator; + return AppsMenu.rootLocator; } @Override From 5cb1718dd1e923480e248ccc64b033b1120f819e Mon Sep 17 00:00:00 2001 From: alanv Date: Tue, 13 Feb 2024 13:29:23 -0600 Subject: [PATCH 3/5] Remove unused import --- src/org/labkey/test/components/ui/navigation/apps/AppsMenu.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/org/labkey/test/components/ui/navigation/apps/AppsMenu.java b/src/org/labkey/test/components/ui/navigation/apps/AppsMenu.java index 4d9520f753..44b53061fa 100644 --- a/src/org/labkey/test/components/ui/navigation/apps/AppsMenu.java +++ b/src/org/labkey/test/components/ui/navigation/apps/AppsMenu.java @@ -4,7 +4,6 @@ import org.labkey.test.WebDriverWrapper; import org.labkey.test.components.Component; import org.labkey.test.components.WebDriverComponent; -import org.labkey.test.components.react.BaseBootstrapMenu; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; From 9f1fe1c516d7b4188425af95a19b9a23dd115759 Mon Sep 17 00:00:00 2001 From: alanv Date: Tue, 13 Feb 2024 13:30:44 -0600 Subject: [PATCH 4/5] ProductMenu: Update to account for new DOM --- .../components/ui/navigation/ProductMenu.java | 68 ++++++++++++------- 1 file changed, 45 insertions(+), 23 deletions(-) diff --git a/src/org/labkey/test/components/ui/navigation/ProductMenu.java b/src/org/labkey/test/components/ui/navigation/ProductMenu.java index e5d0599ebe..f85e1c3a62 100644 --- a/src/org/labkey/test/components/ui/navigation/ProductMenu.java +++ b/src/org/labkey/test/components/ui/navigation/ProductMenu.java @@ -6,8 +6,9 @@ import org.labkey.test.BootstrapLocators; import org.labkey.test.Locator; -import org.labkey.test.components.react.BaseBootstrapMenu; -import org.labkey.test.components.react.MultiMenu; +import org.labkey.test.WebDriverWrapper; +import org.labkey.test.components.Component; +import org.labkey.test.components.WebDriverComponent; import org.labkey.test.util.TestLogger; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; @@ -19,23 +20,37 @@ import java.util.Map; import java.util.stream.Collectors; -public class ProductMenu extends BaseBootstrapMenu +public class ProductMenu extends WebDriverComponent { + private final WebElement _componentElement; + private final WebDriver _driver; protected ProductMenu(WebElement element, WebDriver driver) { - super(element, driver); + _componentElement = element; + _driver = driver; } public static SimpleWebDriverComponentFinder finder(WebDriver driver) { - return new MultiMenu.MultiMenuFinder(driver).withButtonId("product-menu").wrap(ProductMenu::new); + return new SimpleWebDriverComponentFinder<>(driver, rootLocator, ProductMenu::new); } @Override + protected WebDriver getDriver() + { + return _driver; + } + + @Override + public WebElement getComponentElement() + { + return _componentElement; + } + protected boolean isExpanded() { - boolean ariaExpanded = super.isExpanded(); + boolean ariaExpanded = "true".equals(elementCache().toggle.getAttribute("aria-expanded")); boolean menuContentDisplayed = elementCache().menuContent.isDisplayed(); TestLogger.debug(String.format("Product menu expansion state: aria-expanded is %b, menuContentDisplayed is %b.", ariaExpanded, menuContentDisplayed)); @@ -44,6 +59,23 @@ protected boolean isExpanded() ExpectedConditions.invisibilityOfAllElements(BootstrapLocators.loadingSpinner.findElements(this)).apply(getDriver()); } + public void expand() + { + if (!isExpanded()) + { + elementCache().toggle.click(); + WebDriverWrapper.waitFor(this::isExpanded, "AppsMenu did not expand as expected", WebDriverWrapper.WAIT_FOR_JAVASCRIPT); + } + } + + public void collapse() + { + if (isExpanded()) + { + elementCache().toggle.click(); + } + } + public List getMenuSectionHeaders() { expand(); @@ -138,38 +170,28 @@ public int getAdministrationIconCount() public String getButtonTitle() { - WebElement buttonTitle = Locator.tagWithId("button", "product-menu") - .child(Locator.tagWithClass("div", "title")).findElement(this); + WebElement buttonTitle = elementCache().toggle.findElement(Locator.byClass("title")); return buttonTitle.getText(); } public String getButtonSubtitle() { - WebElement buttonSubtitle = Locator.tagWithId("button", "product-menu") - .child(Locator.tagWithClass("div", "subtitle")).findElement(this); + WebElement buttonSubtitle = elementCache().toggle.findElement(Locator.byClass("subtitle")); return buttonSubtitle.getText(); } - @Override - protected Locator getToggleLocator() - { - return Locator.tagWithId("button", "product-menu"); - } - - @Override - protected ElementCache elementCache() - { - return (ElementCache) super.elementCache(); - } - @Override protected ElementCache newElementCache() { return new ElementCache(); } - protected class ElementCache extends BaseBootstrapMenu.ElementCache + static Locator rootLocator = Locator.byClass("product-menu"); + + protected class ElementCache extends Component.ElementCache { + private final WebElement rootElement = rootLocator.findElement(getDriver()); + private final WebElement toggle = Locator.byClass("product-menu-button").findElement(rootElement); private final WebElement menuContent = Locator.tagWithClass("div", "product-menu-content").refindWhenNeeded(this); private final WebElement sectionContent = Locator.tagWithClass("div", "sections-content").refindWhenNeeded(menuContent); From b9d4aa85398273b6c06da076ee0f6b0352ff86c2 Mon Sep 17 00:00:00 2001 From: alanv Date: Tue, 13 Feb 2024 16:32:13 -0600 Subject: [PATCH 5/5] ServerNotificationMenu: Fix to account for new DOM --- .../test/components/ui/navigation/NavBar.java | 3 +- .../notifications/ServerNotificationMenu.java | 80 +++++++++++++------ 2 files changed, 58 insertions(+), 25 deletions(-) diff --git a/src/org/labkey/test/components/ui/navigation/NavBar.java b/src/org/labkey/test/components/ui/navigation/NavBar.java index 1e3b54bde1..6284e5a5e3 100644 --- a/src/org/labkey/test/components/ui/navigation/NavBar.java +++ b/src/org/labkey/test/components/ui/navigation/NavBar.java @@ -86,7 +86,7 @@ public String getUserAvatarSource() */ public ServerNotificationMenu getNotificationMenu() { - return ServerNotificationMenu.finder(getDriver()).find(this); + return elementCache().notificationsMenu; } public ProductMenu getProductMenu() @@ -121,5 +121,6 @@ protected abstract class ElementCache extends Component.ElementCac public Input searchBox = Input.Input(Locator.tagWithClass("input", "navbar__search-input"), getDriver()).findWhenNeeded(this); public MultiMenu searchMenu = new MultiMenu.MultiMenuFinder(getDriver()).withButtonClass("navbar__find-and-search-button").findWhenNeeded(this); public final ProductMenu productMenu = ProductMenu.finder(getDriver()).timeout(1000).findWhenNeeded(this); + public final ServerNotificationMenu notificationsMenu = ServerNotificationMenu.finder(getDriver()).timeout(1000).findWhenNeeded(this); } } diff --git a/src/org/labkey/test/components/ui/notifications/ServerNotificationMenu.java b/src/org/labkey/test/components/ui/notifications/ServerNotificationMenu.java index 9ebe751e64..6821d07e45 100644 --- a/src/org/labkey/test/components/ui/notifications/ServerNotificationMenu.java +++ b/src/org/labkey/test/components/ui/notifications/ServerNotificationMenu.java @@ -2,8 +2,8 @@ import org.labkey.test.Locator; import org.labkey.test.WebDriverWrapper; -import org.labkey.test.components.react.BaseBootstrapMenu; -import org.labkey.test.components.react.MultiMenu; +import org.labkey.test.components.Component; +import org.labkey.test.components.WebDriverComponent; import org.labkey.test.components.ui.pipeline.ImportsPage; import org.openqa.selenium.StaleElementReferenceException; import org.openqa.selenium.WebDriver; @@ -13,17 +13,32 @@ /** * This covers a couple of components under component/notifications. Mostly ServerNotifications.tsx and ServerActivityList.tsx */ -public class ServerNotificationMenu extends BaseBootstrapMenu +public class ServerNotificationMenu extends WebDriverComponent { + private final WebElement _componentElement; + private final WebDriver _driver; protected ServerNotificationMenu(WebElement element, WebDriver driver) { - super(element, driver); + _componentElement = element; + _driver = driver; + } + + @Override + protected WebDriver getDriver() + { + return _driver; + } + + @Override + public WebElement getComponentElement() + { + return _componentElement; } public static SimpleWebDriverComponentFinder finder(WebDriver driver) { - return new MultiMenu.MultiMenuFinder(driver).withButtonId("server-notifications-button").wrap(ServerNotificationMenu::new); + return new SimpleWebDriverComponentFinder<>(driver, rootLocator, ServerNotificationMenu::new); } /** @@ -105,6 +120,31 @@ public boolean isMarkAllVisible() return elementCache().markAll().isDisplayed(); } + protected boolean isExpanded() + { + boolean ariaExpanded = "true".equals(elementCache().toggle.getAttribute("aria-expanded")); + boolean menuContentDisplayed = elementCache().menuContent.isDisplayed(); + + return ariaExpanded && menuContentDisplayed; + } + + public void expand() + { + if (!isExpanded()) + { + elementCache().toggle.click(); + WebDriverWrapper.waitFor(this::isExpanded, "AppsMenu did not expand as expected", WebDriverWrapper.WAIT_FOR_JAVASCRIPT); + } + } + + public void collapse() + { + if (isExpanded()) + { + elementCache().toggle.click(); + } + } + /** * Click the 'Mark all as read' link. This will cause the list to refresh, any references you have to a * {@link ServerNotificationItem} will need to be reacquired. @@ -136,11 +176,11 @@ private WebElement waitForNotificationList() // Wait for the listing container to show up. The listing container is in the open menu, scope the search to that. Locator notificationsContainerLocator = Locator.tagWithClass("div", "server-notifications-listing-container"); - WebDriverWrapper.waitFor(()-> notificationsContainerLocator.refindWhenNeeded(elementCache().findOpenMenu()).isDisplayed(), + WebDriverWrapper.waitFor(()-> notificationsContainerLocator.refindWhenNeeded(elementCache().menuContent).isDisplayed(), "List container did not render.", 500); // Find again (lambda requires a final reference to the component). - WebElement listContainer = notificationsContainerLocator.refindWhenNeeded(elementCache().findOpenMenu()); + WebElement listContainer = notificationsContainerLocator.refindWhenNeeded(elementCache().menuContent); // It may be a moment before any notifications show up. WebDriverWrapper.waitFor(()-> Locator.tagWithClass("ul", "server-notifications-listing") @@ -158,7 +198,7 @@ private WebElement waitForNotificationList() // Find the container again, don't return listContainer WebElement previously found. If the list was slow to // update with the most recent notification the old reference will be stale. - return notificationsContainerLocator.waitForElement(elementCache().findOpenMenu(), 1_000); + return notificationsContainerLocator.waitForElement(elementCache().menuContent, 1_000); } /** @@ -208,26 +248,18 @@ public String getNoNotificationsMessage() } @Override - protected Locator getToggleLocator() + protected ServerNotificationMenu.ElementCache newElementCache() { - return Locator.tagWithId("button", "server-notifications-button"); + return new ElementCache(); } - @Override - protected ElementCache elementCache() - { - return (ElementCache) super.elementCache(); - } + public static final Locator rootLocator = Locator.byClass("server-notifications"); - @Override - protected ElementCache newElementCache() + protected class ElementCache extends Component.ElementCache { - return new ElementCache(); - } + public final WebElement menuContent = Locator.byClass("navbar-menu__content").refindWhenNeeded(this); - protected class ElementCache extends BaseBootstrapMenu.ElementCache - { - public final Locator notificationList = Locator.tagWithClass("ul", "server-notifications-listing"); + public final WebElement toggle = Locator.byClass("navbar-menu-button").findWhenNeeded(this); public final WebElement statusIcon() { @@ -236,14 +268,14 @@ public final WebElement statusIcon() public final WebElement noNotificationsElement() { - return Locator.tagWithClass("div", "server-notifications-footer").refindWhenNeeded(elementCache().findOpenMenu()); + return Locator.tagWithClass("div", "server-notifications-footer").refindWhenNeeded(elementCache().menuContent); } public final WebElement markAll() { return Locator.tagWithClass("h3", "navbar-menu-header") .child(Locator.tagWithClass("div", "server-notifications-link")) - .refindWhenNeeded(elementCache().findOpenMenu()); + .refindWhenNeeded(elementCache().menuContent); } public final WebElement viewAllLink = Locator.tagWithText("div", "View all activity").refindWhenNeeded(this);