capybara 3.29.0 → 3.30.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +19 -1
  3. data/README.md +1 -1
  4. data/lib/capybara/config.rb +7 -3
  5. data/lib/capybara/helpers.rb +3 -1
  6. data/lib/capybara/node/actions.rb +23 -19
  7. data/lib/capybara/node/document.rb +2 -2
  8. data/lib/capybara/node/document_matchers.rb +3 -3
  9. data/lib/capybara/node/element.rb +10 -8
  10. data/lib/capybara/node/finders.rb +12 -10
  11. data/lib/capybara/node/matchers.rb +39 -33
  12. data/lib/capybara/node/simple.rb +3 -1
  13. data/lib/capybara/queries/ancestor_query.rb +1 -1
  14. data/lib/capybara/queries/selector_query.rb +17 -4
  15. data/lib/capybara/queries/sibling_query.rb +1 -1
  16. data/lib/capybara/rack_test/browser.rb +4 -1
  17. data/lib/capybara/rack_test/driver.rb +1 -1
  18. data/lib/capybara/rack_test/form.rb +1 -1
  19. data/lib/capybara/selector.rb +22 -16
  20. data/lib/capybara/selector/css.rb +1 -1
  21. data/lib/capybara/selector/definition.rb +2 -2
  22. data/lib/capybara/selector/definition/button.rb +7 -2
  23. data/lib/capybara/selector/definition/checkbox.rb +2 -2
  24. data/lib/capybara/selector/definition/css.rb +3 -1
  25. data/lib/capybara/selector/definition/datalist_input.rb +1 -1
  26. data/lib/capybara/selector/definition/datalist_option.rb +1 -1
  27. data/lib/capybara/selector/definition/element.rb +1 -1
  28. data/lib/capybara/selector/definition/field.rb +1 -1
  29. data/lib/capybara/selector/definition/file_field.rb +1 -1
  30. data/lib/capybara/selector/definition/fillable_field.rb +1 -1
  31. data/lib/capybara/selector/definition/label.rb +3 -1
  32. data/lib/capybara/selector/definition/radio_button.rb +2 -2
  33. data/lib/capybara/selector/definition/select.rb +1 -1
  34. data/lib/capybara/selector/definition/table.rb +5 -2
  35. data/lib/capybara/selector/filter_set.rb +11 -9
  36. data/lib/capybara/selector/filters/base.rb +6 -1
  37. data/lib/capybara/selector/filters/locator_filter.rb +1 -1
  38. data/lib/capybara/selector/selector.rb +4 -2
  39. data/lib/capybara/selenium/driver.rb +19 -11
  40. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +2 -2
  41. data/lib/capybara/selenium/extensions/html5_drag.rb +6 -5
  42. data/lib/capybara/selenium/node.rb +6 -4
  43. data/lib/capybara/selenium/nodes/chrome_node.rb +7 -3
  44. data/lib/capybara/selenium/nodes/edge_node.rb +3 -1
  45. data/lib/capybara/selenium/nodes/firefox_node.rb +1 -1
  46. data/lib/capybara/server.rb +15 -3
  47. data/lib/capybara/server/checker.rb +1 -1
  48. data/lib/capybara/server/middleware.rb +20 -10
  49. data/lib/capybara/session.rb +10 -8
  50. data/lib/capybara/session/config.rb +6 -2
  51. data/lib/capybara/session/matchers.rb +6 -6
  52. data/lib/capybara/spec/public/test.js +11 -0
  53. data/lib/capybara/spec/session/all_spec.rb +15 -0
  54. data/lib/capybara/spec/session/ancestor_spec.rb +5 -0
  55. data/lib/capybara/spec/session/assert_text_spec.rb +4 -0
  56. data/lib/capybara/spec/session/click_button_spec.rb +5 -0
  57. data/lib/capybara/spec/session/find_spec.rb +20 -0
  58. data/lib/capybara/spec/session/has_table_spec.rb +51 -5
  59. data/lib/capybara/spec/session/has_text_spec.rb +31 -0
  60. data/lib/capybara/spec/session/node_spec.rb +15 -0
  61. data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +2 -2
  62. data/lib/capybara/spec/session/save_screenshot_spec.rb +4 -4
  63. data/lib/capybara/spec/session/selectors_spec.rb +15 -2
  64. data/lib/capybara/spec/views/form.erb +5 -0
  65. data/lib/capybara/version.rb +1 -1
  66. data/spec/dsl_spec.rb +2 -2
  67. data/spec/minitest_spec_spec.rb +46 -46
  68. data/spec/regexp_dissassembler_spec.rb +45 -37
  69. data/spec/result_spec.rb +3 -3
  70. data/spec/rspec/features_spec.rb +1 -0
  71. data/spec/rspec/shared_spec_matchers.rb +3 -3
  72. data/spec/rspec_spec.rb +4 -4
  73. data/spec/selenium_spec_chrome.rb +3 -3
  74. data/spec/selenium_spec_firefox.rb +7 -2
  75. data/spec/server_spec.rb +42 -0
  76. data/spec/session_spec.rb +1 -1
  77. data/spec/shared_selenium_node.rb +3 -3
  78. data/spec/shared_selenium_session.rb +8 -7
  79. metadata +3 -3
