capybara 2.15.0 → 3.0.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 (177) hide show
  1. checksums.yaml +5 -5
  2. data/History.md +137 -2
  3. data/README.md +36 -25
  4. data/lib/capybara/config.rb +11 -57
  5. data/lib/capybara/cucumber.rb +2 -3
  6. data/lib/capybara/driver/base.rb +19 -16
  7. data/lib/capybara/driver/node.rb +5 -4
  8. data/lib/capybara/dsl.rb +1 -0
  9. data/lib/capybara/helpers.rb +19 -29
  10. data/lib/capybara/minitest/spec.rb +16 -13
  11. data/lib/capybara/minitest.rb +140 -137
  12. data/lib/capybara/node/actions.rb +68 -89
  13. data/lib/capybara/node/base.rb +11 -18
  14. data/lib/capybara/node/document.rb +2 -2
  15. data/lib/capybara/node/document_matchers.rb +8 -8
  16. data/lib/capybara/node/element.rb +32 -42
  17. data/lib/capybara/node/finders.rb +64 -71
  18. data/lib/capybara/node/matchers.rb +50 -71
  19. data/lib/capybara/node/simple.rb +11 -17
  20. data/lib/capybara/queries/ancestor_query.rb +12 -8
  21. data/lib/capybara/queries/base_query.rb +22 -18
  22. data/lib/capybara/queries/current_path_query.rb +12 -25
  23. data/lib/capybara/queries/match_query.rb +3 -7
  24. data/lib/capybara/queries/selector_query.rb +100 -96
  25. data/lib/capybara/queries/sibling_query.rb +5 -5
  26. data/lib/capybara/queries/text_query.rb +35 -35
  27. data/lib/capybara/queries/title_query.rb +8 -11
  28. data/lib/capybara/rack_test/browser.rb +15 -18
  29. data/lib/capybara/rack_test/css_handlers.rb +6 -4
  30. data/lib/capybara/rack_test/driver.rb +6 -10
  31. data/lib/capybara/rack_test/form.rb +52 -39
  32. data/lib/capybara/rack_test/node.rb +93 -63
  33. data/lib/capybara/rails.rb +2 -6
  34. data/lib/capybara/result.rb +22 -22
  35. data/lib/capybara/rspec/compound.rb +5 -10
  36. data/lib/capybara/rspec/features.rb +17 -48
  37. data/lib/capybara/rspec/matcher_proxies.rb +31 -15
  38. data/lib/capybara/rspec/matchers.rb +116 -58
  39. data/lib/capybara/rspec.rb +5 -10
  40. data/lib/capybara/selector/css.rb +6 -11
  41. data/lib/capybara/selector/filter.rb +1 -17
  42. data/lib/capybara/selector/filter_set.rb +18 -15
  43. data/lib/capybara/selector/filters/base.rb +7 -6
  44. data/lib/capybara/selector/filters/expression_filter.rb +6 -23
  45. data/lib/capybara/selector/filters/node_filter.rb +2 -12
  46. data/lib/capybara/selector/selector.rb +28 -34
  47. data/lib/capybara/selector.rb +129 -117
  48. data/lib/capybara/selenium/driver.rb +172 -163
  49. data/lib/capybara/selenium/node.rb +218 -104
  50. data/lib/capybara/server.rb +3 -2
  51. data/lib/capybara/session/config.rb +47 -59
  52. data/lib/capybara/session/matchers.rb +23 -14
  53. data/lib/capybara/session.rb +175 -229
  54. data/lib/capybara/spec/fixtures/no_extension +1 -0
  55. data/lib/capybara/spec/public/test.js +38 -6
  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 +30 -1
  59. data/lib/capybara/spec/session/all_spec.rb +31 -18
  60. data/lib/capybara/spec/session/ancestor_spec.rb +6 -8
  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 +31 -23
  65. data/lib/capybara/spec/session/assert_title.rb +13 -3
  66. data/lib/capybara/spec/session/attach_file_spec.rb +57 -29
  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 +24 -32
  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 +19 -8
  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 +23 -0
  81. data/lib/capybara/spec/session/evaluate_script_spec.rb +5 -4
  82. data/lib/capybara/spec/session/execute_script_spec.rb +4 -3
  83. data/lib/capybara/spec/session/fill_in_spec.rb +30 -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 +9 -15
  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/frame_title_spec.rb +23 -0
  91. data/lib/capybara/spec/session/frame/frame_url_spec.rb +23 -0
  92. data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +2 -1
  93. data/lib/capybara/spec/session/frame/within_frame_spec.rb +9 -16
  94. data/lib/capybara/spec/session/go_back_spec.rb +1 -0
  95. data/lib/capybara/spec/session/go_forward_spec.rb +1 -0
  96. data/lib/capybara/spec/session/has_all_selectors_spec.rb +69 -0
  97. data/lib/capybara/spec/session/has_button_spec.rb +2 -1
  98. data/lib/capybara/spec/session/has_css_spec.rb +3 -2
  99. data/lib/capybara/spec/session/has_current_path_spec.rb +49 -22
  100. data/lib/capybara/spec/session/has_field_spec.rb +4 -3
  101. data/lib/capybara/spec/session/has_link_spec.rb +5 -4
  102. data/lib/capybara/spec/session/has_none_selectors_spec.rb +76 -0
  103. data/lib/capybara/spec/session/has_select_spec.rb +32 -31
  104. data/lib/capybara/spec/session/has_selector_spec.rb +5 -4
  105. data/lib/capybara/spec/session/has_table_spec.rb +2 -1
  106. data/lib/capybara/spec/session/has_text_spec.rb +9 -13
  107. data/lib/capybara/spec/session/has_title_spec.rb +1 -0
  108. data/lib/capybara/spec/session/has_xpath_spec.rb +1 -0
  109. data/lib/capybara/spec/session/headers.rb +2 -1
  110. data/lib/capybara/spec/session/html_spec.rb +1 -0
  111. data/lib/capybara/spec/session/node_spec.rb +107 -58
  112. data/lib/capybara/spec/session/node_wrapper_spec.rb +36 -0
  113. data/lib/capybara/spec/session/refresh_spec.rb +6 -2
  114. data/lib/capybara/spec/session/reset_session_spec.rb +19 -0
  115. data/lib/capybara/spec/session/response_code.rb +1 -0
  116. data/lib/capybara/spec/session/save_and_open_page_spec.rb +1 -0
  117. data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +6 -11
  118. data/lib/capybara/spec/session/save_page_spec.rb +1 -17
  119. data/lib/capybara/spec/session/save_screenshot_spec.rb +3 -3
  120. data/lib/capybara/spec/session/select_spec.rb +21 -20
  121. data/lib/capybara/spec/session/selectors_spec.rb +2 -2
  122. data/lib/capybara/spec/session/sibling_spec.rb +1 -1
  123. data/lib/capybara/spec/session/text_spec.rb +17 -3
  124. data/lib/capybara/spec/session/title_spec.rb +11 -1
  125. data/lib/capybara/spec/session/uncheck_spec.rb +4 -3
  126. data/lib/capybara/spec/session/unselect_spec.rb +7 -6
  127. data/lib/capybara/spec/session/visit_spec.rb +64 -3
  128. data/lib/capybara/spec/session/window/become_closed_spec.rb +2 -1
  129. data/lib/capybara/spec/session/window/current_window_spec.rb +1 -0
  130. data/lib/capybara/spec/session/window/open_new_window_spec.rb +1 -0
  131. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +2 -1
  132. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +2 -1
  133. data/lib/capybara/spec/session/window/window_spec.rb +12 -12
  134. data/lib/capybara/spec/session/window/windows_spec.rb +2 -3
  135. data/lib/capybara/spec/session/window/within_window_spec.rb +15 -71
  136. data/lib/capybara/spec/session/within_spec.rb +1 -0
  137. data/lib/capybara/spec/spec_helper.rb +36 -18
  138. data/lib/capybara/spec/test_app.rb +17 -9
  139. data/lib/capybara/spec/views/form.erb +7 -0
  140. data/lib/capybara/spec/views/initial_alert.erb +10 -0
  141. data/lib/capybara/spec/views/with_fixed_header_footer.erb +17 -0
  142. data/lib/capybara/spec/views/with_hover.erb +5 -0
  143. data/lib/capybara/spec/views/with_html.erb +27 -1
  144. data/lib/capybara/spec/views/with_js.erb +11 -0
  145. data/lib/capybara/spec/views/within_frames.erb +4 -1
  146. data/lib/capybara/version.rb +2 -1
  147. data/lib/capybara/window.rb +6 -10
  148. data/lib/capybara.rb +29 -26
  149. data/spec/basic_node_spec.rb +1 -0
  150. data/spec/capybara_spec.rb +16 -69
  151. data/spec/dsl_spec.rb +5 -13
  152. data/spec/filter_set_spec.rb +5 -4
  153. data/spec/fixtures/selenium_driver_rspec_failure.rb +2 -1
  154. data/spec/fixtures/selenium_driver_rspec_success.rb +3 -2
  155. data/spec/minitest_spec.rb +13 -4
  156. data/spec/minitest_spec_spec.rb +12 -3
  157. data/spec/per_session_config_spec.rb +9 -8
  158. data/spec/rack_test_spec.rb +21 -20
  159. data/spec/result_spec.rb +17 -16
  160. data/spec/rspec/features_spec.rb +17 -14
  161. data/spec/rspec/scenarios_spec.rb +5 -7
  162. data/spec/rspec/shared_spec_matchers.rb +96 -99
  163. data/spec/rspec/views_spec.rb +2 -1
  164. data/spec/rspec_matchers_spec.rb +18 -2
  165. data/spec/rspec_spec.rb +11 -15
  166. data/spec/selector_spec.rb +5 -6
  167. data/spec/selenium_spec_chrome.rb +20 -11
  168. data/spec/selenium_spec_edge.rb +27 -0
  169. data/spec/selenium_spec_ie.rb +31 -0
  170. data/spec/selenium_spec_marionette.rb +38 -12
  171. data/spec/server_spec.rb +33 -33
  172. data/spec/session_spec.rb +2 -1
  173. data/spec/shared_selenium_session.rb +82 -22
  174. data/spec/spec_helper.rb +3 -6
  175. metadata +76 -81
  176. data/lib/capybara/query.rb +0 -7
  177. data/spec/selenium_spec_firefox.rb +0 -68
