如何使用XPath仅选择可见元素?

62

我有一个使用GWT编写的应用程序,现在我想使用Selenium编写一些测试。

我使用XPath来识别页面上的元素进行测试。使用id无法工作,因为id值是由GWT自动生成的并且可能会更改。当我意识到可以按标签查找按钮时,情况开始变得顺利:

//button[.='OK']

然而,当我开始运行多个测试时,遇到了问题。我意识到问题在于 GWT 应用程序生成的不同“页面”都保留在 HTML 中的隐藏 <div> 元素中。这意味着我的 Selenium 测试有时会点击当前视图中不可见的隐藏按钮。
使用 Firebug 检查 HTML,看起来 GWT 通过将 display: none 添加到它们的 style 属性中来隐藏 <div> 元素。这意味着我可以按如下方式找到所有隐藏的确定按钮:
//div[contains(@style,'display: none')]//button[.='OK']

这将找到所有隐藏的“确定”按钮,即那些祖先元素<div>具有style中的display: none属性而被隐藏的按钮。

我的问题是:如何使用XPath仅查找可见的“确定”按钮?如何查找没有祖先元素<div>具有style中的display: none属性的按钮?

7个回答

76

这个应该可以正常工作:

.//button[.='OK' and not(ancestor::div[contains(@style,'display:none')])
and not(ancestor::div[contains(@style,'display: none')])]

编辑:

下面是更简单和更有效的表达式:

//div[not(contains(@style,'display:none'))]//button[.='OK']

这个不能正常工作,因为每个按钮都至少有一个在其祖先元素中可见的div。


8
请注意,上述内容未匹配到class="display: none;"(加入空格使其不同). - ReactiveRaven
8
未来的读者请注意:尽管这是一个很好的解决方案(可能是XPath能做到最好的),但并不适用于所有情况,因为给定的元素可能有一个CSS类,其中设置了display: none;,从而使该元素不可见,但仍与此XPath表达式匹配。 - acdcjunior
5
与其保留该空格并检查它,不如在检查之前从属性中去掉该空格,这样可能更好。使用translate(normalize-space(@style), ' ', '')可处理任意数量的空格。 - carlin.scott
1
为什么要重复使用 and not(ancestor::div[contains(@style,'display: none')])? - sureshvv
2
@sureshvv 我花了好几分钟盯着它才明白那部分并没有重复。那里有两个从句:一个说它不能有任何祖先元素的样式属性包含 display:none,另一个也是同样的限制,但是用的是带空格的 display: none - Dave Yarwood
显示剩余6条评论

14

Selenium 2 Webdriver提供isDisplayed()方法来解决此问题,这是Selenium贡献者的杰作。


1
如果display:hidden属性在父元素上而不是元素本身上,那么这是否有效? - Dave Lawrence
2
是的,但您必须针对特定元素进行检查,不能匹配整个集合。 - sitnarf
2
请注意,当在检索(find by *)和使用isDisplayed()检查其可见性之间更改元素时,可能会引发“StaleElementReferenceException”异常。 - Blaise

3
这对我很有效:
//div[not(@hidden)]

对我有用,谢谢。请纠正一下打字错误://div[not(@hidden)] - Cagin Uludamar

0

对我来说,这个方法可以消除隐藏元素:

//div[@open]//*

0

//div[(contains(@style,'display: block'))]//button[@id='buttonid']

这对我很有用。像'display: none'表示隐藏块一样,'display: block'表示当前显示的块,我们可以指定任何内部标签来进行上述识别。


-1

我将这段代码添加到名称映射编辑器中,但它找不到“保留”按钮。系统在编辑器中看到它,但是每当创建一个包含此项目的新测试时,它都不想点击该按钮。

现在还有另一件事,这是动态按钮单击,所以会发生的情况是我将选择打开两个下拉列表的按钮,在其中放置这些项目。第一个项目可以正常工作,但无法识别同一映射项目,用于另一个屏幕的下一次使用。按钮“保留”在两个区域中都是相同的。


目前你的回答不够清晰,请编辑并添加更多细节,以帮助其他人理解它如何回答问题。你可以在帮助中心找到有关如何编写好答案的更多信息。 - Community
请添加更多信息,因为您的答案不够清晰。您可以阅读有关如何撰写良好答案的更多信息(https://stackoverflow.com/help/how-to-answer)。 - George

-5
//div[contains(@style,'display: block')]

这段代码将查找可见元素的xpath


2
你知道还有其他可能的显示值类型吗?比如inlineinline-blockflex等。 - Mike Warren

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接