@@ -48,7 +48,12 @@ module Capybara
48
48
 
49
49
  def apply(subject, name, value, skip_value, ctx)
50
50
  return skip_value if skip?(value)
51
- raise ArgumentError, "Invalid value #{value.inspect} passed to #{self.class.name.split('::').last} #{name}#{" : #{@name}" if @name.is_a?(Regexp)}" unless valid_value?(value)
51
+
52
+ unless valid_value?(value)
53
+ raise ArgumentError,
54
+ "Invalid value #{value.inspect} passed to #{self.class.name.split('::').last} #{name}" \
55
+ "#{" : #{name}" if @name.is_a?(Regexp)}"
56
+ end
52
57
 
53
58
  if @block.arity == 2
54
59
  filter_context(ctx).instance_exec(subject, value, &@block)
@@ -7,7 +7,7 @@ module Capybara
7
7
  module Filters
8
8
  class LocatorFilter < NodeFilter
9
9
  def initialize(block, **options)
10
- super(nil, nil, block, options)
10
+ super(nil, nil, block, **options)
11
11
  end
12
12
 
13
13
  def matches?(node, value, context = nil, exact:)
@@ -56,12 +56,14 @@ module Capybara
56
56
  if format
57
57
  raise ArgumentError, "Selector #{@name} does not support #{format}" unless expressions.key?(format)
58
58
 
59
- instance_exec(locator, options, &expressions[format])
59
+ instance_exec(locator, **options, &expressions[format])
60
60
  else
61
61
  warn 'Selector has no format'
62
62
  end
63
63
  ensure
64
- warn "Locator #{locator.class}:#{locator.inspect} for selector #{name.inspect} must #{locator_description}. This will raise an error in a future version of Capybara." unless locator_valid?(locator)
64
+ unless locator_valid?(locator)
65
+ warn "Locator #{locator.class}:#{locator.inspect} for selector #{name.inspect} must #{locator_description}. This will raise an error in a future version of Capybara."
66
+ end
65
67
  end
66
68
 
67
69
  def add_error(error_msg)
@@ -20,7 +20,9 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
20
20
  require 'capybara/selenium/logger_suppressor'
21
21
  require 'capybara/selenium/patches/atoms'
22
22
  require 'capybara/selenium/patches/is_displayed'
23
- warn "Warning: You're using an unsupported version of selenium-webdriver, please upgrade." if Gem.loaded_specs['selenium-webdriver'].version < Gem::Version.new('3.5.0')
23
+ if Gem.loaded_specs['selenium-webdriver'].version < Gem::Version.new('3.5.0')
24
+ warn "Warning: You're using an unsupported version of selenium-webdriver, please upgrade."
25
+ end
24
26
  rescue LoadError => e
25
27
  raise e unless e.message.match?(/selenium-webdriver/)
26
28
 
@@ -143,7 +145,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
143
145
 
144
146
  switch_to_frame(:parent)
145
147
  begin
146
- return frame.base.obscured?(x: x, y: y)
148
+ frame.base.obscured?(x: x, y: y)
147
149
  ensure
148
150
  switch_to_frame(frame)
149
151
  end
@@ -219,7 +221,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
219
221
 
220
222
  def accept_modal(_type, **options)
221
223
  yield if block_given?
222
- modal = find_modal(options)
224
+ modal = find_modal(**options)
223
225
 
224
226
  modal.send_keys options[:with] if options[:with]
225
227
 
@@ -230,7 +232,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
230
232
 
231
233
  def dismiss_modal(_type, **options)
232
234
  yield if block_given?
233
- modal = find_modal(options)
235
+ modal = find_modal(**options)
234
236
  message = modal.text
235
237
  modal.dismiss
236
238
  message
@@ -238,7 +240,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
238
240
 
