【问题标题】:Iterating through divs with same class name遍历具有相同类名的 div
【发布时间】:2016-11-25 14:23:35
【问题描述】:

我有以下 DOM:

<form id="slideshow">
  <div class="slideshow-item">
  <div class="slideshow-item">
  <div class="slideshow-item">
</form>

我需要遍历这个表单元素中的所有 div,对每个 div 执行一些操作,然后在所有 div 完成后出来。

我将我的定位器定义为:

divs(:slideShowRow, :xpath => "//div[@class='slideshow-item']")

并尝试迭代为:

slideShowRow_elements.each do |e|
  uploadSlideShowImage = e.text_field_element(:xpath => "//input[@type='file']")
  execute_script("$(arguments[0]).show();", uploadSlideShowImage)
  uploadSlideShowImage.send_keys("//path/to/image_file")
  textSlideShowRow = e.text_field_element(:xpath => "//input[@placeholder='Overlay Text']")
  textSlideShowRow.send_keys("row_number_x")
end

问题:

我在这里面临的问题是该操作仅对第一个元素执行,而不是对所有 3 个元素执行。

所以循环运行三次,因为有 3 个 div,但该操作是在同一个 div 元素上执行三次而不是单个 div 元素。

PS:我正在使用带有 Ruby 和 selenium webdriver 的页面对象。

【问题讨论】:

  • 这是遍历元素的正确方法。这将有助于显示“//执行操作”实际上在做什么。
  • 但我在这里面临的问题是该操作仅对第一个元素执行,而不是对所有 3 个元素执行。因此循环运行三次,因为有 3 个 div,但该操作是在同一个第一个 div 元素上执行三次而不是单个 div 元素。
  • 我为每个 div 添加了一个id 属性,分别是“1”、“2”、“3”。当我运行page.slideShowRow_elements.each { |e| p e.attribute('id') } 时,它正确输出了“1”、“2”、“3”。这证明迭代确实有效。如果代码没有按照您的预期执行,我猜想//perform action 做错了什么,或者 Web 应用程序的实现正在做某事。这就是为什么我建议分享您如何执行该操作。在这一点上,重现您的问题的实际页面也会有所帮助。
  • 这可能是一个动态问题,需要等待,但如果没有其余相关代码,则很难判断。
  • 您要执行的操作是什么?

标签: ruby selenium-webdriver cucumber bdd page-object-gem


【解决方案1】:

脚本正确地遍历slideShowRow_elements。问题实际上在于元素在每个 slideShowRow_element 中的位置。

对于线路:

e.text_field_element(:xpath => "//input[@type='file']")

XPath 表达式实际上表示要在页面上任意位置 查找文件字段元素。结果,第一行的那个总是会被抓取。需要告知 XPath 表达式仅在当前行中定位文件字段。这是通过以句点开头的 XPath 表达式来完成的:

e.text_field_element(:xpath => ".//input[@type='file']")

需要对使用的两个 XPath 表达式进行此更改:

slideShowRow_elements.each do |e|
  uploadSlideShowImage = e.text_field_element(:xpath => ".//input[@type='file']")
  execute_script("$(arguments[0]).show();", uploadSlideShowImage) 
  uploadSlideShowImage.send_keys("//path/to/image_file")
  textSlideShowRow = e.text_field_element(:xpath => ".//input[@placeholder='Overlay Text']")
  textSlideShowRow.send_keys("row_number_x")
end

请注意,对于uploadSlideShowImage,您也可以通过不使用 XPath 来避免该问题:

uploadSlideShowImage = e.file_field_element

【讨论】:

  • 我对此有疑问@Justin。当我们通过 .each 进行迭代时,e 表示第一个 div 行元素。现在,当我指定: e.text_field_element(:xpath => "//input[@type='file']") 没有'.'时,它不应该只从第一个元素中获取文件输入。为什么这意味着从页面上的任何位置拾取? (或者在这种情况下总是先拿起)。循环还不够吗?
  • 我同意,这不直观。但是,这正是 XPath 的定义/解释方式。从// 开始意味着开始查看文档根目录,. 表示从上下文节点开始查看。 XPath documentation has some good examples - 特别是“//para 选择文档根的所有 para 后代,因此选择与上下文节点相同的文档中的所有 para 元素”。
  • 如果您将该示例应用于原始代码,这意味着原始代码 e.text_field_element(:xpath =&gt; "//input[@type='file']") 实际上是在说找到同一 document 中的第一个文件字段元素作为幻灯片放映行。由于它在同一个 document 中寻找一个,所以第一个匹配始终是第一行中的那个。
猜你喜欢
  • 2021-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-29
  • 2011-06-11
  • 2021-10-08
  • 1970-01-01
相关资源
最近更新 更多