如何强制Selenium WebDriver单击当前不可见的元素?


99

我正在将Selenium 2 Java API与FirefoxDriver结合使用。当我填写表格时,复选框会根据表格输入添加到页面中。

我想使用Selenium模拟对这些复选框的单击。该元素在常规浏览器中可见且可用,但是selenium断言该元素不可见。

"Element is not currently visible and so may not be interacted with"

我可以强迫硒忽略元素的不可见状态吗?如何强制Selenium与不可见元素进行交互?


你使用的是什么浏览器?您无法与禁用或不可见的元素进行交互,因为最终用户将无法与其进行交互。如果要我尝试诊断问题,则需要提供测试代码和Page源。
2011年

Answers:


102

Selenium根据以下条件确定元素是否可见(使用DOM检查器确定哪些CSS适用于您的元素,请确保您查看计算的样式):

  • 可见度!=隐藏
  • 显示!=无(还将针对每个父元素进行检查)
  • opacity!= 0(不检查单击元素)
  • 高度和宽度均> 0
  • 对于输入,属性类型!=隐藏

您的元素符合这些条件之一。如果您没有能力更改元素的样式,请按照以下方法用javascript强制执行此操作(由于您使用了Selenium2 API,因此假设使用WebDriver):

((JavascriptExecutor)driver).executeScript("arguments[0].checked = true;", inputElement);

但这不会触发javascript事件,如果您依赖该输入的change事件,那么您也必须触发它(有多种方法,最容易使用该页面上加载的任何javascript库)。

可见性检查的来源-

https://github.com/SeleniumHQ/selenium/blob/master/javascript/atoms/dom.js#L577

定义此的WebDriver规范-

https://dvcs.w3.org/hg/webdriver/raw-file/tip/webdriver-spec.html#widl-WebElement-isDisplayed-boolean


1
您是否有条件列表的来源(或规范链接)?
mjs 2012年

2
只要你能读JavaScript中,方法bot.dom.isShown是什么决定的可视性:code.google.com/p/selenium/source/browse/trunk/javascript/atoms/...
lukeis

