bagelmakers
bagelmakers

Reputation: 409

Selenium: searching children of a By locator in Java

I have an enum list of By locators for WebElements on a page. I want to be able to select a specific option of a select box using a combination of the enum as well as additional information of the value of the option I wish to select. Is there any way to do this? I notice that the By class also has the method findElement(searchContext). Could I use this as something along the lines of:

public enum Dictionary {

    TYPE                        (By.id("vehType")),
    PROVINCE                    (By.id("provId")),
    TERRITORY                   (By.id("territoryId")),
    STAT_CODE                   (By.id("statCodeId")),
    CLASS                       (By.id("class1Id"));

    private final By locator;

    private DetailVehicleDictionary (By value) {
        this.locator = value;
    }

    public By getLocation() {
        return this.locator;
    }
}

And then if CLASS is a select box with HTML of:

<select id="class1Id" name="select_box">
    <option value="1"/>
    <option value="2"/>
    <option value="3"/>
</select>

Can I do something along the lines of:

WebElement specificValue = driver.findElement(Dictionary.CLASS.getLocation().findElement(By.cssSelector("option[value=2]"));

I need to have access to the actual element so that I can wait for the value to be present in the DOM. I plan on implementing this in a wait command such as:

wait.until(ExpectedConditions.presenceOfElementLocated(specificValue));

Upvotes: 3

Views: 2085

Answers (2)

Chris R
Chris R

Reputation: 2564

I was trying to do something similar to you - use a WebDriverWait with an ExpectedConditions so that I could wait for the element to be there and located it as a child element relative to an existing one.

Additional methods are now available in Selenium to handle this:

static ExpectedCondition<WebElement> presenceOfNestedElementLocatedBy(By locator, By sub_locator) An expectation for checking child WebElement as a part of parent element to present

static ExpectedCondition<WebElement> presenceOfNestedElementLocatedBy(WebElement element, By sub_locator) An expectation for checking child WebElement as a part of parent element to be present

static ExpectedCondition<java.util.List<WebElement>> presenceOfNestedElementsLocatedBy(By locator, By sub_locator) An expectation for checking child WebElement as a part of parent element to present

So for your case you could do the following:

     wait.until(ExpectedConditions.presenceOfNestedElementLocatedBy(Dictionary.CLASS.getLocation(), By.cssSelector("option[value=2]")));

See here for the Javadocs: https://seleniumhq.github.io/selenium/docs/api/java/org/openqa/selenium/support/ui/ExpectedConditions.html#presenceOfNestedElementLocatedBy-org.openqa.selenium.By-org.openqa.selenium.By-

Upvotes: 1

alecxe
alecxe

Reputation: 473873

Selenium has a special mechanism to handle "select/option" cases:

import org.openqa.selenium.support.ui.Select;  // this is how to import it

WebElement select = driver.findElement(Dictionary.CLASS.getLocation());
Select dropDown = new Select(select); 
dropDown.selectByValue("1");

Answer to a follow-up question: use an Explicit Wait:

WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement select = wait.until(ExpectedConditions.presenceOfElement(Dictionary.CLASS.getLocation()));

In case of waiting for an option to load inside a select, I am afraid, you would need to make a custom ExpectedCondition (not tested):

public static ExpectedCondition<Boolean> selectContainsOption(
    final WebElement select, final By locator) {

    return new ExpectedCondition<Boolean>() {
        @Override
        public Boolean apply(WebDriver driver) {
            try {
                return elementIfVisible(select.findElement(locator));
            } catch (StaleElementReferenceException e) {
                return null;
            }
        }
    };
}

Usage:

WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement select = wait.until(ExpectedConditions.presenceOfElement(Dictionary.CLASS.getLocation()));
WebElement option = wait.until(selectContainsOption(select, By.cssSelector('.//option[@value = "1"]')));   

Upvotes: 3

Related Questions