为什么在使用XPathMapSeleniumWebDriver的元素时会返回两个外观相同的元素?

sdnqo3pr  于 2023-02-08  发布在  其他
关注(0)|答案(5)|浏览(236)

这个问题我已经有一段时间了,但是我从来没有做过任何事情。当Map一些元素进行UI测试时,我有时会遇到返回两个相同结果的元素。
过去我们通过使用findelements,然后使用索引[1]来解决这个问题。
但是我仍然不明白为什么它返回两个元素,而我在代码中只能看到一个应该定位的元素。
下面就是一个例子。您可以在下面看到这个用户名字段框。

如果我用一些XPath表达式

//input[@name='username']

我只希望得到一个元素作为返回,但是使用Chropath工具,我可以看到我得到了两个元素作为返回。

这些元素看起来完全相同,一个没有隐藏,等等。我一直不明白为什么会发生这种情况,因为如果我使用一个查找元素,我会得到一个元素,而不是交互式错误,因为我猜驱动程序不能决定使用哪个元素?或者它们彼此妨碍。
因此,我一直使用的解决方法是:

return self.browser.find_elements(by=By.XPATH, value="//input[@name='username']")[1]

当我实际上应该能够使用:

return self.browser.find_element(by=By.XPATH, value="//input[@name='username']")

这是为什么呢?
一些优秀的React,这让我明白了现在发生了什么。下一步,我将使用以下内容:

for e in self.browser.find_elements(by=By.XPATH, value="//input[@name='username']"):
    if e.is_displayed():
        return e

这似乎对我有用。

1wnzp6jl

1wnzp6jl1#

当一个网站同时有桌面版和移动版或小屏幕版时,我经常看到这种情况。在全屏(或接近全屏)时,桌面元素可见,而小屏幕元素隐藏。一旦你将浏览器调整到足够小,桌面元素隐藏,小屏幕元素可见。
要以通用的方式解决这个问题,可以根据可见性过滤返回的两个元素,例如:

return [e in self.browser.find_elements(by=By.XPATH, value="//input[@name='username']") if e.is_displayed()]

这应该总是返回两个元素中的可见元素。

6rqinv9w

6rqinv9w2#

答案就在快照中:

以下xpath

//input[@name='username']

标识HTML DOM中的2个不同元素。在两个匹配元素中,第一个匹配元素用于 * 移动的显示器 ,当您在 * 桌面模式 * 下访问DOM Tree时,该元素保持隐藏*。在给定的Chropath快照中,classname 作为 modal-content-mobile 是最佳提示。
溶液
在这些情况下,有不同的方法来识别所需的元素,虽然有些用户倾向于使用 index,有些用户倾向于探测 displayedness,但从个人Angular 来看,我发现向上遍历DOM以查找其祖先中属性值的差异,然后最终向下遍历直到所需的元素,这是相当容易和方便的。

twh00eeo

twh00eeo3#

页面上可能有多个具有相同名称属性的相同元素。必须隐藏其中一个元素。
如果你想访问第一个,使用下面的xpath。

return self.browser.find_element(by=By.XPATH, value="(//input[@name='username'])[1]")

如果要访问最后一个,请使用以下命令

return self.browser.find_element(by=By.XPATH, value="(//input[@name='username'])[last()]")
c2e8gylq

c2e8gylq4#

多个元素匹配同一个定位器的情况很常见。
例如,可以为登录实现几个代码块:一个用于计算机浏览器,另一个用于移动浏览器,等等。将根据您用于浏览该页面的内容显示适当的元素。Selenium find_element始终返回在页面上找到的与传递的定位符匹配的第一个元素。
因此,在第一个匹配元素被隐藏的情况下,return self.browser.find_element(by=By.XPATH, value="//input[@name='username']")将总是返回该隐藏元素。
您需要使定位器更加精确以匹配所需的web元素。
"(//input[@name='username'])[2]"这样的定位器可能很好,但是在这里最好使用一个唯一的父元素,比如"//div[@class='pc_modal']//input[@name='username']",所以你的代码应该是这样的:

return self.browser.find_element(By.XPATH, "//div[@class='pc_modal']//input[@name='username']")
brc7rcf0

brc7rcf05#

嗯,严格意义上来说,没有两个元素有相同的XPath表达式。如果你看绝对路径,你会发现不同之处。关键是找到一个唯一的路径。在很多情况下,你会发现一个网页,你会发现许多文本框/标签/下拉框有相同的id,但只是通过它们的绝对路径来区分。
大多数情况下,这取决于开发网页的框架和开发者的偏好,例如,使用React开发的应用程序与使用Angular开发的应用程序相比,DOM结构会有所不同。
是的,你说得对,在这种情况下很难找到感兴趣的元素。在这种情况下,不要只依赖于特定的元素,还要添加父/兄弟或祖先来访问该元素。虽然这可能需要一些时间,也可能不太直接,但大多数情况下都可以找到唯一的XPath。
有一些测试自动化工具,比如Ranorex,有一个对象浏览器(objext spy),可以用来固定任何web元素,并访问其属性,比如隐藏、可见、启用等。但是这些工具不是免费的:(

相关问题