capybara 2.18.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 (172) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +55 -1
  3. data/README.md +18 -17
  4. data/lib/capybara/config.rb +11 -58
  5. data/lib/capybara/cucumber.rb +2 -3
  6. data/lib/capybara/driver/base.rb +15 -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 +15 -14
  11. data/lib/capybara/minitest.rb +139 -138
  12. data/lib/capybara/node/actions.rb +60 -81
  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 +30 -40
  17. data/lib/capybara/node/finders.rb +62 -70
  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 +11 -7
  21. data/lib/capybara/queries/base_query.rb +22 -18
  22. data/lib/capybara/queries/current_path_query.rb +8 -24
  23. data/lib/capybara/queries/match_query.rb +3 -7
  24. data/lib/capybara/queries/selector_query.rb +92 -95
  25. data/lib/capybara/queries/sibling_query.rb +4 -4
  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 +50 -40
  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 +70 -61
  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 +131 -125
  49. data/lib/capybara/selenium/node.rb +197 -115
  50. data/lib/capybara/server.rb +3 -2
  51. data/lib/capybara/session/config.rb +47 -67
  52. data/lib/capybara/session/matchers.rb +8 -7
  53. data/lib/capybara/session.rb +138 -224
  54. data/lib/capybara/spec/public/test.js +25 -4
  55. data/lib/capybara/spec/session/accept_alert_spec.rb +1 -0
  56. data/lib/capybara/spec/session/accept_confirm_spec.rb +3 -2
  57. data/lib/capybara/spec/session/accept_prompt_spec.rb +1 -0
  58. data/lib/capybara/spec/session/all_spec.rb +31 -18
  59. data/lib/capybara/spec/session/ancestor_spec.rb +6 -8
  60. data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +6 -5
  61. data/lib/capybara/spec/session/assert_current_path.rb +12 -11
  62. data/lib/capybara/spec/session/assert_selector.rb +1 -0
  63. data/lib/capybara/spec/session/assert_text.rb +23 -23
  64. data/lib/capybara/spec/session/assert_title.rb +13 -3
  65. data/lib/capybara/spec/session/attach_file_spec.rb +51 -30
  66. data/lib/capybara/spec/session/body_spec.rb +1 -0
  67. data/lib/capybara/spec/session/check_spec.rb +7 -6
  68. data/lib/capybara/spec/session/choose_spec.rb +5 -4
  69. data/lib/capybara/spec/session/click_button_spec.rb +24 -32
  70. data/lib/capybara/spec/session/click_link_or_button_spec.rb +8 -7
  71. data/lib/capybara/spec/session/click_link_spec.rb +8 -7
  72. data/lib/capybara/spec/session/current_scope_spec.rb +4 -3
  73. data/lib/capybara/spec/session/current_url_spec.rb +17 -6
  74. data/lib/capybara/spec/session/dismiss_confirm_spec.rb +1 -1
  75. data/lib/capybara/spec/session/dismiss_prompt_spec.rb +1 -0
  76. data/lib/capybara/spec/session/element/assert_match_selector.rb +1 -1
  77. data/lib/capybara/spec/session/element/match_xpath_spec.rb +1 -1
  78. data/lib/capybara/spec/session/element/matches_selector_spec.rb +5 -5
  79. data/lib/capybara/spec/session/evaluate_async_script_spec.rb +3 -2
  80. data/lib/capybara/spec/session/evaluate_script_spec.rb +4 -3
  81. data/lib/capybara/spec/session/execute_script_spec.rb +4 -3
  82. data/lib/capybara/spec/session/fill_in_spec.rb +30 -5
  83. data/lib/capybara/spec/session/find_button_spec.rb +4 -3
  84. data/lib/capybara/spec/session/find_by_id_spec.rb +2 -1
  85. data/lib/capybara/spec/session/find_field_spec.rb +9 -15
  86. data/lib/capybara/spec/session/find_link_spec.rb +6 -5
  87. data/lib/capybara/spec/session/find_spec.rb +37 -31
  88. data/lib/capybara/spec/session/first_spec.rb +60 -33
  89. data/lib/capybara/spec/session/frame/frame_title_spec.rb +23 -0
  90. data/lib/capybara/spec/session/frame/frame_url_spec.rb +23 -0
  91. data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +2 -1
  92. data/lib/capybara/spec/session/frame/within_frame_spec.rb +9 -16
  93. data/lib/capybara/spec/session/go_back_spec.rb +1 -0
  94. data/lib/capybara/spec/session/go_forward_spec.rb +1 -0
  95. data/lib/capybara/spec/session/has_all_selectors_spec.rb +15 -15
  96. data/lib/capybara/spec/session/has_button_spec.rb +2 -1
  97. data/lib/capybara/spec/session/has_css_spec.rb +3 -2
  98. data/lib/capybara/spec/session/has_current_path_spec.rb +12 -28
  99. data/lib/capybara/spec/session/has_field_spec.rb +4 -3
  100. data/lib/capybara/spec/session/has_link_spec.rb +1 -0
  101. data/lib/capybara/spec/session/has_none_selectors_spec.rb +17 -17
  102. data/lib/capybara/spec/session/has_select_spec.rb +30 -29
  103. data/lib/capybara/spec/session/has_selector_spec.rb +5 -4
  104. data/lib/capybara/spec/session/has_table_spec.rb +2 -1
  105. data/lib/capybara/spec/session/has_text_spec.rb +9 -13
  106. data/lib/capybara/spec/session/has_title_spec.rb +1 -0
  107. data/lib/capybara/spec/session/has_xpath_spec.rb +1 -0
  108. data/lib/capybara/spec/session/headers.rb +2 -1
  109. data/lib/capybara/spec/session/html_spec.rb +1 -0
  110. data/lib/capybara/spec/session/node_spec.rb +91 -56
  111. data/lib/capybara/spec/session/node_wrapper_spec.rb +36 -0
  112. data/lib/capybara/spec/session/refresh_spec.rb +6 -2
  113. data/lib/capybara/spec/session/reset_session_spec.rb +19 -0
  114. data/lib/capybara/spec/session/response_code.rb +1 -0
  115. data/lib/capybara/spec/session/save_and_open_page_spec.rb +1 -0
  116. data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +6 -11
  117. data/lib/capybara/spec/session/save_page_spec.rb +1 -17
  118. data/lib/capybara/spec/session/save_screenshot_spec.rb +3 -3
  119. data/lib/capybara/spec/session/select_spec.rb +20 -20
  120. data/lib/capybara/spec/session/selectors_spec.rb +2 -2
  121. data/lib/capybara/spec/session/sibling_spec.rb +1 -1
  122. data/lib/capybara/spec/session/text_spec.rb +17 -3
  123. data/lib/capybara/spec/session/title_spec.rb +11 -1
  124. data/lib/capybara/spec/session/uncheck_spec.rb +4 -3
  125. data/lib/capybara/spec/session/unselect_spec.rb +6 -5
  126. data/lib/capybara/spec/session/visit_spec.rb +9 -3
  127. data/lib/capybara/spec/session/window/become_closed_spec.rb +2 -1
  128. data/lib/capybara/spec/session/window/current_window_spec.rb +1 -0
  129. data/lib/capybara/spec/session/window/open_new_window_spec.rb +1 -0
  130. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +2 -1
  131. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +2 -1
  132. data/lib/capybara/spec/session/window/window_spec.rb +12 -12
  133. data/lib/capybara/spec/session/window/windows_spec.rb +2 -3
  134. data/lib/capybara/spec/session/window/within_window_spec.rb +15 -71
  135. data/lib/capybara/spec/session/within_spec.rb +1 -0
  136. data/lib/capybara/spec/spec_helper.rb +34 -18
  137. data/lib/capybara/spec/test_app.rb +17 -9
  138. data/lib/capybara/spec/views/form.erb +7 -0
  139. data/lib/capybara/spec/views/with_html.erb +23 -1
  140. data/lib/capybara/spec/views/within_frames.erb +4 -1
  141. data/lib/capybara/version.rb +2 -1
  142. data/lib/capybara/window.rb +6 -10
  143. data/lib/capybara.rb +28 -25
  144. data/spec/basic_node_spec.rb +1 -0
  145. data/spec/capybara_spec.rb +11 -50
  146. data/spec/dsl_spec.rb +5 -13
  147. data/spec/filter_set_spec.rb +5 -4
  148. data/spec/fixtures/selenium_driver_rspec_failure.rb +2 -1
  149. data/spec/fixtures/selenium_driver_rspec_success.rb +3 -2
  150. data/spec/minitest_spec.rb +4 -3
  151. data/spec/minitest_spec_spec.rb +3 -2
  152. data/spec/per_session_config_spec.rb +9 -8
  153. data/spec/rack_test_spec.rb +21 -20
  154. data/spec/result_spec.rb +17 -16
  155. data/spec/rspec/features_spec.rb +17 -14
  156. data/spec/rspec/scenarios_spec.rb +5 -7
  157. data/spec/rspec/shared_spec_matchers.rb +96 -99
  158. data/spec/rspec/views_spec.rb +2 -1
  159. data/spec/rspec_matchers_spec.rb +18 -2
  160. data/spec/rspec_spec.rb +11 -15
  161. data/spec/selector_spec.rb +5 -6
  162. data/spec/selenium_spec_chrome.rb +9 -4
  163. data/spec/selenium_spec_edge.rb +27 -0
  164. data/spec/selenium_spec_ie.rb +31 -0
  165. data/spec/selenium_spec_marionette.rb +28 -12
  166. data/spec/server_spec.rb +33 -33
  167. data/spec/session_spec.rb +2 -1
  168. data/spec/shared_selenium_session.rb +36 -22
  169. data/spec/spec_helper.rb +3 -6
  170. metadata +68 -85
  171. data/lib/capybara/query.rb +0 -7
  172. data/spec/selenium_spec_firefox.rb +0 -68
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'capybara/session/matchers'
3
4
  require 'addressable/uri'
