如果xpath返回2个WebElements,Selenium是否只能单击可见元素

dsi*_*ler 1 java selenium xpath selenium-webdriver

我有一个响应式设计,我需要与之交互的很多项目都有2个WebElements.一个用于桌面,一个用于移动,我正在尝试使用PageFactory.以下是我现在要识别并与元素交互的内容.

//this returns 2 webelements, one for desktop and one for mobile
    @FindBy(xpath = "//selector-dropdown/p")
    private WebElement dropdown;

    public void ClickDropdown() throws InterruptedException {       
        WebDriverWait wait = new WebDriverWait(driver, 15);
        wait.until(ExpectedConditions.visibilityOf(dropdown)).click();

    }
Run Code Online (Sandbox Code Playgroud)

我的印象是ExpectedConditions.visibilityOf(WebElement)会发现第一个元素可见.现在,当我在桌面上打开应用程序时,它会找到该元素(桌面是DOM中的第一个).但是在移动设备上,它等待可见性超时,因为它等待第一个变得可见.

我的另一种方法是使用@FindBy来声明每个元素两次,然后创建一个if语句来决定采用哪个路径.这项额外的工作是否能使其发挥作用?

SiK*_*ing 5

你的假设"... ExpectedConditions.visibilityOf(WebElement)会发现第一个元素可见." 是错的!您需要将WebElement声明为List,找到所有这些,然后选择一个可见的.以下是我过去成功使用的示例:

@FindBy(xpath = "//input[@ng-model='loginData.username']")
private List<WebElement> txtUsername;

public String getUsername() {
    driverWait.until(CustomExpectedConditions.presenceOfAllElements(txtUsername));
    for (WebElement oneUsername : txtUsername) {
        if (oneUsername.isDisplayed())
            return oneUsername.getAttribute("value");
    }
    return null;
}

public void setUsername(String username) {
    driverWait.until(CustomExpectedConditions.presenceOfAllElements(txtUsername));
    for (WebElement oneUsername : txtUsername) {
        if (oneUsername.isDisplayed()) {
            oneUsername.clear();
            oneUsername.sendKeys(username);
            break;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

根据其他地方的讨论,这里是CustomExpectedConditions:

public class CustomExpectedConditions {
    /**
     * Based on {@link ExpectedConditions#presenceOfAllElementsLocatedBy(org.openqa.selenium.By)}.
     * 
     * @param elements
     * @return
     */
    public static ExpectedCondition<List<WebElement>> presenceOfAllElements(
            final List<WebElement> elements) {
        return new ExpectedCondition<List<WebElement>>() {

            @Override
            public List<WebElement> apply(WebDriver driver) {
                // List<WebElement> elements = findElements(locator, driver);
                return elements.size() > 0 ? elements : null;
            }
        };
    }
}
Run Code Online (Sandbox Code Playgroud)


mrf*_*ter 5

将@Andersons 和@SiKing 的答案组合成一个可以在任何地方使用的解决方案,您可以PageObjects在基类中为所有人提供一个方法,您可能已经拥有:

protected WebElement getVisibleElement(List<WebElement> elements)
{
    //Need a guard clause here to ensure there are exactly two elements,
    //Or make the wait check for all elements more safely. Either way,
    //consider changing the method name to be clear about expectations

    WebDriverWait wait = new WebDriverWait(driver, 15);
    wait.until(
        ExpectedConditions.or(
             //This should be done more safely, unless already guarded to expect 2 elements
             ExpectedConditions.visibilityOf(elements.get(0))),
             ExpectedConditions.visibilityOf(elements.get(1)))
        )
    );

    for (WebElement element : elements) {
        if (element.isDisplayed())
        {
            return element;
        }
    }
    //Throw element not visible exception or something
}
Run Code Online (Sandbox Code Playgroud)

然后在您的 PageObject 中:

@FindBy(xpath = "//selector-dropdown/p")
private List<WebElement> dropdown;

public void ClickDropdown() throws InterruptedException {       
    getVisibleElement(dropdown)).click();

}
Run Code Online (Sandbox Code Playgroud)