module CapybaraTestHelpers::Selectors
Public: Adds aliasing for element selectors to make it easier to encapsulate how to find a particular kind of element in the UI.
Constants
- SELECTOR_SEPARATOR
Public Class Methods
# File lib/capybara_test_helpers/selectors.rb, line 38 def self.included(base) base.extend(ClassMethods) end
Public Instance Methods
Internal: Inspects the arguments for a SelectorQuery, and resolves a selector alias if provided.
Returns a pair of arguments and keywords to initialize a SelectorQuery.
# File lib/capybara_test_helpers/selectors.rb, line 97 def resolve_alias_for_selector_query(args, kwargs, filter_block) # Extract the explicitly provided selector, if any. Example: `find_button`. explicit_type = args.shift if selectors.key?(args[1]) if selectors.key?(args[0]) args, kwargs = locator_for(*args, **kwargs) # Remove the type provided by the alias, and add back the explicit one. if explicit_type args.shift if args[0].is_a?(Symbol) args.unshift(explicit_type) end end [args, kwargs, wrap_filter(filter_block)] end
Public: Returns the available selectors for the test helper, or an empty Hash if selectors are not defined.
# File lib/capybara_test_helpers/selectors.rb, line 89 def selectors self.class.selectors end
Private Instance Methods
Internal: Combines parent and child classes to preserve the order.
# File lib/capybara_test_helpers/selectors.rb, line 168 def combine_css_selectors(selectors) return selectors unless selectors.size > 1 && selectors.all? { |selector| selector.is_a?(String) } selectors.reduce { |parent_selectors, children_selectors| parent_selectors.split(SELECTOR_SEPARATOR).flat_map { |parent_selector| children_selectors.split(SELECTOR_SEPARATOR).map { |children_selector| "#{ parent_selector }#{ children_selector }" } }.join(SELECTOR_SEPARATOR) } end
Internal: Resolves a complex locator alias, which might reference other locator aliases as well.
# File lib/capybara_test_helpers/selectors.rb, line 148 def combine_locator_fragments(fragments) return fragments unless fragments.any? { |fragment| fragment.is_a?(Symbol) } fragments = fragments.map { |fragment| resolve_locator_alias(fragment) } flat_fragments = fragments.flatten(1) type = flat_fragments.shift if flat_fragments.first.is_a?(Symbol) # Only flatten fragments if it's CSS or XPath if type.nil? || type == :css || type == :xpath fragments = flat_fragments else type = nil end options = fragments.pop if fragments.last.is_a?(Hash) [type, *combine_css_selectors(fragments), options].compact end
Internal: Returns the query locator defined under the specified alias.
NOTE: In most cases, the query locator is a simple CSS selector, but it also supports any of the built-in Capybara
selectors.
Returns an Array with the Capybara
locator arguments, and options if any.
# File lib/capybara_test_helpers/selectors.rb, line 127 def locator_for(*args, **kwargs) if args.size == 1 args = [*Array.wrap(resolve_locator_alias(args.first))] kwargs = args.pop.deep_merge(kwargs) if args.last.is_a?(Hash) end [args, kwargs] rescue KeyError => error raise NotImplementedError, "A selector in #{ self.class.name } is not defined, #{ error.message }" end
Internal: Checks if there's a Capybara
selector defined by that name.
# File lib/capybara_test_helpers/selectors.rb, line 117 def registered_selector?(name) Capybara::Selector.all.key?(name) end
Internal: Resolves one of the segments of a locator alias.
# File lib/capybara_test_helpers/selectors.rb, line 138 def resolve_locator_alias(fragment) return fragment unless fragment.is_a?(Symbol) && (selectors.key?(fragment) || !registered_selector?(fragment)) locator = selectors.fetch(fragment) locator.is_a?(Array) ? combine_locator_fragments(locator) : locator end