Class: CapybaraTestHelpers::TestHelper

Inherits:
Object
  • Object
show all
Includes:
Capybara::DSL, Actions, Assertions, Finders, Matchers, Selectors, Synchronization, RSpec::Matchers, RSpec::Mocks::ExampleMethods
Defined in:
lib/capybara_test_helpers/test_helper.rb

Overview

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.

Constant Summary

Constants included from Synchronization

Synchronization::EXPECTATION_ERRORS

Constants included from Selectors

Selectors::SELECTOR_SEPARATOR

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Assertions

#have, #have_value, #invert_expectation, #not_to, #should, #should_not

Methods included from Actions

#blur, #focus, #type_in

Methods included from Finders

#all

Methods included from Selectors

included, #resolve_alias_for_selector_query, #selectors

Constructor Details

#initialize(query_context, test_context: query_context, negated: nil) ⇒ TestHelper

Returns a new instance of TestHelper.



36
37
38
# File 'lib/capybara_test_helpers/test_helper.rb', line 36

def initialize(query_context, test_context: query_context, negated: nil)
  @query_context, @test_context, @negated = query_context, test_context, negated
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class CapybaraTestHelpers::Assertions

Instance Attribute Details

#query_contextObject (readonly)

Returns the value of attribute query_context.



34
35
36
# File 'lib/capybara_test_helpers/test_helper.rb', line 34

def query_context
  @query_context
end

#test_contextObject (readonly)

Returns the value of attribute test_context.



34
35
36
# File 'lib/capybara_test_helpers/test_helper.rb', line 34

def test_context
  @test_context
end

Class Method Details

.delegate_to_test_context(*method_names) ⇒ Object

Public: Make methods in the test context available in the helpers.



137
138
139
# File 'lib/capybara_test_helpers/test_helper.rb', line 137

def delegate_to_test_context(*method_names)
  delegate(*method_names, to: :test_context)
end

.method_added(method_name) ⇒ Object

Internal: Fail early if a reserved method is redefined.



167
168
169
170
171
172
# File 'lib/capybara_test_helpers/test_helper.rb', line 167

def method_added(method_name)
  return unless CapybaraTestHelpers::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

.on_test_helper_loadObject

Internal: Allows to perform certain actions just before a test helper will be loaded for the first time.



162
163
164
# File 'lib/capybara_test_helpers/test_helper.rb', line 162

def on_test_helper_load
  define_getters_for_selectors
end

.use_test_helpers(*helper_names) ⇒ Object

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


150
151
152
153
154
155
156
157
158
# File 'lib/capybara_test_helpers/test_helper.rb', line 150

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

Instance Method Details

#friendly_nameObject

Internal: Returns the name of the class without the suffix.

Example: ‘current_page’ for CurrentPageTestHelper.



102
103
104
# File 'lib/capybara_test_helpers/test_helper.rb', line 102

def friendly_name
  self.class.name.chomp('TestHelper').underscore
end

#inspectObject

Public: To make the benchmark log less verbose.



41
42
43
44
45
# File 'lib/capybara_test_helpers/test_helper.rb', line 41

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

#inspect_nodeObject

Public: Makes it easier to inspect the current element.



48
49
50
# File 'lib/capybara_test_helpers/test_helper.rb', line 48

def inspect_node
  to_capybara_node.inspect
end

#to_capybara_nodeObject

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.



56
57
58
59
60
61
# File 'lib/capybara_test_helpers/test_helper.rb', line 56

def to_capybara_node
  return current_context if current_element?
  return find_element(:el) if selectors.key?(:el)

  raise_missing_element_error
end

#within(*args, **kwargs, &block) ⇒ Object

Public: Scopes the Capybara queries in the block to be inside the specified selector.



85
86
87
88
89
# File 'lib/capybara_test_helpers/test_helper.rb', line 85

def within(*args, **kwargs, &block)
  return be_within(*args, **kwargs) unless block_given? # RSpec matcher.

  within_element(*args, **kwargs, &block)
end

#within_documentObject

Public: Unscopes the inner block from any previous ‘within` calls.



92
93
94
95
96
97
# File 'lib/capybara_test_helpers/test_helper.rb', line 92

def within_document
  page.instance_exec { scopes << nil }
  yield wrap_element(page.document)
ensure
  page.instance_exec { scopes.pop }
end

#within_element(*args, **kwargs, &block) ⇒ Object

Public: Scopes the Capybara queries in the block to be inside the specified selector.



77
78
79
80
81
# File 'lib/capybara_test_helpers/test_helper.rb', line 77

def within_element(*args, **kwargs, &block)
  locator = args.empty? ? [self] : args
  kwargs[:test_helper] = self
  page.within(*locator, **kwargs, &block)
end

#wrap_element(element) ⇒ Object

Public: Wraps a Capybara::Node::Element or test helper with a test helper object of this class.



65
66
67
68
69
70
71
72
73
# File 'lib/capybara_test_helpers/test_helper.rb', line 65

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