From 39be1aedef71006606267c70aae4a081e7fd7312 Mon Sep 17 00:00:00 2001 From: labkey-tchad Date: Fri, 17 Apr 2026 14:03:13 -0700 Subject: [PATCH 1/2] Update tests for new experiment graph --- src/org/labkey/test/Locator.java | 5 -- .../labkey/test/pipeline/ExperimentGraph.java | 63 ++++++++++++------- 2 files changed, 39 insertions(+), 29 deletions(-) diff --git a/src/org/labkey/test/Locator.java b/src/org/labkey/test/Locator.java index 17bd5dc435..57503a7795 100644 --- a/src/org/labkey/test/Locator.java +++ b/src/org/labkey/test/Locator.java @@ -901,11 +901,6 @@ public static XPathLocator radioButton() return tag("input").withAttribute("type", "radio"); } - public static XPathLocator imageMapLinkByTitle(String imageMapName, String title) - { - return tag("map").withAttribute("name", imageMapName).child(tag("area").withAttribute("title", title)); - } - public static XPathLocator lookupLink(String schemaName, String queryName, String pkName) { String linkText = schemaName + "." + queryName + "." + (null != pkName ? pkName : ""); diff --git a/src/org/labkey/test/pipeline/ExperimentGraph.java b/src/org/labkey/test/pipeline/ExperimentGraph.java index ef9efaf46a..e1266ecea1 100644 --- a/src/org/labkey/test/pipeline/ExperimentGraph.java +++ b/src/org/labkey/test/pipeline/ExperimentGraph.java @@ -15,28 +15,43 @@ */ package org.labkey.test.pipeline; -import org.apache.commons.lang3.StringUtils; +import org.labkey.test.BaseWebDriverTest; import org.labkey.test.Locator; +import org.labkey.test.components.WebDriverComponent; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; -import static org.junit.Assert.*; +import static org.junit.Assert.assertTrue; /** * ExperimentGraph */ -public class ExperimentGraph +public class ExperimentGraph extends WebDriverComponent { - private static final String MAP_NAME = "graphmap"; - - private final PipelineWebTestBase _test; + private final WebElement _el; + private final WebDriver _driver; - public ExperimentGraph(PipelineWebTestBase test) + public ExperimentGraph(BaseWebDriverTest test) { - _test = test; + _driver = test.getDriver(); + _el = Locator.id("graph_root").findElement(test.getDriver()); + } + + @Override + protected WebDriver getDriver() + { + return _driver; + } + + @Override + public WebElement getComponentElement() + { + return _el; } public void clickLink(String link) { - _test.clickAndWait(Locator.imageMapLinkByTitle(MAP_NAME, link)); + getWrapper().clickAndWait(svgLinkByTitle(link)); } public void clickInputLink(String input) @@ -61,7 +76,7 @@ public String getOutputLinkText(String output) public boolean isNodePresent(String link) { - return _test.isElementPresent(Locator.imageMapLinkByTitle(MAP_NAME, link)); + return svgLinkByTitle(link).isDisplayed(); } public boolean isInputPresent(String input) @@ -94,20 +109,14 @@ public void validate(PipelineTestParams tp) String[] names = tp.getExperimentLinks(); for (String name : names) { - if (_test.isTextPresent(name)) - { - assertNodePresent(name); - String baseName = getBaseName(tp); - assertInputPresent(tp.getParametersFile()); - for (String inputExt : tp.getInputExtensions()) - assertInputPresent(baseName + inputExt); - for (String outputExt : tp.getOutputExtensions()) - assertOutputPresent(baseName + outputExt); - return; - } + assertNodePresent(name); + String baseName = getBaseName(tp); + assertInputPresent(tp.getParametersFile()); + for (String inputExt : tp.getInputExtensions()) + assertInputPresent(baseName + inputExt); + for (String outputExt : tp.getOutputExtensions()) + assertOutputPresent(baseName + outputExt); } - - assertTrue("Unable to find experiment links: " + StringUtils.join(names, ", "), false); } private String getBaseName(PipelineTestParams tp) @@ -122,7 +131,7 @@ private String getBaseName(PipelineTestParams tp) { for (String sampleName : sampleNames) { - if (_test.isTextPresent(sampleName)) + if (getWrapper().isTextPresent(sampleName)) return sampleName; } } @@ -130,4 +139,10 @@ private String getBaseName(PipelineTestParams tp) // Probably fail later, but simpler than checking for null return. return "all"; } + + private WebElement svgLinkByTitle(String title) + { + return Locator.css("a").withAttribute("xlink\\:title", title).findWhenNeeded(_el); + } + } From 76c12821a9830a90a2ab6929074c5ca5ee29dd3e Mon Sep 17 00:00:00 2001 From: labkey-tchad Date: Fri, 17 Apr 2026 17:22:36 -0700 Subject: [PATCH 2/2] Fix locator to work with new experiment graph --- .../labkey/test/pipeline/ExperimentGraph.java | 28 ++++++++--------- .../test/selenium/ReclickingWebElement.java | 31 +++++++++---------- .../test/util/selenium/ScrollUtils.java | 14 ++++++++- 3 files changed, 40 insertions(+), 33 deletions(-) diff --git a/src/org/labkey/test/pipeline/ExperimentGraph.java b/src/org/labkey/test/pipeline/ExperimentGraph.java index e1266ecea1..4c98db3a8e 100644 --- a/src/org/labkey/test/pipeline/ExperimentGraph.java +++ b/src/org/labkey/test/pipeline/ExperimentGraph.java @@ -17,16 +17,19 @@ import org.labkey.test.BaseWebDriverTest; import org.labkey.test.Locator; +import org.labkey.test.components.Component; import org.labkey.test.components.WebDriverComponent; +import org.labkey.test.util.selenium.ScrollUtils; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import static org.junit.Assert.assertTrue; +import static org.labkey.test.Locator.xq; /** * ExperimentGraph */ -public class ExperimentGraph extends WebDriverComponent +public class ExperimentGraph extends WebDriverComponent.ElementCache> { private final WebElement _el; private final WebDriver _driver; @@ -34,7 +37,7 @@ public class ExperimentGraph extends WebDriverComponent public ExperimentGraph(BaseWebDriverTest test) { _driver = test.getDriver(); - _el = Locator.id("graph_root").findElement(test.getDriver()); + _el = Locator.id("graph_root").parent().findElement(test.getDriver()); } @Override @@ -51,7 +54,8 @@ public WebElement getComponentElement() public void clickLink(String link) { - getWrapper().clickAndWait(svgLinkByTitle(link)); + ScrollUtils.scrollIntoViewPort(getComponentElement()); + getWrapper().doAndWaitForPageToLoad(() -> getWrapper().actionClick(svgLinkByTitle(link))); } public void clickInputLink(String input) @@ -122,27 +126,21 @@ public void validate(PipelineTestParams tp) private String getBaseName(PipelineTestParams tp) { String[] sampleNames = tp.getSampleNames(); - if (sampleNames.length == 0) + for (String sampleName : sampleNames) { - // AbstractMS2SearchProtocol.getJoinedBaseName() is hard-coded to use "all" - return "all"; - } - else - { - for (String sampleName : sampleNames) - { - if (getWrapper().isTextPresent(sampleName)) - return sampleName; - } + if (getWrapper().isTextPresent(sampleName)) + return sampleName; } + // AbstractMS2SearchProtocol.getJoinedBaseName() is hard-coded to use "all" // Probably fail later, but simpler than checking for null return. return "all"; } private WebElement svgLinkByTitle(String title) { - return Locator.css("a").withAttribute("xlink\\:title", title).findWhenNeeded(_el); + // Funky locator to find element within an SVG + return Locator.xpath(".//*[local-name()='a'][@*[local-name()='title']=" + xq(title) + "]").findWhenNeeded(_el); } } diff --git a/src/org/labkey/test/selenium/ReclickingWebElement.java b/src/org/labkey/test/selenium/ReclickingWebElement.java index 0417cf1c19..4a33152c8e 100644 --- a/src/org/labkey/test/selenium/ReclickingWebElement.java +++ b/src/org/labkey/test/selenium/ReclickingWebElement.java @@ -15,14 +15,13 @@ */ package org.labkey.test.selenium; -import org.apache.commons.lang3.mutable.Mutable; -import org.apache.commons.lang3.mutable.MutableObject; import org.jetbrains.annotations.NotNull; import org.junit.Assert; import org.junit.Test; import org.labkey.test.Locator; import org.labkey.test.WebDriverWrapper; import org.labkey.test.components.core.ProjectMenu; +import org.labkey.test.util.CachingSupplier; import org.labkey.test.util.TestLogger; import org.labkey.test.util.selenium.ScrollUtils; import org.labkey.test.util.selenium.WebDriverUtils; @@ -44,7 +43,8 @@ import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Collectors; + +import static org.apache.commons.lang3.StringUtils.trimToEmpty; public class ReclickingWebElement extends WebElementDecorator { @@ -68,7 +68,7 @@ public void click() { if (getDriver() != null) { - final String shortMessage = ex.getMessage().split("\n")[0]; + final String shortMessage = trimToEmpty(ex.getMessage()).split("\n")[0]; TestLogger.debug("Retry click: " + shortMessage); revealElement(getWrappedElement(), shortMessage); super.click(); @@ -84,7 +84,7 @@ public void click() && getDriver().getClass().isAssignableFrom(FirefoxDriver.class)) { String tagName = getWrappedElement().getTagName(); - List classes = Arrays.asList(getWrappedElement().getAttribute("class").toLowerCase().trim().split("\\s")); + List classes = Arrays.asList(trimToEmpty(getWrappedElement().getAttribute("class")).toLowerCase().split("\\s")); if ("tr".equals(tagName)) { if (!clickRowInFirefox()) @@ -123,7 +123,7 @@ private void actionClick() */ private void clickImageMapArea() { - String shape = getWrappedElement().getAttribute("shape"); + String shape = trimToEmpty(getWrappedElement().getAttribute("shape")); if (shape.equals("default")) { throw new IllegalArgumentException("Refusing to click the 'default' of an image map. Can't guarantee that it won't click a different instead"); @@ -146,13 +146,13 @@ private void clickImageMapArea() /** * Calculate the center of a convex <area> in an image-map. Can handle 'rect', 'circle', and 'poly' shapes * Doc: tag_area - * TODO: Implement this formula for concave polygons [https://en.wikipedia.org/wiki/Centroid#Of_a_polygon] + * Does not handle concave polygons [https://en.wikipedia.org/wiki/Centroid#Of_a_polygon] * @return The center point of the area element relative to the image */ @NotNull private Point getAreaCenter() { - List coords = Arrays.stream(getWrappedElement().getAttribute("coords").split(",")).map(Integer::parseInt).collect(Collectors.toList()); + List coords = Arrays.stream(trimToEmpty(getWrappedElement().getAttribute("coords")).split(",")).map(Integer::parseInt).toList(); int minX = Integer.MAX_VALUE; Integer maxX = 0; int minY = Integer.MAX_VALUE; @@ -223,7 +223,7 @@ private void revealElement(WebElement el, String shortMessage) if (interceptingElements.size() == 1) { //noinspection ResultOfMethodCallIgnored - WebDriverWrapper.waitFor(() -> ExpectedConditions.stalenessOf(interceptingElements.get(0)).apply(getDriver()), 1_000); + WebDriverWrapper.waitFor(() -> ExpectedConditions.stalenessOf(interceptingElements.getFirst()).apply(getDriver()), 1_000); } else if (interceptingElements.size() > 1) { @@ -262,20 +262,17 @@ private static Locator.XPathLocator parseInterceptingElementLoc(String shortMess return interceptingElLoc; } - private Mutable _webDriver = null; + private final CachingSupplier _webDriver = new CachingSupplier<>(() -> WebDriverUtils.extractWrappedDriver(getWrappedElement())); private WebDriver getDriver() { - if (_webDriver == null) - { - _webDriver = new MutableObject<>(WebDriverUtils.extractWrappedDriver(getWrappedElement())); - } - return _webDriver.getValue(); + return _webDriver.get(); } - public static class TempEceptionParser + // Run manually to test parsing of exception message + public static class TempExceptionParserTest { @Test - public void testInterceptinElLoc() + public void testInterceptingElLoc() { final Locator.XPathLocator xPathLocator = parseInterceptingElementLoc("Element is not clickable at point (732,301) because another element " + "
obscures it"); diff --git a/src/org/labkey/test/util/selenium/ScrollUtils.java b/src/org/labkey/test/util/selenium/ScrollUtils.java index e56802ebe0..aeb25868d3 100644 --- a/src/org/labkey/test/util/selenium/ScrollUtils.java +++ b/src/org/labkey/test/util/selenium/ScrollUtils.java @@ -64,13 +64,25 @@ public static boolean scrollUnderFloatingHeader(WebElement targetElement) if (floatingHeaders.stream().anyMatch(headerEl -> rectanglesOverlap(rect, headerEl.getRect()))) { TestLogger.debug("Scrolled under floating headers:\n" + floatingHeaders.stream().map(WebElement::toString).collect(Collectors.joining("\n"))); - ((Locatable) targetElement).getCoordinates().inViewPort(); // 'inViewPort()' will scroll element into view + scrollIntoViewPort(targetElement); return true; } } return false; } + /** + * An alternate method for scrolling an element into view. Tends to get more of the element into view. + * + * @param targetElement the element to scroll into view + * @return the target element + */ + public static WebElement scrollIntoViewPort(WebElement targetElement) + { + ((Locatable) targetElement).getCoordinates().inViewPort(); // 'inViewPort()' will scroll element into view + return targetElement; + } + private static boolean rectanglesOverlap(Rectangle r1, Rectangle r2) { return r1.getX() < r2.getX() + r2.getWidth() && r2.getX() < r1.getX() + r1.getWidth()