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/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); 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..44b53061fa 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,66 @@ 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 +70,7 @@ protected AppsMenu(WebElement element, WebDriver driver) public ProductsNavContainer showProductsPanel() { expand(); + return new ProductsNavContainer.ProductNavContainerFinder(getDriver()).withTitle("Applications") .waitFor(); } @@ -43,26 +88,38 @@ 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 Locator getToggleLocator() + protected AppsMenu.ElementCache newElementCache() { - return BootstrapMenu.Locators.dropdownToggle(); + return new AppsMenu.ElementCache(); } + protected class ElementCache extends Component.ElementCache + { + 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() + { + 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 final Locator _locator = Locator.XPathLocator.union( + Locator.byClass("product-navigation-menu"), // Bio/FM/SM + Locator.id("headerProductDropdown") // LKS + ); public AppsMenuFinder(WebDriver driver) { @@ -72,7 +129,7 @@ public AppsMenuFinder(WebDriver driver) @Override protected Locator locator() { - return _locator; + return AppsMenu.rootLocator; } @Override 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);