capybara 2.18.0 → 3.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (168) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +26 -1
  3. data/README.md +12 -12
  4. data/lib/capybara.rb +13 -25
  5. data/lib/capybara/config.rb +11 -57
  6. data/lib/capybara/cucumber.rb +2 -3
  7. data/lib/capybara/driver/base.rb +5 -16
  8. data/lib/capybara/driver/node.rb +5 -4
  9. data/lib/capybara/dsl.rb +1 -0
  10. data/lib/capybara/helpers.rb +16 -28
  11. data/lib/capybara/minitest.rb +139 -138
  12. data/lib/capybara/minitest/spec.rb +15 -14
  13. data/lib/capybara/node/actions.rb +59 -81
  14. data/lib/capybara/node/base.rb +11 -18
  15. data/lib/capybara/node/document.rb +2 -2
  16. data/lib/capybara/node/document_matchers.rb +8 -8
  17. data/lib/capybara/node/element.rb +30 -40
  18. data/lib/capybara/node/finders.rb +62 -70
  19. data/lib/capybara/node/matchers.rb +48 -71
  20. data/lib/capybara/node/simple.rb +11 -17
  21. data/lib/capybara/queries/ancestor_query.rb +4 -6
  22. data/lib/capybara/queries/base_query.rb +18 -17
  23. data/lib/capybara/queries/current_path_query.rb +8 -24
  24. data/lib/capybara/queries/match_query.rb +3 -7
  25. data/lib/capybara/queries/selector_query.rb +92 -95
  26. data/lib/capybara/queries/sibling_query.rb +4 -4
  27. data/lib/capybara/queries/text_query.rb +37 -34
  28. data/lib/capybara/queries/title_query.rb +8 -11
  29. data/lib/capybara/rack_test/browser.rb +15 -18
  30. data/lib/capybara/rack_test/css_handlers.rb +6 -4
  31. data/lib/capybara/rack_test/driver.rb +6 -10
  32. data/lib/capybara/rack_test/form.rb +50 -40
  33. data/lib/capybara/rack_test/node.rb +70 -56
  34. data/lib/capybara/rails.rb +2 -6
  35. data/lib/capybara/result.rb +22 -22
  36. data/lib/capybara/rspec.rb +5 -10
  37. data/lib/capybara/rspec/compound.rb +5 -10
  38. data/lib/capybara/rspec/features.rb +17 -48
  39. data/lib/capybara/rspec/matcher_proxies.rb +31 -15
  40. data/lib/capybara/rspec/matchers.rb +70 -60
  41. data/lib/capybara/selector.rb +129 -117
  42. data/lib/capybara/selector/css.rb +6 -11
  43. data/lib/capybara/selector/filter.rb +1 -17
  44. data/lib/capybara/selector/filter_set.rb +17 -14
  45. data/lib/capybara/selector/filters/base.rb +7 -6
  46. data/lib/capybara/selector/filters/expression_filter.rb +6 -23
  47. data/lib/capybara/selector/filters/node_filter.rb +2 -12
  48. data/lib/capybara/selector/selector.rb +27 -33
  49. data/lib/capybara/selenium/driver.rb +113 -127
  50. data/lib/capybara/selenium/node.rb +148 -113
  51. data/lib/capybara/server.rb +3 -2
  52. data/lib/capybara/session.rb +137 -223
  53. data/lib/capybara/session/config.rb +47 -67
  54. data/lib/capybara/session/matchers.rb +8 -7
  55. data/lib/capybara/spec/public/test.js +26 -4
  56. data/lib/capybara/spec/session/accept_alert_spec.rb +1 -0
  57. data/lib/capybara/spec/session/accept_confirm_spec.rb +3 -2
  58. data/lib/capybara/spec/session/accept_prompt_spec.rb +1 -0
  59. data/lib/capybara/spec/session/all_spec.rb +31 -18
  60. data/lib/capybara/spec/session/ancestor_spec.rb +2 -4
  61. data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +6 -5
  62. data/lib/capybara/spec/session/assert_current_path.rb +12 -11
  63. data/lib/capybara/spec/session/assert_selector.rb +1 -0
  64. data/lib/capybara/spec/session/assert_text.rb +18 -17
  65. data/lib/capybara/spec/session/assert_title.rb +1 -0
  66. data/lib/capybara/spec/session/attach_file_spec.rb +14 -13
  67. data/lib/capybara/spec/session/body_spec.rb +1 -0
  68. data/lib/capybara/spec/session/check_spec.rb +7 -6
  69. data/lib/capybara/spec/session/choose_spec.rb +5 -4
  70. data/lib/capybara/spec/session/click_button_spec.rb +20 -28
  71. data/lib/capybara/spec/session/click_link_or_button_spec.rb +8 -7
  72. data/lib/capybara/spec/session/click_link_spec.rb +8 -7
  73. data/lib/capybara/spec/session/current_scope_spec.rb +4 -3
  74. data/lib/capybara/spec/session/current_url_spec.rb +7 -6
  75. data/lib/capybara/spec/session/dismiss_confirm_spec.rb +1 -1
  76. data/lib/capybara/spec/session/dismiss_prompt_spec.rb +1 -0
  77. data/lib/capybara/spec/session/element/assert_match_selector.rb +1 -1
  78. data/lib/capybara/spec/session/element/match_xpath_spec.rb +1 -1
  79. data/lib/capybara/spec/session/element/matches_selector_spec.rb +5 -5
  80. data/lib/capybara/spec/session/evaluate_async_script_spec.rb +3 -2
  81. data/lib/capybara/spec/session/evaluate_script_spec.rb +4 -3
  82. data/lib/capybara/spec/session/execute_script_spec.rb +4 -3
  83. data/lib/capybara/spec/session/fill_in_spec.rb +6 -5
  84. data/lib/capybara/spec/session/find_button_spec.rb +4 -3
  85. data/lib/capybara/spec/session/find_by_id_spec.rb +2 -1
  86. data/lib/capybara/spec/session/find_field_spec.rb +8 -14
  87. data/lib/capybara/spec/session/find_link_spec.rb +6 -5
  88. data/lib/capybara/spec/session/find_spec.rb +37 -31
  89. data/lib/capybara/spec/session/first_spec.rb +60 -33
  90. data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +2 -1
  91. data/lib/capybara/spec/session/frame/within_frame_spec.rb +9 -16
  92. data/lib/capybara/spec/session/go_back_spec.rb +1 -0
  93. data/lib/capybara/spec/session/go_forward_spec.rb +1 -0
  94. data/lib/capybara/spec/session/has_all_selectors_spec.rb +15 -15
  95. data/lib/capybara/spec/session/has_button_spec.rb +2 -1
  96. data/lib/capybara/spec/session/has_css_spec.rb +3 -2
  97. data/lib/capybara/spec/session/has_current_path_spec.rb +12 -28
  98. data/lib/capybara/spec/session/has_field_spec.rb +4 -3
  99. data/lib/capybara/spec/session/has_link_spec.rb +1 -0
  100. data/lib/capybara/spec/session/has_none_selectors_spec.rb +17 -17
  101. data/lib/capybara/spec/session/has_select_spec.rb +30 -29
  102. data/lib/capybara/spec/session/has_selector_spec.rb +5 -4
  103. data/lib/capybara/spec/session/has_table_spec.rb +2 -1
  104. data/lib/capybara/spec/session/has_text_spec.rb +6 -5
  105. data/lib/capybara/spec/session/has_title_spec.rb +1 -0
  106. data/lib/capybara/spec/session/has_xpath_spec.rb +1 -0
  107. data/lib/capybara/spec/session/headers.rb +2 -1
  108. data/lib/capybara/spec/session/html_spec.rb +1 -0
  109. data/lib/capybara/spec/session/node_spec.rb +91 -56
  110. data/lib/capybara/spec/session/node_wrapper_spec.rb +36 -0
  111. data/lib/capybara/spec/session/refresh_spec.rb +4 -2
  112. data/lib/capybara/spec/session/reset_session_spec.rb +1 -0
  113. data/lib/capybara/spec/session/response_code.rb +1 -0
  114. data/lib/capybara/spec/session/save_and_open_page_spec.rb +1 -0
  115. data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +6 -11
  116. data/lib/capybara/spec/session/save_page_spec.rb +1 -17
  117. data/lib/capybara/spec/session/save_screenshot_spec.rb +1 -1
  118. data/lib/capybara/spec/session/select_spec.rb +20 -20
  119. data/lib/capybara/spec/session/selectors_spec.rb +2 -2
  120. data/lib/capybara/spec/session/sibling_spec.rb +1 -1
  121. data/lib/capybara/spec/session/text_spec.rb +1 -0
  122. data/lib/capybara/spec/session/title_spec.rb +1 -1
  123. data/lib/capybara/spec/session/uncheck_spec.rb +4 -3
  124. data/lib/capybara/spec/session/unselect_spec.rb +6 -5
  125. data/lib/capybara/spec/session/visit_spec.rb +9 -3
  126. data/lib/capybara/spec/session/window/become_closed_spec.rb +2 -1
  127. data/lib/capybara/spec/session/window/current_window_spec.rb +1 -0
  128. data/lib/capybara/spec/session/window/open_new_window_spec.rb +1 -0
  129. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +2 -1
  130. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +2 -1
  131. data/lib/capybara/spec/session/window/window_spec.rb +12 -12
  132. data/lib/capybara/spec/session/window/windows_spec.rb +2 -3
  133. data/lib/capybara/spec/session/window/within_window_spec.rb +13 -68
  134. data/lib/capybara/spec/session/within_spec.rb +1 -0
  135. data/lib/capybara/spec/spec_helper.rb +26 -18
  136. data/lib/capybara/spec/test_app.rb +8 -9
  137. data/lib/capybara/spec/views/form.erb +1 -0
  138. data/lib/capybara/spec/views/with_html.erb +3 -1
  139. data/lib/capybara/spec/views/within_frames.erb +4 -1
  140. data/lib/capybara/version.rb +2 -1
  141. data/lib/capybara/window.rb +6 -10
  142. data/spec/basic_node_spec.rb +1 -0
  143. data/spec/capybara_spec.rb +9 -32
  144. data/spec/dsl_spec.rb +5 -13
  145. data/spec/filter_set_spec.rb +5 -4
  146. data/spec/fixtures/selenium_driver_rspec_failure.rb +2 -1
  147. data/spec/fixtures/selenium_driver_rspec_success.rb +3 -2
  148. data/spec/minitest_spec.rb +4 -3
  149. data/spec/minitest_spec_spec.rb +3 -2
  150. data/spec/per_session_config_spec.rb +9 -8
  151. data/spec/rack_test_spec.rb +21 -20
  152. data/spec/result_spec.rb +17 -16
  153. data/spec/rspec/features_spec.rb +17 -14
  154. data/spec/rspec/scenarios_spec.rb +5 -7
  155. data/spec/rspec/shared_spec_matchers.rb +96 -99
  156. data/spec/rspec/views_spec.rb +2 -1
  157. data/spec/rspec_matchers_spec.rb +19 -2
  158. data/spec/rspec_spec.rb +11 -15
  159. data/spec/selector_spec.rb +5 -6
  160. data/spec/selenium_spec_chrome.rb +7 -4
  161. data/spec/selenium_spec_marionette.rb +26 -12
  162. data/spec/server_spec.rb +33 -33
  163. data/spec/session_spec.rb +2 -1
  164. data/spec/shared_selenium_session.rb +27 -21
  165. data/spec/spec_helper.rb +2 -5
  166. metadata +66 -87
  167. data/lib/capybara/query.rb +0 -7
  168. data/spec/selenium_spec_firefox.rb +0 -68
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Capybara
3
4
  module Node