239
241
  def quit
240
242
  @browser&.quit
241
- rescue Selenium::WebDriver::Error::SessionNotCreatedError, Errno::ECONNREFUSED # rubocop:disable Lint/HandleExceptions
243
+ rescue Selenium::WebDriver::Error::SessionNotCreatedError, Errno::ECONNREFUSED # rubocop:disable Lint/SuppressedException
242
244
  # Browser must have already gone
243
245
  rescue Selenium::WebDriver::Error::UnknownError => e
244
246
  unless silenced_unknown_error_message?(e.message) # Most likely already gone
@@ -290,7 +292,7 @@ private
290
292
  def clear_browser_state
291
293
  delete_all_cookies
292
294
  clear_storage
293
- rescue *clear_browser_state_errors # rubocop:disable Lint/HandleExceptions
295
+ rescue *clear_browser_state_errors # rubocop:disable Lint/SuppressedException
294
296
  # delete_all_cookies fails when we've previously gone
295
297
  # to about:blank, so we rescue this error and do nothing
296
298
  # instead.
@@ -314,7 +316,7 @@ private
314
316
  def clear_storage
315
317
  clear_session_storage unless options[:clear_session_storage] == false
316
318
  clear_local_storage unless options[:clear_local_storage] == false
317
- rescue Selenium::WebDriver::Error::JavascriptError # rubocop:disable Lint/HandleExceptions
319
+ rescue Selenium::WebDriver::Error::JavascriptError # rubocop:disable Lint/SuppressedException
318
320
  # session/local storage may not be available if on non-http pages (e.g. about:blank)
319
321
  end
320
322
 
@@ -325,7 +327,9 @@ private
325
327
  begin
326
328
  @browser&.execute_script('window.sessionStorage.clear()')
327
329
  rescue # rubocop:disable Style/RescueStandardError
328
- warn 'sessionStorage clear requested but is not supported by this driver' unless options[:clear_session_storage].nil?
330
+ unless options[:clear_session_storage].nil?
331
+ warn 'sessionStorage clear requested but is not supported by this driver'
332
+ end
329
333
  end
330
334
  end
331
335
  end
@@ -337,7 +341,9 @@ private
337
341
  begin
338
342
  @browser&.execute_script('window.localStorage.clear()')
339
343
  rescue # rubocop:disable Style/RescueStandardError
340
- warn 'localStorage clear requested but is not supported by this driver' unless options[:clear_local_storage].nil?
344
+ unless options[:clear_local_storage].nil?
345
+ warn 'localStorage clear requested but is not supported by this driver'
346
+ end
341
347
  end
342
348
  end
343
349
  end
@@ -346,7 +352,7 @@ private
346
352
  @browser.navigate.to(url)
347
353
  sleep 0.1 # slight wait for alert
348
354
  @browser.switch_to.alert.accept
349
- rescue modal_error # rubocop:disable Lint/HandleExceptions
355
+ rescue modal_error # rubocop:disable Lint/SuppressedException
350
356
  # alert now gone, should mean navigation happened
351
357
  end
352
358
 
@@ -378,7 +384,9 @@ private
378
384
  alert = @browser.switch_to.alert
379
385
  regexp = text.is_a?(Regexp) ? text : Regexp.new(Regexp.escape(text.to_s))
380
386
  matched = alert.text.match?(regexp)
381
- raise Capybara::ModalNotFound, "Unable to find modal dialog with #{text} - found '#{alert.text}' instead." unless matched
387
+ unless matched
388
+ raise Capybara::ModalNotFound, "Unable to find modal dialog with #{text} - found '#{alert.text}' instead."
389
+ end
382
390
 
383
391
  alert
384
392
  end
@@ -46,7 +46,7 @@ module Capybara::Selenium::Driver::W3CFirefoxDriver
46
46
  begin
47
47
  # Firefox 68 hangs if we try to switch windows while a modal is visible
48
48
  browser.switch_to.alert&.dismiss
49
- rescue Selenium::WebDriver::Error::NoSuchAlertError # rubocop:disable Lint/HandleExceptions
49
+ rescue Selenium::WebDriver::Error::NoSuchAlertError # rubocop:disable Lint/SuppressedException
50
50
  # Swallow
51
51
  end
52
52
  end
@@ -61,7 +61,7 @@ module Capybara::Selenium::Driver::W3CFirefoxDriver
61
61
  accept_modal :confirm, wait: 0.1 do
62
62
  super
63
63
  end
