capybara 3.24.0 → 3.29.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +79 -1
  3. data/README.md +2 -2
  4. data/lib/capybara.rb +2 -0
  5. data/lib/capybara/driver/node.rb +4 -0
  6. data/lib/capybara/minitest.rb +29 -29
  7. data/lib/capybara/node/actions.rb +3 -2
  8. data/lib/capybara/node/element.rb +60 -19
  9. data/lib/capybara/node/matchers.rb +7 -7
  10. data/lib/capybara/node/simple.rb +2 -1
  11. data/lib/capybara/queries/ancestor_query.rb +5 -9
  12. data/lib/capybara/queries/selector_query.rb +204 -3
  13. data/lib/capybara/queries/sibling_query.rb +4 -10
  14. data/lib/capybara/queries/text_query.rb +7 -1
  15. data/lib/capybara/rack_test/node.rb +13 -2
  16. data/lib/capybara/registrations/patches/puma_ssl.rb +27 -0
  17. data/lib/capybara/registrations/servers.rb +7 -1
  18. data/lib/capybara/result.rb +5 -5
  19. data/lib/capybara/rspec/matchers.rb +65 -43
  20. data/lib/capybara/rspec/matchers/base.rb +7 -0
  21. data/lib/capybara/rspec/matchers/have_ancestor.rb +1 -4
  22. data/lib/capybara/rspec/matchers/have_selector.rb +1 -4
  23. data/lib/capybara/rspec/matchers/have_sibling.rb +1 -4
  24. data/lib/capybara/rspec/matchers/have_text.rb +1 -4
  25. data/lib/capybara/rspec/matchers/spatial_sugar.rb +38 -0
  26. data/lib/capybara/selector.rb +11 -1
  27. data/lib/capybara/selector/builders/css_builder.rb +10 -6
  28. data/lib/capybara/selector/builders/xpath_builder.rb +1 -1
  29. data/lib/capybara/selector/definition/fillable_field.rb +1 -1
  30. data/lib/capybara/selector/definition/option.rb +1 -1
  31. data/lib/capybara/selector/regexp_disassembler.rb +7 -0
  32. data/lib/capybara/selenium/atoms/isDisplayed.min.js +1 -1
  33. data/lib/capybara/selenium/atoms/src/isDisplayed.js +9 -9
  34. data/lib/capybara/selenium/driver.rb +21 -12
  35. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +9 -8
  36. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +14 -10
  37. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +16 -0
  38. data/lib/capybara/selenium/driver_specializations/safari_driver.rb +0 -4
  39. data/lib/capybara/selenium/extensions/file_input_click_emulation.rb +34 -0
  40. data/lib/capybara/selenium/extensions/find.rb +34 -23
  41. data/lib/capybara/selenium/extensions/html5_drag.rb +32 -5
  42. data/lib/capybara/selenium/extensions/modifier_keys_stack.rb +28 -0
  43. data/lib/capybara/selenium/node.rb +59 -18
  44. data/lib/capybara/selenium/nodes/chrome_node.rb +51 -8
  45. data/lib/capybara/selenium/nodes/edge_node.rb +28 -12
  46. data/lib/capybara/selenium/nodes/firefox_node.rb +18 -27
  47. data/lib/capybara/selenium/nodes/safari_node.rb +1 -27
  48. data/lib/capybara/selenium/patches/is_displayed.rb +16 -0
  49. data/lib/capybara/server.rb +4 -0
  50. data/lib/capybara/server/animation_disabler.rb +1 -1
  51. data/lib/capybara/session.rb +4 -4
  52. data/lib/capybara/session/config.rb +3 -1
  53. data/lib/capybara/spec/public/offset.js +6 -0
  54. data/lib/capybara/spec/session/find_spec.rb +32 -0
  55. data/lib/capybara/spec/session/has_ancestor_spec.rb +2 -0
  56. data/lib/capybara/spec/session/has_css_spec.rb +18 -0
  57. data/lib/capybara/spec/session/has_field_spec.rb +18 -0
  58. data/lib/capybara/spec/session/has_text_spec.rb +6 -0
  59. data/lib/capybara/spec/session/node_spec.rb +237 -3
  60. data/lib/capybara/spec/session/selectors_spec.rb +1 -1
  61. data/lib/capybara/spec/spec_helper.rb +1 -0
  62. data/lib/capybara/spec/views/form.erb +6 -1
  63. data/lib/capybara/spec/views/offset.erb +32 -0
  64. data/lib/capybara/spec/views/spatial.erb +31 -0
  65. data/lib/capybara/spec/views/with_animation.erb +29 -1
  66. data/lib/capybara/spec/views/with_dragula.erb +22 -0
  67. data/lib/capybara/spec/views/with_html.erb +22 -0
  68. data/lib/capybara/spec/views/with_js.erb +1 -1
  69. data/lib/capybara/spec/views/with_jstree.erb +26 -0
  70. data/lib/capybara/version.rb +1 -1
  71. data/spec/basic_node_spec.rb +6 -6
  72. data/spec/capybara_spec.rb +28 -28
  73. data/spec/dsl_spec.rb +1 -1
  74. data/spec/filter_set_spec.rb +5 -5
  75. data/spec/fixtures/selenium_driver_rspec_failure.rb +1 -1
  76. data/spec/fixtures/selenium_driver_rspec_success.rb +1 -1
  77. data/spec/rack_test_spec.rb +10 -9
  78. data/spec/regexp_dissassembler_spec.rb +12 -2
  79. data/spec/result_spec.rb +1 -1
  80. data/spec/rspec/shared_spec_matchers.rb +2 -2
  81. data/spec/rspec_spec.rb +1 -1
  82. data/spec/selector_spec.rb +15 -15
  83. data/spec/selenium_spec_chrome.rb +42 -0
  84. data/spec/selenium_spec_chrome_remote.rb +0 -6
  85. data/spec/selenium_spec_edge.rb +15 -12
  86. data/spec/selenium_spec_firefox.rb +2 -4
  87. data/spec/selenium_spec_firefox_remote.rb +0 -8
  88. data/spec/selenium_spec_ie.rb +1 -6
  89. data/spec/server_spec.rb +26 -17
  90. data/spec/session_spec.rb +4 -4
  91. data/spec/shared_selenium_node.rb +36 -0
  92. data/spec/shared_selenium_session.rb +9 -1
  93. metadata +17 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2ea1da81bd27199aadc0d73d61e33b7ff0ea9911114acc375ea2e6f798a49eb4