4
-
5
5
  ##
6
6
  #
7
7
  # A {Capybara::Node::Simple} is a simpler version of {Capybara::Node::Base} which
@@ -28,7 +28,7 @@ module Capybara
28
28
  #
29
29
  # @return [String] The text of the element
30
30
  #
31
- def text(type=nil)
31
+ def text(_type = nil)
32
32
  native.text
33
33
  end
34
34
 
@@ -45,7 +45,7 @@ module Capybara
45
45
  attr_name = name.to_s
46
46
  if attr_name == 'value'
47
47
  value
48
- elsif 'input' == tag_name and 'checkbox' == native[:type] and 'checked' == attr_name
48
+ elsif tag_name == 'input' and native[:type] == 'checkbox' and attr_name == 'checked'
49
49
  native['checked'] == 'checked'
50
50
  else
51
51
  native[attr_name]
@@ -79,12 +79,12 @@ module Capybara
79
79
  native['_capybara_raw_value']
80
80
  elsif tag_name == 'select'
81
81
  if native['multiple'] == 'multiple'
82
- native.xpath(".//option[@selected='selected']").map { |option| option[:value] || option.content }
82
+ native.xpath(".//option[@selected='selected']").map { |option| option[:value] || option.content }
83
83
  else
84
84
  option = native.xpath(".//option[@selected='selected']").first || native.xpath(".//option").first