64
- rescue Capybara::ModalNotFound # rubocop:disable Lint/HandleExceptions
64
+ rescue Capybara::ModalNotFound # rubocop:disable Lint/SuppressedException
65
65
  # No modal was opened - page has refreshed - ignore
66
66
  end
67
67
 
@@ -166,17 +166,18 @@ class Capybara::Selenium::Node
166
166
  var dragOverOpts = Object.assign({clientX: targetCenter.x, clientY: targetCenter.y}, opts);
167
167
  var dragOverEvent = new DragEvent('dragover', dragOverOpts);
168
168
  target.dispatchEvent(dragOverEvent);
169
- window.setTimeout(dragLeave, step_delay, dragOverEvent.defaultPrevented);
169
+ window.setTimeout(dragLeave, step_delay, dragOverEvent.defaultPrevented, dragOverOpts);
170
170
  }
171
171
 
172
- function dragLeave(drop) {
173
- var dragLeaveEvent = new DragEvent('dragleave', opts);
172
+ function dragLeave(drop, dragOverOpts) {
173
+ var dragLeaveOptions = Object.assign({}, opts, dragOverOpts);
174
+ var dragLeaveEvent = new DragEvent('dragleave', dragLeaveOptions);
174
175
  target.dispatchEvent(dragLeaveEvent);
175
176
  if (drop) {
176
- var dropEvent = new DragEvent('drop', opts);
177
+ var dropEvent = new DragEvent('drop', dragLeaveOptions);
177
178
  target.dispatchEvent(dropEvent);
178
179
  }
179
- var dragEndEvent = new DragEvent('dragend', opts);
180
+ var dragEndEvent = new DragEvent('dragend', dragLeaveOptions);
180
181
  source.dispatchEvent(dragEndEvent);
181
182
  callback.call(true);
182
183
  }
@@ -54,7 +54,9 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
54
54
  # :backspace => send backspace keystrokes to clear the field <br/>
55
55
  # Array => an array of keys to send before the value being set, e.g. [[:command, 'a'], :backspace]
56
56
  def set(value, **options)
57
- raise ArgumentError, "Value cannot be an Array when 'multiple' attribute is not present. Not a #{value.class}" if value.is_a?(Array) && !multiple?
57
+ if value.is_a?(Array) && !multiple?
58
+ raise ArgumentError, "Value cannot be an Array when 'multiple' attribute is not present. Not a #{value.class}"
59
+ end
58
60
 
59
61
  tag_name, type = attrs(:tagName, :type).map { |val| val&.downcase }
60
62
  @tag_name ||= tag_name
@@ -77,10 +79,10 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
77
79
  when 'color'
78
80
  set_color(value)
79
81
  else
80
- set_text(value, options)
82
+ set_text(value, **options)
81
83
  end
82
84
  when 'textarea'
83
- set_text(value, options)
85
+ set_text(value, **options)
84
86
  else
85
87
  set_content_editable(value)
86
88
  end
@@ -202,7 +204,7 @@ protected
202
204
  JS
203
205
  begin
204
206
  driver.execute_script(script, self)
205
- rescue StandardError # rubocop:disable Lint/HandleExceptions
207
+ rescue StandardError # rubocop:disable Lint/SuppressedException
206
208
  # Swallow error if scrollIntoView with options isn't supported
207
209
  end
208
210
  end
@@ -25,7 +25,9 @@ class Capybara::Selenium::ChromeNode < Capybara::Selenium::Node
25
25
  end
26
26
  super
27
27
  rescue *file_errors => e
28
- raise ArgumentError, "Selenium < 3.14 with remote Chrome doesn't support multiple file upload" if e.message.match?(/File not found : .+\n.+/m)
28
+ if e.message.match?(/File not found : .+\n.+/m)
29
+ raise ArgumentError, "Selenium < 3.14 with remote Chrome doesn't support multiple file upload"
30
+ end
29
31
 
30
32
  raise
31
33
  end
@@ -34,13 +36,15 @@ class Capybara::Selenium::ChromeNode < Capybara::Selenium::Node
34
36
  html5_drop(*args)
35
37
  end
36
38
 
37
- def click(*)
39
+ def click(*, **)
38
40
  super
39
41
  rescue ::Selenium::WebDriver::Error::ElementClickInterceptedError
40
42
  raise
41
43
  rescue ::Selenium::WebDriver::Error::WebDriverError => e
42
44
  # chromedriver 74 (at least on mac) raises the wrong error for this
43
- raise ::Selenium::WebDriver::Error::ElementClickInterceptedError, e.message if e.message.match?(/element click intercepted/)
45
+ if e.message.match?(/element click intercepted/)
46
+ raise ::Selenium::WebDriver::Error::ElementClickInterceptedError, e.message
47
+ end
44
48
 
45
49
  raise
46
50
  end
@@ -25,7 +25,9 @@ class Capybara::Selenium::EdgeNode < Capybara::Selenium::Node
25
25
  end
26
26
  super
27
27
  rescue *file_errors => e
28
- raise ArgumentError, "Selenium < 3.14 with remote Chrome doesn't support multiple file upload" if e.message.match?(/File not found : .+\n.+/m)
28
+ if e.message.match?(/File not found : .+\n.+/m)
29
+ raise ArgumentError, "Selenium < 3.14 with remote Chrome doesn't support multiple file upload"
30
+ end
29
31
 
30
32
  raise
31
33
  end
@@ -14,7 +14,7 @@ class Capybara::Selenium::FirefoxNode < Capybara::Selenium::Node
14
14
  warn 'You are attempting to click a table row which has issues in geckodriver/marionette - '\
15
15
  'see https://github.com/mozilla/geckodriver/issues/1228. Your test should probably be '\
16
16
  'clicking on a table cell like a user would. Clicking the first cell in the row instead.'
17
- return find_css('th:first-child,td:first-child')[0].click(keys, options)
17
+ return find_css('th:first-child,td:first-child')[0].click(keys, **options)
18
18
  end
19
19
  raise
20
20
  end
@@ -24,7 +24,9 @@ module Capybara
24
24
  host: Capybara.server_host,
25
25
  reportable_errors: Capybara.server_errors,
26
26
  extra_middleware: [])
