capybara 3.29.0 → 3.31.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 (101) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +40 -1
  3. data/README.md +1 -1
  4. data/lib/capybara/config.rb +7 -3
  5. data/lib/capybara/dsl.rb +10 -2
  6. data/lib/capybara/helpers.rb +3 -1
  7. data/lib/capybara/minitest.rb +18 -4
  8. data/lib/capybara/node/actions.rb +23 -19
  9. data/lib/capybara/node/document.rb +2 -2
  10. data/lib/capybara/node/document_matchers.rb +3 -3
  11. data/lib/capybara/node/element.rb +21 -16
  12. data/lib/capybara/node/finders.rb +17 -11
  13. data/lib/capybara/node/matchers.rb +60 -45
  14. data/lib/capybara/node/simple.rb +4 -2
  15. data/lib/capybara/queries/ancestor_query.rb +1 -1
  16. data/lib/capybara/queries/base_query.rb +2 -1
  17. data/lib/capybara/queries/selector_query.rb +17 -4
  18. data/lib/capybara/queries/sibling_query.rb +1 -1
  19. data/lib/capybara/rack_test/browser.rb +4 -1
  20. data/lib/capybara/rack_test/driver.rb +1 -1
  21. data/lib/capybara/rack_test/form.rb +1 -1
  22. data/lib/capybara/rack_test/node.rb +34 -9
  23. data/lib/capybara/result.rb +24 -4
  24. data/lib/capybara/rspec/matchers.rb +27 -27
  25. data/lib/capybara/rspec/matchers/base.rb +12 -6
  26. data/lib/capybara/rspec/matchers/count_sugar.rb +2 -1
  27. data/lib/capybara/rspec/matchers/have_ancestor.rb +4 -3
  28. data/lib/capybara/rspec/matchers/have_current_path.rb +2 -2
  29. data/lib/capybara/rspec/matchers/have_selector.rb +15 -7
  30. data/lib/capybara/rspec/matchers/have_sibling.rb +3 -3
  31. data/lib/capybara/rspec/matchers/have_text.rb +2 -2
  32. data/lib/capybara/rspec/matchers/have_title.rb +2 -2
  33. data/lib/capybara/rspec/matchers/match_selector.rb +3 -3
  34. data/lib/capybara/rspec/matchers/match_style.rb +2 -2
  35. data/lib/capybara/rspec/matchers/spatial_sugar.rb +2 -1
  36. data/lib/capybara/selector.rb +24 -16
  37. data/lib/capybara/selector/css.rb +1 -1
  38. data/lib/capybara/selector/definition.rb +2 -2
  39. data/lib/capybara/selector/definition/button.rb +7 -2
  40. data/lib/capybara/selector/definition/checkbox.rb +2 -2
  41. data/lib/capybara/selector/definition/css.rb +3 -1
  42. data/lib/capybara/selector/definition/datalist_input.rb +1 -1
  43. data/lib/capybara/selector/definition/datalist_option.rb +1 -1
  44. data/lib/capybara/selector/definition/element.rb +1 -1
  45. data/lib/capybara/selector/definition/field.rb +1 -1
  46. data/lib/capybara/selector/definition/file_field.rb +1 -1
  47. data/lib/capybara/selector/definition/fillable_field.rb +1 -1
  48. data/lib/capybara/selector/definition/label.rb +4 -2
  49. data/lib/capybara/selector/definition/radio_button.rb +2 -2
  50. data/lib/capybara/selector/definition/select.rb +32 -13
  51. data/lib/capybara/selector/definition/table.rb +5 -2
  52. data/lib/capybara/selector/filter_set.rb +11 -9
  53. data/lib/capybara/selector/filters/base.rb +6 -1
  54. data/lib/capybara/selector/filters/locator_filter.rb +1 -1
  55. data/lib/capybara/selector/selector.rb +4 -2
  56. data/lib/capybara/selenium/driver.rb +19 -11
  57. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +1 -1
  58. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +2 -2
  59. data/lib/capybara/selenium/extensions/html5_drag.rb +30 -13
  60. data/lib/capybara/selenium/node.rb +29 -10
  61. data/lib/capybara/selenium/nodes/chrome_node.rb +11 -5
  62. data/lib/capybara/selenium/nodes/edge_node.rb +4 -2
  63. data/lib/capybara/selenium/nodes/firefox_node.rb +2 -2
  64. data/lib/capybara/server.rb +15 -3
  65. data/lib/capybara/server/checker.rb +1 -1
  66. data/lib/capybara/server/middleware.rb +20 -10
  67. data/lib/capybara/session.rb +40 -23
  68. data/lib/capybara/session/config.rb +6 -2
  69. data/lib/capybara/session/matchers.rb +6 -6
  70. data/lib/capybara/spec/public/test.js +51 -6
  71. data/lib/capybara/spec/session/all_spec.rb +60 -5
  72. data/lib/capybara/spec/session/ancestor_spec.rb +5 -0
  73. data/lib/capybara/spec/session/assert_text_spec.rb +9 -5
  74. data/lib/capybara/spec/session/click_button_spec.rb +5 -0
  75. data/lib/capybara/spec/session/fill_in_spec.rb +20 -0
  76. data/lib/capybara/spec/session/find_spec.rb +20 -0
  77. data/lib/capybara/spec/session/has_css_spec.rb +3 -3
  78. data/lib/capybara/spec/session/has_select_spec.rb +28 -0
  79. data/lib/capybara/spec/session/has_table_spec.rb +51 -5
  80. data/lib/capybara/spec/session/has_text_spec.rb +35 -0
  81. data/lib/capybara/spec/session/node_spec.rb +106 -2
  82. data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +2 -2
  83. data/lib/capybara/spec/session/save_screenshot_spec.rb +4 -4
  84. data/lib/capybara/spec/session/selectors_spec.rb +15 -2
  85. data/lib/capybara/spec/views/form.erb +11 -1
  86. data/lib/capybara/version.rb +1 -1
  87. data/spec/dsl_spec.rb +2 -2
  88. data/spec/minitest_spec_spec.rb +46 -46
  89. data/spec/rack_test_spec.rb +0 -1
  90. data/spec/regexp_dissassembler_spec.rb +45 -37
  91. data/spec/result_spec.rb +7 -3
  92. data/spec/rspec/features_spec.rb +1 -0
  93. data/spec/rspec/shared_spec_matchers.rb +3 -3
  94. data/spec/rspec_spec.rb +4 -4
  95. data/spec/selenium_spec_chrome.rb +5 -4
  96. data/spec/selenium_spec_firefox.rb +7 -2
  97. data/spec/server_spec.rb +42 -0
  98. data/spec/session_spec.rb +1 -1
  99. data/spec/shared_selenium_node.rb +3 -3
  100. data/spec/shared_selenium_session.rb +8 -7
  101. metadata +3 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5f11a887ca6aed51d064d9c8eb797e0db4605a3d013082a11f4f4b1013b27bef