4
5
 
5
6
  module Capybara
6
-
7
7
  ##
8
8
  #
9
9
  # The Session class represents a single user's interaction with the system. The Session can use
@@ -38,64 +38,63 @@ module Capybara
38
38
  class Session
39
39
  include Capybara::SessionMatchers
40
40
 
41
- NODE_METHODS = [
42
- :all, :first, :attach_file, :text, :check, :choose,
43
- :click_link_or_button, :click_button, :click_link, :field_labeled,
44
- :fill_in, :find, :find_all, :find_button, :find_by_id, :find_field, :find_link,
45
- :has_content?, :has_text?, :has_css?, :has_no_content?, :has_no_text?,
46
- :has_no_css?, :has_no_xpath?, :resolve, :has_xpath?, :select, :uncheck,
47
- :has_link?, :has_no_link?, :has_button?, :has_no_button?, :has_field?,
48
- :has_no_field?, :has_checked_field?, :has_unchecked_field?,
49
- :has_no_table?, :has_table?, :unselect, :has_select?, :has_no_select?,
50
- :has_selector?, :has_no_selector?, :click_on, :has_no_checked_field?,
51
- :has_no_unchecked_field?, :query, :assert_selector, :assert_no_selector,
52
- :assert_all_of_selectors, :assert_none_of_selectors,
53
- :refute_selector, :assert_text, :assert_no_text
54
- ]
41
+ NODE_METHODS = %i[
42
+ all first attach_file text check choose
43
+ click_link_or_button click_button click_link
44
+ fill_in find find_all find_button find_by_id find_field find_link
45
+ has_content? has_text? has_css? has_no_content? has_no_text?
46
+ has_no_css? has_no_xpath? resolve has_xpath? select uncheck
47
+ has_link? has_no_link? has_button? has_no_button? has_field?
48
+ has_no_field? has_checked_field? has_unchecked_field?
49
+ has_no_table? has_table? unselect has_select? has_no_select?
50
+ has_selector? has_no_selector? click_on has_no_checked_field?
51
+ has_no_unchecked_field? query assert_selector assert_no_selector
52
+ assert_all_of_selectors assert_none_of_selectors
53
+ refute_selector assert_text assert_no_text
54
+ ].freeze
55
55
  # @api private