4
- data.tar.gz: 30279a8a5ab221ae029bc95625c7c82ad11cdf68d91ef6be33e7a0b022268537
3
+ metadata.gz: 5f11a887ca6aed51d064d9c8eb797e0db4605a3d013082a11f4f4b1013b27bef
4
+ data.tar.gz: 714e834fdb1c2f0e692f547a1d032113dd888d6905eddecc60f05503720bcd8e
5
5
  SHA512:
6
- metadata.gz: 0b8d7f760540297a204ae5eb0dac8b9450e8961652de87d543ae114edb9af6a48219db7c55a40e004d49847431ef545cc5628a6bbde858e58921209f984852d2
7
- data.tar.gz: 56d10157a97fd98f7e2e23c98fc21f0dc0f70f53338a271c9fa22b639648d919134fe1c7c803be43f435a9618d49e2517ccce5d207139635c49d9f6f18a66bd6
6
+ metadata.gz: 82c37d1b9c8d1c7f9d858f8d7aebebfc2ecee4c5e35d35f9a3c949d978e4e97d48f78b9d5f93079e209fc779ab31e5707ecce8ac0d2a4ce8108fc3be2437e1bc
7
+ data.tar.gz: '06886b335dd0ef5f93f59a09026877bc460e6430b2d2f1902cd31a3179b1bd52b9418a1b43ab558dcf18e92b198506023c3549a065949bb33f881538ec9e018d'
data/History.md CHANGED
@@ -1,5 +1,83 @@
1
+ # Version 3.29.0
2
+ Release date: Unreleased
3
+
4
+ ### Added
5
+
6
+ * Allow clicking on file input when using the block version of `attach_file` with Chrome and Firefox
7
+ * Spatial filters (`left_of`, `right_of`, `above`, `below`, `near`)
8
+ * rack_test driver now supports clicking on details elements to open/close them
9
+
10
+ ### Fixed
11
+
12
+ * rack_test driver correctly determines visibility for open details elements descendants
13
+
14
+ ### Changed
15
+
16
+ * Results will now be lazily evaluated when using JRuby >= 9.2.8.0
17
+
18
+
19
+ # Version 3.28.0
20
+ Release date: 2019-08-03
21
+
22
+ ### Added
23
+
24
+ * Allow forcing HTML5 or legacy dragging via the `:html5` option to `drag_to` when using Selenium with Chrome or Firefox
25
+ * Autodetection of drag type interprets not seeing the mousedown event as legacy.
26
+ * HTML5 form validation `:valid` node filter added to `:field` and `:fillable_field` selectors
27
+ * When using Capybara registered :puma server - patches Puma 4.0.x to fix SSL connection behavior. Removes
28
+ default `queue_requests` setting - Issue #2227
29
+
30
+ # Version 3.27.0
31
+ Release date: 2019-07-28
32
+
33
+ ### Added
34
+
35
+ * Allow to use chromedriver/geckodriver native `is_element_displayed` endpoint via Selenium
36
+ driver `native_displayed` option for performance reasons. Disabled by default due to endpoints
37
+ currently not handling <details> element descendants visibility correctly.
38
+
39
+ ### Fixed
40
+
41
+ * Ignore negative lookahead/lookbehind regex when performing initial XPath text matching
42
+ * Reloading of elements found via `ancestor` and `sibling`
43
+ * Only default puma settings to `queue_requests: false` when using SSL
44
+ * Visibility of descendants of <details> elements is correctly determined when using rack_test
45
+ and the selenium driver with Capybara optimized atoms
46
+ * local/session storage clearance in Chrome when clearing only one of them - Issue #2233
47
+
48
+ # Version 3.26.0
49
+ Release date: 2019-07-15
50
+
51
+ ### Added
52
+
53
+ * `w3c_click_offset` configuration option applies to `right_click` and `double_click` as well as `click`
54
+ * Warning when passing `nil` to the text/content assertions/expectations
55
+ * `Session#server_url` returns the base url the AUT is being run at (when controlled by Capybara)
56
+ * `option` selector type accepts an integer as locator
57
+
58
+ ### Fixed
59
+
60
+ * Default puma server registration now specifies `queue_requests: false` - Issue #2227
61
+ * Workaround issue with FF 68 and hanging during reset if a system modal is visible
62
+ * Don't expand file path if it's already absolute - Issue #2228
63
+
64
+ # Version 3.25.0
65
+ Release date: 2019-06-27
66
+
67
+ ### Added
68
+
69
+ * Animation disabler also disables before and after pseudoelements - Issue #2221 [Daniel Heath]
70
+ * `w3c_click_offset` configuration option to determine whether click offsets are calculated from element
71
+ center or top left corner
72
+
73
+ ### Fixed
74
+
75
+ * Woraround issue with chromedriver 76/77 in W3C mode losing mouse state during legacy drag. Only fixed if
76
+ both source and target are simultaenously inside the viewport - Issue #2223
77
+ * Negative ancestor expectations/predicates were incorrectly checking siblings rather than ancestors
78
+
1
79
  # Version 3.24.0