85
85
  option[:value] || option.content if option
86
86
  end
87
- elsif tag_name == 'input' && %w(radio checkbox).include?(native[:type])
87
+ elsif tag_name == 'input' && %w[radio checkbox].include?(native[:type])
88
88
  native[:value] || 'on'
89
89
  else
90
90
  native[:value]
@@ -100,14 +100,13 @@ module Capybara
100
100
  # @return [Boolean] Whether the element is visible
101
101
  #
102
102
  def visible?(check_ancestors = true)
103
- return false if (tag_name == 'input') && (native[:type]=="hidden")
103
+ return false if (tag_name == 'input') && (native[:type] == "hidden")
104
104
 
105
105
  if check_ancestors
106
- #check size because oldest supported nokogiri doesnt support xpath boolean() function
107
- native.xpath("./ancestor-or-self::*[contains(@style, 'display:none') or contains(@style, 'display: none') or @hidden or name()='script' or name()='head']").size() == 0
106
+ !native.xpath("boolean(./ancestor-or-self::*[contains(@style, 'display:none') or contains(@style, 'display: none') or @hidden or name()='script' or name()='head'])")
108
107
  else
109
- #no need for an xpath if only checking the current element
110
- !(native.has_attribute?('hidden') || (native[:style] =~ /display:\s?none/) || %w(script head).include?(tag_name))
108
+ # No need for an xpath if only checking the current element
109
+ !(native.has_attribute?('hidden') || (native[:style] =~ /display:\s?none/) || %w[script head].include?(tag_name))
111
110
  end