4
- data.tar.gz: 714e834fdb1c2f0e692f547a1d032113dd888d6905eddecc60f05503720bcd8e
3
+ metadata.gz: dd31d35629d475d7fdaba1d6e415599d995a08f27b28fa619a3a4449b61b91d8
4
+ data.tar.gz: 27c812629e2d99e8f4c62fa7961df9b499c5346b1c61092faf487f592356033d
5
5
  SHA512:
6
- metadata.gz: 82c37d1b9c8d1c7f9d858f8d7aebebfc2ecee4c5e35d35f9a3c949d978e4e97d48f78b9d5f93079e209fc779ab31e5707ecce8ac0d2a4ce8108fc3be2437e1bc
7
- data.tar.gz: '06886b335dd0ef5f93f59a09026877bc460e6430b2d2f1902cd31a3179b1bd52b9418a1b43ab558dcf18e92b198506023c3549a065949bb33f881538ec9e018d'
6
+ metadata.gz: 946e3f2de0137ddaa6e3a2febba2c87244997737c54a10024133de110ca41b8aeddcb66e0437bef5d826e9fe21d4c42701674c3864bd578d24c30c7b1f90e2a9
7
+ data.tar.gz: f9409de3e2e0ea44e0bb6b6f77cce7e0e8f5a4d95c43fb62af2eb63d11e755d6a8c00b9b9b4d2bbe2729538d0d1038e92468e0a7994d1578b50e05b5227b87f4
data/History.md CHANGED
@@ -1,5 +1,44 @@
1
+ # Version 3.31.0
2
+ Release date: 2020-01-26
3
+
4
+ ### Added
5
+
6
+ * Support setting range inputs with the selenium driver [Andrew White]
7
+ * Support setting range inputs with the rack driver
8
+ * Support drop modifier keys in drag & drop [Elliot Crosby-McCullough]
9
+ * `enabled_options` and `disabled options` filters for select selector
10
+ * Support beginless ranges
11
+ * Optionally allow `all` results to be reloaded when stable - Beta feature - may be removed in
12
+ future version if problems occur
13
+
14
+ ### Fixed
15
+
16
+ * Fix Ruby 2.7 deprecation notices around keyword arguments. I have tried to do this without
17
+ any breaking changes, but due to the nature of the 2.7 changes and some selector types accepting
18
+ Hashes as locators there are a lot of edge cases. If you find any broken cases please report
19
+ them and I'll see if they're fixable.
20
+ * Clicking on details/summary element behavior in rack_test driver_
21
+
22
+ # Version 3.30.0
23
+ Release date: 2019-12-24
24
+
25
+ ### Added
26
+
27
+ * Display pending requests when they don't complete in time [Juan Carlos Medina]
28
+ * :order option in selector queries - set to :reverse to for reverse document order results
29
+ * Support regexp for :name and :placeholder options in selectors that import filters from
30
+ _field filter set
31
+
32
+ ### Fixed
33
+
34
+ * Issue around automatic port assignment - Issue #2245
35
+ * Label selector when label has no id - Issue #2260
36
+ * Preserve clientX/clientY in Selenium HTML5 drag emulation [Nicolò G.]
37
+ * table selector using :with_cols option if last specified column matched but others didn't - Issue #2287
38
+ * Some tests updated for Ruby 2.7 behavior change around keyword args
39
+
1
40
  # Version 3.29.0