56
- DOCUMENT_METHODS = [
57
- :title, :assert_title, :assert_no_title, :has_title?, :has_no_title?
58
- ]
59
- SESSION_METHODS = [
60
- :body, :html, :source, :current_url, :current_host, :current_path,
61
- :execute_script, :evaluate_script, :visit, :refresh, :go_back, :go_forward,
62
- :within, :within_element, :within_fieldset, :within_table, :within_frame, :switch_to_frame,
63
- :current_window, :windows, :open_new_window, :switch_to_window, :within_window, :window_opened_by,
64
- :save_page, :save_and_open_page, :save_screenshot,
65
- :save_and_open_screenshot, :reset_session!, :response_headers,
66
- :status_code, :current_scope,
67
- :assert_current_path, :assert_no_current_path, :has_current_path?, :has_no_current_path?
68
- ] + DOCUMENT_METHODS
69
- MODAL_METHODS = [
70
- :accept_alert, :accept_confirm, :dismiss_confirm, :accept_prompt,
71
- :dismiss_prompt
72
- ]
56
+ DOCUMENT_METHODS = %i[
57
+ title assert_title assert_no_title has_title? has_no_title?
58
+ ].freeze
59
+ SESSION_METHODS = %i[
60
+ body html source current_url current_host current_path
61
+ execute_script evaluate_script visit refresh go_back go_forward
62
+ within within_element within_fieldset within_table within_frame switch_to_frame
63
+ current_window windows open_new_window switch_to_window within_window window_opened_by
64
+ save_page save_and_open_page save_screenshot
65
+ save_and_open_screenshot reset_session! response_headers
66
+ status_code current_scope
67
+ assert_current_path assert_no_current_path has_current_path? has_no_current_path?
68
+ ].freeze + DOCUMENT_METHODS
69
+ MODAL_METHODS = %i[
70
+ accept_alert accept_confirm dismiss_confirm accept_prompt dismiss_prompt
71
+ ].freeze
73
72
  DSL_METHODS = NODE_METHODS + SESSION_METHODS + MODAL_METHODS
74
73
 
75
74
  attr_reader :mode, :app, :server
76
75
  attr_accessor :synchronized
77
76
 
78
- def initialize(mode, app=nil)
77
+ def initialize(mode, app = nil)
79
78
  raise TypeError, "The second parameter to Session::new should be a rack app if passed." if app && !app.respond_to?(:call)
80
79
  @@instance_created = true
81
80
  @mode = mode