这里的inputElement是什么。我运行下面的代码WebElement inputElement = driver.findElement(By.xpath(PASSWORD_PATH)); (((JavascriptExecutor)driver).executeScript(“ arguments [0] .checked = true;”,inputElement); 但是没有帮助inputElement.sendKeys(password);
Deepak Goel 2012年

2
@NIleshSharma python在驱动程序对象本身上直接具有方法execute_script:driver.execute_script(...)
lukeis 2012年


27

有时,这意味着页面上有多个具有相同属性的元素,您要尝试使用它们来搜索,并且您正在“与错误的对象交谈”。

如果您的元素不能由:id或:name(或:class)唯一标识,则可能会比较棘手。

有时通过:xpath搜索元素会有所帮助,在某些情况下,这甚至是不切实际的。

在这种情况下,您可能必须获取所有符合条件的元素,然后通过索引引用正确的元素。很脏,但是可以用。

我正在使用Ruby on Rails应用程序中的Selenium / Watir,因此在我的情况下,示例为:

browser = Watir::Browser.new(:firefox, :profile => "default")       
browser.goto("http://www.google.com/analytics")
# login
browser.divs(:text, "+ New Property").last.click

希望这可以帮助。


在dom元素中添加ID为我修复了问题
naoru 2014年

我遇到了同样的问题,并调整了XPath,以便可以区分出唯一的元素。
JohnL

我有同样的问题。更改了对findElements()的调用以计算匹配项,并且再有一个匹配元素。谢谢!
白羊座'18

对我来说太多了。始终确保选择标准对于您认为与之交互的元素足够具体。很多时候我有两个元素在起作用,一个元素被隐藏了,并给了我这个错误。
克里斯(Chris

14

我有一个类似的问题,但这与元素在视口中不可见有关。我拍了一个屏幕截图,意识到浏览器窗口太窄,无法看到该元素。我做了其中之一,它起作用了:

driver.maximize_window()

请参阅:WebDriver.maximize_window()


7

或者您可以使用Selenium Action Class来模拟用户交互-例如

    WebDriver = new FirefoxDriver();

    WebElement menu = driver.findElement(By.xpath("")); // the triger event element

    Actions build = new Actions(driver); // heare you state ActionBuider
    build.moveToElement(menu).build().perform(); // Here you perform hover mouse over the needed elemnt to triger the visibility of the hidden
    WebElement m2m= driver.findElement(By.xpath(""));//the previous non visible element
    m2m.click();

7

还有另一种情况,可见元素将被识别为不可见:

  • 元素经过CSS转换后
  • 当元素的父元素经过CSS转换时

为了检查您不想与之交互的元素是否经过CSS转换,请在CHROME上执行以下操作:

  1. 公开检查员
  2. 查找有趣的元素(或更可能是其父元素,应该是div元素)
  3. 选择“计算”标签
  4. 如果有参数:webkit-transform:matrix(...),则表示该元素是CSS转换的,硒2可能无法将其识别为可见元素


2

我在Internet Explorer 9中使用硒2遇到了同样的问题,但是我的解决方法确实很奇怪。我无法单击表单中的输入->硒重复,它们不可见。

当我的表格上有弯曲的阴影时,就会发生这种情况-> http://www.paulund.co.uk/creating-different-css3-box-shadows-effects:具体出现在“效果2”中

我不知道为什么以及为什么该伪元素解决方案停止了硒测试,但是它对我有用。


2

由于Selenium旨在模仿用户交互,因此您不能强制用户通常无法访问的元素进行访问/更改。

如果发生此错误,请检查:

  • 元素在您的视口中可见,请尝试最大化webdriver正在使用的当前窗口(例如,maximize()node.js中maximize_window()在Python中),
  • 您的元素没有出现两次(在同一选择器下),而您选择了错误的元素,
  • 如果您的元素是隐藏的,那么请考虑使其可见,
  • 如果尽管有限制,您仍想访问/更改隐藏元素的值,则可以使用Javascript(例如,executeScript()node.js中execute_script()在Python中)。

1
我不知道硒的设计是如此严格。看来,从一般意义上讲,它并不是真正的自动化工具,而是更多的自动化用户交互工具。我猜有点道理。感谢您的澄清!
DanielLidström18年

1

我只是通过在ror项目中使用capybara来解决此错误,方法是添加:

Capybara.ignore_elements = true

features/support/env.rb


1

我只是通过等待元素显示属性来解决此错误

waitFor() { element.displayed }

在此页面上的所有答案中,这是通过“ Bootstrap Modal”对话框解决了我的问题的原因。谢谢@Suat Keskin!
alastairs

1

我进入硒元素的ElementNotVisibleException异常,在带有引导程序字形作为模板链接的django站点上进行功能测试,如下所示:

<a href="{% url 'item-add' %}"><span class="glyphicon glyphicon-plus text-danger"></span></a>

在我的功能测试期间,引导程序样式未加载,然后尝试单击此类链接将引发ElementNotVisibleException。我设法使它们可点击,只需在标记中添加一个空格即可,如下所示:

<a href="{% url 'item-add' %}"><span class="glyphicon glyphicon-plus text-danger">&nbsp;</span></a>

1

此页面上有很多好的答案。

  1. 我通常从maximum.window()开始,实际上是在驱动程序Factory或初始化驱动程序的任何地方进行的。这是默认情况下执行的操作-始终执行。
  2. 由于某些javascript延迟,通常需要等待元素。

上面都对各种细节进行了讨论。我没有看到的答案是ScrollToElement。听起来您正在处理元素列表,而处理时您正在创建更多元素(复选框)。这可能导致列表中的元素移出可见页面。有时您可以用肉眼看到该元素,但无法单击它。处理列表时,有时必须插入滚动。

  • 设置一个断点,并检查您正在使用的元素是否在窗口边缘,右上/左下。有时,在这种情况下,您无法通过硒获取信息,但可以使用鼠标手动单击。

因为我遇到了这个问题,所以我创建了一个PageScroll.java并将滚动脚本放在那里。这是此类中的一些方法:

public static void scrollToTop(WebDriver driver) {
      ((JavascriptExecutor) driver)
        .executeScript("window.scrollTo(0,0)");
    }

    public static void scrollToBottom(WebDriver driver) {
      ((JavascriptExecutor) driver)
        .executeScript("window.scrollTo(0, document.body.scrollHeight)");
    }

    public static void scrollToElementTop(WebDriver driver, WebElement element) {
      ((JavascriptExecutor) driver).executeScript(
        "arguments[0].scrollIntoView(true);", element);
    }

    public static void scrollToElementBottom(WebDriver driver, WebElement element) {
      ((JavascriptExecutor) driver).executeScript(
        "arguments[0].scrollIntoView(false);", element);
    }

有关更多示例,请参见使用Selenium将元素滚动到视图中。


0

接受的答案对我有用。下面是一些代码,用于查找使Selenium认为它不可见的父元素。

function getStyles(element){
	
	computedStyle = window.getComputedStyle(element);

	if(computedStyle.opacity === 0
	|| computedStyle.display === "none"
	|| computedStyle.visibility === "hidden"
	|| (computedStyle.height < 0 && computedStyle.height < 0)
	|| element.type === "hidden") {
		console.log("Found an element that Selenium will consider to not be visible")
		console.log(element);
		console.log("opacity: " + computedStyle.opacity);
		console.log("display: " + computedStyle.display);
		console.log("visibility: " + computedStyle.visibility);
		console.log("height: " + computedStyle.height);
		console.log("width: " + computedStyle.width);
	}

	if(element.parentElement){
		getStyles(element.parentElement);
	}
}

getStyles(document.getElementById('REPLACE WITH THE ID OF THE ELEMENT YOU THINK IS VISIBLE BUT SELENIUM CAN NOT FIND'));


0

在这里添加我的沙粒:如果元素位于固定的div后面,则将其视为不可见,您将无法单击它;这最近发生在我身上,我解决了执行上面推荐的脚本的问题,该脚本可以:

document.evaluate("<xpath locator for element to be clicked>", document, null, XPathResult.ANY_TYPE, null).iterateNext().click()", locator);

此处的定位器是什么?
Anjana
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.