Search code examples
javaseleniumwebdriverselenium-webdriverfunctional-testing

Selenium Element Location


Is there an easy way to find a child element from another element (both of these items have been located using a PageFactory)? We have a set of containers which hold many modules, and I'd like to ensure that they are displaying in their proper locations.

The API only seems to have the following method:

webElement.findElement(s).(By by);

Is there an easy way to do the following:

webElement.findElement(s)(WebElement webElement);

or even better:

webElement.contains(WebElement webElement);

Solution

  • I finally got what you need. My best solution would be something in the way of:

    public static void assertContains(WebElement outerElem, WebElement innerElem) {
        // get borders of outer element
        Point outerLoc = outerElem.getLocation();
        Dimension outerDim = outerElem.getSize();
        int outerLeftX = outerLoc.getX();
        int outerRightX = outerLeftX + outerDim.getWidth();
        int outerTopY = outerLoc.getY();
        int outerBottomY = outerTopY + outerDim.getHeight();
    
        // get borders of inner element
        Point innerLoc = innerElem.getLocation();
        Dimension innerDim = innerElem.getSize();
        int innerLeftX = innerLoc.getX();
        int innerRightX = innerLeftX + innerDim.getWidth();
        int innerTopY = innerLoc.getY();
        int innerBottomY = innerTopY + innerDim.getHeight();
    
        // assures the inner borders don't cross the outer borders
        final String errorMsg = "ughh, some error message";
        final boolean contains = (outerLeftX <= innerLeftX)
                && (innerRightX <= outerRightX)
                && (outerTopY <= innerTopY)
                && (innerBottomY <= outerBottomY);
        assertTrue(errorMsg, contains);
    }
    

    ...works only if none of those containers overlap. If they do, I'd try some dark and wild magic with innerElem.getTag() and getText() and test whether the outer text contains the inner element. One way of doing it:

    public static void assertContains(WebElement outer, WebElement inner) {
        // e.g. //div[text()='some text in inner element']
        final String findInner = ".//" + inner.getTagName() + "[text()='" + inner.getText() + "']";
        try {
            outerElem.findElement(By.xpath(findInner));
        } catch (NoSuchElementException ignored) {
            fail("Some horrible message! We are all doomed!");
        }
        // passed
    }
    

    ...or something similar. It is possible that normalize-space() or contains() (or both) will be needed due to tags in tags in tags in...

    And, of course, this is still guessing. The first method may have false positives and negatives (but I like it more given my needs), the second should only have false positives. You can combine them or invent something yourself (e.g. using Reflection as you have already stated).

    Or file a bug.