112
111
  end
113
112
 
@@ -140,7 +139,7 @@ module Capybara
140
139
  native.has_attribute?('selected')
141
140
  end
142
141
 
143
- def synchronize(seconds=nil)
142
+ def synchronize(_seconds = nil)
144
143
  yield # simple nodes don't need to wait
145
144
  end
146
145
 
@@ -152,12 +151,7 @@ module Capybara
152
151
  #
153
152
  # @return [String] The title of the document
154
153
  def title
155
- if native.respond_to? :title
156
- native.title
157
- else
158
- #old versions of nokogiri don't have #title - remove in 3.0
159
- native.xpath('/html/head/title | /html/title').first.text
160
- end
154
+ native.title
161
155
  end
162
156
 
163
157
  def inspect
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Capybara
3
4
  module Queries
4
5
  class AncestorQuery < MatchQuery
@@ -7,17 +8,14 @@ module Capybara
7
8
  @child_node = node
8
9
  node.synchronize do
9
10
  match_results = super(node.session.current_scope, exact)
10
- node.all(:xpath, XPath.ancestor) do |el|
11
- match_results.include?(el)
12
- end
11
+ node.all(:xpath, XPath.ancestor) { |el| match_results.include?(el) }
13
12
  end
14
13
  end
15
14
 
16
15
  def description
16
+ child_query = @child_node && @child_node.instance_variable_get(:@query)
17
17
  desc = super
18
- if @child_node && (child_query = @child_node.instance_variable_get(:@query))
19
- desc += " that is an ancestor of #{child_query.description}"
20
- end
18
+ desc += " that is an ancestor of #{child_query.description}" if child_query
21
19
  desc
22
20
  end
23
21
  end
@@ -1,9 +1,10 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Capybara
3
4
  # @api private
4
5
  module Queries
5
6
  class BaseQuery
6
- COUNT_KEYS = [:count, :minimum, :maximum, :between]
7
+ COUNT_KEYS = %i[count minimum maximum between].freeze
7
8
 
8
9
  attr_reader :options
9
10
  attr_writer :session_options
@@ -20,7 +21,7 @@ module Capybara
20
21
  self.class.wait(options, session_options.default_max_wait_time)
21
22
  end
22
23
 
23
- def self.wait(options, default=Capybara.default_max_wait_time)
24
+ def self.wait(options, default = Capybara.default_max_wait_time)
24
25
  options.fetch(:wait, default) || 0
25
26
  end
26
27
 
@@ -30,11 +31,7 @@ module Capybara
30
31
  # Returns false if query does not have any count options specified.
31
32
  #
32
33
  def expects_none?
33
- if COUNT_KEYS.any? { |k| options.has_key? k }
34
- matches_count?(0)
35
- else
36
- false
37
- end
34
+ count_specified? ? matches_count?(0) : false
38
35
  end
39
36
 
40
37
  ##
@@ -47,11 +44,11 @@ module Capybara
47
44
  # @param [Integer] count The actual number. Should be coercible via Integer()
48
45
  #
49
46
  def matches_count?(count)