82
81
  @app = app
83
82
  if block_given?
84
83
  raise "A configuration block is only accepted when Capybara.threadsafe == true" unless Capybara.threadsafe
85
- yield config if block_given?
84
+ yield config
86
85
  end
87
- if config.run_server and @app and driver.needs_server?
88
- @server = Capybara::Server.new(@app, config.server_port, config.server_host, config.server_errors).boot
86
+ @server = if config.run_server and @app and driver.needs_server?
87
+ Capybara::Server.new(@app, config.server_port, config.server_host, config.server_errors).boot
89
88
  else
90
- @server = nil
89
+ nil
91
90
  end
92
91
  @touched = false
93
92
  end
94
93
 
95
94
  def driver
96
95
  @driver ||= begin
97
- unless Capybara.drivers.has_key?(mode)
98
- other_drivers = Capybara.drivers.keys.map { |key| key.inspect }
96
+ unless Capybara.drivers.key?(mode)
97
+ other_drivers = Capybara.drivers.keys.map(&:inspect)
99
98
  raise Capybara::DriverNotFoundError, "no driver called #{mode.inspect} was found, available drivers: #{other_drivers.join(', ')}"
100
99
  end
101
100
  driver = Capybara.drivers[mode].call(app)
@@ -145,7 +144,7 @@ module Capybara
145
144
  raise CapybaraError, "Your application server raised an error - It has been raised in your test code because Capybara.raise_server_errors == true"
146
145
  end
147
146
  rescue CapybaraError
148
- #needed to get the cause set correctly in JRuby -- otherwise we could just do raise @server.error
147
+ # needed to get the cause set correctly in JRuby -- otherwise we could just do raise @server.error
149
148
  raise @server.error, @server.error.message, @server.error.backtrace
150
149
  ensure
151
150
  @server.reset_error!
@@ -196,8 +195,9 @@ module Capybara
196
195
 
197
196
  # Addressable doesn't support opaque URIs - we want nil here
198
197
  return nil if uri.scheme == "about"
198
+
199
199
  path = uri.path
200
- path if path and not path.empty?
200
+ path if path && !path.empty?
201
201
  end
202
202
 
203
203
  ##
@@ -259,15 +259,15 @@ module Capybara
259
259
  if visit_uri.relative?
260
260
  uri_base.port ||= @server.port if @server && config.always_include_port
261
261
 
262
- visit_uri_parts = visit_uri.to_hash.delete_if { |k,v| v.nil? }
262
+ visit_uri_parts = visit_uri.to_hash.delete_if { |_k, v| v.nil? }
263
263
 
264
264
  # Useful to people deploying to a subdirectory
265
265
  # and/or single page apps where only the url fragment changes
266
266
  visit_uri_parts[:path] = uri_base.path + visit_uri.path
267
267
 
268
268
  visit_uri = uri_base.merge(visit_uri_parts)
269
- else
270
- visit_uri.port ||= @server.port if @server && config.always_include_port
269
+ elsif @server && config.always_include_port
270
+ visit_uri.port ||= @server.port
271
271
  end
272
272
  end
273
273
 
@@ -335,7 +335,7 @@ module Capybara
335
335
  # @raise [Capybara::ElementNotFound] If the scope can't be found before time expires
336
336
  #
337
337
  def within(*args)
338
- new_scope = if args.first.is_a?(Capybara::Node::Base) then args.first else find(*args) end
338
+ new_scope = args.first.respond_to?(:to_capybara_node) ? args.first.to_capybara_node : find(*args)
339
339
  begin
340
340
  scopes.push(new_scope)
341
341
  yield
@@ -352,9 +352,7 @@ module Capybara
352
352
  # @param [String] locator Id or legend of the fieldset
353
353
  #
354
354
  def within_fieldset(locator)
355
- within :fieldset, locator do
356
- yield
357
- end
355
+ within(:fieldset, locator) { yield }
358
356
  end
359
357
 
360
358
  ##
@@ -364,9 +362,7 @@ module Capybara
364
362
  # @param [String] locator Id or caption of the table
365
363
  #
366
364
  def within_table(locator)
367
- within :table, locator do
368
- yield
369
- end
365
+ within(:table, locator) { yield }
370
366
  end
371
367
 
372
368
  ##
@@ -390,15 +386,19 @@ module Capybara
390
386
  driver.switch_to_frame(frame)
391
387
  scopes.push(:frame)
392
388
  when :parent
393
- raise Capybara::ScopeError, "`switch_to_frame(:parent)` cannot be called from inside a descendant frame's "\
394
- "`within` block." if scopes.last() != :frame
389
+ if scopes.last != :frame
390
+ raise Capybara::ScopeError, "`switch_to_frame(:parent)` cannot be called from inside a descendant frame's "\
391
+ "`within` block."
392
+ end
395
393
  scopes.pop
396
394
  driver.switch_to_frame(:parent)
397
395
  when :top