27
- warn 'Positional arguments, other than the application, to Server#new are deprecated, please use keyword arguments' unless deprecated_options.empty?
27
+ unless deprecated_options.empty?
28
+ warn 'Positional arguments, other than the application, to Server#new are deprecated, please use keyword arguments'
29
+ end
28
30
  @app = app
29
31
  @extra_middleware = extra_middleware
30
32
  @server_thread = nil # suppress warnings
@@ -61,7 +63,7 @@ module Capybara
61
63
  def wait_for_pending_requests
62
64
  timer = Capybara::Helpers.timer(expire_in: 60)
63
65
  while pending_requests?
64
- raise 'Requests did not finish in 60 seconds' if timer.expired?
66
+ raise "Requests did not finish in 60 seconds: #{middleware.pending_requests}" if timer.expired?
65
67
 
66
68
  sleep 0.01
67
69
  end
@@ -106,7 +108,17 @@ module Capybara
106
108
 
107
109
  def find_available_port(host)
108
110
  server = TCPServer.new(host, 0)
109
- server.addr[1]
111
+ port = server.addr[1]
112
+ server.close
113
+
114
+ # Workaround issue where some platforms (mac, ???) when passed a host
115
+ # of '0.0.0.0' will return a port that is only available on one of the
116
+ # ip addresses that resolves to, but the next binding to that port requires
117
+ # that port to be available on all ips
118
+ server = TCPServer.new(host, port)
119
+ port
120
+ rescue Errno::EADDRINUSE
121
+ retry
110
122
  ensure
111
123
  server&.close
112
124
  end
@@ -29,7 +29,7 @@ module Capybara
29
29
  end
30
30
 
31
31
  def https_request(&block)
32
- make_request(ssl_options, &block)
32
+ make_request(**ssl_options, &block)
33
33
  end
34
34
 
35
35
  def make_request(**options, &block)
@@ -4,19 +4,25 @@ module Capybara
4
4
  class Server
5
5
  class Middleware
6
6
  class Counter
7
- attr_reader :value
8
-
9
7
  def initialize
10
- @value = 0
8
+ @value = []
11
9
  @mutex = Mutex.new
12
10
  end
13
11
 
14
- def increment
15
- @mutex.synchronize { @value += 1 }
12
+ def increment(uri)
13
+ @mutex.synchronize { @value.push(uri) }
14
+ end
15
+
16
+ def decrement(uri)
17
+ @mutex.synchronize { @value.delete_at(@value.index(uri) || @value.length) }
16
18
  end
17
19
 
18
- def decrement
19
- @mutex.synchronize { @value -= 1 }
20
+ def positive?
21
+ @mutex.synchronize { @value.length.positive? }
22
+ end
23
+
24
+ def value
25
+ @mutex.synchronize { @value.dup }
20
26
  end