50
- return (Integer(options[:count]) == count) if options[:count]
47
+ return (Integer(options[:count]) == count) if options[:count]
51
48
  return false if options[:maximum] && (Integer(options[:maximum]) < count)
52
49
  return false if options[:minimum] && (Integer(options[:minimum]) > count)
53
- return false if options[:between] && !(options[:between] === count)
54
- return true
50
+ return false if options[:between] && !options[:between].include?(count)
51
+ true
55
52
  end
56
53
 
57
54
  ##
@@ -66,10 +63,14 @@ module Capybara
66
63
  String.new("expected not to find #{description}") << count_message
67
64
  end
68
65
 
69
- private
66
+ private
67
+
68
+ def count_specified?
69
+ COUNT_KEYS.any? { |k| options.key? k }
70
+ end
70
71
 
71
72
  def count_message
72
- message = String.new()
73
+ message = "".dup
73
74
  if options[:count]
74
75
  message << " #{options[:count]} #{Capybara::Helpers.declension('time', 'times', options[:count])}"
75
76
  elsif options[:between]
@@ -84,11 +85,11 @@ module Capybara
84
85
 
85
86
  def assert_valid_keys
86
87
  invalid_keys = @options.keys - valid_keys
87
- unless invalid_keys.empty?
88
- invalid_names = invalid_keys.map(&:inspect).join(", ")
89
- valid_names = valid_keys.map(&:inspect).join(", ")
90
- raise ArgumentError, "invalid keys #{invalid_names}, should be one of #{valid_names}"
91
- end
88
+ return if invalid_keys.empty?
89
+
90
+ invalid_names = invalid_keys.map(&:inspect).join(", ")
91
+ valid_names = valid_keys.map(&:inspect).join(", ")
92
+ raise ArgumentError, "invalid keys #{invalid_names}, should be one of #{valid_names}"
92
93
  end
93
94
  end
94
95
  end
@@ -1,34 +1,25 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'addressable/uri'
3
4
 
4
5
  module Capybara
5
6
  # @api private
6
7
  module Queries
7
8
  class CurrentPathQuery < BaseQuery
8
- def initialize(expected_path, options = {})
9
+ def initialize(expected_path, **options)
9
10
  super(options)
10
11
  @expected_path = expected_path
11
- warn "DEPRECATED: The :only_path option is deprecated in favor of the :ignore_query option" if options.has_key?(:only_path)
12
-
13
12
  @options = {
14
13
  url: !@expected_path.is_a?(Regexp) && !::Addressable::URI.parse(@expected_path || "").hostname.nil?,
15
- only_path: false,
16
- ignore_query: false }.merge(options)
14
+ ignore_query: false
15
+ }.merge(options)
17
16
  assert_valid_keys
18
17
  end
19
18
 
20
19
  def resolves_for?(session)
21
20
  uri = ::Addressable::URI.parse(session.current_url)
22
21
  uri.query = nil if uri && options[:ignore_query]
23
- @actual_path = if options[:url]
24
- uri.to_s
25
- else
26
- if options[:only_path]
27
- uri && uri.path
28
- else
29
- uri && uri.request_uri
30
- end
31
- end
22
+ @actual_path = options[:url] ? uri.to_s : uri && uri.request_uri
32
23
 
33
24
  if @expected_path.is_a? Regexp
34
25
  @actual_path.to_s.match(@expected_path)
@@ -45,22 +36,15 @@ module Capybara
45
36
  failure_message_helper(' not')
46
37
  end
47
38
 
48
- private
39
+ private
49
40
 
50
41
  def failure_message_helper(negated = '')
51
- verb = (@expected_path.is_a?(Regexp))? 'match' : 'equal'
42
+ verb = @expected_path.is_a?(Regexp) ? 'match' : 'equal'
52
43
  "expected #{@actual_path.inspect}#{negated} to #{verb} #{@expected_path.inspect}"
53
44
  end
54
45
 
55
46
  def valid_keys
56
- [:wait, :url, :only_path, :ignore_query]
57
- end
58
-
59
- def assert_valid_keys
60
- super
61
- if options[:url] && options[:only_path]
62
- raise ArgumentError, "the :url and :only_path options cannot both be true"
63
- end
47
+ %i[wait url ignore_query]
64
48
  end
65
49
  end
66
50
  end
@@ -2,18 +2,14 @@ module Capybara
2
2
  module Queries
3
3
  class MatchQuery < Capybara::Queries::SelectorQuery
4
4
  def visible
