page_magic 1.2.7 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.rubocop.yml +23 -4
- data/.simplecov +5 -3
- data/.zsh_config +6 -0
- data/Dockerfile +11 -0
- data/Gemfile +13 -13
- data/Gemfile.lock +135 -144
- data/Makefile +17 -0
- data/README.md +48 -4
- data/Rakefile +12 -2
- data/VERSION +1 -1
- data/circle.yml +4 -2
- data/lib/active_support/core_ext/object/to_query.rb +84 -0
- data/lib/page_magic.rb +22 -20
- data/lib/page_magic/class_methods.rb +5 -2
- data/lib/page_magic/comparator.rb +37 -0
- data/lib/page_magic/comparator/fuzzy.rb +23 -0
- data/lib/page_magic/comparator/literal.rb +22 -0
- data/lib/page_magic/comparator/null.rb +26 -0
- data/lib/page_magic/comparator/parameter_map.rb +52 -0
- data/lib/page_magic/driver.rb +3 -0
- data/lib/page_magic/drivers.rb +6 -5
- data/lib/page_magic/drivers/poltergeist.rb +2 -0
- data/lib/page_magic/drivers/rack_test.rb +3 -1
- data/lib/page_magic/drivers/selenium.rb +4 -2
- data/lib/page_magic/element.rb +35 -15
- data/lib/page_magic/element/locators.rb +8 -5
- data/lib/page_magic/element/not_found.rb +38 -0
- data/lib/page_magic/element/query.rb +21 -20
- data/lib/page_magic/element/query/multiple_results.rb +21 -0
- data/lib/page_magic/element/query/prefetched_result.rb +26 -0
- data/lib/page_magic/element/query/single_result.rb +20 -0
- data/lib/page_magic/element/selector.rb +41 -16
- data/lib/page_magic/element/selector/methods.rb +18 -0
- data/lib/page_magic/element/selector/model.rb +21 -0
- data/lib/page_magic/element_context.rb +7 -21
- data/lib/page_magic/element_definition_builder.rb +20 -24
- data/lib/page_magic/elements.rb +65 -68
- data/lib/page_magic/elements/config.rb +103 -0
- data/lib/page_magic/elements/inheritance_hooks.rb +15 -0
- data/lib/page_magic/elements/types.rb +25 -0
- data/lib/page_magic/exceptions.rb +6 -1
- data/lib/page_magic/instance_methods.rb +8 -3
- data/lib/page_magic/mapping.rb +79 -0
- data/lib/page_magic/session.rb +15 -35
- data/lib/page_magic/session_methods.rb +3 -1
- data/lib/page_magic/transitions.rb +49 -0
- data/lib/page_magic/utils/string.rb +18 -0
- data/lib/page_magic/utils/url.rb +20 -0
- data/lib/page_magic/wait_methods.rb +3 -0
- data/lib/page_magic/watcher.rb +12 -17
- data/lib/page_magic/watchers.rb +31 -15
- data/page_magic.gemspec +17 -13
- data/spec/lib/active_support/core_ext/object/to_query_test.rb +78 -0
- data/spec/page_magic/class_methods_spec.rb +66 -37
- data/spec/page_magic/comparator/fuzzy_spec.rb +44 -0
- data/spec/page_magic/comparator/literal_spec.rb +41 -0
- data/spec/page_magic/comparator/null_spec.rb +35 -0
- data/spec/page_magic/comparator/parameter_map_spec.rb +75 -0
- data/spec/page_magic/driver_spec.rb +26 -28
- data/spec/page_magic/drivers/poltergeist_spec.rb +6 -7
- data/spec/page_magic/drivers/rack_test_spec.rb +6 -9
- data/spec/page_magic/drivers/selenium_spec.rb +11 -12
- data/spec/page_magic/drivers_spec.rb +38 -29
- data/spec/page_magic/element/locators_spec.rb +28 -25
- data/spec/page_magic/element/not_found_spec.rb +24 -0
- data/spec/page_magic/element/query/multiple_results_spec.rb +14 -0
- data/spec/page_magic/element/query/single_result_spec.rb +21 -0
- data/spec/page_magic/element/query_spec.rb +26 -45
- data/spec/page_magic/element/selector_spec.rb +120 -110
- data/spec/page_magic/element_context_spec.rb +47 -87
- data/spec/page_magic/element_definition_builder_spec.rb +14 -71
- data/spec/page_magic/element_spec.rb +256 -0
- data/spec/page_magic/elements/config_spec.rb +200 -0
- data/spec/page_magic/elements_spec.rb +90 -127
- data/spec/page_magic/instance_methods_spec.rb +65 -63
- data/spec/page_magic/mapping_spec.rb +181 -0
- data/spec/page_magic/session_methods_spec.rb +29 -25
- data/spec/page_magic/session_spec.rb +109 -199
- data/spec/page_magic/transitions_spec.rb +43 -0
- data/spec/page_magic/utils/string_spec.rb +29 -0
- data/spec/page_magic/utils/url_spec.rb +9 -0
- data/spec/page_magic/wait_methods_spec.rb +16 -22
- data/spec/page_magic/watcher_spec.rb +22 -0
- data/spec/page_magic/watchers_spec.rb +58 -62
- data/spec/page_magic_spec.rb +31 -30
- data/spec/spec_helper.rb +9 -2
- data/spec/support/shared_contexts.rb +3 -1
- data/spec/support/shared_examples.rb +17 -17
- metadata +101 -48
- data/lib/page_magic/element/query_builder.rb +0 -48
- data/lib/page_magic/element/selector_methods.rb +0 -13
- data/lib/page_magic/matcher.rb +0 -121
- data/spec/element_spec.rb +0 -249
- data/spec/page_magic/element/query_builder_spec.rb +0 -108
- data/spec/page_magic/matcher_spec.rb +0 -336
- data/spec/support/shared_contexts/files_context.rb +0 -7
- data/spec/support/shared_contexts/nested_elements_html_context.rb +0 -16
- data/spec/support/shared_contexts/rack_application_context.rb +0 -9
- data/spec/support/shared_contexts/webapp_fixture_context.rb +0 -39
- data/spec/watcher_spec.rb +0 -61
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PageMagic
|
4
|
+
class Comparator
|
5
|
+
# class Map - used to model parameter matching requirements
|
6
|
+
class ParameterMap < Comparator
|
7
|
+
def initialize(map)
|
8
|
+
comparator = normalise(map).keys.each_with_object({}) do |key, params|
|
9
|
+
params[key] = Comparator.for(map[key])
|
10
|
+
end
|
11
|
+
|
12
|
+
fuzzy = comparator.values.any?(&:fuzzy?)
|
13
|
+
super(comparator, fuzzy)
|
14
|
+
end
|
15
|
+
|
16
|
+
def <=>(other)
|
17
|
+
return 0 if empty? && other.empty?
|
18
|
+
return 1 if other.empty?
|
19
|
+
if (comparator.keys.size <=> other.comparator.keys.size).zero?
|
20
|
+
return literal_matchers.size <=> other.literal_matchers.size
|
21
|
+
end
|
22
|
+
|
23
|
+
0
|
24
|
+
end
|
25
|
+
|
26
|
+
def empty?
|
27
|
+
comparator.empty?
|
28
|
+
end
|
29
|
+
|
30
|
+
def literal_matchers
|
31
|
+
comparator.values.find_all { |matcher| !matcher.fuzzy? }
|
32
|
+
end
|
33
|
+
|
34
|
+
def match?(params)
|
35
|
+
params_copy = normalise(params)
|
36
|
+
comparator.each do |key, value|
|
37
|
+
param = params_copy[key]
|
38
|
+
return false unless value&.match?(param)
|
39
|
+
end
|
40
|
+
true
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def normalise(hash)
|
46
|
+
hash.keys.each_with_object({}) do |key, map|
|
47
|
+
map[key.to_sym] = hash[key]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/page_magic/driver.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module PageMagic
|
2
4
|
# class Driver - instances are factories for drivers used by PageMagic
|
3
5
|
class Driver
|
4
6
|
attr_reader :supported_browsers, :handler
|
7
|
+
|
5
8
|
# Creates a driver definition
|
6
9
|
# @example
|
7
10
|
# Driver.new do |rack_application, options|
|
data/lib/page_magic/drivers.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'driver'
|
4
|
+
require_relative 'utils/string'
|
2
5
|
module PageMagic
|
3
6
|
# class Drivers - creates an object that can be used to hold driver definitions
|
4
7
|
# These PageMagic gets the user's chosen driver from this object.
|
@@ -16,12 +19,10 @@ module PageMagic
|
|
16
19
|
# Loads drivers defined in files at the given path
|
17
20
|
# @param [String] path where the drivers are located
|
18
21
|
def load(path = "#{__dir__}/drivers")
|
19
|
-
|
20
|
-
|
21
|
-
Dir["#{path}/*.rb"].each do |driver_file|
|
22
|
+
Dir["#{path}/*.rb"].sort.each do |driver_file|
|
22
23
|
require driver_file
|
23
24
|
driver_name = File.basename(driver_file)[/(.*)\.rb$/, 1]
|
24
|
-
register self.class.const_get(
|
25
|
+
register self.class.const_get(Utils::String.classify(driver_name))
|
25
26
|
end
|
26
27
|
end
|
27
28
|
|
@@ -1,4 +1,6 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
PageMagic::Drivers::Selenium = PageMagic::Driver.new(:chrome, :firefox) do |app, options, browser|
|
2
|
-
require 'watir
|
3
|
-
Capybara::Selenium::Driver.new(app, options.dup.merge(browser: browser))
|
4
|
+
require 'watir'
|
5
|
+
Capybara::Selenium::Driver.new(app, **options.dup.merge(browser: browser))
|
4
6
|
end
|
data/lib/page_magic/element.rb
CHANGED
@@ -1,17 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'forwardable'
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
4
|
+
require_relative 'element/not_found'
|
5
|
+
require_relative 'element/selector/methods'
|
6
|
+
require_relative 'element/locators'
|
7
|
+
require_relative 'element/selector'
|
8
|
+
require_relative 'element/query'
|
6
9
|
module PageMagic
|
7
10
|
# class Element - represents an element in a html page.
|
8
11
|
class Element
|
9
|
-
EVENT_TYPES = [
|
12
|
+
EVENT_TYPES = %i[set select select_option unselect_option click].freeze
|
10
13
|
DEFAULT_HOOK = proc {}.freeze
|
11
|
-
EVENT_NOT_SUPPORTED_MSG = '%s event not supported'
|
14
|
+
EVENT_NOT_SUPPORTED_MSG = '%s event not supported'
|
12
15
|
|
13
|
-
include
|
14
|
-
|
16
|
+
include Locators
|
17
|
+
include WaitMethods
|
18
|
+
include SessionMethods
|
19
|
+
include Watchers
|
20
|
+
include Selector::Methods
|
21
|
+
extend Forwardable
|
22
|
+
extend Selector::Methods
|
23
|
+
extend Elements
|
15
24
|
|
16
25
|
attr_reader :type, :name, :parent_element, :browser_element, :before_events, :after_events
|
17
26
|
|
@@ -24,7 +33,7 @@ module PageMagic
|
|
24
33
|
# @!method before_events
|
25
34
|
# If a block is passed in, it adds it to be run before an event is triggered on an element.
|
26
35
|
# @see .after_events
|
27
|
-
%i
|
36
|
+
%i[after_events before_events].each do |method|
|
28
37
|
define_method method do |&block|
|
29
38
|
instance_variable_name = "@#{method}".to_sym
|
30
39
|
instance_variable_value = instance_variable_get(instance_variable_name) || [DEFAULT_HOOK]
|
@@ -38,6 +47,7 @@ module PageMagic
|
|
38
47
|
# @return [Element]
|
39
48
|
def parent_element(page_element = nil)
|
40
49
|
return @parent_page_element unless page_element
|
50
|
+
|
41
51
|
@parent_page_element = page_element
|
42
52
|
end
|
43
53
|
|
@@ -49,10 +59,16 @@ module PageMagic
|
|
49
59
|
clazz.after_events.replace(after_events)
|
50
60
|
end
|
51
61
|
|
62
|
+
def load(source)
|
63
|
+
new(Capybara::Node::Simple.new(source))
|
64
|
+
end
|
65
|
+
|
52
66
|
# Defines watchers to be used by instances
|
53
67
|
# @see Watchers#watch
|
54
68
|
def watch(name, method = nil, &block)
|
55
|
-
before_events
|
69
|
+
before_events do
|
70
|
+
watch(name, method: method, &block)
|
71
|
+
end
|
56
72
|
end
|
57
73
|
|
58
74
|
def ==(other)
|
@@ -78,9 +94,7 @@ module PageMagic
|
|
78
94
|
# @raise [NotSupportedException] if the wrapped Capybara element does not support the method
|
79
95
|
EVENT_TYPES.each do |method|
|
80
96
|
define_method method do |*args|
|
81
|
-
unless browser_element.respond_to?(method)
|
82
|
-
raise NotSupportedException, EVENT_NOT_SUPPORTED_MSG % method
|
83
|
-
end
|
97
|
+
raise NotSupportedException, EVENT_NOT_SUPPORTED_MSG % method unless browser_element.respond_to?(method)
|
84
98
|
|
85
99
|
browser_element.send(method, *args)
|
86
100
|
end
|
@@ -91,16 +105,21 @@ module PageMagic
|
|
91
105
|
rescue ElementMissingException
|
92
106
|
begin
|
93
107
|
return browser_element.send(method, *args, &block) if browser_element.respond_to?(method)
|
94
|
-
|
108
|
+
|
109
|
+
parent_element.send(method, *args, &block)
|
95
110
|
rescue NoMethodError
|
96
111
|
super
|
97
112
|
end
|
98
113
|
end
|
99
114
|
|
100
|
-
def
|
115
|
+
def respond_to_missing?(*args)
|
101
116
|
super || contains_element?(args.first) || browser_element.respond_to?(*args) || parent_element.respond_to?(*args)
|
102
117
|
end
|
103
118
|
|
119
|
+
# def respond_to_missing?(*args)
|
120
|
+
# respond_to?(*args)
|
121
|
+
# end
|
122
|
+
|
104
123
|
# @!method session
|
105
124
|
# get the current session
|
106
125
|
# @return [Session] returns the session of the parent page element.
|
@@ -131,6 +150,7 @@ module PageMagic
|
|
131
150
|
def wrap_events(raw_element)
|
132
151
|
EVENT_TYPES.each do |action_method|
|
133
152
|
next unless raw_element.respond_to?(action_method)
|
153
|
+
|
134
154
|
apply_hooks(raw_element: raw_element,
|
135
155
|
capybara_method: action_method,
|
136
156
|
before_events: before_events,
|
@@ -1,22 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module PageMagic
|
2
4
|
# for the benefit of pull review :@
|
3
5
|
class Element
|
4
6
|
# contains method for finding element definitions
|
5
7
|
module Locators
|
6
8
|
# message used when raising {ElementMissingException} from methods within this module
|
7
|
-
ELEMENT_NOT_DEFINED_MSG = 'Element not defined: %s'
|
9
|
+
ELEMENT_NOT_DEFINED_MSG = 'Element not defined: %s'
|
8
10
|
|
9
11
|
# find an element definition based on its name
|
10
12
|
# @param [Symbol] name name of the element
|
11
13
|
# @return [Element] element definition with the given name
|
12
14
|
# @raise [ElementMissingException] raised when element with the given name is not found
|
13
15
|
def element_by_name(name, *args)
|
14
|
-
|
15
|
-
raise ElementMissingException, (ELEMENT_NOT_DEFINED_MSG % name) unless
|
16
|
-
|
16
|
+
definition = element_definitions[name]
|
17
|
+
raise ElementMissingException, (ELEMENT_NOT_DEFINED_MSG % name) unless definition
|
18
|
+
|
19
|
+
definition.call(self, *args)
|
17
20
|
end
|
18
21
|
|
19
|
-
# @return [Array] class level defined element definitions
|
22
|
+
# @return [Array<Element>] class level defined element definitions
|
20
23
|
def element_definitions
|
21
24
|
self.class.element_definitions
|
22
25
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PageMagic
|
4
|
+
class Element
|
5
|
+
# class NotFound - Used to represent elements which are missing. All method calls other than
|
6
|
+
# to those that check visibility thrown a {PageMagic::ElementMissingException} exception
|
7
|
+
class NotFound
|
8
|
+
# @private [Capybara::ElementNotFound] exception
|
9
|
+
def initialize(exception)
|
10
|
+
@exception = exception
|
11
|
+
end
|
12
|
+
|
13
|
+
# @return [Boolean] - always false
|
14
|
+
def visible?
|
15
|
+
false
|
16
|
+
end
|
17
|
+
|
18
|
+
# @return [Boolean] - always false
|
19
|
+
def present?
|
20
|
+
false
|
21
|
+
end
|
22
|
+
|
23
|
+
# @raise [PageMagic::ElementMissingException]
|
24
|
+
def method_missing(*_args)
|
25
|
+
raise ElementMissingException, exception.message
|
26
|
+
end
|
27
|
+
|
28
|
+
# @return [Boolean] - always true
|
29
|
+
def respond_to_missing?(*_args)
|
30
|
+
true
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
attr_reader :exception
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -1,35 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'query/multiple_results'
|
4
|
+
require_relative 'query/single_result'
|
5
|
+
require_relative 'query/prefetched_result'
|
1
6
|
module PageMagic
|
2
7
|
class Element
|
3
8
|
# class Query - executes query on capybara driver
|
4
9
|
class Query
|
5
|
-
|
6
|
-
ELEMENT_NOT_FOUND_MSG = 'Unable to find %s'.freeze
|
7
|
-
|
8
|
-
attr_reader :args, :multiple_results
|
10
|
+
attr_reader :selector_args, :options
|
9
11
|
|
10
|
-
|
12
|
+
DEFAULT_DECORATOR = proc { |arg| arg }.freeze
|
11
13
|
|
12
|
-
def initialize(
|
13
|
-
@
|
14
|
-
@
|
14
|
+
def initialize(*selector_args, options: {})
|
15
|
+
@selector_args = selector_args
|
16
|
+
@options = options
|
15
17
|
end
|
16
18
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
rescue Capybara::Ambiguous => e
|
26
|
-
raise AmbiguousQueryException, e.message
|
19
|
+
# TODO: - test for decoration?
|
20
|
+
# Run query against the scope of the given element
|
21
|
+
# The supplied block will be used to decorate the results
|
22
|
+
# @param [Capybara::Node::Element] capybara_element the element to be searched within
|
23
|
+
# @return [Array<Capybara::Node::Element>] the results
|
24
|
+
# @return [NullElement] when the element is not found
|
25
|
+
def execute(capybara_element, &block)
|
26
|
+
find(capybara_element, &(block || DEFAULT_DECORATOR))
|
27
27
|
rescue Capybara::ElementNotFound => e
|
28
|
-
|
28
|
+
NotFound.new(e)
|
29
29
|
end
|
30
30
|
|
31
31
|
def ==(other)
|
32
|
-
other.respond_to?(:
|
32
|
+
other.respond_to?(:selector_args) && selector_args == other.selector_args &&
|
33
|
+
other.respond_to?(:options) && options == other.options
|
33
34
|
end
|
34
35
|
end
|
35
36
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PageMagic
|
4
|
+
class Element
|
5
|
+
class Query
|
6
|
+
# class MultipleResults - use to query for multiple results
|
7
|
+
class MultipleResults < Query
|
8
|
+
# Find multiple elements
|
9
|
+
# The supplied block will be used to decorate the results
|
10
|
+
# @param [Capybara::Node::Element] capybara_element the element to be searched within
|
11
|
+
# @return [Array<Capybara::Node::Element>] the results
|
12
|
+
def find(capybara_element, &block)
|
13
|
+
results = capybara_element.all(*selector_args, **options).to_a.tap do |result|
|
14
|
+
raise Capybara::ElementNotFound if result.empty?
|
15
|
+
end
|
16
|
+
results.collect { |result| block.call(result) }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PageMagic
|
4
|
+
class Element
|
5
|
+
class Query
|
6
|
+
# class PrefetchedResult - used to return element that has already been retrieved
|
7
|
+
class PrefetchedResult < Query
|
8
|
+
def initialize(prefetched_element)
|
9
|
+
super
|
10
|
+
@prefetched_element = prefetched_element
|
11
|
+
end
|
12
|
+
|
13
|
+
# Returns the object provided to `initialize`
|
14
|
+
# The supplied block will be used to decorate the results
|
15
|
+
# @return [Capybara::Node::Element] the object supplied to `initialize`
|
16
|
+
def find(_capybara_element, &block)
|
17
|
+
block.call(prefetched_element)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
attr_reader :prefetched_element
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PageMagic
|
4
|
+
class Element
|
5
|
+
class Query
|
6
|
+
# class SingleResult - use to query when only one result should be expected
|
7
|
+
class SingleResult < Query
|
8
|
+
# Find an element
|
9
|
+
# The supplied block will be used to decorate the results
|
10
|
+
# @param [Capybara::Node::Element] capybara_element the element to be searched within
|
11
|
+
# @return [Object] the results
|
12
|
+
def find(capybara_element, &block)
|
13
|
+
block.call capybara_element.find(*selector_args, **options)
|
14
|
+
rescue Capybara::Ambiguous => e
|
15
|
+
raise AmbiguousQueryException, e.message
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -1,40 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'selector/model'
|
1
4
|
module PageMagic
|
5
|
+
# Capybara::Finder
|
2
6
|
class Element
|
3
7
|
# class Selector - models the selection criteria understood by Capybara
|
4
8
|
class Selector
|
5
9
|
class << self
|
6
|
-
# Find a
|
10
|
+
# Find a Selector using it's name
|
7
11
|
# @param [Symbol] name the name of the required Selector in snakecase format. See class constants for available
|
8
12
|
# selectors
|
9
13
|
# @return [Selector] returns the predefined selector with the given name
|
10
14
|
def find(name)
|
11
|
-
|
12
|
-
raise UnsupportedCriteriaException unless
|
13
|
-
|
15
|
+
selector_name = selector_constant_name(name)
|
16
|
+
raise UnsupportedCriteriaException unless selector_name
|
17
|
+
|
18
|
+
const_get(selector_name)
|
14
19
|
end
|
15
|
-
end
|
16
20
|
|
17
|
-
|
21
|
+
private
|
22
|
+
|
23
|
+
def selector_constant_name(name)
|
24
|
+
constants.find { |constant| constant.to_s.casecmp(name.to_s).zero? }
|
25
|
+
end
|
26
|
+
end
|
18
27
|
|
28
|
+
# Initialize a new selector
|
29
|
+
# a block can be supplied to decorate the query. E.g.
|
30
|
+
# @example
|
31
|
+
# Selector.new(supports_type: false) do |arg|
|
32
|
+
# "*[name='#{arg}']"
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# @param [Symbol] selector the identifier for the selector
|
36
|
+
# @param [Boolean] supports_type whether the element type being searched for can be used as part of the query
|
37
|
+
# @param [Boolean] exact whether an exact match is required. E.g. element should include exactly the same text
|
19
38
|
def initialize(selector = nil, supports_type: false, exact: false, &formatter)
|
20
|
-
@
|
39
|
+
@selector = selector
|
21
40
|
@formatter = formatter || proc { |arg| arg }
|
22
41
|
@supports_type = supports_type
|
23
|
-
@
|
42
|
+
@options = {}.tap do |hash|
|
43
|
+
hash[:exact] = true if exact
|
44
|
+
end
|
24
45
|
end
|
25
46
|
|
26
47
|
# Build selector query parameters for Capybara's find method
|
27
48
|
# @param [Symbol] element_type the type of browser element being found. e.g :link
|
28
|
-
# @param [Hash] locator the selection method and its parameter. E.g. text: 'click me'
|
29
|
-
def build(element_type, locator)
|
30
|
-
[].
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
49
|
+
# @param [Hash<Symbol,String>] locator the selection method and its parameter. E.g. text: 'click me'
|
50
|
+
def build(element_type, locator, options: {})
|
51
|
+
array = [type(element_type), selector, formatter.call(locator)].compact
|
52
|
+
Model.new(array, self.options.merge(options))
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def type(element_type)
|
58
|
+
supports_type ? element_type : nil
|
36
59
|
end
|
37
60
|
|
61
|
+
attr_reader :supports_type, :options, :selector, :formatter
|
62
|
+
|
38
63
|
XPATH = Selector.new(:xpath, supports_type: false)
|
39
64
|
ID = Selector.new(:id, supports_type: false)
|
40
65
|
LABEL = Selector.new(:field, supports_type: false, exact: true)
|