Ruby自动化测试中如何递归检查嵌套元素是否存在?
Great question! When working with nested elements in SitePrism (paired with Capybara/Selenium), you absolutely can implement a recursive check to verify all parent elements exist before accessing a child’s text. Let’s break down how to approach this, including both recursive and iterative methods, plus notes on SitePrism’s built-in behavior.
Understanding SitePrism’s Implicit Scoping
First, it’s worth noting that SitePrism already scopes child elements to their parent components/pages. When you call your_page.course_and_section_id.text, Capybara will automatically wait for the parent element (if it’s a component) to exist before attempting to locate the child. However, if you want explicit control over checking the entire parent chain (e.g., to log which parent is missing or avoid raising an error immediately), a custom check is useful.
Recursive Check Method
You can write a recursive helper method that traverses up the element’s parent chain, verifying each exists. Here’s an example:
def all_parents_exist?(element) # Base case: stop when we reach the top-level SitePrism Page (no parent element to check) return true if element.parent.is_a?(SitePrism::Page) # Check if the current parent exists, then recurse up to its parent element.parent.exists? && all_parents_exist?(element.parent) end # To check the child element plus all parents: def element_and_ancestors_exist?(element) all_parents_exist?(element) && element.exists? end
How to Use It
In your test, you can call this method before accessing the element’s text:
course_element = page.course_and_section_id if element_and_ancestors_exist?(course_element) puts course_element.text else # Handle missing elements (e.g., log an error, fail gracefully) puts "Error: The element or one of its parents could not be found." end
Iterative Alternative (Non-Recursive)
If recursion feels overkill, you can use an iterative approach to loop up the parent chain:
def all_parents_exist?(element) current_parent = element.parent while current_parent.is_a?(SitePrism::Element) || current_parent.is_a?(SitePrism::Component) return false unless current_parent.exists? current_parent = current_parent.parent end true end
Customizing Wait Times
Capybara’s exists? method uses the default wait time (set via Capybara.default_max_wait_time), but you can override it for specific checks:
# Wait up to 10 seconds for the parent element to exist element.parent.exists?(wait: 10)
Key Notes
- Built-in Error Handling: If you skip the explicit check and just call
course_and_section_id.text, Capybara will raise aCapybara::ElementNotFounderror if any parent or the child is missing. The explicit check lets you handle this scenario more gracefully. - SitePrism Components: If your nested elements are part of SitePrism components, the parent chain will include those components, and
exists?will work the same way as it does for individual elements.
内容的提问来源于stack exchange,提问作者Andrew Allison