398
396
  idx = scopes.index(:frame)
399
397
  if idx
400
- raise Capybara::ScopeError, "`switch_to_frame(:top)` cannot be called from inside a descendant frame's "\
401
- "`within` block." if scopes.slice(idx..-1).any? {|scope| ![:frame, nil].include?(scope)}
398
+ if scopes.slice(idx..-1).any? { |scope| ![:frame, nil].include?(scope) }
399
+ raise Capybara::ScopeError, "`switch_to_frame(:top)` cannot be called from inside a descendant frame's "\
400
+ "`within` block."
401
+ end
402
402
  scopes.slice!(idx..-1)
403
403
  driver.switch_to_frame(:top)
404
404
  end
@@ -413,34 +413,16 @@ module Capybara
413
413
  # @overload within_frame(element)
414
414
  # @param [Capybara::Node::Element] frame element
415
415
  # @overload within_frame([kind = :frame], locator, options = {})
416
- # @param [Symobl] kind Optional selector type (:css, :xpath, :field, etc.) - Defaults to :frame
416
+ # @param [Symbol] kind Optional selector type (:css, :xpath, :field, etc.) - Defaults to :frame
417
417
  # @param [String] locator The locator for the given selector kind. For :frame this is the name/id of a frame/iframe element
418
418
  # @overload within_frame(index)
419
419
  # @param [Integer] index index of a frame (0 based)
420
420
  def within_frame(*args)
421
- frame = _find_frame(*args)
422
-
421
+ switch_to_frame(_find_frame(*args))
423
422
  begin
424
- switch_to_frame(frame)
425
- begin
426
- yield
427
- ensure
428
- switch_to_frame(:parent)
429
- end
430
- rescue Capybara::NotSupportedByDriverError
431
- # Support older driver frame API for now
432
- if driver.respond_to?(:within_frame)
433
- begin
434
- scopes.push(:frame)
435
- driver.within_frame(frame) do
436
- yield
437
- end
438
- ensure
439
- scopes.pop
440
- end
441
- else
442
- raise
443
- end
423
+ yield
424
+ ensure
425
+ switch_to_frame(:parent)
444
426
  end
445
427
  end
446
428
 
@@ -493,15 +475,11 @@ module Capybara
493
475
  # `within_frame` methods
494
476
  # @raise [ArgumentError] if both or neither arguments were provided
495
477
  #
496
- def switch_to_window(window = nil, options= {}, &window_locator)
497
- options, window = window, nil if window.is_a? Hash
498
-
478
+ def switch_to_window(window = nil, **options, &window_locator)
499
479
  block_given = block_given?
500
- if window && block_given
501
- raise ArgumentError, "`switch_to_window` can take either a block or a window, not both"
502
- elsif !window && !block_given
503
- raise ArgumentError, "`switch_to_window`: either window or block should be provided"
504
- elsif !scopes.last.nil?
480
+ raise ArgumentError, "`switch_to_window` can take either a block or a window, not both" if window && block_given
481
+ raise ArgumentError, "`switch_to_window`: either window or block should be provided" if !window && !block_given
482
+ unless scopes.last.nil?
505
483
  raise Capybara::ScopeError, "`switch_to_window` is not supposed to be invoked from "\
506
484
  "`within` or `within_frame` blocks."
507
485
  end
@@ -526,51 +504,30 @@ module Capybara
526
504
  # @example
527
505
  # within_window(->{ page.title == 'Page title' }) { click_button 'Submit' }
528
506
  # @raise [Capybara::WindowError] if no window matching lambda was found
529
- # @overload within_window(string) { do_something }
530
- # @deprecated Pass window or lambda instead
531
- # @param [String] handle, name, url or title of the window
532
507
  #
533
508
  # @raise [Capybara::ScopeError] if this method is invoked inside `within_frame` method
534
509
  # @return value returned by the block
535
510
  #
536
- def within_window(window_or_handle)
537
- if window_or_handle.instance_of?(Capybara::Window)
538
- original = current_window
539
- scopes << nil
540
- begin
541
- _switch_to_window(window_or_handle) unless original == window_or_handle
542
- begin
543
- yield
544
- ensure
545
- _switch_to_window(original) unless original == window_or_handle
546
- end
547
- ensure
548
- scopes.pop
549
- end
550
- elsif window_or_handle.is_a?(Proc)
551
- original = current_window
552
- scopes << nil
553
- begin
554
- _switch_to_window { window_or_handle.call }
555
- begin
556
- yield
557
- ensure
558
- _switch_to_window(original)
559
- end
560
- ensure
561
- scopes.pop
511
+ def within_window(window_or_proc)
512
+ original = current_window
513
+ scopes << nil
514
+ begin
515
+ case window_or_proc
516
+ when Capybara::Window
517
+ _switch_to_window(window_or_proc) unless original == window_or_proc
518
+ when Proc
519
+ _switch_to_window { window_or_proc.call }
520
+ else
521
+ raise ArgumentError("`#within_window` requires a `Capybara::Window` instance or a lambda")
562
522
  end
