rubyrecursioncucumbercapybarasite-prism

Recursively check if nested elements exist


Just to give you a background, I'm using Ruby for creating automated tests along with Selenium, Cucumber, Capybara and SitePrism. I have some tests that need to check the text of a certain element on the page, for example:

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

However, I would like to check if all the parent elements exist before calling .text on the nested course_and_section_id element. For example, to check the text of this particular element I would do:

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

Is there any way to recursively check if something exists in Ruby like this? Something that could be called like: has_text?(section.top.course.section_id) maybe?


Solution

  • There is nothing builtin to ruby that would do this because the methods you're calling return the element, or raise an exception. If they returned the element or nil then the suggestion of Cary Swoveland to use &. would be the answer.

    The critical thing to remember here is what you're actually trying to do. Since you're writing automated tests, you're (most likely) not trying to check whether or not the elements exist (tests should be predictable and repeatable so you should know the elements are going to exist) but rather just wait for the elements to exist before getting the text. This means what you really want is probably more like

    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
    

    You can write a helper method to make that easier, something like

    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
    

    which could be called as

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