@@ -1,12 +1,12 @@
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
- # Finds a button or link by id, text or value and clicks it. Also looks at image
9
- # alt text inside the link.
8
+ # Finds a button or link and clicks it. See {Capybara::Node::Actions#click_button} and
9
+ # {Capybara::Node::Actions#click_link} for what locator will match against for each type of element
10
10
  # @!macro waiting_behavior
11
11
  # If the driver is capable of executing JavaScript, +$0+ will wait for a set amount of time
12
12
  # and continuously retry finding the element until either the element is found or the time
@@ -16,12 +16,11 @@ module Capybara
16
16
  #
17
17
  # @overload click_link_or_button([locator], options)
18
18
  #
19
- # @param [String] locator Text, id or value of link or button
19
+ # @param [String] locator See {Capybara::Node::Actions#click_button} and {Capybara::Node::Actions#click_link}
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
 
@@ -80,15 +77,11 @@ module Capybara
80
77
  # @option options [String] :id Match fields that match the id attribute
81
78
  # @option options [String] :name Match fields that match the name attribute
82
79
  # @option options [String] :placeholder Match fields that match the placeholder attribute
83
- # @option options [String, Array<String>] :class Match links that match the class(es) provided
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
 
@@ -108,13 +101,13 @@ module Capybara
108
101
  # @option options [String] :option Value of the radio_button to choose
