capybara 2.5.0 → 2.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (205) hide show
  1. checksums.yaml +5 -5
  2. data/.yard/templates_custom/default/class/html/selectors.erb +38 -0
  3. data/.yard/templates_custom/default/class/html/setup.rb +17 -0
  4. data/.yard/yard_extensions.rb +78 -0
  5. data/.yardopts +1 -0
  6. data/History.md +413 -10
  7. data/License.txt +1 -1
  8. data/README.md +237 -130
  9. data/lib/capybara/config.rb +132 -0
  10. data/lib/capybara/cucumber.rb +3 -1
  11. data/lib/capybara/driver/base.rb +27 -6
  12. data/lib/capybara/driver/node.rb +14 -5
  13. data/lib/capybara/dsl.rb +2 -3
  14. data/lib/capybara/helpers.rb +13 -65
  15. data/lib/capybara/minitest/spec.rb +177 -0
  16. data/lib/capybara/minitest.rb +278 -0
  17. data/lib/capybara/node/actions.rb +180 -24
  18. data/lib/capybara/node/base.rb +17 -5
  19. data/lib/capybara/node/document.rb +5 -0
  20. data/lib/capybara/node/document_matchers.rb +15 -14
  21. data/lib/capybara/node/element.rb +55 -7
  22. data/lib/capybara/node/finders.rb +179 -67
  23. data/lib/capybara/node/matchers.rb +301 -105
  24. data/lib/capybara/node/simple.rb +15 -4
  25. data/lib/capybara/queries/ancestor_query.rb +25 -0
  26. data/lib/capybara/queries/base_query.rb +69 -3
  27. data/lib/capybara/queries/current_path_query.rb +17 -8
  28. data/lib/capybara/queries/match_query.rb +19 -0
  29. data/lib/capybara/queries/selector_query.rb +251 -0
  30. data/lib/capybara/queries/sibling_query.rb +25 -0
  31. data/lib/capybara/queries/text_query.rb +67 -16
  32. data/lib/capybara/queries/title_query.rb +4 -2
  33. data/lib/capybara/query.rb +3 -131
  34. data/lib/capybara/rack_test/browser.rb +14 -5
  35. data/lib/capybara/rack_test/css_handlers.rb +1 -0
  36. data/lib/capybara/rack_test/driver.rb +15 -8
  37. data/lib/capybara/rack_test/form.rb +34 -12
  38. data/lib/capybara/rack_test/node.rb +29 -12
  39. data/lib/capybara/rails.rb +3 -3
  40. data/lib/capybara/result.rb +104 -9
  41. data/lib/capybara/rspec/compound.rb +95 -0
  42. data/lib/capybara/rspec/features.rb +17 -6
  43. data/lib/capybara/rspec/matcher_proxies.rb +45 -0
  44. data/lib/capybara/rspec/matchers.rb +199 -80
  45. data/lib/capybara/rspec.rb +4 -2
  46. data/lib/capybara/selector/css.rb +30 -0
  47. data/lib/capybara/selector/filter.rb +20 -0
  48. data/lib/capybara/selector/filter_set.rb +74 -0
  49. data/lib/capybara/selector/filters/base.rb +33 -0
  50. data/lib/capybara/selector/filters/expression_filter.rb +40 -0
  51. data/lib/capybara/selector/filters/node_filter.rb +27 -0
  52. data/lib/capybara/selector/selector.rb +276 -0
  53. data/lib/capybara/selector.rb +452 -157
  54. data/lib/capybara/selenium/driver.rb +282 -81
  55. data/lib/capybara/selenium/node.rb +144 -46
  56. data/lib/capybara/server.rb +59 -16
  57. data/lib/capybara/session/config.rb +114 -0
  58. data/lib/capybara/session/matchers.rb +29 -19
  59. data/lib/capybara/session.rb +378 -143
  60. data/lib/capybara/spec/fixtures/no_extension +1 -0
  61. data/lib/capybara/spec/public/jquery-ui.js +13 -791
  62. data/lib/capybara/spec/public/jquery.js +4 -9045
  63. data/lib/capybara/spec/public/test.js +45 -11
  64. data/lib/capybara/spec/session/accept_alert_spec.rb +30 -7
  65. data/lib/capybara/spec/session/accept_confirm_spec.rb +14 -2
  66. data/lib/capybara/spec/session/accept_prompt_spec.rb +35 -6
  67. data/lib/capybara/spec/session/all_spec.rb +45 -32
  68. data/lib/capybara/spec/session/ancestor_spec.rb +85 -0
  69. data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +110 -0
  70. data/lib/capybara/spec/session/assert_current_path.rb +15 -2
  71. data/lib/capybara/spec/session/assert_selector.rb +29 -28
  72. data/lib/capybara/spec/session/assert_text.rb +59 -20
  73. data/lib/capybara/spec/session/assert_title.rb +25 -11
  74. data/lib/capybara/spec/session/attach_file_spec.rb +42 -4
  75. data/lib/capybara/spec/session/body_spec.rb +1 -0
  76. data/lib/capybara/spec/session/check_spec.rb +90 -14
  77. data/lib/capybara/spec/session/choose_spec.rb +31 -5
  78. data/lib/capybara/spec/session/click_button_spec.rb +20 -9
  79. data/lib/capybara/spec/session/click_link_or_button_spec.rb +15 -9
  80. data/lib/capybara/spec/session/click_link_spec.rb +39 -15
  81. data/lib/capybara/spec/session/current_scope_spec.rb +2 -1
  82. data/lib/capybara/spec/session/current_url_spec.rb +12 -3
  83. data/lib/capybara/spec/session/dismiss_confirm_spec.rb +6 -5
  84. data/lib/capybara/spec/session/dismiss_prompt_spec.rb +4 -3
  85. data/lib/capybara/spec/session/element/assert_match_selector.rb +36 -0
  86. data/lib/capybara/spec/session/element/match_css_spec.rb +23 -0
  87. data/lib/capybara/spec/session/element/match_xpath_spec.rb +23 -0
  88. data/lib/capybara/spec/session/element/matches_selector_spec.rb +106 -0
  89. data/lib/capybara/spec/session/evaluate_async_script_spec.rb +22 -0
  90. data/lib/capybara/spec/session/evaluate_script_spec.rb +23 -1
  91. data/lib/capybara/spec/session/execute_script_spec.rb +22 -3
  92. data/lib/capybara/spec/session/fill_in_spec.rb +50 -32
  93. data/lib/capybara/spec/session/find_button_spec.rb +43 -2
  94. data/lib/capybara/spec/session/find_by_id_spec.rb +3 -2
  95. data/lib/capybara/spec/session/find_field_spec.rb +42 -6
  96. data/lib/capybara/spec/session/find_link_spec.rb +22 -3
  97. data/lib/capybara/spec/session/find_spec.rb +103 -57
  98. data/lib/capybara/spec/session/first_spec.rb +34 -18
  99. data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +103 -0
  100. data/lib/capybara/spec/session/{within_frame_spec.rb → frame/within_frame_spec.rb} +44 -2
  101. data/lib/capybara/spec/session/go_back_spec.rb +2 -1
  102. data/lib/capybara/spec/session/go_forward_spec.rb +2 -1
  103. data/lib/capybara/spec/session/has_all_selectors_spec.rb +69 -0
  104. data/lib/capybara/spec/session/has_button_spec.rb +17 -8
  105. data/lib/capybara/spec/session/has_css_spec.rb +85 -73
  106. data/lib/capybara/spec/session/has_current_path_spec.rb +91 -7
  107. data/lib/capybara/spec/session/has_field_spec.rb +93 -58
  108. data/lib/capybara/spec/session/has_link_spec.rb +9 -8
  109. data/lib/capybara/spec/session/has_none_selectors_spec.rb +76 -0
  110. data/lib/capybara/spec/session/has_select_spec.rb +159 -59
  111. data/lib/capybara/spec/session/has_selector_spec.rb +64 -28
  112. data/lib/capybara/spec/session/has_table_spec.rb +1 -0
  113. data/lib/capybara/spec/session/has_text_spec.rb +27 -12
  114. data/lib/capybara/spec/session/has_title_spec.rb +22 -4
  115. data/lib/capybara/spec/session/has_xpath_spec.rb +32 -29
  116. data/lib/capybara/spec/session/headers.rb +2 -1
  117. data/lib/capybara/spec/session/html_spec.rb +4 -3
  118. data/lib/capybara/spec/session/node_spec.rb +198 -38
  119. data/lib/capybara/spec/session/refresh_spec.rb +28 -0
  120. data/lib/capybara/spec/session/reset_session_spec.rb +46 -5
  121. data/lib/capybara/spec/session/response_code.rb +2 -1
  122. data/lib/capybara/spec/session/save_and_open_page_spec.rb +1 -0
  123. data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +6 -5
  124. data/lib/capybara/spec/session/save_page_spec.rb +34 -2
  125. data/lib/capybara/spec/session/save_screenshot_spec.rb +31 -1
  126. data/lib/capybara/spec/session/screenshot_spec.rb +4 -2
  127. data/lib/capybara/spec/session/select_spec.rb +34 -32
  128. data/lib/capybara/spec/session/selectors_spec.rb +65 -0
  129. data/lib/capybara/spec/session/sibling_spec.rb +52 -0
  130. data/lib/capybara/spec/session/text_spec.rb +4 -4
  131. data/lib/capybara/spec/session/title_spec.rb +2 -1
  132. data/lib/capybara/spec/session/uncheck_spec.rb +42 -2
  133. data/lib/capybara/spec/session/unselect_spec.rb +17 -16
  134. data/lib/capybara/spec/session/visit_spec.rb +77 -2
  135. data/lib/capybara/spec/session/window/become_closed_spec.rb +12 -11
  136. data/lib/capybara/spec/session/window/current_window_spec.rb +1 -0
  137. data/lib/capybara/spec/session/window/open_new_window_spec.rb +1 -0
  138. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +16 -11
  139. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +7 -4
  140. data/lib/capybara/spec/session/window/window_spec.rb +36 -29
  141. data/lib/capybara/spec/session/window/windows_spec.rb +1 -0
  142. data/lib/capybara/spec/session/window/within_window_spec.rb +31 -7
  143. data/lib/capybara/spec/session/within_spec.rb +14 -6
  144. data/lib/capybara/spec/spec_helper.rb +37 -4
  145. data/lib/capybara/spec/test_app.rb +15 -3
  146. data/lib/capybara/spec/views/buttons.erb +1 -0
  147. data/lib/capybara/spec/views/fieldsets.erb +2 -1
  148. data/lib/capybara/spec/views/form.erb +169 -9
  149. data/lib/capybara/spec/views/frame_child.erb +10 -2
  150. data/lib/capybara/spec/views/frame_one.erb +2 -1
  151. data/lib/capybara/spec/views/frame_parent.erb +3 -2
  152. data/lib/capybara/spec/views/frame_two.erb +2 -1
  153. data/lib/capybara/spec/views/header_links.erb +1 -0
  154. data/lib/capybara/spec/views/host_links.erb +1 -0
  155. data/lib/capybara/spec/views/initial_alert.erb +10 -0
  156. data/lib/capybara/spec/views/path.erb +1 -0
  157. data/lib/capybara/spec/views/popup_one.erb +1 -0
  158. data/lib/capybara/spec/views/popup_two.erb +1 -0
  159. data/lib/capybara/spec/views/postback.erb +2 -1
  160. data/lib/capybara/spec/views/tables.erb +1 -0
  161. data/lib/capybara/spec/views/with_base_tag.erb +1 -0
  162. data/lib/capybara/spec/views/with_count.erb +2 -1
  163. data/lib/capybara/spec/views/with_fixed_header_footer.erb +17 -0
  164. data/lib/capybara/spec/views/with_hover.erb +7 -1
  165. data/lib/capybara/spec/views/with_html.erb +40 -2
  166. data/lib/capybara/spec/views/with_html_entities.erb +1 -0
  167. data/lib/capybara/spec/views/with_js.erb +32 -1
  168. data/lib/capybara/spec/views/with_scope.erb +1 -0
  169. data/lib/capybara/spec/views/with_simple_html.erb +2 -1
  170. data/lib/capybara/spec/views/with_slow_unload.erb +17 -0
  171. data/lib/capybara/spec/views/with_title.erb +2 -1
  172. data/lib/capybara/spec/views/with_unload_alert.erb +14 -0
  173. data/lib/capybara/spec/views/with_windows.erb +7 -0
  174. data/lib/capybara/spec/views/within_frames.erb +3 -2
  175. data/lib/capybara/version.rb +2 -1
  176. data/lib/capybara/window.rb +20 -3
  177. data/lib/capybara.rb +189 -93
  178. data/spec/basic_node_spec.rb +7 -6
  179. data/spec/capybara_spec.rb +90 -4
  180. data/spec/dsl_spec.rb +3 -1
  181. data/spec/filter_set_spec.rb +28 -0
  182. data/spec/fixtures/capybara.csv +1 -0
  183. data/spec/fixtures/selenium_driver_rspec_failure.rb +5 -1
  184. data/spec/fixtures/selenium_driver_rspec_success.rb +5 -1
  185. data/spec/minitest_spec.rb +130 -0
  186. data/spec/minitest_spec_spec.rb +135 -0
  187. data/spec/per_session_config_spec.rb +67 -0
  188. data/spec/rack_test_spec.rb +50 -7
  189. data/spec/result_spec.rb +76 -0
  190. data/spec/rspec/features_spec.rb +21 -8
  191. data/spec/rspec/scenarios_spec.rb +21 -0
  192. data/spec/rspec/{matchers_spec.rb → shared_spec_matchers.rb} +160 -54
  193. data/spec/rspec/views_spec.rb +5 -0
  194. data/spec/rspec_matchers_spec.rb +46 -0
  195. data/spec/rspec_spec.rb +79 -1
  196. data/spec/selector_spec.rb +199 -0
  197. data/spec/selenium_spec_chrome.rb +54 -9
  198. data/spec/selenium_spec_firefox.rb +68 -0
  199. data/spec/selenium_spec_marionette.rb +127 -0
  200. data/spec/server_spec.rb +102 -14
  201. data/spec/session_spec.rb +54 -0
  202. data/spec/shared_selenium_session.rb +215 -0
  203. data/spec/spec_helper.rb +7 -0
  204. metadata +140 -15
  205. data/spec/selenium_spec.rb +0 -128
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+ require 'capybara/selector/filter'
3
+
4
+ module Capybara
5
+ class Selector
6
+ class FilterSet
7
+ attr_reader :descriptions
8
+
9
+ def initialize(name, &block)
10
+ @name = name
11
+ @descriptions = []
12
+ instance_eval(&block)
13
+ end
14
+
15
+ def filter(name, *types_and_options, &block)
16
+ add_filter(name, Filters::NodeFilter, *types_and_options, &block)
17
+ end
18
+
19
+ def expression_filter(name, *types_and_options, &block)
20
+ add_filter(name, Filters::ExpressionFilter, *types_and_options, &block)
21
+ end
22
+
23
+ def describe(&block)
24
+ descriptions.push block
25
+ end
26
+
27
+ def description(options={})
28
+ options_with_defaults = options.dup
29
+ filters.each do |name, filter|
30
+ options_with_defaults[name] = filter.default if filter.default? && !options_with_defaults.has_key?(name)
31
+ end
32
+
33
+ @descriptions.map do |desc|
34
+ desc.call(options_with_defaults).to_s
35
+ end.join
36
+ end
37
+
38
+ def filters
39
+ @filters ||= {}
40
+ end
41
+
42
+ def node_filters
43
+ filters.reject { |_n, f| f.nil? || f.is_a?(Filters::ExpressionFilter) }.freeze
44
+ end
45
+
46
+ def expression_filters
47
+ filters.select { |_n, f| f.nil? || f.is_a?(Filters::ExpressionFilter) }.freeze
48
+ end
49
+
50
+ class << self
51
+
52
+ def all
53
+ @filter_sets ||= {}
54
+ end
55
+
56
+ def add(name, &block)
57
+ all[name.to_sym] = FilterSet.new(name.to_sym, &block)
58
+ end
59
+
60
+ def remove(name)
61
+ all.delete(name.to_sym)
62
+ end
63
+ end
64
+
65
+ private
66
+
67
+ def add_filter(name, filter_class, *types_and_options, &block)
68
+ options = types_and_options.last.is_a?(Hash) ? types_and_options.pop.dup : {}
69
+ types_and_options.each { |k| options[k] = true}
70
+ filters[name] = filter_class.new(name, block, options)
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+ module Capybara
3
+ class Selector
4
+ module Filters
5
+ class Base
6
+ def initialize(name, block, options={})
7
+ @name = name
8
+ @block = block
9
+ @options = options
10
+ @options[:valid_values] = [true,false] if options[:boolean]
11
+ end
12
+
13
+ def default?
14
+ @options.has_key?(:default)
15
+ end
16
+
17
+ def default
18
+ @options[:default]
19
+ end
20
+
21
+ def skip?(value)
22
+ @options.has_key?(:skip_if) && value == @options[:skip_if]
23
+ end
24
+
25
+ private
26
+
27
+ def valid_value?(value)
28
+ !@options.has_key?(:valid_values) || Array(@options[:valid_values]).include?(value)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+ require 'capybara/selector/filters/base'
3
+
4
+ module Capybara
5
+ class Selector
6
+ module Filters
7
+ class ExpressionFilter < Base
8
+ def apply_filter(expr, value)
9
+ return expr if skip?(value)
10
+
11
+ if !valid_value?(value)
12
+ msg = "Invalid value #{value.inspect} passed to expression filter #{@name} - "
13
+ if default?
14
+ warn msg + "defaulting to #{default}"
15
+ value = default
16
+ else
17
+ warn msg + "skipping"
18
+ return expr
19
+ end
20
+ end
21
+
22
+ @block.call(expr, value)
23
+ end
24
+ end
25
+
26
+ class IdentityExpressionFilter < ExpressionFilter
27
+ def initialize
28
+ end
29
+
30
+ def default?
31
+ false
32
+ end
33
+
34
+ def apply_filter(expr, _value)
35
+ return expr
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+ require 'capybara/selector/filters/base'
3
+
4
+ module Capybara
5
+ class Selector
6
+ module Filters
7
+ class NodeFilter < Base
8
+ def matches?(node, value)
9
+ return true if skip?(value)
10
+
11
+ if !valid_value?(value)
12
+ msg = "Invalid value #{value.inspect} passed to filter #{@name} - "
13
+ if default?
14
+ warn msg + "defaulting to #{default}"
15
+ value = default
16
+ else
17
+ warn msg + "skipping"
18
+ return true
19
+ end
20
+ end
21
+
22
+ @block.call(node, value)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,276 @@
1
+ # frozen_string_literal: true
2
+ require 'capybara/selector/filter_set'
3
+ require 'capybara/selector/css'
4
+ require 'xpath'
5
+
6
+ #Patch XPath to allow a nil condition in where
7
+ module XPath
8
+ class Renderer
9
+ undef :where if method_defined?(:where)
10
+ def where(on, condition)
11
+ condition = condition.to_s
12
+ if !condition.empty?
13
+ "#{on}[#{condition}]"
14
+ else
15
+ "#{on}"
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ module Capybara
22
+ class Selector
23
+
24
+ attr_reader :name, :format
25
+
26
+ class << self
27
+ def all
28
+ @selectors ||= {}
29
+ end
30
+
31
+ def add(name, &block)
32
+ all[name.to_sym] = Capybara::Selector.new(name.to_sym, &block)
33
+ end
34
+
35
+ def update(name, &block)
36
+ all[name.to_sym].instance_eval(&block)
37
+ end
38
+
39
+ def remove(name)
40
+ all.delete(name.to_sym)
41
+ end
42
+ end
43
+
44
+ def initialize(name, &block)
45
+ @name = name
46
+ @filter_set = FilterSet.add(name){}
47
+ @match = nil
48
+ @label = nil
49
+ @failure_message = nil
50
+ @description = nil
51
+ @format = nil
52
+ @expression = nil
53
+ @expression_filters = {}
54
+ @default_visibility = nil
55
+ instance_eval(&block)
56
+ end
57
+
58
+ def custom_filters
59
+ @filter_set.filters
60
+ end
61
+
62
+ def node_filters
63
+ @filter_set.node_filters
64
+ end
65
+
66
+ def expression_filters
67
+ @filter_set.expression_filters
68
+ end
69
+
70
+ ##
71
+ #
72
+ # Define a selector by an xpath expression
73
+ #
74
+ # @overload xpath(*expression_filters, &block)
75
+ # @param [Array<Symbol>] expression_filters ([]) Names of filters that can be implemented via this expression
76
+ # @yield [locator, options] The block to use to generate the XPath expression
77
+ # @yieldparam [String] locator The locator string passed to the query
78
+ # @yieldparam [Hash] options The options hash passed to the query
79
+ # @yieldreturn [#to_xpath, #to_s] An object that can produce an xpath expression
80
+ #
81
+ # @overload xpath()
82
+ # @return [#call] The block that will be called to generate the XPath expression
83
+ #
84
+ def xpath(*expression_filters, &block)
85
+ if block
86
+ @format, @expression = :xpath, block
87
+ expression_filters.flatten.each { |ef| custom_filters[ef] = Filters::IdentityExpressionFilter.new }
88
+ end
89
+ format == :xpath ? @expression : nil
90
+ end
91
+
92
+ ##
93
+ #
94
+ # Define a selector by a CSS selector
95
+ #
96
+ # @overload css(*expression_filters, &block)
97
+ # @param [Array<Symbol>] expression_filters ([]) Names of filters that can be implemented via this CSS selector
98
+ # @yield [locator, options] The block to use to generate the CSS selector
99
+ # @yieldparam [String] locator The locator string passed to the query
100
+ # @yieldparam [Hash] options The options hash passed to the query
101
+ # @yieldreturn [#to_s] An object that can produce a CSS selector
102
+ #
103
+ # @overload css()
104
+ # @return [#call] The block that will be called to generate the CSS selector
105
+ #
106
+ def css(*expression_filters, &block)
107
+ if block
108
+ @format, @expression = :css, block
109
+ expression_filters.flatten.each { |ef| custom_filters[ef] = nil }
110
+ end
111
+ format == :css ? @expression : nil
112
+ end
113
+
114
+ ##
115
+ #
116
+ # Automatic selector detection
117
+ #
118
+ # @yield [locator] This block takes the passed in locator string and returns whether or not it matches the selector
119
+ # @yieldparam [String], locator The locator string used to determin if it matches the selector
120
+ # @yieldreturn [Boolean] Whether this selector matches the locator string
121
+ # @return [#call] The block that will be used to detect selector match
122
+ #
123
+ def match(&block)
124
+ @match = block if block
125
+ @match
126
+ end
127
+
128
+ ##
129
+ #
130
+ # Set/get a descriptive label for the selector
131
+ #
132
+ # @overload label(label)
133
+ # @param [String] label A descriptive label for this selector - used in error messages
134
+ # @overload label()
135
+ # @return [String] The currently set label
136
+ #
137
+ def label(label=nil)
138
+ @label = label if label
139
+ @label
140
+ end
141
+
142
+ ##
143
+ #
144
+ # Description of the selector
145
+ #
146
+ # @param [Hash] options The options of the query used to generate the description
147
+ # @return [String] Description of the selector when used with the options passed
148
+ #
149
+ def description(options={})
150
+ @filter_set.description(options)
151
+ end
152
+
153
+ def call(locator, options={})
154
+ if format
155
+ # @expression.call(locator, options.select {|k,v| @expression_filters.include?(k)})
156
+ @expression.call(locator, options)
157
+ else
158
+ warn "Selector has no format"
159
+ end
160
+ end
161
+
162
+ ##
163
+ #
164
+ # Should this selector be used for the passed in locator
165
+ #
166
+ # This is used by the automatic selector selection mechanism when no selector type is passed to a selector query
167
+ #
168
+ # @param [String] locator The locator passed to the query
169
+ # @return [Boolean] Whether or not to use this selector
170
+ #
171
+ def match?(locator)
172
+ @match and @match.call(locator)
173
+ end
174
+
175
+ ##
176
+ #
177
+ # Define a non-expression filter for use with this selector
178
+ #
179
+ # @overload filter(name, *types, options={}, &block)
180
+ # @param [Symbol] name The filter name
181
+ # @param [Array<Symbol>] types The types of the filter - currently valid types are [:boolean]
182
+ # @param [Hash] options ({}) Options of the filter
183
+ # @option options [Array<>] :valid_values Valid values for this filter
184
+ # @option options :default The default value of the filter (if any)
185
+ # @option options :skip_if Value of the filter that will cause it to be skipped
186
+ #
187
+ def filter(name, *types_and_options, &block)
188
+ options = types_and_options.last.is_a?(Hash) ? types_and_options.pop.dup : {}
189
+ types_and_options.each { |k| options[k] = true }
190
+ custom_filters[name] = Filters::NodeFilter.new(name, block, options)
191
+ end
192
+
193
+ def expression_filter(name, *types_and_options, &block)
194
+ options = types_and_options.last.is_a?(Hash) ? types_and_options.pop.dup : {}
195
+ types_and_options.each { |k| options[k] = true }
196
+ custom_filters[name] = Filters::ExpressionFilter.new(name, block, options)
197
+ end
198
+
199
+ def filter_set(name, filters_to_use = nil)
200
+ f_set = FilterSet.all[name]
201
+ f_set.filters.each do |n, filter|
202
+ custom_filters[n] = filter if filters_to_use.nil? || filters_to_use.include?(n)
203
+ end
204
+
205
+ f_set.descriptions.each { |desc| @filter_set.describe(&desc) }
206
+ end
207
+
208
+ def describe &block
209
+ @filter_set.describe(&block)
210
+ end
211
+
212
+ ##
213
+ #
214
+ # Set the default visibility mode that shouble be used if no visibile option is passed when using the selector.
215
+ # If not specified will default to the behavior indicated by Capybara.ignore_hidden_elements
216
+ #
217
+ # @param [Symbol] default_visibility Only find elements with the specified visibility:
218
+ # * :all - finds visible and invisible elements.
219
+ # * :hidden - only finds invisible elements.
220
+ # * :visible - only finds visible elements.
221
+ def visible(default_visibility)
222
+ @default_visibility = default_visibility
223
+ end
224
+
225
+ def default_visibility(fallback = Capybara.ignore_hidden_elements)
226
+ if @default_visibility.nil?
227
+ fallback
228
+ else
229
+ @default_visibility
230
+ end
231
+ end
232
+
233
+ private
234
+
235
+ def locate_field(xpath, locator, options={})
236
+ locate_xpath = xpath #need to save original xpath for the label wrap
237
+ if locator
238
+ locator = locator.to_s
239
+ attr_matchers = XPath.attr(:id).equals(locator).or(
240
+ XPath.attr(:name).equals(locator)).or(
241
+ XPath.attr(:placeholder).equals(locator)).or(
242
+ XPath.attr(:id).equals(XPath.anywhere(:label)[XPath.string.n.is(locator)].attr(:for)))
243
+ attr_matchers = attr_matchers.or XPath.attr(:'aria-label').is(locator) if options[:enable_aria_label]
244
+
245
+ locate_xpath = locate_xpath[attr_matchers]
246
+ locate_xpath = locate_xpath.union(XPath.descendant(:label)[XPath.string.n.is(locator)].descendant(xpath))
247
+ end
248
+
249
+ # locate_xpath = [:name, :placeholder].inject(locate_xpath) { |memo, ef| memo[find_by_attr(ef, options[ef])] }
250
+ locate_xpath
251
+ end
252
+
253
+ def describe_all_expression_filters(opts={})
254
+ expression_filters.map { |ef| " with #{ef} #{opts[ef]}" if opts.has_key?(ef) }.join
255
+ end
256
+
257
+ def find_by_attr(attribute, value)
258
+ finder_name = "find_by_#{attribute}_attr"
259
+ if respond_to?(finder_name, true)
260
+ send(finder_name, value)
261
+ else
262
+ value ? XPath.attr(attribute).equals(value) : nil
263
+ end
264
+ end
265
+
266
+ def find_by_class_attr(classes)
267
+ if classes
268
+ Array(classes).map do |klass|
269
+ "contains(concat(' ',normalize-space(@class),' '),' #{klass} ')"
270
+ end.join(" and ").to_sym
271
+ else
272
+ nil
273
+ end
274
+ end
275
+ end
276
+ end