递归检查嵌套元素是否存在

Recursively check if nested elements exist

为了给您介绍背景,我使用 Ruby 与 Selenium、Cucumber、Capybara 和 SitePrism 一起创建自动化测试。我有一些测试需要检查页面上某个元素的文本,例如:

def get_section_id
  return section.top.course.section_id.text
end

但是,我想在对嵌套的 course_and_section_id 元素调用 .text 之前检查是否所有父元素都存在。例如,要检查这个特定元素的文本,我会这样做:

if(has_section? && section.has_top? && section.top.has_course? && section.top.course.has_section_id?)
  return section.top.course.section_id.text
end

有没有什么方法可以像这样递归地检查 Ruby 中是否存在某些东西?可以这样称呼的东西:has_text?(section.top.course.section_id) 也许?

听起来您可能想要以下内容。

arr = [section, :top, :course, :section_id, :text]
arr.reduce { |e,m| e && e.respond_to?(m) && e.public_send(m) } 

因为 reduce 没有参数 memo e 的初始值是 section。如果 e 变为 nilfalse 它将保持该值。

ruby 没有任何内置功能可以执行此操作,因为您正在调用 return 元素的方法,或引发异常。如果他们 returned 元素或 nil 那么 Cary Swoveland 使用 &. 的建议就是答案。

这里要记住的关键是您实际尝试做的事情。由于您正在编写自动化测试,因此您(很可能)不会尝试检查元素是否存在(测试应该是可预测和可重复的,因此您应该知道元素将存在),而只是等待元素在获取文本之前存在。这意味着你真正想要的可能更像

def get_section_id
  wait_until_section_visible
  section.wait_until_top_visible
  section.top.wait_until_course_visible
  section.top.course.wait_until_section_id_visible
  return section.top.course.section_id.text
end

您可以编写一个辅助方法来简化操作,例如

def get_text_from_nested_element(*args)
  args.reduce(self) do |scope, arg| 
    scope.send("wait_until_#{arg}_visible")
    scope.send(arg)
  end.text
end

可以称为

def get_section_id
  get_text_from_nested_element(:section, :top, :course, :section_id)
end

虽然这有点过时,但事实上 &. 在最优雅的时候在这里不起作用,这可能是一个有用的功能

如果您可以在 GH 上使用示例页面提出它,这将很有用,那么我们可以考虑引入它

卢克