563
- else
564
- offending_line = caller.first
565
- file_line = offending_line.match(/^(.+?):(\d+)/)[0]
566
- warn "DEPRECATION WARNING: Passing string argument to #within_window is deprecated. "\
567
- "Pass window object or lambda. (called from #{file_line})"
523
+
568
524
  begin
569
- scopes << nil
570
- driver.within_window(window_or_handle) { yield }
525
+ yield
571
526
  ensure
572
- scopes.pop
527
+ _switch_to_window(original) unless original == window_or_proc
573
528
  end
529
+ ensure
530
+ scopes.pop
574
531
  end
575
532
  end
576
533
 
@@ -580,15 +537,16 @@ module Capybara
580
537
  # It's better to use this method than `windows.last`
581
538
  # {https://dvcs.w3.org/hg/webdriver/raw-file/default/webdriver-spec.html#h_note_10 as order of windows isn't defined in some drivers}
582
539
  #
583
- # @param options [Hash]
584
- # @option options [Numeric] :wait (Capybara.default_max_wait_time) maximum wait time
585
- # @return [Capybara::Window] the window that has been opened within a block
586
- # @raise [Capybara::WindowError] if block passed to window hasn't opened window
587
- # or opened more than one window
540
+ # @overload window_opened_by(**options, &block)
541
+ # @param options [Hash]
542
+ # @option options [Numeric] :wait (Capybara.default_max_wait_time) maximum wait time
543
+ # @return [Capybara::Window] the window that has been opened within a block
544
+ # @raise [Capybara::WindowError] if block passed to window hasn't opened window
545
+ # or opened more than one window
588
546
  #
589
- def window_opened_by(options = {}, &block)
547
+ def window_opened_by(**options)
590
548
  old_handles = driver.window_handles
591
- block.call
549
+ yield
592
550
 
593
551
  wait_time = Capybara::Queries::BaseQuery.wait(options, config.default_max_wait_time)
594
552
  document.synchronize(wait_time, errors: [Capybara::WindowError]) do
@@ -612,12 +570,7 @@ module Capybara
612
570
  #
613
571
  def execute_script(script, *args)
614
572
  @touched = true
615
- if args.empty?
616
- driver.execute_script(script)
617
- else
618
- raise Capybara::NotSupportedByDriverError, "The current driver does not support execute_script arguments" if driver.method(:execute_script).arity == 1
619
- driver.execute_script(script, *args.map { |arg| arg.is_a?(Capybara::Node::Element) ? arg.base : arg} )
620
- end
573
+ driver.execute_script(script, *args.map { |arg| arg.is_a?(Capybara::Node::Element) ? arg.base : arg })
621
574
  end
622
575
 
623
576
  ##
@@ -631,12 +584,7 @@ module Capybara
631
584
  #
632
585
  def evaluate_script(script, *args)
633
586
  @touched = true
634
- result = if args.empty?
635
- driver.evaluate_script(script)
636
- else
637
- raise Capybara::NotSupportedByDriverError, "The current driver does not support evaluate_script arguments" if driver.method(:evaluate_script).arity == 1
638
- driver.evaluate_script(script, *args.map { |arg| arg.is_a?(Capybara::Node::Element) ? arg.base : arg} )
639
- end
587
+ result = driver.evaluate_script(script, *args.map { |arg| arg.is_a?(Capybara::Node::Element) ? arg.base : arg })
640
588
  element_script_result(result)
641
589
  end
642
590
 
@@ -649,12 +597,7 @@ module Capybara
649
597
  #
650
598
  def evaluate_async_script(script, *args)
651
599
  @touched = true
652
- result = if args.empty?
653
- driver.evaluate_async_script(script)
654
- else
655
- raise Capybara::NotSupportedByDriverError, "The current driver does not support evaluate_async_script arguments" if driver.method(:evaluate_async_script).arity == 1
656
- driver.evaluate_async_script(script, *args.map { |arg| arg.is_a?(Capybara::Node::Element) ? arg.base : arg} )
657
- end
600
+ result = driver.evaluate_async_script(script, *args.map { |arg| arg.is_a?(Capybara::Node::Element) ? arg.base : arg })
658
601
  element_script_result(result)
659
602
  end
660
603
 
@@ -678,9 +621,8 @@ module Capybara
678
621
  # @return [String] the message shown in the modal
679
622
  # @raise [Capybara::ModalNotFound] if modal dialog hasn't been found
680
623
  #
681
- #
682
- def accept_alert(text_or_options=nil, options={}, &blk)
683
- accept_modal(:alert, text_or_options, options, &blk)
624
+ def accept_alert(text = nil, **options, &blk)
625
+ accept_modal(:alert, text, options, &blk)
684
626
  end
685
627
 
686
628
  ##
@@ -689,8 +631,8 @@ module Capybara
689
631
  #