21
27
  end
22
28
 
@@ -31,8 +37,12 @@ module Capybara
31
37
  @server_errors = server_errors
32
38
  end
33
39
 
40
+ def pending_requests
41
+ @counter.value
42
+ end
43
+
34
44
  def pending_requests?
35
- @counter.value.positive?
45
+ @counter.positive?
36
46
  end
37
47
 
38
48
  def clear_error
@@ -43,14 +53,14 @@ module Capybara
43
53
  if env['PATH_INFO'] == '/__identify__'
44
54
  [200, {}, [@app.object_id.to_s]]
45
55
  else
46
- @counter.increment
56
+ @counter.increment(env['REQUEST_URI'])
47
57
  begin
48
58
  @extended_app.call(env)
49
59
  rescue *@server_errors => e
50
60
  @error ||= e
51
61
  raise e
52
62
  ensure
53
- @counter.decrement
63
+ @counter.decrement(env['REQUEST_URI'])
54
64
  end
55
65
  end
56
66
  end
@@ -75,7 +75,9 @@ module Capybara
75
75
  attr_accessor :synchronized
76
76
 
77
77
  def initialize(mode, app = nil)
78
- raise TypeError, 'The second parameter to Session::new should be a rack app if passed.' if app && !app.respond_to?(:call)
78
+ if app && !app.respond_to?(:call)
79
+ raise TypeError, 'The second parameter to Session::new should be a rack app if passed.'
80
+ end
79
81
 
80
82
  @@instance_created = true # rubocop:disable Style/ClassVars
81
83
  @mode = mode
@@ -88,7 +90,7 @@ module Capybara
88
90
  @server = if config.run_server && @app && driver.needs_server?
89
91
  server_options = { port: config.server_port, host: config.server_host, reportable_errors: config.server_errors }
90
92
  server_options[:extra_middleware] = [Capybara::Server::AnimationDisabler] if config.disable_animation
91
- Capybara::Server.new(@app, server_options).boot
93
+ Capybara::Server.new(@app, **server_options).boot
92
94
  end
93
95
  @touched = false
94
96
  end
@@ -494,7 +496,7 @@ module Capybara
494
496
  '`within` or `within_frame` blocks.'
495
497
  end
496
498
 
497
- _switch_to_window(window, options, &window_locator)
499
+ _switch_to_window(window, **options, &window_locator)
498
500
  end
499
501
 
500
502
  ##
@@ -528,7 +530,7 @@ module Capybara
528
530
  when Proc
529
531
  _switch_to_window { window_or_proc.call }
530
532
  else
531
- raise ArgumentError('`#within_window` requires a `Capybara::Window` instance or a lambda')
533
+ raise ArgumentError, '`#within_window` requires a `Capybara::Window` instance or a lambda'
532
534
  end
533
535
 
534
536
  begin
@@ -721,7 +723,7 @@ module Capybara
721
723
  # @param [Hash] options a customizable set of options
722
724
  # @return [String] the path to which the file was saved
723
725
  def save_screenshot(path = nil, **options)
724
- prepare_path(path, 'png').tap { |p_path| driver.save_screenshot(p_path, options) }
726
+ prepare_path(path, 'png').tap { |p_path| driver.save_screenshot(p_path, **options) }
725
727
  end
726
728
 
727
729
  ##
@@ -736,7 +738,7 @@ module Capybara
736
738
  # @param [Hash] options a customizable set of options
737
739
  #
738
740
  def save_and_open_screenshot(path = nil, **options)
739
- save_screenshot(path, options).tap { |s_path| open_file(s_path) } # rubocop:disable Lint/Debugger
741
+ save_screenshot(path, **options).tap { |s_path| open_file(s_path) } # rubocop:disable Lint/Debugger
740
742
  end
741
743
 
742
744
  def document
@@ -819,11 +821,11 @@ module Capybara
819
821
  end
820
822
 
821
823
  def accept_modal(type, text_or_options, options, &blk)
822
- driver.accept_modal(type, modal_options(text_or_options, options), &blk)
824
+ driver.accept_modal(type, **modal_options(text_or_options, **options), &blk)
823
825
  end
824
826
 
825
827
  def dismiss_modal(type, text_or_options, options, &blk)
826
- driver.dismiss_modal(type, modal_options(text_or_options, options), &blk)
828
+ driver.dismiss_modal(type, **modal_options(text_or_options, **options), &blk)
827
829
  end
828
830
 
829
831
  def modal_options(text = nil, **options)