2
- Release date: Unreleased
41
+ Release date: 2019-09-02
3
42
 
4
43
  ### Added
5
44
 
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.29.x version of Capybara.
10
+ **Note** You are viewing the README for the 3.31.x stable branch 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
@@ -27,7 +27,9 @@ module Capybara
27
27
  attr_writer :reuse_server
28
28
 
29
29
  def threadsafe=(bool)
30
- raise 'Threadsafe setting cannot be changed once a session is created' if (bool != threadsafe) && Session.instance_created?
30
+ if (bool != threadsafe) && Session.instance_created?
31
+ raise 'Threadsafe setting cannot be changed once a session is created'
32
+ end
31
33
 
32
34
  @threadsafe = bool
33
35
  end
@@ -59,7 +61,7 @@ module Capybara
59
61
  @server = if name.respond_to? :call
60
62
  name
61
63
  elsif options
62
- proc { |app, port, host| Capybara.servers[name.to_sym].call(app, port, host, options) }
64
+ proc { |app, port, host| Capybara.servers[name.to_sym].call(app, port, host, **options) }
63
65
  else
64
66
  Capybara.servers[name.to_sym]
65
67
  end
@@ -83,7 +85,9 @@ module Capybara
83
85
 
84
86
  def deprecate(method, alternate_method, once = false)
85
87
  @deprecation_notified ||= {}
86
- warn "DEPRECATED: ##{method} is deprecated, please use ##{alternate_method} instead" unless once && @deprecation_notified[method]
88
+ unless once && @deprecation_notified[method]
89
+ warn "DEPRECATED: ##{method} is deprecated, please use ##{alternate_method} instead"
90
+ end
87
91
  @deprecation_notified[method] = true
88
92
  end
89
93
  end
@@ -47,8 +47,16 @@ module Capybara
47
47
  end
48
48
 
49
49
  Session::DSL_METHODS.each do |method|
50
- define_method method do |*args, &block|
51
- page.send method, *args, &block
50
+ if RUBY_VERSION >= '2.7'
51
+ class_eval <<~METHOD, __FILE__, __LINE__ + 1
52
+ def #{method}(...)
53
+ page.method("#{method}").call(...)
54
+ end
55
+ METHOD
56
+ else
57
+ define_method method do |*args, &block|
58
+ page.send method, *args, &block
59
+ end
52
60
  end
53
61
  end
54
62
  end
@@ -87,7 +87,9 @@ module Capybara
87
87
  end
88
88
 
89
89
  def expired?