690
632
  # @macro modal_params
691
633
  #
692
- def accept_confirm(text_or_options=nil, options={}, &blk)
693
- accept_modal(:confirm, text_or_options, options, &blk)
634
+ def accept_confirm(text = nil, **options, &blk)
635
+ accept_modal(:confirm, text, options, &blk)
694
636
  end
695
637
 
696
638
  ##
@@ -699,8 +641,8 @@ module Capybara
699
641
  #
700
642
  # @macro modal_params
701
643
  #
702
- def dismiss_confirm(text_or_options=nil, options={}, &blk)
703
- dismiss_modal(:confirm, text_or_options, options, &blk)
644
+ def dismiss_confirm(text = nil, **options, &blk)
645
+ dismiss_modal(:confirm, text, options, &blk)
704
646
  end
705
647
 
706
648
  ##
@@ -710,8 +652,8 @@ module Capybara
710
652
  # @macro modal_params
711
653
  # @option options [String] :with Response to provide to the prompt
712
654
  #
713
- def accept_prompt(text_or_options=nil, options={}, &blk)
714
- accept_modal(:prompt, text_or_options, options, &blk)
655
+ def accept_prompt(text = nil, **options, &blk)
656
+ accept_modal(:prompt, text, options, &blk)
715
657
  end
716
658
 
717
659
  ##
@@ -720,8 +662,8 @@ module Capybara
720
662
  #
721
663
  # @macro modal_params
722
664
  #
723
- def dismiss_prompt(text_or_options=nil, options={}, &blk)
724
- dismiss_modal(:prompt, text_or_options, options, &blk)
665
+ def dismiss_prompt(text = nil, **options, &blk)
666
+ dismiss_modal(:prompt, text, options, &blk)
725
667
  end
726
668
 
727
669
  ##
@@ -731,17 +673,15 @@ module Capybara
731
673
  #
732
674
  # If invoked without arguments it will save file to `Capybara.save_path`
733
675
  # and file will be given randomly generated filename. If invoked with a relative path
734
- # the path will be relative to `Capybara.save_path`, which is different from
735
- # the previous behavior with `Capybara.save_and_open_page_path` where the relative path was
736
- # relative to Dir.pwd
676
+ # the path will be relative to `Capybara.save_path`
737
677
  #
738
678
  # @param [String] path the path to where it should be saved
739
679
  # @return [String] the path to which the file was saved
740
680
  #
741
681
  def save_page(path = nil)
742
- path = prepare_path(path, 'html')
743
- File.write(path, Capybara::Helpers.inject_asset_host(body, config.asset_host), mode: 'wb')
744
- path
682
+ prepare_path(path, 'html').tap do |p|
683
+ File.write(p, Capybara::Helpers.inject_asset_host(body, host: config.asset_host), mode: 'wb')
684
+ end
745
685
  end
746
686
 
747
687
  ##
@@ -750,15 +690,12 @@ module Capybara
750
690
  #
751
691
  # If invoked without arguments it will save file to `Capybara.save_path`
752
692
  # and file will be given randomly generated filename. If invoked with a relative path
753
- # the path will be relative to `Capybara.save_path`, which is different from
754
- # the previous behavior with `Capybara.save_and_open_page_path` where the relative path was
755
- # relative to Dir.pwd
693
+ # the path will be relative to `Capybara.save_path`
756
694
  #
757
695
  # @param [String] path the path to where it should be saved
758
696
  #
759
697
  def save_and_open_page(path = nil)
760
- path = save_page(path)
761
- open_file(path)
698
+ save_page(path).tap { |p| open_file(p) }
762
699
  end
763
700
 
764
701
  ##
@@ -767,17 +704,13 @@ module Capybara
767
704
  #
768
705
  # If invoked without arguments it will save file to `Capybara.save_path`
769
706
  # and file will be given randomly generated filename. If invoked with a relative path
770
- # the path will be relative to `Capybara.save_path`, which is different from
771
- # the previous behavior with `Capybara.save_and_open_page_path` where the relative path was
772
- # relative to Dir.pwd
707
+ # the path will be relative to `Capybara.save_path`
773
708
  #
774
709
  # @param [String] path the path to where it should be saved
775
710
  # @param [Hash] options a customizable set of options
776
711
  # @return [String] the path to which the file was saved
777
- def save_screenshot(path = nil, options = {})
778
- path = prepare_path(path, 'png')
779
- driver.save_screenshot(path, options)
780
- path
712
+ def save_screenshot(path = nil, **options)
713
+ prepare_path(path, 'png').tap { |p| driver.save_screenshot(p, options) }
781
714
  end
782
715
 
783
716
  ##
@@ -786,16 +719,15 @@ module Capybara
786
719
  #
787
720
  # If invoked without arguments it will save file to `Capybara.save_path`
788
721
  # and file will be given randomly generated filename. If invoked with a relative path
