Selenium - select 来自 angularjs 组件的输入

Selenium - select an input from an angularjs component

<md-datepicker ng-model="mc.date.from" required="" md-val="">
  <span class="input-group date" style="width:144px">
    <input size="16" type="text"
           class="form-control"
           autocomplete="off">
    <span class="input-group-btn">
    <button class="btn btn-default" tabindex="-1" >
      <i class="glyphicon glyphicon-calendar"></i>
    </button>
    </span>
  </span>
</md-datepicker>

我有一个 AngularJs 组件,其中包含类型 textinput。我已经使用以下代码输入 date。当我 运行 无头测试时,它大多数时候都失败了。

WebElement fromDate = driver.findElement(
    By.tagName("md-datepicker"))
    .findElement(By.tagName("input"));

if (fromDate.getAttribute("value").length() > 0) {
    fromDate.clear();
}
fromDate.sendKeys(startDate);

我填的datepicker之前还有几个inputs,但是当测试到datepciker的时候,因为找不到,所以失败了。

如何解决这个问题?

更新

我在上面的代码之前就用过这个方法。

public static void waitUntilVisible(By locator) {
    final long startTime = System.currentTimeMillis();
    final Duration duration = Duration.ofSeconds(2);
    Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
        .pollingEvery(duration)
        .ignoring(StaleElementReferenceException.class);

    while ((System.currentTimeMillis() - startTime) < 91000) {
        try {
            wait.until(ExpectedConditions.presenceOfElementLocated(locator));
            break;
        } catch (StaleElementReferenceException e) {
            log.info("", e);
        }
    }
}

由于 <input> 元素是 Angular 元素,因此您必须引入 WebDriverWait 才能使所需的 元素可点击,您可以使用以下任一解决方案:

  • cssSelector:

    WebElement elem = new WebDriverWait(driver, 20).until(ExpectedConditions.elementToBeClickable(By.cssSelector("md-datepicker[ng-model$='from']>span.input-group.date>input.form-control")));
    elem.click();
    elem.clear();
    elem.sendKeys(startDate);
    
  • xpath:

    WebElement elem = new WebDriverWait(driver, 20).until(ExpectedConditions.elementToBeClickable(By.xpath("//md-datepicker[contains(@ng-model,'from')]/span[@class='input-group date']/input[@class='form-control']")));
    elem.click();
    elem.clear();
    elem.sendKeys(startDate);
    

更新

根据你的问题更新函数 waitUntilVisible() 对我来说看起来像是一个纯粹的开销,你正在为 presenceOfElementLocated() 实施 FluentWait 忽略 StaleElementReferenceException,这可以通过定制的 WebDriverWaitExpectedConditions 作为 [=17 轻松实现=].

您可以尝试等待元素的可见性:

WebElement fromDate =
                new WebDriverWait(driver, 10)
                .until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("md-datepicker input")));

您可以尝试使用 cssSelector,不建议使用 xpath 执行 headless

WebElement fromDate = driver.findElement(
    By.cssSelector(".input-group.date"))
    .findElement(By.cssSelector(".form-control"));
if (fromDate.getAttribute("value").length() > 0) {
    fromDate.clear();
}
fromDate.sendKeys(startDate);

我只能通过尝试捕获 StaleElementReferenceException.

的 catch 块来解决这个问题
   WebElement input;
    try {
        input = driver.findElement(
            By.tagName("md-datepicker"))
            .findElement(By.tagName("input"));

    } catch(StaleElementReferenceException e) {
        input = driver.findElement(By.xpath("//md-datepicker/span/input"));
    }

    if (input.getAttribute("value").length() > 0) {
        input.clear();
    }

正如我在问题中所述,我使用 waitUntilVisible 方法来等待输入的存在。


我在 2018 年 10 月 29 日问过这个问题。当时我使用的是 selenium 版本 3.14.0。但是这种方法选择输入也不应该使用 selenium 版本 3.141.0.


2021 年 9 月 30 日更新

等到元素可点击。

    public WebElement getElementWhenClickable(By selector) {
        return new WebDriverWait(driver, 60)
                .ignoring(StaleElementReferenceException.class)
                .until(ExpectedConditions.elementToBeClickable(selector));
    }

找到它最近的唯一父级。

WebElement parent = getElementWhenClickable(By.cssSelector("#parent"))

找到输入

WebElement input = parent.findElement(By.cssSelector("md-datepicker[ng-model=\"mc.date.from\"] input"))