5
- if options.has_key?(:visible)
6
- super
7
- else
8
- :all
9
- end
5
+ options.key?(:visible) ? super : :all
10
6
  end
11
7
 
12
- private
8
+ private
13
9
 
14
10
  def valid_keys
15
11
  super - COUNT_KEYS
16
12
  end
17
13
  end
18
14
  end
19
- end
15
+ end
@@ -1,36 +1,24 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Capybara
3
4
  module Queries
4
5
  class SelectorQuery < Queries::BaseQuery
5
6
  attr_accessor :selector, :locator, :options, :expression, :find, :negative
6
7
 
7
- VALID_KEYS = COUNT_KEYS + [:text, :id, :class, :visible, :exact, :exact_text, :match, :wait, :filter_set]
8
- VALID_MATCH = [:first, :smart, :prefer_exact, :one]
8
+ VALID_KEYS = COUNT_KEYS + %i[text id class visible exact exact_text match wait filter_set]
9
+ VALID_MATCH = %i[first smart prefer_exact one].freeze
9
10
 
10
- def initialize(*args, &filter_block)
11
+ def initialize(*args, session_options:, **options, &filter_block)
11
12
  @resolved_node = nil
12
- @options = if args.last.is_a?(Hash) then args.pop.dup else {} end
13
+ @options = options.dup
13
14
  super(@options)
15
+ self.session_options = session_options
14
16
 
17
+ @selector = find_selector(args[0].is_a?(Symbol) ? args.shift : args[0])
18
+ @locator = args.shift
15
19
  @filter_block = filter_block
16
20
 
17
- if args[0].is_a?(Symbol)
18
- @selector = Selector.all.fetch(args.shift) do |selector_type|
19
- raise ArgumentError, "Unknown selector type (:#{selector_type})"
20
- end
21
- @locator = args.shift
22
- else
23
- @selector = Selector.all.values.find { |s| s.match?(args[0]) }
24
- @locator = args.shift
25
- end
26
- @selector ||= Selector.all[session_options.default_selector]
27
-
28
- warn "Unused parameters passed to #{self.class.name} : #{args}" unless args.empty?
29
-
30
- # for compatibility with Capybara 2.0
31
- if session_options.exact_options and @selector == Selector.all[:option]
32
- @options[:exact] = true
33
- end
21
+ raise ArgumentError, "Unused parameters passed to #{self.class.name} : #{args}" unless args.empty?
34
22
 
35
23
  @expression = @selector.call(@locator, @options.merge(enable_aria_label: session_options.enable_aria_label))
36
24
 
@@ -40,10 +28,10 @@ module Capybara
40
28
  end
41
29
 
42
30
  def name; selector.name; end
43
- def label; selector.label or selector.name; end
31
+ def label; selector.label || selector.name; end
44
32
 
45
33
  def description
46
- @description = String.new()
34
+ @description = "".dup
47
35
  @description << "visible " if visible == :visible
48
36
  @description << "non-visible " if visible == :hidden
49
37
  @description << "#{label} #{locator.inspect}"
@@ -58,80 +46,39 @@ module Capybara
58
46
  end
59
47
 
60
48
  def matches_filters?(node)
61
- if options[:text]
62
- regexp = if options[:text].is_a?(Regexp)
63
- options[:text]
64
- else
65
- if exact_text == true
66
- /\A#{Regexp.escape(options[:text].to_s)}\z/
67
- else
68
- Regexp.escape(options[:text].to_s)
69
- end
70
- end
71
- text_visible = visible
72
- text_visible = :all if text_visible == :hidden
73
- return false if not node.text(text_visible).match(regexp)
74
- end
75
-
76
- if exact_text.is_a?(String)
77
- regexp = /\A#{Regexp.escape(options[:exact_text])}\z/
78
- text_visible = visible
79
- text_visible = :all if text_visible == :hidden
80
- return false if not node.text(text_visible).match(regexp)
81
- end
49
+ return false if options[:text] && !matches_text_filter(node, options[:text])
50
+ return false if exact_text.is_a?(String) && !matches_exact_text_filter(node, exact_text)
82
51
 
83
52
  case visible
84
- when :visible then return false unless node.visible?
85
- when :hidden then return false if node.visible?
53
+ when :visible then return false unless node.visible?
54
+ when :hidden then return false if node.visible?
86
55
  end
87
56
 