90
- raise Capybara::FrozenInTime, 'Time appears to be frozen. Capybara does not work with libraries which freeze time, consider using time travelling instead' if stalled?
90
+ if stalled?
91
+ raise Capybara::FrozenInTime, 'Time appears to be frozen. Capybara does not work with libraries which freeze time, consider using time travelling instead'
92
+ end
91
93
 
92
94
  current - @start >= @expire_in
93
95
  end
@@ -52,6 +52,7 @@ module Capybara
52
52
  raise ::Minitest::Assertion, e.message
53
53
  end
54
54
  ASSERTION
55
+ ruby2_keywords "assert_#{assertion_name}" if respond_to?(:ruby2_keywords)
55
56
  end
56
57
 
57
58
  alias_method :refute_title, :assert_no_title
@@ -109,6 +110,7 @@ module Capybara
109
110
  raise ::Minitest::Assertion, e.message
110
111
  end
111
112
  ASSERTION
113
+ ruby2_keywords "assert_#{assertion_name}" if respond_to?(:ruby2_keywords)
112
114
  end
113
115
 
114
116
  alias_method :refute_selector, :assert_no_selector
@@ -120,14 +122,16 @@ module Capybara
120
122
  define_method "assert_#{selector_type}" do |*args, &optional_filter_block|
121
123
  subject, args = determine_subject(args)
122
124
  locator, options = extract_locator(args)
123
- assert_selector(subject, selector_type.to_sym, locator, options, &optional_filter_block)
125
+ assert_selector(subject, selector_type.to_sym, locator, **options, &optional_filter_block)
124
126
  end
127
+ ruby2_keywords "assert_#{selector_type}" if respond_to?(:ruby2_keywords)
125
128
 
126
129
  define_method "assert_no_#{selector_type}" do |*args, &optional_filter_block|
127
130
  subject, args = determine_subject(args)
128
131
  locator, options = extract_locator(args)
129
- assert_no_selector(subject, selector_type.to_sym, locator, options, &optional_filter_block)
132
+ assert_no_selector(subject, selector_type.to_sym, locator, **options, &optional_filter_block)
130
133
  end
134
+ ruby2_keywords "assert_no_#{selector_type}" if respond_to?(:ruby2_keywords)
131
135
  alias_method "refute_#{selector_type}", "assert_no_#{selector_type}"
132
136
  end
133
137
 
@@ -135,14 +139,22 @@ module Capybara
135
139
  define_method "assert_#{field_type}_field" do |*args, &optional_filter_block|
136
140
  subject, args = determine_subject(args)
137
141
  locator, options = extract_locator(args)
138
- assert_selector(subject, :field, locator, options.merge(field_type.to_sym => true), &optional_filter_block)
142
+ assert_selector(subject, :field, locator, **options.merge(field_type.to_sym => true), &optional_filter_block)
139
143
  end
144
+ ruby2_keywords "assert_#{field_type}_field" if respond_to?(:ruby2_keywords)
140
145
 
141
146
  define_method "assert_no_#{field_type}_field" do |*args, &optional_filter_block|
142
147
  subject, args = determine_subject(args)
143
148
  locator, options = extract_locator(args)
144
- assert_no_selector(subject, :field, locator, options.merge(field_type.to_sym => true), &optional_filter_block)
149
+ assert_no_selector(
150
+ subject,
151
+ :field,
152
+ locator,
153
+ **options.merge(field_type.to_sym => true),
154
+ &optional_filter_block
155
+ )
145
156
  end
157
+ ruby2_keywords "assert_no_#{field_type}_field" if respond_to?(:ruby2_keywords)
146
158
  alias_method "refute_#{field_type}_field", "assert_no_#{field_type}_field"
147
159
  end
148
160
 
@@ -151,11 +163,13 @@ module Capybara
151
163
  subject, args = determine_subject(args)
152
164
  assert_matches_selector(subject, selector_type.to_sym, *args, &optional_filter_block)
153
165
  end
166
+ ruby2_keywords "assert_matches_#{selector_type}" if respond_to?(:ruby2_keywords)
154
167
 
155
168
  define_method "assert_not_matches_#{selector_type}" do |*args, &optional_filter_block|
156
169
  subject, args = determine_subject(args)
157
170
  assert_not_matches_selector(subject, selector_type.to_sym, *args, &optional_filter_block)
158
171
  end
172
+ ruby2_keywords "assert_not_matches_#{selector_type}" if respond_to?(:ruby2_keywords)
159
173
  alias_method "refute_matches_#{selector_type}", "assert_not_matches_#{selector_type}"
