Selenium - 从 angularjs 组件中选择一个输入
Posted
技术标签:
【中文标题】Selenium - 从 angularjs 组件中选择一个输入【英文标题】:Selenium - select an input from an angularjs component 【发布时间】:2019-04-02 07:24:13 【问题描述】:<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 组件,其中包含 input
类型的 text
。我使用以下代码输入了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);
【问题讨论】:
【参考方案1】:由于<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,这可能是通过定制的 WebDriverWait 轻松实现,ExpectedConditions 为 elementToBeClickable()
。
【讨论】:
感谢您的回答。如果我省略span.input-group.date
怎么办?每当我有一个 angularjs 元素时,我是否必须等待?
WebDriverWait 对 Angular 有什么特别的影响,我相信它只有助于同步,直到元素可点击....我们是否必须做一些特别的事情来处理 Angular 元素?
@mahan - Angular 对 Promise 起作用,如果 Promise 未解决,元素可能无法加载,因此 Angular 元素需要良好的同步,就像我们对 ajax 元素所做的一样。但我不确定 webdriver 等待对角度元素有多大帮助,如果您的应用程序中有更多角度元素,建议使用 ng-webdriver
@mahan 正如你提到的 ...在我填写的日期选择器之前还有一些其他输入... 所以为了完全匹配 Ancestor 节点即<md-datepicker>
、Descendent 节点即<span>
和下一个Descendent 节点即<input>
在构造Locator Strategies 时被考虑。但是,如果省略 span.input-group.date
仍然唯一标识所需元素,这将是最佳方式。
@AmitJain WebDriverWait 是处理Angular 元素的唯一 方式,无论您等待元素存在/可见性/交互性,它都有助于同步。 Promise 是通过 OP 正在使用的 Selenium 的 Java 客户端 在内部处理的,因此考虑到 Promise 和 ng-webdriver 是 超出范围 i> 这个问题。【参考方案2】:
您可以尝试等待元素的可见性:
WebElement fromDate =
new WebDriverWait(driver, 10)
.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("md-datepicker input")));
【讨论】:
【参考方案3】:您可以尝试使用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);
【讨论】:
我有多个输入。因此,我使用md-datepicker
我在许多日期选择器上工作过,您会发现针对不同输入或日期文本分类的 css 存在差异,因此您可以区分它们我相信 selenium 不适用于任何 ng 元素,它无法识别它们稳定性。
我同意你的看法。但输入的父母没有唯一标识符。【参考方案4】:
我只能通过尝试捕获 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
。但是这种方法选择输入也不应该使用硒版本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"))
【讨论】:
以上是关于Selenium - 从 angularjs 组件中选择一个输入的主要内容,如果未能解决你的问题,请参考以下文章