88
- res = node_filters.all? do |name, filter|
89
- if options.has_key?(name)
90
- filter.matches?(node, options[name])
91
- elsif filter.default?
92
- filter.matches?(node, filter.default)
93
- else
94
- true
95
- end
96
- end
97
-
98
- res &&= if node.respond_to?(:session)
99
- node.session.using_wait_time(0){ @filter_block.call(node) }
100
- else
101
- @filter_block.call(node)
102
- end unless @filter_block.nil?
103
-
104
- res
105
-
57
+ matches_node_filters?(node) && matches_filter_block?(node)
106
58
  rescue *(node.respond_to?(:session) ? node.session.driver.invalid_element_errors : [])
107
59
  return false
108
60
  end
109
61
 
110
62
  def visible
111
- case (vis = options.fetch(:visible){ @selector.default_visibility(session_options.ignore_hidden_elements) })
112
- when true then :visible
113
- when false then :all
114
- else vis
63
+ case (vis = options.fetch(:visible) { @selector.default_visibility(session_options.ignore_hidden_elements) })
64
+ when true then :visible
65
+ when false then :all
66
+ else vis
115
67
  end
116
68
  end
117
69
 
118
70
  def exact?
119
- return false if !supports_exact?
120
- options.fetch(:exact, session_options.exact)
71
+ supports_exact? ? options.fetch(:exact, session_options.exact) : false
121
72
  end
122
73
 
123
74
  def match
124
75
  options.fetch(:match, session_options.match)
125
76
  end
126
77
 
127
- def xpath(exact=nil)
128
- exact = self.exact? if exact.nil?
78
+ def xpath(exact = nil)
79
+ exact = exact? if exact.nil?
129
80
  expr = apply_expression_filters(@expression)
130
- expr = if expr.respond_to?(:to_xpath) and exact
131
- expr.to_xpath(:exact)
132
- else
133
- expr.to_s
134
- end
81
+ expr = exact ? expr.to_xpath(:exact) : expr.to_s if expr.respond_to?(:to_xpath)
135
82
  filtered_xpath(expr)
136
83
  end
137
84
 
@@ -144,9 +91,9 @@ module Capybara
144
91
  @resolved_node = node
145
92
  node.synchronize do
146
93
  children = if selector.format == :css
147
- node.find_css(self.css)
94
+ node.find_css(css)
148
95
  else
149
- node.find_xpath(self.xpath(exact))
96
+ node.find_xpath(xpath(exact))
150
97
  end.map do |child|
151
98
  if node.is_a?(Capybara::Node::Base)
152
99
  Capybara::Node::Element.new(node.session, child, node, self)
@@ -163,14 +110,45 @@ module Capybara
163
110
  @expression.respond_to? :to_xpath
164
111
  end
165
112
 
166
- private
113
+ private
114
+
115
+ def find_selector(locator)
116
+ selector = if locator.is_a?(Symbol)
117
+ Selector.all.fetch(locator) { |sel_type| raise ArgumentError, "Unknown selector type (:#{sel_type})" }
118
+ else
119
+ Selector.all.values.find { |s| s.match?(locator) }
120
+ end
121
+ selector || Selector.all[session_options.default_selector]
122
+ end
167
123
 
168
124
  def valid_keys
169
125
  VALID_KEYS + custom_keys
170
126
  end
171
127
 
128
+ def matches_node_filters?(node)
129
+ node_filters.all? do |name, filter|
130
+ if options.key?(name)
131
+ filter.matches?(node, options[name])
132
+ elsif filter.default?
133
+ filter.matches?(node, filter.default)
134
+ else
135
+ true
136
+ end
137
+ end
138
+ end
139
+
140
+ def matches_filter_block?(node)
141
+ return true unless @filter_block
142
+
143
+ if node.respond_to?(:session)
144
+ node.session.using_wait_time(0) { @filter_block.call(node) }
145
+ else
146
+ @filter_block.call(node)
147
+ end
148
+ end
149
+
172
150
  def node_filters
173
- if options.has_key?(:filter_set)
151
+ if options.key?(:filter_set)
174
152
  ::Capybara::Selector::FilterSet.all[options[:filter_set]].node_filters
175
153
  else
176
154
  @selector.node_filters
@@ -179,7 +157,7 @@ module Capybara
179
157
 
180
158
  def expression_filters
181
159
  filters = @selector.expression_filters
182
- filters.merge ::Capybara::Selector::FilterSet.all[options[:filter_set]].expression_filters if options.has_key?(:filter_set)
160
+ filters.merge ::Capybara::Selector::FilterSet.all[options[:filter_set]].expression_filters if options.key?(:filter_set)
183
161
  filters
