capybara 2.18.0 → 3.0.0.rc1

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 (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
@@ -3,32 +3,34 @@ require 'minitest/spec'
3
3
  module Capybara
4
4
  module Minitest
5
5
  module Expectations
6
- %w(text content title current_path).each do |assertion|
6
+ %w[text content title current_path].each do |assertion|
7
7
  infect_an_assertion "assert_#{assertion}", "must_have_#{assertion}", :reverse
8
8
  infect_an_assertion "refute_#{assertion}", "wont_have_#{assertion}", :reverse
9
9
  end
10
10
 
11
- (%w(selector xpath css link button field select table checked_field unchecked_field).flat_map do |assertion|
12
- [["assert_#{assertion}", "must_have_#{assertion}"],
13
- ["refute_#{assertion}", "wont_have_#{assertion}"]]
14
- end + [["assert_all_of_selectors", "must_have_all_of_selectors"],
15
- ["assert_none_of_selectors", "must_have_none_of_selectors"]] +
16
- %w(selector xpath css).flat_map do |assertion|
17
- [["assert_matches_#{assertion}", "must_match_#{assertion}"],
18
- ["refute_matches_#{assertion}", "wont_match_#{assertion}"]]
11
+ # rubocop:disable Style/MultilineBlockChain
12
+ (%w[selector xpath css link button field select table checked_field unchecked_field].flat_map do |assertion|
13
+ [%W[assert_#{assertion} must_have_#{assertion}],
14
+ %W[refute_#{assertion} wont_have_#{assertion}]]
15
+ end + [%w[assert_all_of_selectors must_have_all_of_selectors],
16
+ %w[assert_none_of_selectors must_have_none_of_selectors]] +
17
+ %w[selector xpath css].flat_map do |assertion|
18
+ [%W[assert_matches_#{assertion} must_match_#{assertion}],
19
+ %W[refute_matches_#{assertion} wont_match_#{assertion}]]
19
20
  end).each do |(meth, new_name)|
20
- self.class_eval <<-EOM, __FILE__, __LINE__ + 1
21
+ class_eval <<-ASSERTION, __FILE__, __LINE__ + 1
21
22
  def #{new_name} *args, &block
22
23
  ::Minitest::Expectation.new(self, ::Minitest::Spec.current).#{new_name}(*args, &block)
23
24
  end
24
- EOM
25
+ ASSERTION
25
26
 
26
- ::Minitest::Expectation.class_eval <<-EOM, __FILE__, __LINE__ + 1
27
+ ::Minitest::Expectation.class_eval <<-ASSERTION, __FILE__, __LINE__ + 1
27
28
  def #{new_name} *args, &block
28
29
  ctx.#{meth}(target, *args, &block)
29
30
  end
30
- EOM
31
+ ASSERTION
31
32
  end
33
+ # rubocop:enable Style/MultilineBlockChain
32
34
 
33
35
  ##
34
36
  # Expectation that there is xpath
@@ -159,7 +161,6 @@ module Capybara
159
161
  #
160
162
  # @!method wont_have_current_path
161
163
  # see {Capybara::SessionMatchers#assert_no_current_path}
162
-
163
164
  end
164
165
  end
165
166
  end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Capybara
3
4
  module Node
4
5
  module Actions
5
-
6
6
  ##
7
7
  #
8
8
  # Finds a button or link and clicks it. See {Capybara::Node::Actions#click_button} and
@@ -20,8 +20,7 @@ module Capybara
20
20
  #
21
21
  # @return [Capybara::Node::Element] The element clicked
22
22
  #
23
- def click_link_or_button(locator=nil, options={})
24
- locator, options = nil, locator if locator.is_a? Hash
23
+ def click_link_or_button(locator = nil, **options)
25
24
  find(:link_or_button, locator, options).click
26
25
  end
27
26
  alias_method :click_on, :click_link_or_button
@@ -38,8 +37,7 @@ module Capybara
38
37
  # @param options See {Capybara::Node::Finders#find_link}
39
38
  #
40
39
  # @return [Capybara::Node::Element] The element clicked
41
- def click_link(locator=nil, options={})
42
- locator, options = nil, locator if locator.is_a? Hash
40
+ def click_link(locator = nil, **options)
43
41
  find(:link, locator, options).click
44
42
  end
45
43
 
@@ -56,8 +54,7 @@ module Capybara
56
54
  # @param [String] locator Which button to find
57
55
  # @param options See {Capybara::Node::Finders#find_button}
58
56
  # @return [Capybara::Node::Element] The element clicked
59
- def click_button(locator=nil, options={})
60
- locator, options = nil, locator if locator.is_a? Hash
57
+ def click_button(locator = nil, **options)
61
58
  find(:button, locator, options).click
62
59
  end
63
60
 
@@ -83,12 +80,8 @@ module Capybara
83
80
  # @option options [String, Array<String>] :class Match fields that match the class(es) provided
84
81
  #
85
82
  # @return [Capybara::Node::Element] The element filled_in
86
- def fill_in(locator, options={})
87
- locator, options = nil, locator if locator.is_a? Hash
88
- raise "Must pass a hash containing 'with'" if not options.is_a?(Hash) or not options.has_key?(:with)
89
- with = options.delete(:with)
90
- fill_options = options.delete(:fill_options)
91
- options[:with] = options.delete(:currently_with) if options.has_key?(:currently_with)
83
+ def fill_in(locator = nil, with:, fill_options: {}, **options)
84
+ options[:with] = options.delete(:currently_with) if options.key?(:currently_with)
92
85
  find(:fillable_field, locator, options).set(with, fill_options)
93
86
  end
94
87
 
@@ -113,8 +106,8 @@ module Capybara
113
106
  # @macro label_click
114
107
  #
115
108
  # @return [Capybara::Node::Element] The element chosen or the label clicked
116
- def choose(locator, options={})
117
- _check_with_label(:radio_button, true, locator, options)
109
+ def choose(locator = nil, **options)
110
+ _check_with_label(:radio_button, true, locator, **options)
118
111
  end
119
112
 
120
113
  ##
@@ -136,8 +129,8 @@ module Capybara
136
129
  # @macro waiting_behavior
137
130
  #
138
131
  # @return [Capybara::Node::Element] The element checked or the label clicked
139
- def check(locator, options={})
140
- _check_with_label(:checkbox, true, locator, options)
132
+ def check(locator, **options)
133
+ _check_with_label(:checkbox, true, locator, **options)
141
134
  end
142
135
 
143
136
  ##
@@ -159,8 +152,8 @@ module Capybara
159
152
  # @macro waiting_behavior
160
153
  #
161
154
  # @return [Capybara::Node::Element] The element unchecked or the label clicked
162
- def uncheck(locator, options={})
163
- _check_with_label(:checkbox, false, locator, options)
155
+ def uncheck(locator = nil, **options)
156
+ _check_with_label(:checkbox, false, locator, **options)
164
157
  end
165
158
 
166
159
  ##
@@ -180,13 +173,9 @@ module Capybara
180
173
  # @option options [String] :from The id, name or label of the select box
181
174
  #
182
175
  # @return [Capybara::Node::Element] The option element selected
183
- def select(value, options={})
184
- if options.has_key?(:from)
185
- from = options.delete(:from)
186
- find(:select, from, options).find(:option, value, options).select_option
187
- else
188
- find(:option, value, options).select_option
189
- end
176
+ def select(value = nil, from: nil, **options)
177
+ scope = from ? find(:select, from, options) : self
178
+ scope.find(:option, value, options).select_option
190
179
  end
191
180
 
192
181
  ##
@@ -203,13 +192,9 @@ module Capybara
203
192
  # @param [Hash{:from => String}] options The id, name or label of the select box
204
193
  #
205
194
  # @return [Capybara::Node::Element] The option element unselected
206
- def unselect(value, options={})
207
- if options.has_key?(:from)
208
- from = options.delete(:from)
209
- find(:select, from, options).find(:option, value, options).unselect_option
210
- else
211
- find(:option, value, options).unselect_option
212
- end
195
+ def unselect(value = nil, from: nil, **options)
196
+ scope = from ? find(:select, from, options) : self
197
+ scope.find(:option, value, options).unselect_option
213
198
  end
214
199
 
215
200
  ##
@@ -233,68 +218,44 @@ module Capybara
233
218
  # @option options [true, Hash] make_visible A Hash of CSS styles to change before attempting to attach the file, if `true` { opacity: 1, display: 'block', visibility: 'visible' } is used (may not be supported by all drivers)
234
219
  #
235
220
  # @return [Capybara::Node::Element] The file field element
236
- def attach_file(locator, path, options={})
237
- locator, path, options = nil, locator, path if path.is_a? Hash
221
+ def attach_file(locator = nil, path, make_visible: nil, **options) # rubocop:disable Style/OptionalArguments
238
222
  Array(path).each do |p|
239
223
  raise Capybara::FileNotFound, "cannot attach file, #{p} does not exist" unless File.exist?(p.to_s)
240
224
  end
241
225
  # Allow user to update the CSS style of the file input since they are so often hidden on a page
242
- if style = options.delete(:make_visible)
243
- style = { opacity: 1, display: 'block', visibility: 'visible' } if style == true
244
- ff = find(:file_field, locator, options.merge({visible: :all}))
245
- _update_style(ff, style)
246
- if ff.visible?
247
- begin
248
- ff.set(path)
249
- ensure
250
- _reset_style(ff)
251
- end
252
- else
253
- raise ExpectationNotMet, "The style changes in :make_visible did not make the file input visible"
254
- end
226
+ if make_visible
227
+ ff = find(:file_field, locator, options.merge(visible: :all))
228
+ while_visible(ff, make_visible) { |el| el.set(path) }
255
229
  else
256
230
  find(:file_field, locator, options).set(path)
257
231
  end
258
232
  end
259
233
 
260
234
  private
261
- def _update_style(element, style)
262
- script = <<-JS
263
- var el = arguments[0];
264
- el.capybara_style_cache = el.style.cssText;
265
- var css = arguments[1];
266
- for (var prop in css){
267
- if (css.hasOwnProperty(prop)) {
268
- el.style[prop] = css[prop]
269
- }
270
- }
271
- JS
272
- begin
273
- session.execute_script(script, element, style)
274
- rescue Capybara::NotSupportedByDriverError
275
- warn "The :make_visible option is not supported by the current driver - ignoring"
276
- end
277
- end
278
235
 
279
- def _reset_style(element)
280
- script = <<-JS
281
- var el = arguments[0];
282
- if (el.hasOwnProperty('capybara_style_cache')) {
283
- el.style.cssText = el.capybara_style_cache;
284
- delete el.capybara_style_cache;
285
- }
286
- JS
236
+ def while_visible(element, visible_css)
237
+ visible_css = { opacity: 1, display: 'block', visibility: 'visible' } if visible_css == true
238
+ _update_style(element, visible_css)
239
+ raise ExpectationNotMet, "The style changes in :make_visible did not make the file input visible" unless element.visible?
287
240
  begin
288
- session.execute_script(script, element)
289
- rescue
241
+ yield element
242
+ ensure
243
+ _reset_style(element)
290
244
  end
291
245
  end
292
246
 
247
+ def _update_style(element, style)
248
+ session.execute_script(UPDATE_STYLE_SCRIPT, element, style)
249
+ rescue Capybara::NotSupportedByDriverError
250
+ warn "The :make_visible option is not supported by the current driver - ignoring"
251
+ end
293
252
 
294
- def _check_with_label(selector, checked, locator, options)
295
- locator, options = nil, locator if locator.is_a? Hash
296
- allow_label_click = options.delete(:allow_label_click) { session_options.automatic_label_click }
253
+ def _reset_style(element)
254
+ session.execute_script(RESET_STYLE_SCRIPT, element)
255
+ rescue # swallow extra errors
256
+ end
297
257
 
258
+ def _check_with_label(selector, checked, locator, allow_label_click: session_options.automatic_label_click, **options)
298
259
  synchronize(Capybara::Queries::BaseQuery.wait(options, session_options.default_max_wait_time)) do
299
260
  begin
300
261
  el = find(selector, locator, options)
@@ -303,15 +264,32 @@ module Capybara
303
264
  raise unless allow_label_click && catch_error?(e)
304
265
  begin
305
266
  el ||= find(selector, locator, options.merge(visible: :all))
306
- label = find(:label, for: el, visible: true)
307
- label.click unless (el.checked? == checked)
308
- rescue
267
+ find(:label, for: el, visible: true).click unless el.checked? == checked
268
+ rescue # swallow extra errors - raise original
309
269
  raise e
310
270
  end
311
271
  end
312
272
  end
313
273
  end
314
274
 
275
+ UPDATE_STYLE_SCRIPT = <<-'JS'.freeze
276
+ var el = arguments[0];
277
+ el.capybara_style_cache = el.style.cssText;
278
+ var css = arguments[1];
279
+ for (var prop in css){
280
+ if (css.hasOwnProperty(prop)) {
281
+ el.style[prop] = css[prop]
282
+ }
283
+ }
284
+ JS
285
+
286
+ RESET_STYLE_SCRIPT = <<-'JS'.freeze
287
+ var el = arguments[0];
288
+ if (el.hasOwnProperty('capybara_style_cache')) {
289
+ el.style.cssText = el.capybara_style_cache;
290
+ delete el.capybara_style_cache;
291
+ }
292
+ JS
315
293
  end
316
294
  end
317
295
  end
@@ -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::Base} represents either an element on a page through the subclass
@@ -67,26 +67,23 @@ module Capybara
67
67
  # time has passed. On rubies/platforms which don't support access to a monotonic process clock
68
68
  # if the return value of `Time.now` is stubbed out, Capybara will raise `Capybara::FrozenInTime`.
69
69
  #
70
- # @param [Integer] seconds Number of seconds to retry this block
71
- # @param options [Hash]
72
- # @option options [Array<Exception>] :errors (driver.invalid_element_errors +
70
+ # @param [Integer] seconds (current sessions default_max_wait_time) Maximum number of seconds to retry this block
71
+ # @param [Array<Exception>] errors (driver.invalid_element_errors +
73
72
  # [Capybara::ElementNotFound]) exception types that cause the block to be rerun
74
73
  # @return [Object] The result of the given block
75
74
  # @raise [Capybara::FrozenInTime] If the return value of `Time.now` appears stuck
76
75
  #
77
- def synchronize(seconds=session_options.default_max_wait_time, options = {})
78
- start_time = Capybara::Helpers.monotonic_time
79
-
76
+ def synchronize(seconds = session_options.default_max_wait_time, errors: nil)
80
77
  if session.synchronized
81
78
  yield
82
79
  else
83
80
  session.synchronized = true
81
+ start_time = Capybara::Helpers.monotonic_time
84
82
  begin
85
83
  yield
86
84
  rescue => e
87
85
  session.raise_server_error!
88
- raise e unless driver.wait?
89
- raise e unless catch_error?(e, options[:errors])
86
+ raise e unless driver.wait? && catch_error?(e, errors)
90
87
  raise e if (Capybara::Helpers.monotonic_time - start_time) >= seconds
91
88
  sleep(0.05)
92
89
  raise Capybara::FrozenInTime, "time appears to be frozen, Capybara does not work with libraries which freeze time, consider using time travelling instead" if Capybara::Helpers.monotonic_time == start_time
@@ -108,24 +105,20 @@ module Capybara
108
105
  base.find_xpath(xpath)
109
106
  end
110
107
 
111
- # @deprecated Use query_scope instead
112
- def parent
113
- warn "DEPRECATED: #parent is deprecated in favor of #query_scope - Note: #parent was not the elements parent in the document so it's most likely not what you wanted anyway"
114
- query_scope
115
- end
116
-
117
108
  # @api private
118
109
  def session_options
119
110
  session.config
120
111
  end
121
112
 
113
+ def to_capybara_node
114
+ self
115
+ end
116
+
122
117
  protected
123
118
 
124
119
  def catch_error?(error, errors = nil)
125
120
  errors ||= (driver.invalid_element_errors + [Capybara::ElementNotFound])
126
- errors.any? do |type|
127
- error.is_a?(type)
128
- end
121
+ errors.any? { |type| error.is_a?(type) }
129
122
  end
130
123
 
131
124
  def driver
@@ -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::Document} represents an HTML document. Any operation
@@ -20,7 +20,7 @@ module Capybara
20
20
  #
21
21
  # @return [String] The text of the document
22
22
  #
23
- def text(type=nil)
23
+ def text(type = nil)
24
24
  find(:xpath, '/html').text(type)
25
25
  end
26
26
 
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Capybara
3
4
  module Node
4
5
  module DocumentMatchers
@@ -15,8 +16,8 @@ module Capybara
15
16
  # @raise [Capybara::ExpectationNotMet] if the assertion hasn't succeeded during wait time
16
17
  # @return [true]
17
18
  #
18
- def assert_title(title, options = {})
19
- _verify_title(title,options) { |query| raise Capybara::ExpectationNotMet, query.failure_message unless query.resolves_for?(self) }
19
+ def assert_title(title, **options)
20
+ _verify_title(title, options) { |query| raise Capybara::ExpectationNotMet, query.failure_message unless query.resolves_for?(self) }
20
21
  end
21
22
 
22
23
  ##
@@ -26,8 +27,8 @@ module Capybara
26
27
  # @raise [Capybara::ExpectationNotMet] if the assertion hasn't succeeded during wait time
27
28
  # @return [true]
28
29
  #
29
- def assert_no_title(title, options = {})
30
- _verify_title(title,options) { |query| raise Capybara::ExpectationNotMet, query.negative_failure_message if query.resolves_for?(self) }
30
+ def assert_no_title(title, **options)
31
+ _verify_title(title, options) { |query| raise Capybara::ExpectationNotMet, query.negative_failure_message if query.resolves_for?(self) }
31
32
  end
32
33
 
33
34
  ##
@@ -36,7 +37,7 @@ module Capybara
36
37
  # @macro title_query_params
37
38
  # @return [Boolean]
38
39
  #
39
- def has_title?(title, options = {})
40
+ def has_title?(title, **options)
40
41
  assert_title(title, options)
41
42
  rescue Capybara::ExpectationNotMet
42
43
  return false
@@ -48,13 +49,13 @@ module Capybara
48
49
  # @macro title_query_params
49
50
  # @return [Boolean]
50
51
  #
51
- def has_no_title?(title, options = {})
52
+ def has_no_title?(title, **options)
52
53
  assert_no_title(title, options)
53
54
  rescue Capybara::ExpectationNotMet
54
55
  return false
55
56
  end
56
57
 
57
- private
58
+ private
58
59
 
59
60
  def _verify_title(title, options)
60
61
  query = Capybara::Queries::TitleQuery.new(title, options)
@@ -63,7 +64,6 @@ module Capybara
63
64
  end
64
65
  return true
65
66
  end
66
-
67
67
  end
68
68
  end
69
69
  end
@@ -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::Element} represents a single element on the page. It is possible
@@ -22,7 +22,6 @@ module Capybara
22
22
  # @see Capybara::Node
23
23
  #
24
24
  class Element < Base
25
-
26
25
  def initialize(session, base, query_scope, query)
27
26
  super(session, base)
28
27
  @query_scope = query_scope
@@ -54,7 +53,7 @@ module Capybara
54
53
  # @param [:all, :visible] type Whether to return only visible or all text
55
54
  # @return [String] The text of the element
56
55
  #
57
- def text(type=nil)
56
+ def text(type = nil)
58
57
  type ||= :all unless session_options.ignore_hidden_elements or session_options.visible_text_only
59
58
  synchronize do
60
59
  if type == :all
@@ -94,23 +93,10 @@ module Capybara
94
93
  # @param [Hash{}] options Driver specific options for how to set the value
95
94
  #
96
95
  # @return [Capybara::Node::Element] The element
97
- def set(value, options={})
98
- options ||= {}
99
-
100
- driver_supports_options = (base.method(:set).arity != 1)
101
-
102
- unless options.empty? || driver_supports_options
103
- warn "Options passed to Capybara::Node#set but the driver doesn't support them"
104
- end
105
-
106
- synchronize do
107
- if driver_supports_options
108
- base.set(value, options)
109
- else
110
- base.set(value)
111
- end
112
- end
113
- return self
96
+ def set(value, **options)
97
+ raise Capybara::ReadOnlyElementError, "Attempt to set readonly element with value: #{value}" if readonly?
98
+ synchronize { base.set(value, options) }
99
+ self
114
100
  end
115
101
 
116
102
  ##
@@ -121,7 +107,7 @@ module Capybara
121
107
  def select_option
122
108
  warn "Attempt to select disabled option: #{value || text}" if disabled?
123
109
  synchronize { base.select_option }
124
- return self
110
+ self
125
111
  end
126
112
 
127
113
  ##
@@ -131,37 +117,43 @@ module Capybara
131
117
  # @return [Capybara::Node::Element] The element
132
118
  def unselect_option
133
119
  synchronize { base.unselect_option }
134
- return self
120
+ self
135
121
  end
136
122
 
137
123
  ##
138
124
  #
139
125
  # Click the Element
140
126
  #
127
+ # @!macro click_modifiers
128
+ # @overload $0(*key_modifiers=[], offset={x: nil, y: nil})
129
+ # @param [Array<:alt, :control, :meta, :shift>] *key_modifiers Keys to be held down when clicking
130
+ # @param [Hash] offset x and y coordinates to offset the click location from the top left corner of the element. If not specified will click the middle of the element.
141
131
  # @return [Capybara::Node::Element] The element
142
- def click
143
- synchronize { base.click }
144
- return self
132
+ def click(*keys, **offset)
133
+ synchronize { base.click(keys, offset) }
134
+ self
145
135
  end
146
136
 
147
137
  ##
148
138
  #
149
139
  # Right Click the Element
150
140
  #
141
+ # @macro click_modifiers
151
142
  # @return [Capybara::Node::Element] The element
152
- def right_click
153
- synchronize { base.right_click }
154
- return self
143
+ def right_click(*keys, **offset)
144
+ synchronize { base.right_click(keys, offset) }
145
+ self
155
146
  end
156
147
 
157
148
  ##
158
149
  #
159
150
  # Double Click the Element
160
151
  #
152
+ # @macro click_modifiers
161
153
  # @return [Capybara::Node::Element] The element
162
- def double_click
163
- synchronize { base.double_click }
164
- return self
154
+ def double_click(*keys, **offset)
155
+ synchronize { base.double_click(keys, offset) }
156
+ self
165
157
  end
166
158
 
167
159
  ##
@@ -237,7 +229,7 @@ module Capybara
237
229
  # @return [Capybara::Node::Element] The element
238
230
  def send_keys(*args)
239
231
  synchronize { base.send_keys(*args) }
240
- return self
232
+ self
241
233
  end
242
234
 
243
235
  ##
@@ -247,7 +239,7 @@ module Capybara
247
239
  # @return [Capybara::Node::Element] The element
248
240
  def hover
249
241
  synchronize { base.hover }
250
- return self
242
+ self
251
243
  end
252
244
 
253
245
  ##
@@ -339,7 +331,7 @@ module Capybara
339
331
  # @return [Capybara::Node::Element] The element
340
332
  def trigger(event)
341
333
  synchronize { base.trigger(event) }
342
- return self
334
+ self
343
335
  end
344
336
 
345
337
  ##
@@ -355,7 +347,7 @@ module Capybara
355
347
  # @return [Capybara::Node::Element] The element
356
348
  def drag_to(node)
357
349
  synchronize { base.drag_to(node.base) }
358
- return self
350
+ self
359
351
  end
360
352
 
361
353
  def reload
@@ -375,11 +367,9 @@ module Capybara
375
367
  rescue NotSupportedByDriverError
376
368
  %(#<Capybara::Node::Element tag="#{base.tag_name}">)
377
369
  rescue => e
378
- if session.driver.invalid_element_errors.any? { |et| e.is_a?(et)}
379
- %(Obsolete #<Capybara::Node::Element>)
380
- else
381
- raise
382
- end
370
+ raise unless session.driver.invalid_element_errors.any? { |et| e.is_a?(et) }
371
+
372
+ %(Obsolete #<Capybara::Node::Element>)
383
373
  end
384
374
  end
385
375
  end