2
- Release date: 2079-06-13
80
+ Release date: 2019-06-13
3
81
 
4
82
  ### Added
5
83
 
data/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
  [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/jnicklas/capybara?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
8
8
  [![SemVer](https://api.dependabot.com/badges/compatibility_score?dependency-name=capybara&package-manager=bundler&version-scheme=semver)](https://dependabot.com/compatibility-score.html?dependency-name=capybara&package-manager=bundler&version-scheme=semver)
9
9
 
10
- **Note** You are viewing the README for the 3.24.x version of Capybara.
10
+ **Note** You are viewing the README for the 3.29.x version of Capybara.
11
11
 
12
12
  Capybara helps you test web applications by simulating how a real user would
13
13
  interact with your app. It is agnostic about the driver running your tests and
@@ -391,7 +391,7 @@ Capybara supports [Selenium 3.5+
391
391
  In order to use Selenium, you'll need to install the `selenium-webdriver` gem,
392
392
  and add it to your Gemfile if you're using bundler.
393
393
 
394
- Capybara pre-registers a number of named drives that use Selenium - they are:
394
+ Capybara pre-registers a number of named drivers that use Selenium - they are:
395
395
 
396
396
  * :selenium => Selenium driving Firefox
397
397
  * :selenium_headless => Selenium driving Firefox in a headless configuration
@@ -97,6 +97,7 @@ module Capybara
97
97
  # and {configure raise_server_errors} is `true`.
98
98
  # - **test_id** (Symbol, String, `nil` = `nil`) - Optional attribute to match locator against with built-in selectors along with id.
99
99
  # - **threadsafe** (Boolean = `false`) - Whether sessions can be configured individually.
100
+ # - **w3c_click_offset** (Boolean = 'false') - Whether click offsets should be from element center (true) or top left (false)
100
101
  #
101
102
  # #### DSL Options
102
103
  #
@@ -506,4 +507,5 @@ Capybara.configure do |config|
506
507
  config.predicates_wait = true
507
508
  config.default_normalize_ws = false
508
509
  config.allow_gumbo = false
510
+ config.w3c_click_offset = false
509
511
  end
@@ -113,6 +113,10 @@ module Capybara
113
113
  !!self[:multiple]
114
114
  end
115
115
 
116
+ def rect
117
+ raise NotSupportedByDriverError, 'Capybara::Driver::Node#rect'
118
+ end
119
+
116
120
  def path
117
121
  raise NotSupportedByDriverError, 'Capybara::Driver::Node#path'
118
122
  end
@@ -9,38 +9,38 @@ module Capybara
9
9
  ## Assert text exists
10
10
  #
11
11
  # @!method assert_text
12
- # see {Capybara::Node::Matchers#assert_text}
12
+ # @see Capybara::Node::Matchers#assert_text
13
13
 
14
14
  ## Assert text does not exist
15
15
  #
16
16
  # @!method assert_no_text
17
- # see {Capybara::Node::Matchers#assert_no_text}
17
+ # @see Capybara::Node::Matchers#assert_no_text
18
18
 
19
19
  ##
20
20
  # Assertion that page title does match
21
21
  #
22
22
  # @!method assert_title
23
- # see {Capybara::Node::DocumentMatchers#assert_title}
23
+ # @see Capybara::Node::DocumentMatchers#assert_title
24
24
 
25
25
  ##
26
26
  # Assertion that page title does not match
27
27
  #
28
28
  # @!method refute_title
29
29
  # @!method assert_no_title
30
- # see {Capybara::Node::DocumentMatchers#assert_no_title}
30
+ # @see Capybara::Node::DocumentMatchers#assert_no_title
31
31
 
32
32
  ##
33
33
  # Assertion that current path matches
34
34
  #
35
35
  # @!method assert_current_path
36
- # see {Capybara::SessionMatchers#assert_current_path}
36
+ # @see Capybara::SessionMatchers#assert_current_path
37
37
 
38
38
  ##
39
39
  # Assertion that current page does not match
40
40
  #
41
41
  # @!method refute_current_path
42
42
  # @!method assert_no_current_path
43
- # see {Capybara::SessionMatchers#assert_no_current_path}
43
+ # @see Capybara::SessionMatchers#assert_no_current_path
44
44
 
45
45
  %w[text no_text title no_title current_path no_current_path].each do |assertion_name|
46
46
  class_eval <<-ASSERTION, __FILE__, __LINE__ + 1
@@ -64,37 +64,37 @@ module Capybara
64
64
  ## Assert selector exists on page
65
65
  #
66
66
  # @!method assert_selector
67
- # see {Capybara::Node::Matchers#assert_selector}
67
+ # @see Capybara::Node::Matchers#assert_selector
68
68
 
69
69
  ## Assert selector does not exist on page
70
70
  #
71
71
  # @!method assert_no_selector
72
- # see {Capybara::Node::Matchers#assert_no_selector}
72
+ # @see Capybara::Node::Matchers#assert_no_selector
73
73
 
74
74
  ## Assert element matches selector
75
75
  #
76
76
  # @!method assert_matches_selector
77
- # see {Capybara::Node::Matchers#assert_matches_selector}
77
+ # @see Capybara::Node::Matchers#assert_matches_selector
78
78
 
79
79
  ## Assert element does not match selector
80
80
  #
81
81
  # @!method assert_xpath
82
- # see {Capybara::Node::Matchers#assert_not_matches_selector}
82
+ # @see Capybara::Node::Matchers#assert_not_matches_selector
83
83
 
84
84
  ## Assert element has the provided CSS styles
85
85
  #
86
86
  # @!method assert_matches_style
87
- # see {Capybara::Node::Matchers#assert_matches_style}
87
+ # @see Capybara::Node::Matchers#assert_matches_style
88
88
 
89
89
  ## Assert element has a matching sibling
90
90
  #
91
91
  # @!method assert_sibling
92
- # see {Capybara::Node::Matchers#assert_sibling}
92
+ # @see Capybara::Node::Matchers#assert_sibling
93
93
 
94
94
  ## Assert element has a matching ancestor
95
95
  #
96
96
  # @!method assert_ancestor
97
- # see {Capybara::Node::Matchers#assert_ancestor}
97
+ # @see Capybara::Node::Matchers#assert_ancestor
98
98
 
99
99
  %w[selector no_selector matches_style
100
100
  all_of_selectors none_of_selectors any_of_selectors
@@ -163,72 +163,72 @@ module Capybara
163
163
  # Assertion that there is xpath
164
164
  #
165
165
  # @!method assert_xpath
166
- # see {Capybara::Node::Matchers#has_xpath?}
166
+ # @see Capybara::Node::Matchers#has_xpath?
167
167
 
168
168
  ##
169
169
  # Assertion that there is no xpath
170
170
  #
171
171
  # @!method refute_xpath
172
172
  # @!method assert_no_xpath
173
- # see {Capybara::Node::Matchers#has_no_xpath?}
173
+ # @see Capybara::Node::Matchers#has_no_xpath?
174
174
 
175
175
  ##
176
176
  # Assertion that there is css
177
177
  #
178
178
  # @!method assert_css
179
- # see {Capybara::Node::Matchers#has_css?}
179
+ # @see Capybara::Node::Matchers#has_css?
180
180
 
181
181
  ##
182
182
  # Assertion that there is no css
183
183
  #
184
184
  # @!method refute_css
185
185
  # @!method assert_no_css
186
- # see {Capybara::Node::Matchers#has_no_css?}
186
+ # @see Capybara::Node::Matchers#has_no_css?
187
187
 
188
188
  ##
189
189
  # Assertion that there is link
190
190
  #
191
191
  # @!method assert_link
192
- # see {Capybara::Node::Matchers#has_link?}
192
+ # @see Capybara::Node::Matchers#has_link?
193
193
 
194
194
  ##
195
195
  # Assertion that there is no link
196
196
  #
197
197
  # @!method assert_no_link
198
198
  # @!method refute_link
199
- # see {Capybara::Node::Matchers#has_no_link?}
199
+ # @see Capybara::Node::Matchers#has_no_link?
200
200
 
201
201
  ##
202
202
  # Assertion that there is button
203
203
  #
204
204
  # @!method assert_button
205
- # see {Capybara::Node::Matchers#has_button?}
205
+ # @see Capybara::Node::Matchers#has_button?
206
206
 
207
207
  ##
208
208
  # Assertion that there is no button
209
209
  #
210
210
  # @!method refute_button
211
211
  # @!method assert_no_button
212
- # see {Capybara::Node::Matchers#has_no_button?}
212
+ # @see Capybara::Node::Matchers#has_no_button?
213
213
 
214
214
  ##
215
215
  # Assertion that there is field
216
216
  #
217
217
  # @!method assert_field
218
- # see {Capybara::Node::Matchers#has_field?}
218
+ # @see Capybara::Node::Matchers#has_field?
219
219
 
220
220
  ##
221
221
  # Assertion that there is no field
222
222
  #
223
223
  # @!method refute_field
224
224
  # @!method assert_no_field
225
- # see {Capybara::Node::Matchers#has_no_field?}
225
+ # @see Capybara::Node::Matchers#has_no_field?
226
226
 
227
227
  ##
228
228
  # Assertion that there is checked_field
229
229
  #
230
230
  # @!method assert_checked_field
231
- # see {Capybara::Node::Matchers#has_checked_field?}
231
+ # @see Capybara::Node::Matchers#has_checked_field?
232
232
 
233
233
  ##
234
234
  # Assertion that there is no checked_field
@@ -240,7 +240,7 @@ module Capybara
240
240
  # Assertion that there is unchecked_field
241
241
  #
242
242
  # @!method assert_unchecked_field
243
- # see {Capybara::Node::Matchers#has_unchecked_field?}
243
+ # @see Capybara::Node::Matchers#has_unchecked_field?
244
244
 
245
245
  ##
246
246
  # Assertion that there is no unchecked_field
@@ -252,27 +252,27 @@ module Capybara
252
252
  # Assertion that there is select
253
253
  #
254
254
  # @!method assert_select
255
- # see {Capybara::Node::Matchers#has_select?}
255
+ # @see Capybara::Node::Matchers#has_select?
256
256
 
257
257
  ##
258
258
  # Assertion that there is no select
259
259
  #
260
260
  # @!method refute_select
261
261
  # @!method assert_no_select
262
- # see {Capybara::Node::Matchers#has_no_select?}
262
+ # @see Capybara::Node::Matchers#has_no_select?
263
263
 
264
264
  ##
265
265
  # Assertion that there is table
266
266
  #
267
267
  # @!method assert_table
268
- # see {Capybara::Node::Matchers#has_table?}
268
+ # @see Capybara::Node::Matchers#has_table?
269
269
 
270
270
  ##
271
271
  # Assertion that there is no table
272
272
  #
273
273
  # @!method refute_table
274
274
  # @!method assert_no_table
275
- # see {Capybara::Node::Matchers#has_no_table?}
275
+ # @see Capybara::Node::Matchers#has_no_table?
276
276
 
277
277
  private
278
278
 
@@ -288,6 +288,7 @@ module Capybara
288
288
  execute_script CAPTURE_FILE_ELEMENT_SCRIPT
289
289
  yield
290
290
  file_field = evaluate_script 'window._capybara_clicked_file_input'
291
+ raise ArgumentError, "Capybara was unable to determine the file input you're attaching to" unless file_field
291
292
  rescue ::Capybara::NotSupportedByDriverError
292
293
  warn 'Block mode of `#attach_file` is not supported by the current driver - ignoring.'
293
294
  end
@@ -307,12 +308,12 @@ module Capybara
307
308
  synchronize(Capybara::Queries::BaseQuery.wait(options, session_options.default_max_wait_time)) do
308
309
  begin
309
310
  find(:select, from, options)
310
- rescue Capybara::ElementNotFound => select_error
311
+ rescue Capybara::ElementNotFound => select_error # rubocop:disable Naming/RescuedExceptionsVariableName
311
312
  raise if %i[selected with_selected multiple].any? { |option| options.key?(option) }
312
313
 
313
314
  begin
314
315
  find(:datalist_input, from, options)
315
- rescue Capybara::ElementNotFound => dlinput_error
316
+ rescue Capybara::ElementNotFound => dlinput_error # rubocop:disable Naming/RescuedExceptionsVariableName
316
317
  raise Capybara::ElementNotFound, "#{select_error.message} and #{dlinput_error.message}"
317
318
  end
318
319
  end
@@ -157,14 +157,15 @@ module Capybara
157
157
  # Both x: and y: must be specified if an offset is wanted, if not specified the click will occur at the middle of the element.
158
158
  # @overload $0(*modifier_keys, wait: nil, **offset)
159
159
  # @param *modifier_keys [:alt, :control, :meta, :shift] ([]) Keys to be held down when clicking
160
- # @option offset [Integer] x X coordinate to offset the click location from the top left corner of the element
161
- # @option offset [Integer] y Y coordinate to offset the click location from the top left corner of the element
160
+ # @option options [Integer] x X coordinate to offset the click location. If {Capybara.configure w3c_click_offset} is `true` the
161
+ # offset will be from the element center, otherwise it will be from the top left corner of the element
162
+ # @option options [Integer] y Y coordinate to offset the click location. If {Capybara.configure w3c_click_offset} is `true` the
163
+ # offset will be from the element center, otherwise it will be from the top left corner of the element
162
164
  # @return [Capybara::Node::Element] The element
163
- def click(*keys, wait: nil, **offset)
164
- raise ArgumentError, 'You must specify both x: and y: for a click offset' if nil ^ offset[:x] ^ offset[:y]
165
-
166
- synchronize(wait) { base.click(Array(keys), offset) }
167
- self
165
+ def click(*keys, **options)
166
+ perform_click_action(keys, options) do |k, opts|
167
+ base.click(k, opts)
168
+ end
168
169
  end
169
170
 
170
171
  ##
@@ -174,11 +175,10 @@ module Capybara
174
175
  # @macro action_waiting_behavior
175
176
  # @macro click_modifiers
176
177
  # @return [Capybara::Node::Element] The element
177
- def right_click(*keys, wait: nil, **offset)
178
- raise ArgumentError, 'You must specify both x: and y: for a click offset' if nil ^ offset[:x] ^ offset[:y]
179
-
180
- synchronize(wait) { base.right_click(keys, offset) }
181
- self
178
+ def right_click(*keys, **options)
179
+ perform_click_action(keys, options) do |k, opts|
180
+ base.right_click(k, opts)
181
+ end
182
182
  end
183
183
 
184
184
  ##
@@ -188,11 +188,10 @@ module Capybara
188
188
  # @macro action_waiting_behavior
189
189
  # @macro click_modifiers
190
190
  # @return [Capybara::Node::Element] The element
191
- def double_click(*keys, wait: nil, **offset)
192
- raise ArgumentError, 'You must specify both x: and y: for a click offset' if nil ^ offset[:x] ^ offset[:y]
193
-
194
- synchronize(wait) { base.double_click(keys, offset) }
195
- self
191
+ def double_click(*keys, **options)
192
+ perform_click_action(keys, options) do |k, opts|
193
+ base.double_click(k, opts)
194
+ end
196
195
  end
197
196
 
198
197
  ##
@@ -372,6 +371,10 @@ module Capybara
372
371
  synchronize { base.path }
373
372
  end
374
373
 
374
+ def rect
375
+ synchronize { base.rect }
376
+ end
377
+
375
378
  ##
376
379
  #
377
380
  # Trigger any event on the current element, for example mouseover or focus
@@ -397,8 +400,13 @@ module Capybara
397
400
  #
398
401
  # @param [Capybara::Node::Element] node The element to drag to
399
402
  # @param [Hash] options Driver specific options for dragging. May not be supported by all drivers.
403
+ # @option options [Numeric] :delay (0.05) When using Chrome/Firefox with Selenium and HTML5 dragging this is the number
404
+ # of seconds between each stage of the drag.
405
+ # @option options [Boolean] :html5 When using Chrome/Firefox with Selenium enables to force the use of HTML5
406
+ # (true) or legacy (false) dragging. If not specified the driver will attempt to
407
+ # detect the correct method to use.
400
408
  #
401
- # @return [Capybara::Node::Element] The element
409
+ # @return [Capybara::Node::Element] The dragged element
402
410
  def drag_to(node, **options)
403
411
  synchronize { base.drag_to(node.base, **options) }
404
412
  self
@@ -511,11 +519,34 @@ module Capybara
511
519
  JS
512
520
  end
513
521
 
522
+ ##
523
+ #
524
+ # Toggle the elements background color between white and black for a period of time.
525
+ #
526
+ # @return [Capybara::Node::Element] The element
527
+ def flash
528
+ execute_script(<<~JS, 100)
529
+ async function flash(el, delay){
530
+ var old_bg = el.style.backgroundColor;
531
+ var colors = ["black", "white"];
532
+ for(var i=0; i<20; i++){
533
+ el.style.backgroundColor = colors[i % colors.length];
534
+ await new Promise(resolve => setTimeout(resolve, delay));
535
+ }
536
+ el.style.backgroundColor = old_bg;
537
+ }
538
+ flash(this, arguments[0]);
539
+ JS
540
+
541
+ self
542
+ end
543
+
514
544
  # @api private
515
545
  def reload
516
546
  if @allow_reload
517
547
  begin
518
- reloaded = query_scope.reload.first(@query.name, @query.locator, @query.options)
548
+ reloaded = @query.resolve_for(query_scope.reload)&.first
549
+
519
550
  @base = reloaded.base if reloaded
520
551
  rescue StandardError => e
521
552
  raise e unless catch_error?(e)
@@ -553,6 +584,16 @@ module Capybara
553
584
  return result;
554
585
  }).apply(this, arguments)
555
586
  JS
587
+
588
+ private
589
+
590
+ def perform_click_action(keys, wait: nil, **options)
591
+ raise ArgumentError, 'You must specify both x: and y: for a click offset' if nil ^ options[:x] ^ options[:y]
592
+
593
+ options[:offset] ||= :center if session_options.w3c_click_offset
594
+ synchronize(wait) { yield keys, options }
595
+ self
596
+ end
556
597
  end
557
598
  end
558
599
  end