160
174
  end
161
175
 
@@ -23,7 +23,7 @@ module Capybara
23
23
  # @return [Capybara::Node::Element] The element clicked
24
24
  #
25
25
  def click_link_or_button(locator = nil, **options)
26
- find(:link_or_button, locator, options).click
26
+ find(:link_or_button, locator, **options).click
27
27
  end
28
28
  alias_method :click_on, :click_link_or_button
29
29
 
@@ -39,7 +39,7 @@ module Capybara
39
39
  #
40
40
  # @return [Capybara::Node::Element] The element clicked
41
41
  def click_link(locator = nil, **options)
42
- find(:link, locator, options).click
42
+ find(:link, locator, **options).click
43
43
  end
44
44
 
45
45
  ##
@@ -55,7 +55,7 @@ module Capybara
55
55
  # @param [Hash] options See {Capybara::Node::Finders#find_button}
56
56
  # @return [Capybara::Node::Element] The element clicked
57
57
  def click_button(locator = nil, **options)
58
- find(:button, locator, options).click
58
+ find(:button, locator, **options).click
59
59
  end
60
60
 
61
61
  ##
@@ -88,7 +88,7 @@ module Capybara
88
88
  def fill_in(locator = nil, with:, currently_with: nil, fill_options: {}, **find_options)
89
89
  find_options[:with] = currently_with if currently_with
90
90
  find_options[:allow_self] = true if locator.nil?
91
- find(:fillable_field, locator, find_options).set(with, fill_options)
91
+ find(:fillable_field, locator, **find_options).set(with, **fill_options)
92
92
  end
93
93
 
94
94
  # @!macro label_click
@@ -119,7 +119,7 @@ module Capybara
119
119
  #
120
120
  # @return [Capybara::Node::Element] The element chosen or the label clicked
121
121
  def choose(locator = nil, **options)
122
- _check_with_label(:radio_button, true, locator, options)
122
+ _check_with_label(:radio_button, true, locator, **options)
123
123
  end
124
124
 
125
125
  ##
@@ -147,7 +147,7 @@ module Capybara
147
147
  #
148
148
  # @return [Capybara::Node::Element] The element checked or the label clicked
149
149
  def check(locator = nil, **options)
150
- _check_with_label(:checkbox, true, locator, options)
150
+ _check_with_label(:checkbox, true, locator, **options)
151
151
  end
152
152
 
153
153
  ##
@@ -175,7 +175,7 @@ module Capybara
175
175
  #
176
176
  # @return [Capybara::Node::Element] The element unchecked or the label clicked
177
177
  def uncheck(locator = nil, **options)
178
- _check_with_label(:checkbox, false, locator, options)
178
+ _check_with_label(:checkbox, false, locator, **options)
179
179
  end
180
180
 
181
181
  ##
@@ -205,7 +205,7 @@ module Capybara
205
205
  if el.respond_to?(:tag_name) && (el.tag_name == 'input')
206
206
  select_datalist_option(el, value)
207
207
  else
208
- el.find(:option, value, options).select_option
208
+ el.find(:option, value, **options).select_option
209
209
  end
210
210
  end
211
211
 
@@ -229,8 +229,8 @@ module Capybara
229
229
  def unselect(value = nil, from: nil, **options)
230
230
  raise ArgumentError, 'The :from option does not take an element' if from.is_a? Capybara::Node::Element
231
231
 
232
- scope = from ? find(:select, from, options) : self
233
- scope.find(:option, value, options).unselect_option
232
+ scope = from ? find(:select, from, **options) : self
233
+ scope.find(:option, value, **options).unselect_option
234
234
  end
235
235
 
236
236
  ##
@@ -276,7 +276,9 @@ module Capybara
276
276
  # @yield Block whose actions will trigger the system file chooser to be shown
277
277
  # @return [Capybara::Node::Element] The file field element
278
278
  def attach_file(locator = nil, paths, make_visible: nil, **options) # rubocop:disable Style/OptionalArguments
279
- raise ArgumentError, '``#attach_file` does not support passing both a locator and a block' if locator && block_given?
279
+ if locator && block_given?
280
+ raise ArgumentError, '``#attach_file` does not support passing both a locator and a block'
281
+ end
280
282
 
281
283
  Array(paths).each do |path|
