如果xpath返回2 WebElements

时间:2017-03-22 15:23:41

标签: 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();

    }

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

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

4 个答案:

答案 0 :(得分:5)

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

BITMAPV5HEADER bi;
bi.bV5Size = sizeof(BITMAPV5HEADER);
bi.bV5Width = width;
bi.bV5Height = -height;
bi.bV5Planes = 1;
bi.bV5BitCount = 32;
bi.bV5Compression = BI_RGB;
bi.bV5SizeImage = 0;
bi.bV5XPelsPerMeter = 0;
bi.bV5YPelsPerMeter = 0;
bi.bV5ClrUsed = 0;
bi.bV5ClrImportant = 0;
bi.bV5AlphaMask = 0x000000FF;
bi.bV5RedMask = 0x0000FF00;
bi.bV5GreenMask = 0x00FF0000;
bi.bV5BlueMask = 0xFF000000;
bi.bV5CSType = LCS_sRGB;
bi.bV5Endpoints = CIEXYZTRIPLE();
bi.bV5GammaRed = 0;
bi.bV5GammaGreen = 0;
bi.bV5GammaBlue = 0;
bi.bV5Intent = LCS_GM_IMAGES;
bi.bV5ProfileData = 0;
bi.bV5ProfileSize = 0;
bi.bV5Reserved = 0;

*hBmp = CreateDIBitmap(hdc, (BITMAPINFOHEADER *) &bi, CBM_INIT, data, (BITMAPINFO *)&bi, DIB_RGB_COLORS);

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

@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;
        }
    }
}

答案 1 :(得分:1)

将@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
}

然后在你的PageObject:

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

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

}

答案 2 :(得分:0)

据我所知Java,您可以将多个条件与ExpectedConditions.and()结合使用,如下所示:

WebDriverWait wait = new WebDriverWait(driver, 15);
wait.until(
      ExpectedConditions.and(
           ExpectedConditions.visibilityOf(driver.findElement(By.xpath("(//selector-dropdown/p)[1]"))),
           ExpectedConditions.visibilityOf(driver.findElement(By.xpath("(//selector-dropdown/p)[2]" )))
      )
  );

或者只是尝试

ExpectedConditions.visibilityOfAllElementsLocatedBy(By.xpath("//selector-dropdown/p"));

等待所有与指定选择器匹配的元素变为可见

答案 3 :(得分:-1)

这是我提出的方法,也许有人可以使用完整的解决方案。这将A.等待列表中的第一个元素可见,然后B.将可见的元素指定为单个元素。等待很短,因为它不应该花费超过一秒的时间来确定哪个元素是可见的。

    protected WebElement getVisibleElement(List<WebElement> elements) {
    WebDriverWait wait = new WebDriverWait(driver, 1);
    WebElement rE = null;
    int elementsSize = elements.size();
    for (int i = 0; i < elementsSize; i++) {
        System.out.println("test" + i);
        try {
            wait.until(ExpectedConditions.or(ExpectedConditions.visibilityOf(elements.get(i))));
            break;
        } catch (Exception e) {
            //handle exception however you like
        }
    }
    for (WebElement element : elements) {
        if (element.isDisplayed()) {
            System.out.println("found and assigning to rE");
            rE = element;
            break;
        }
    }
    return rE;
}