789
- # the path will be relative to `Capybara.save_path`, which is different from
790
- # the previous behavior with `Capybara.save_and_open_page_path` where the relative path was
791
- # relative to Dir.pwd
722
+ # the path will be relative to `Capybara.save_path`
792
723
  #
793
724
  # @param [String] path the path to where it should be saved
794
725
  # @param [Hash] options a customizable set of options
795
726
  #
796
- def save_and_open_screenshot(path = nil, options = {})
797
- path = save_screenshot(path, options)
798
- open_file(path)
727
+ def save_and_open_screenshot(path = nil, **options)
728
+ # rubocop:disable Lint/Debugger
729
+ save_screenshot(path, options).tap { |p| open_file(p) }
730
+ # rubocop:enable Lint/Debugger
799
731
  end
800
732
 
801
733
  def document
@@ -821,8 +753,7 @@ module Capybara
821
753
 
822
754
  def current_scope
823
755
  scope = scopes.last
824
- scope = document if [nil, :frame].include? scope
825
- scope
756
+ [nil, :frame].include?(scope) ? document : scope
826
757
  end
827
758
 
828
759
  ##
@@ -864,6 +795,7 @@ module Capybara
864
795
  Capybara::ReadOnlySessionConfig.new(Capybara.session_options)
865
796
  end
866
797
  end
798
+
867
799
  private
868
800
 
869
801
  @@instance_created = false
@@ -876,32 +808,21 @@ module Capybara
876
808
  driver.dismiss_modal(type, modal_options(text_or_options, options), &blk)
877
809
  end
878
810
 
879
- def modal_options(text_or_options, options)
880
- text_or_options, options = nil, text_or_options if text_or_options.is_a?(Hash)
881
- options[:text] ||= text_or_options unless text_or_options.nil?
811
+ def modal_options(text = nil, **options)
812
+ options[:text] ||= text unless text.nil?
882
813
  options[:wait] ||= config.default_max_wait_time
883
814
  options
884
815
  end
885
816
 
886
-
887
817
  def open_file(path)
888
- begin
889
- require "launchy"
890
- Launchy.open(path)
891
- rescue LoadError
892
- warn "File saved to #{path}."
893
- warn "Please install the launchy gem to open the file automatically."
894
- end
818
+ require "launchy"
819
+ Launchy.open(path)
820
+ rescue LoadError
821
+ warn "File saved to #{path}.\nPlease install the launchy gem to open the file automatically."
895
822
  end
896
823
 
897
824
  def prepare_path(path, extension)
898
- if config.save_path || config.save_and_open_page_path.nil?
899
- path = File.expand_path(path || default_fn(extension), config.save_path)
900
- else
901
- path = File.expand_path(default_fn(extension), config.save_and_open_page_path) if path.nil?
902
- end
903
- FileUtils.mkdir_p(File.dirname(path))
904
- path
825
+ File.expand_path(path || default_fn(extension), config.save_path).tap { |p| FileUtils.mkdir_p(File.dirname(p)) }
905
826
  end
906
827
 
907
828
  def default_fn(extension)
@@ -927,26 +848,22 @@ module Capybara
927
848
  end
928
849
 
929
850
  def _find_frame(*args)
930
- within(document) do # Previous 2.x versions ignored current scope when finding frames - consider changing in 3.0
931
- case args[0]
932
- when Capybara::Node::Element
933
- args[0]
934
- when String, Hash
935
- find(:frame, *args)
936
- when Symbol
937
- find(*args)
938
- when Integer
939
- idx = args[0]
940
- all(:frame, minimum: idx+1)[idx]
941
- else
942
- raise TypeError
943
- end
851
+ case args[0]
852
+ when Capybara::Node::Element
853
+ args[0]
854
+ when String, Hash
855
+ find(:frame, *args)
856
+ when Symbol
857
+ find(*args)
858
+ when Integer
859
+ idx = args[0]
860
+ all(:frame, minimum: idx + 1)[idx]
861
+ else
862
+ raise TypeError
944
863
  end
945
864
  end
946
865
 
947
- def _switch_to_window(window = nil, options= {})
948
- options, window = window, nil if window.is_a? Hash
949
-
866
+ def _switch_to_window(window = nil, **options)
950
867
  raise Capybara::ScopeError, "Window cannot be switched inside a `within_frame` block" if scopes.include?(:frame)
951
868
  raise Capybara::ScopeError, "Window cannot be switch inside a `within` block" unless scopes.last.nil?
952
869
 
@@ -960,9 +877,7 @@ module Capybara
960
877
  begin
961
878
  driver.window_handles.each do |handle|
962
879
  driver.switch_to_window handle
963
- if yield
964
- return Window.new(self, handle)
965
- end
880
+ return Window.new(self, handle) if yield
966
881
  end
967
882
  rescue => e
968
883
  driver.switch_to_window(original_window_handle)
@@ -974,6 +889,5 @@ module Capybara
974
889
  end
975
890
  end
976
891
  end
977
-
978
892
  end
979
893
  end