282
284
  raise Capybara::FileNotFound, "cannot attach file, #{path} does not exist" unless File.exist?(path.to_s)
@@ -295,10 +297,10 @@ module Capybara
295
297
  end
296
298
  # Allow user to update the CSS style of the file input since they are so often hidden on a page
297
299
  if make_visible
298
- ff = file_field || find(:file_field, locator, options.merge(visible: :all))
300
+ ff = file_field || find(:file_field, locator, **options.merge(visible: :all))
299
301
  while_visible(ff, make_visible) { |el| el.set(paths) }
300
302
  else
301
- (file_field || find(:file_field, locator, options)).set(paths)
303
+ (file_field || find(:file_field, locator, **options)).set(paths)
302
304
  end
303
305
  end
304
306
 
@@ -307,12 +309,12 @@ module Capybara
307
309
  def find_select_or_datalist_input(from, options)
308
310
  synchronize(Capybara::Queries::BaseQuery.wait(options, session_options.default_max_wait_time)) do
309
311
  begin
310
- find(:select, from, options)
312
+ find(:select, from, **options)
311
313
  rescue Capybara::ElementNotFound => select_error # rubocop:disable Naming/RescuedExceptionsVariableName
312
314
  raise if %i[selected with_selected multiple].any? { |option| options.key?(option) }
313
315
 
314
316
  begin
315
- find(:datalist_input, from, options)
317
+ find(:datalist_input, from, **options)
316
318
  rescue Capybara::ElementNotFound => dlinput_error # rubocop:disable Naming/RescuedExceptionsVariableName
317
319
  raise Capybara::ElementNotFound, "#{select_error.message} and #{dlinput_error.message}"
318
320
  end
@@ -338,7 +340,9 @@ module Capybara
338
340
  visible_css = { opacity: 1, display: 'block', visibility: 'visible', width: 'auto', height: 'auto' }
339
341
  end
340
342
  _update_style(element, visible_css)
341
- raise ExpectationNotMet, 'The style changes in :make_visible did not make the file input visible' unless element.visible?
343
+ unless element.visible?
344
+ raise ExpectationNotMet, 'The style changes in :make_visible did not make the file input visible'
345
+ end
342
346
 
343
347
  begin
344
348
  yield element
@@ -355,7 +359,7 @@ module Capybara
355
359
 
356
360
  def _reset_style(element)
357
361
  element.execute_script(RESET_STYLE_SCRIPT)
358
- rescue StandardError # rubocop:disable Lint/HandleExceptions swallow extra errors
362
+ rescue StandardError # rubocop:disable Lint/SuppressedException swallow extra errors
359
363
  end
360
364
 
