class Capybara::Compose::TestHelper
Public: Base class to create test helpers that have full access to the Capybara
DSL, while easily defining custom assertions, getters, and actions.
It also supports locator aliases to prevent duplication and keep tests easier to understand and to maintain.
Attributes
Public Class Methods
# File lib/capybara/compose/test_helper.rb, line 33 def initialize(query_context, test_context: query_context, negated: nil) @query_context, @test_context, @negated = query_context, test_context, negated end
Private Class Methods
Public: Make methods in the test context available in the helpers.
# File lib/capybara/compose/test_helper.rb, line 134 def delegate_to_test_context(*method_names) delegate(*method_names, to: :test_context) end
Internal: Fail early if a reserved method is redefined.
# File lib/capybara/compose/test_helper.rb, line 164 def method_added(method_name) return unless Capybara::Compose::RESERVED_METHODS.include?(method_name) raise "A method with the name #{ method_name.inspect } is part of the Capybara DSL," \ ' overriding it could cause unexpected issues that could be very hard to debug.' end
Internal: Allows to perform certain actions just before a test helper will be loaded for the first time.
# File lib/capybara/compose/test_helper.rb, line 159 def on_test_helper_load define_getters_for_selectors end
Public: Allows to make other test helpers available.
NOTE: When you call a helper the “negated” state is preserved for assertions.
NOTE: You can also pass an element to a test helper to “wrap” a specified element with the specified test helper class.
Example:
dropdown(element).toggle_menu
# File lib/capybara/compose/test_helper.rb, line 147 def use_test_helpers(*helper_names) helper_names.each do |helper_name| private define_method(helper_name) { |element = nil| test_helper = test_context.get_test_helper(helper_name) test_helper = test_helper.wrap_element(element) if element @negated.nil? ? test_helper : test_helper.should(@negated) } end end
Public Instance Methods
Internal: Returns the name of the class without the suffix.
Example: 'current_page' for CurrentPageTestHelper.
# File lib/capybara/compose/test_helper.rb, line 99 def friendly_name self.class.name.chomp('TestHelper').underscore end
Public: To make the benchmark log less verbose.
# File lib/capybara/compose/test_helper.rb, line 38 def inspect %(#<#{ self.class.name } #{ current_element? ? %(tag="#{ base.tag_name }") : object_id }>) rescue *page.driver.invalid_element_errors %(#<#{ self.class.name } #{ object_id }>) end
Public: Makes it easier to inspect the current element.
# File lib/capybara/compose/test_helper.rb, line 45 def inspect_node to_capybara_node.inspect end
Public: Casts the current context as a Capybara::Node::Element.
NOTE: Uses the :el convention, which means actions can be performed directly on the test helper if an :el selector is defined.
# File lib/capybara/compose/test_helper.rb, line 53 def to_capybara_node return current_context if current_element? return find_element(:el) if selectors.key?(:el) raise_missing_element_error end
Public: Scopes the Capybara
queries in the block to be inside the specified selector.
# File lib/capybara/compose/test_helper.rb, line 82 def within(*args, **kwargs, &block) return be_within(*args, **kwargs) unless block_given? # RSpec matcher. within_element(*args, **kwargs, &block) end
Public: Unscopes the inner block from any previous `within` calls.
# File lib/capybara/compose/test_helper.rb, line 89 def within_document page.instance_exec { scopes << nil } yield wrap_element(page.document) ensure page.instance_exec { scopes.pop } end
Public: Scopes the Capybara
queries in the block to be inside the specified selector.
# File lib/capybara/compose/test_helper.rb, line 74 def within_element(*args, **kwargs, &block) locator = args.empty? ? [self] : args kwargs[:test_helper] = self page.within(*locator, **kwargs, &block) end
Public: Wraps a Capybara::Node::Element or test helper with a test helper object of this class.
# File lib/capybara/compose/test_helper.rb, line 62 def wrap_element(element) if element.is_a?(Enumerable) element.map { |node| wrap_element(node) } else raise ArgumentError, "#{ element.inspect } must be a test helper or element." unless element.respond_to?(:to_capybara_node) self.class.new(element.to_capybara_node, test_context: test_context) end end
Protected Instance Methods
Internal: Used to perform assertions and others.
# File lib/capybara/compose/test_helper.rb, line 106 def current_context query_context.respond_to?(:to_capybara_node) ? query_context : page end
Internal: Returns true if the current context is an element.
# File lib/capybara/compose/test_helper.rb, line 111 def current_element? current_context.is_a?(Capybara::Node::Element) end
Private Instance Methods
Internal: Helper to provide more information on the error.
# File lib/capybara/compose/test_helper.rb, line 124 def raise_missing_element_error method_caller = caller.select { |x| x['test_helpers'] }[1] method_caller_name = method_caller&.match(/in `(\w+)'/) method_caller_name = method_caller_name ? method_caller_name[1] : method_caller raise ArgumentError, "You are calling the `#{ method_caller_name }' method on the test helper but :el is not defined nor there's a current element.\n"\ 'Define :el, or find an element before performing the action.' end
Internal: Wraps the optional filter block to ensure we pass it a test helper instead of a raw Capybara::Node::Element.
# File lib/capybara/compose/test_helper.rb, line 119 def wrap_filter(filter) proc { |capybara_node_element| filter.call(wrap_element(capybara_node_element)) } if filter end