109
102
  # @option options [String] :id Match fields that match the id attribute
110
103
  # @option options [String] :name Match fields that match the name attribute
111
- # @option options [String, Array<String>] :class Match links that match the class(es) provided
104
+ # @option options [String, Array<String>] :class Match fields that match the class(es) provided
112
105
  # @macro waiting_behavior
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
  ##
@@ -131,13 +124,13 @@ module Capybara
131
124
  # @option options [String] :option Value of the checkbox to select
132
125
  # @option options [String] id Match fields that match the id attribute
133
126
  # @option options [String] name Match fields that match the name attribute
134
- # @option options [String, Array<String>] :class Match links that match the class(es) provided
127
+ # @option options [String, Array<String>] :class Match fields that match the class(es) provided
135
128
  # @macro label_click
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
  ##
@@ -154,13 +147,13 @@ module Capybara
154
147
  # @option options [String] :option Value of the checkbox to deselect
155
148
  # @option options [String] id Match fields that match the id attribute
156
149
  # @option options [String] name Match fields that match the name attribute
157
- # @option options [String, Array<String>] :class Match links that match the class(es) provided
150
+ # @option options [String, Array<String>] :class Match fields that match the class(es) provided
158
151
  # @macro label_click
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
  ##
@@ -229,72 +214,48 @@ module Capybara
229
214
  # @option options [Boolean] multiple Match field which allows multiple file selection
230
215
  # @option options [String] id Match fields that match the id attribute
231
216
  # @option options [String] name Match fields that match the name attribute
232
- # @option options [String, Array<String>] :class Match links that match the class(es) provided
217
+ # @option options [String, Array<String>] :class Match fields that match the class(es) provided
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,33 @@ 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
+ res = find(:label, for: el, visible: true).click unless el.checked? == checked
268
+ res
269
+ rescue # swallow extra errors - raise original
309
270
  raise e
310
271
  end
311
272
  end
312
273
  end
313
274
  end
314
275
 
276
+ UPDATE_STYLE_SCRIPT = <<-'JS'.freeze
277
+ var el = arguments[0];
278
+ el.capybara_style_cache = el.style.cssText;
279
+ var css = arguments[1];
280
+ for (var prop in css){
281
+ if (css.hasOwnProperty(prop)) {
282
+ el.style[prop] = css[prop]
283
+ }
284
+ }
285
+ JS
286
+
287
+ RESET_STYLE_SCRIPT = <<-'JS'.freeze
288
+ var el = arguments[0];
289
+ if (el.hasOwnProperty('capybara_style_cache')) {
290
+ el.style.cssText = el.capybara_style_cache;
291
+ delete el.capybara_style_cache;
292
+ }
293
+ JS
315
294
  end
316
295
  end
317
296
  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
@@ -371,15 +363,13 @@ module Capybara
371
363
  end
372
364
 
373
365
  def inspect
374
- %(#<Capybara::Node::Element tag="#{tag_name}" path="#{path}">)
366
+ %(#<Capybara::Node::Element tag="#{base.tag_name}" path="#{base.path}">)
375
367
  rescue NotSupportedByDriverError
376
- %(#<Capybara::Node::Element tag="#{tag_name}">)
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