361
365
  def _check_with_label(selector, checked, locator,
@@ -364,13 +368,13 @@ module Capybara
364
368
 
365
369
  synchronize(Capybara::Queries::BaseQuery.wait(options, session_options.default_max_wait_time)) do
366
370
  begin
367
- el = find(selector, locator, options)
371
+ el = find(selector, locator, **options)
368
372
  el.set(checked)
369
373
  rescue StandardError => e
370
374
  raise unless allow_label_click && catch_error?(e)
371
375
 
372
376
  begin
373
- el ||= find(selector, locator, options.merge(visible: :all))
377
+ el ||= find(selector, locator, **options.merge(visible: :all))
374
378
  el.session.find(:label, for: el, visible: true).click unless el.checked? == checked
375
379
  rescue StandardError # swallow extra errors - raise original
376
380
  raise e
@@ -40,8 +40,8 @@ module Capybara
40
40
  find(:xpath, '/html').evaluate_script(*args)
41
41
  end
42
42
 
43
- def scroll_to(*args)
44
- find(:xpath, '//body').scroll_to(*args)
43
+ def scroll_to(*args, **options)
44
+ find(:xpath, '//body').scroll_to(*args, **options)
45
45
  end
46
46
  end
47
47
  end
@@ -42,7 +42,7 @@ module Capybara
42
42
  # @return [Boolean]
43
43
  #
44
44
  def has_title?(title, **options)
45
- make_predicate(options) { assert_title(title, options) }
45
+ make_predicate(options) { assert_title(title, **options) }
46
46
  end
47
47
 
48
48
  ##
@@ -52,13 +52,13 @@ module Capybara
52
52
  # @return [Boolean]
53
53
  #
54
54
  def has_no_title?(title, **options)
55
- make_predicate(options) { assert_no_title(title, options) }
55
+ make_predicate(options) { assert_no_title(title, **options) }
56
56
  end
57
57
 
58
58
  private
59
59
 
60
60
  def _verify_title(title, options)
61
- query = Capybara::Queries::TitleQuery.new(title, options)
61
+ query = Capybara::Queries::TitleQuery.new(title, **options)
62
62
  synchronize(query.wait) { yield(query) }
63
63
  true
64
64
  end
@@ -27,9 +27,11 @@ module Capybara
27
27
  @query_scope = query_scope
28
28
  @query = query
29
29
  @allow_reload = false
30
+ @query_idx = nil
30
31
  end
31
32
 
32
- def allow_reload!
33
+ def allow_reload!(idx = nil)
34
+ @query_idx = idx
33
35
  @allow_reload = true
34
36
  end
35
37
 
@@ -113,10 +115,12 @@ module Capybara
113
115
  #
114
116
  # @return [Capybara::Node::Element] The element
115
117
  def set(value, **options)
116
- raise Capybara::ReadOnlyElementError, "Attempt to set readonly element with value: #{value}" if ENV['CAPYBARA_THOROUGH'] && readonly?
118
+ if ENV['CAPYBARA_THOROUGH'] && readonly?
119
+ raise Capybara::ReadOnlyElementError, "Attempt to set readonly element with value: #{value}"
120
+ end
117
121
 
118
122
  options = session_options.default_set_options.to_h.merge(options)
119
- synchronize { base.set(value, options) }
123
+ synchronize { base.set(value, **options) }
120
124
  self
121
125
  end
122
126
 
@@ -163,8 +167,8 @@ module Capybara
163
167
  # offset will be from the element center, otherwise it will be from the top left corner of the element
164
168
  # @return [Capybara::Node::Element] The element
165
169
  def click(*keys, **options)
166
- perform_click_action(keys, options) do |k, opts|
167
- base.click(k, opts)
170
+ perform_click_action(keys, **options) do |k, opts|
171
+ base.click(k, **opts)
168
172
  end
169
173
  end
170
174
 
@@ -176,8 +180,8 @@ module Capybara
176
180
  # @macro click_modifiers
177
181
  # @return [Capybara::Node::Element] The element
178
182
  def right_click(*keys, **options)
179
- perform_click_action(keys, options) do |k, opts|
180
- base.right_click(k, opts)
183
+ perform_click_action(keys, **options) do |k, opts|
184
+ base.right_click(k, **opts)
181
185
  end
182
186
  end
183
187
 
@@ -189,8 +193,8 @@ module Capybara
189
193
  # @macro click_modifiers
190
194
  # @return [Capybara::Node::Element] The element
191
195
  def double_click(*keys, **options)
192
- perform_click_action(keys, options) do |k, opts|
193
- base.double_click(k, opts)
196
+ perform_click_action(keys, **options) do |k, opts|
197
+ base.double_click(k, **opts)
194
198
  end
195
199
  end
196
200
 
@@ -405,6 +409,8 @@ module Capybara
405
409
  # @option options [Boolean] :html5 When using Chrome/Firefox with Selenium enables to force the use of HTML5
406
410
  # (true) or legacy (false) dragging. If not specified the driver will attempt to
407
411
  # detect the correct method to use.
412
+ # @option options [Array<Symbol>,Symbol] :drop_modifiers Modifier keys which should be held while the dragged element is dropped.
413
+ #
408
414
  #
409
415
  # @return [Capybara::Node::Element] The dragged element
410
416
  def drag_to(node, **options)
@@ -543,14 +549,13 @@ module Capybara
543
549
 
544
550
  # @api private
545
551
  def reload
546
- if @allow_reload
547
- begin
548
- reloaded = @query.resolve_for(query_scope.reload)&.first
552
+ return self unless @allow_reload
549
553
 
550
- @base = reloaded.base if reloaded
551
- rescue StandardError => e
552
- raise e unless catch_error?(e)
553
- end
554
+ begin
555
+ reloaded = @query.resolve_for(query_scope.reload)[@query_idx.to_i]
556
+ @base = reloaded.base if reloaded
557
+ rescue StandardError => e
558
+ raise e unless catch_error?(e)
554
559
  end
555
560
  self
556
561
  end