184
162
  end
185
163
 
@@ -195,13 +173,13 @@ module Capybara
195
173
  end
196
174
 
197
175
  def filtered_xpath(expr)
198
- if options.has_key?(:id) || options.has_key?(:class)
176
+ if options.key?(:id) || options.key?(:class)
199
177
  expr = "(#{expr})"
200
- expr = "#{expr}[#{XPath.attr(:id) == options[:id]}]" if options.has_key?(:id) && !custom_keys.include?(:id)
201
- if options.has_key?(:class) && !custom_keys.include?(:class)
178
+ expr = "#{expr}[#{XPath.attr(:id) == options[:id]}]" if options.key?(:id) && !custom_keys.include?(:id)
179
+ if options.key?(:class) && !custom_keys.include?(:class)
202
180
  class_xpath = Array(options[:class]).map do |klass|
203
- "contains(concat(' ',normalize-space(@class),' '),' #{klass} ')"
204
- end.join(" and ")
181
+ XPath.attr(:class).contains_word(klass)
182
+ end.reduce(:&)
205
183
  expr = "#{expr}[#{class_xpath}]"
206
184
  end
207
185
  end
@@ -209,12 +187,12 @@ module Capybara
209
187
  end
210
188
 
211
189
  def filtered_css(expr)
212
- if options.has_key?(:id) || options.has_key?(:class)
190
+ if options.key?(:id) || options.key?(:class)
213
191
  css_selectors = expr.split(',').map(&:rstrip)
214
192
  expr = css_selectors.map do |sel|
215
- sel += "##{Capybara::Selector::CSS.escape(options[:id])}" if options.has_key?(:id) && !custom_keys.include?(:id)
216
- sel += Array(options[:class]).map { |k| ".#{Capybara::Selector::CSS.escape(k)}"}.join if options.has_key?(:class) && !custom_keys.include?(:class)
217
- sel
193
+ sel += "##{Capybara::Selector::CSS.escape(options[:id])}" if options.key?(:id) && !custom_keys.include?(:id)
194
+ sel += Array(options[:class]).map { |k| ".#{Capybara::Selector::CSS.escape(k)}" }.join if options.key?(:class) && !custom_keys.include?(:class)
195
+ sel
218
196
  end.join(", ")
219
197
  end
220
198
  expr
@@ -222,7 +200,7 @@ module Capybara
222
200
 
223
201
  def apply_expression_filters(expr)
224
202
  expression_filters.inject(expr) do |memo, (name, ef)|
225
- if options.has_key?(name)
203
+ if options.key?(name)
226
204
  ef.apply_filter(memo, options[name])
227
205
  elsif ef.default?
228
206
  ef.apply_filter(memo, ef.default)
@@ -233,9 +211,8 @@ module Capybara
233
211
  end
234
212
 
235
213
  def warn_exact_usage
236
- if options.has_key?(:exact) && !supports_exact?
237
- warn "The :exact option only has an effect on queries using the XPath#is method. Using it with the query \"#{expression}\" has no effect."
238
- end
214
+ return unless options.key?(:exact) && !supports_exact?
215
+ warn "The :exact option only has an effect on queries using the XPath#is method. Using it with the query \"#{expression}\" has no effect."
239
216
  end
240
217
 
241
218
  def exact_text
@@ -246,6 +223,26 @@ module Capybara
246
223
  @resolved_node && !(@resolved_node.is_a?(::Capybara::Node::Document) ||
247
224
  (@resolved_node.is_a?(::Capybara::Node::Simple) && @resolved_node.path == '/'))
248
225
  end
226
+
227
+ def matches_text_filter(node, text_option)
228
+ regexp = if text_option.is_a?(Regexp)
229
+ text_option
230
+ elsif exact_text == true
231
+ /\A#{Regexp.escape(text_option.to_s)}\z/
232
+ else
233
+ Regexp.escape(text_option.to_s)
234
+ end
235
+ text_visible = visible
236
+ text_visible = :all if text_visible == :hidden
237
+ node.text(text_visible).match(regexp)
238
+ end
239
+
240
+ def matches_exact_text_filter(node, exact_text_option)
241
+ regexp = /\A#{Regexp.escape(exact_text_option)}\z/
242
+ text_visible = visible
243
+ text_visible = :all if text_visible == :hidden
244
+ node.text(text_visible).match(regexp)
245
+ end
249
246
  end
250
247
  end
251
248
  end