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,14 +1,15 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require "uri"
4
+ require "English"
3
5
 
4
6
  class Capybara::Selenium::Driver < Capybara::Driver::Base
5
-
6
7
  DEFAULT_OPTIONS = {
7
- :browser => :firefox,
8
+ browser: :firefox,
8
9
  clear_local_storage: false,
9
10
  clear_session_storage: false
10
- }
11
- SPECIAL_OPTIONS = [:browser, :clear_local_storage, :clear_session_storage]
11
+ }.freeze
12
+ SPECIAL_OPTIONS = %i[browser clear_local_storage clear_session_storage].freeze
12
13
 
13
14
  attr_reader :app, :options
14
15
 
@@ -16,18 +17,19 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
16
17
  unless @browser
17
18
  if firefox?
18
19
  options[:desired_capabilities] ||= {}
19
- options[:desired_capabilities].merge!({ unexpectedAlertBehaviour: "ignore" })
20
+ options[:desired_capabilities][:unexpectedAlertBehaviour] = "ignore"
20
21
  end
21
22
 
22
- @processed_options = options.reject { |key,_val| SPECIAL_OPTIONS.include?(key) }
23
+ @processed_options = options.reject { |key, _val| SPECIAL_OPTIONS.include?(key) }
23
24
  @browser = Selenium::WebDriver.for(options[:browser], @processed_options)
24
25
 
25
26
  @w3c = ((defined?(Selenium::WebDriver::Remote::W3CCapabilities) && @browser.capabilities.is_a?(Selenium::WebDriver::Remote::W3CCapabilities)) ||
26
27
  (defined?(Selenium::WebDriver::Remote::W3C::Capabilities) && @browser.capabilities.is_a?(Selenium::WebDriver::Remote::W3C::Capabilities)))
27
28
  main = Process.pid
29
+
28
30
  at_exit do
29
31
  # Store the exit status of the test run since it goes away after calling the at_exit proc...
30
- @exit_status = $!.status if $!.is_a?(SystemExit)
32
+ @exit_status = $ERROR_INFO.status if $ERROR_INFO.is_a?(SystemExit)
31
33
  quit if Process.pid == main
32
34
  exit @exit_status if @exit_status # Force exit with stored status
33
35
  end
@@ -35,7 +37,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
35
37
  @browser
36
38
  end
37
39
 
38
- def initialize(app, options={})
40
+ def initialize(app, **options)
39
41
  load_selenium
40
42
  @session = nil
41
43
  @app = app
@@ -50,10 +52,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
50
52
  end
51
53
 
52
54
  def refresh
53
- accept_modal(nil, wait: 0.1) do
54
- browser.navigate.refresh
55
- end
56
- rescue Capybara::ModalNotFound
55
+ browser.navigate.refresh
57
56
  end
58
57
 
59
58
  def go_back
@@ -88,7 +87,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
88
87
  def needs_server?; true; end
89
88
 
90
89
  def execute_script(script, *args)
91
- browser.execute_script(script, *args.map { |arg| arg.is_a?(Capybara::Selenium::Node) ? arg.native : arg} )
90
+ browser.execute_script(script, *args.map { |arg| arg.is_a?(Capybara::Selenium::Node) ? arg.native : arg })
92
91
  end
93
92
 
94
93
  def evaluate_script(script, *args)
@@ -98,66 +97,69 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
98
97
 
99
98
  def evaluate_async_script(script, *args)
100
99
  browser.manage.timeouts.script_timeout = Capybara.default_max_wait_time
101
- result = browser.execute_async_script(script, *args.map { |arg| arg.is_a?(Capybara::Selenium::Node) ? arg.native : arg} )
100
+ result = browser.execute_async_script(script, *args.map { |arg| arg.is_a?(Capybara::Selenium::Node) ? arg.native : arg })
102
101
  unwrap_script_result(result)
103
102
  end
104
103
 
105
- def save_screenshot(path, _options={})
104
+ def save_screenshot(path, **_options)
106
105
  browser.save_screenshot(path)
107
106
  end
108
107
 
109
108
  def reset!
110
109
  # Use instance variable directly so we avoid starting the browser just to reset the session
111
- if @browser
112
- navigated = false
113
- start_time = Capybara::Helpers.monotonic_time
110
+ return unless @browser
111
+
112
+ if firefox? || chrome?
113
+ switch_to_window(window_handles.first)
114
+ window_handles.slice(1..-1).each { |win| close_window(win) }
115
+ end
116
+
117
+ navigated = false
118
+ start_time = Capybara::Helpers.monotonic_time
119
+ begin
120
+ unless navigated
121
+ # Only trigger a navigation if we haven't done it already, otherwise it
122
+ # can trigger an endless series of unload modals
123
+ begin
124
+ @browser.manage.delete_all_cookies
125
+ clear_storage
126
+ rescue Selenium::WebDriver::Error::UnhandledError
127
+ # delete_all_cookies fails when we've previously gone
128
+ # to about:blank, so we rescue this error and do nothing
129
+ # instead.
130
+ end
131
+ @browser.navigate.to("about:blank")
132
+ end
133
+ navigated = true
134
+
135
+ # Ensure the page is empty and trigger an UnhandledAlertError for any modals that appear during unload
136
+ until find_xpath("/html/body/*").empty?
137
+ raise Capybara::ExpectationNotMet, 'Timed out waiting for Selenium session reset' if (Capybara::Helpers.monotonic_time - start_time) >= 10
138
+ sleep 0.05
139
+ end
140
+ rescue Selenium::WebDriver::Error::UnhandledAlertError, Selenium::WebDriver::Error::UnexpectedAlertOpenError
141
+ # This error is thrown if an unhandled alert is on the page
142
+ # Firefox appears to automatically dismiss this alert, chrome does not
143
+ # We'll try to accept it
114
144
  begin
115
- if !navigated
116
- # Only trigger a navigation if we haven't done it already, otherwise it
117
- # can trigger an endless series of unload modals
145
+ @browser.switch_to.alert.accept
146
+ sleep 0.25 # allow time for the modal to be handled
147
+ rescue modal_error
148
+ # The alert is now gone
149
+ if current_url != "about:blank"
118
150
  begin
119
- @browser.manage.delete_all_cookies
120
- if options[:clear_session_storage]
121
- if @browser.respond_to? :session_storage
122
- @browser.session_storage.clear
123
- else
124
- warn "sessionStorage clear requested but is not available for this driver"
125
- end
126
- end
127
- if options[:clear_local_storage]
128
- if @browser.respond_to? :local_storage
129
- @browser.local_storage.clear
130
- else
131
- warn "localStorage clear requested but is not available for this driver"
132
- end
133
- end
134
- rescue Selenium::WebDriver::Error::UnhandledError
135
- # delete_all_cookies fails when we've previously gone
136
- # to about:blank, so we rescue this error and do nothing
137
- # instead.
151
+ # If navigation has not occurred attempt again and accept alert
152
+ # since FF may have dismissed the alert at first attempt
153
+ @browser.navigate.to("about:blank")
154
+ sleep 0.1 # slight wait for alert
155
+ @browser.switch_to.alert.accept
156
+ rescue modal_error # rubocop:disable Metrics/BlockNesting
157
+ # alert now gone, should mean navigation happened
138
158
  end
139
- @browser.navigate.to("about:blank")
140
- end
141
- navigated = true
142
-
143
- #Ensure the page is empty and trigger an UnhandledAlertError for any modals that appear during unload
144
- until find_xpath("/html/body/*").empty? do
145
- raise Capybara::ExpectationNotMet.new('Timed out waiting for Selenium session reset') if (Capybara::Helpers.monotonic_time - start_time) >= 10
146
- sleep 0.05
147
159
  end
148
- rescue Selenium::WebDriver::Error::UnhandledAlertError, Selenium::WebDriver::Error::UnexpectedAlertOpenError
149
- # This error is thrown if an unhandled alert is on the page
150
- # Firefox appears to automatically dismiss this alert, chrome does not
151
- # We'll try to accept it
152
- begin
153
- @browser.switch_to.alert.accept
154
- sleep 0.25 # allow time for the modal to be handled
155
- rescue modal_error
156
- # The alert is now gone - nothing to do
157
- end
158
- # try cleaning up the browser again
159
- retry
160
160
  end
161
+ # try cleaning up the browser again
162
+ retry
161
163
  end
162
164
  end
163
165
 
@@ -209,6 +211,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
209
211
  end
210
212
 
211
213
  def close_window(handle)
214
+ raise ArgumentError, "Not allowed to close the primary window" if handle == window_handles.first
212
215
  within_given_window(handle) do
213
216
  browser.close
214
217
  end
@@ -226,12 +229,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
226
229
  browser.switch_to.window handle
227
230
  end
228
231
 
229
- def within_window(locator)
230
- handle = find_window(locator)
231
- browser.switch_to.window(handle) { yield }
232
- end
233
-
234
- def accept_modal(_type, options={})
232
+ def accept_modal(_type, **options)
235
233
  yield if block_given?
236
234
  modal = find_modal(options)
237
235
 
@@ -242,7 +240,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
242
240
  message
243
241
  end
244
242
 
245
- def dismiss_modal(_type, options={})
243
+ def dismiss_modal(_type, **options)
246
244
  yield if block_given?
247
245
  modal = find_modal(options)
248
246
  message = modal.text
@@ -264,14 +262,18 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
264
262
  end
265
263
 
266
264
  def invalid_element_errors
267
- [::Selenium::WebDriver::Error::StaleElementReferenceError,
268
- ::Selenium::WebDriver::Error::UnhandledError,
269
- ::Selenium::WebDriver::Error::ElementNotVisibleError,
270
- ::Selenium::WebDriver::Error::InvalidSelectorError, # Work around a race condition that can occur with chromedriver and #go_back/#go_forward
271
- ::Selenium::WebDriver::Error::ElementNotInteractableError,
272
- ::Selenium::WebDriver::Error::ElementClickInterceptedError,
273
- ::Selenium::WebDriver::Error::InvalidElementStateError,
274
- ::Selenium::WebDriver::Error::ElementNotSelectableError,
265
+ [
266
+ ::Selenium::WebDriver::Error::StaleElementReferenceError,
267
+ ::Selenium::WebDriver::Error::UnhandledError,
268
+ ::Selenium::WebDriver::Error::ElementNotVisibleError,
269
+ ::Selenium::WebDriver::Error::InvalidSelectorError, # Work around a race condition that can occur with chromedriver and #go_back/#go_forward
270
+ ::Selenium::WebDriver::Error::ElementNotInteractableError,
271
+ ::Selenium::WebDriver::Error::ElementClickInterceptedError,
272
+ ::Selenium::WebDriver::Error::InvalidElementStateError,
273
+ ::Selenium::WebDriver::Error::ElementNotSelectableError,
274
+ ::Selenium::WebDriver::Error::ElementNotSelectableError,
275
+ ::Selenium::WebDriver::Error::NoSuchElementError, # IE
276
+ ::Selenium::WebDriver::Error::InvalidArgumentError # IE
275
277
  ]
276
278
  end
277
279
 
@@ -294,18 +296,39 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
294
296
  browser_name == "chrome"
295
297
  end
296
298
 
297
- # @deprecated This method is being removed
298
- def browser_initialized?
299
- super && !@browser.nil?
299
+ # @api private
300
+ def edge?
301
+ browser_name == "edge"
300
302
  end
301
303
 
302
- private
303
-
304
304
  # @api private
305
+ def ie?
306
+ browser_name == "ie"
307
+ end
308
+
309
+ private
310
+
305
311
  def browser_name
306
312
  options[:browser].to_s
307
313
  end
308
314
 
315
+ def clear_storage
316
+ if options[:clear_session_storage]
317
+ if @browser.respond_to? :session_storage
318
+ @browser.session_storage.clear
319
+ else
320
+ warn "sessionStorage clear requested but is not available for this driver"
321
+ end
322
+ end
323
+ if options[:clear_local_storage]
324
+ if @browser.respond_to? :local_storage
325
+ @browser.local_storage.clear
326
+ else
327
+ warn "localStorage clear requested but is not available for this driver"
328
+ end
329
+ end
330
+ end
331
+
309
332
  def modal_error
310
333
  if defined?(Selenium::WebDriver::Error::NoSuchAlertError)
311
334
  Selenium::WebDriver::Error::NoSuchAlertError
@@ -314,23 +337,6 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
314
337
  end
315
338
  end
316
339
 
317
- def find_window(locator)
318
- handles = browser.window_handles
319
- return locator if handles.include? locator
320
-
321
- original_handle = browser.window_handle
322
- handles.each do |handle|
323
- switch_to_window(handle)
324
- if (locator == browser.execute_script("return window.name") ||
325
- browser.title.include?(locator) ||
326
- browser.current_url.include?(locator))
327
- switch_to_window(original_handle)
328
- return handle
329
- end
330
- end
331
- raise Capybara::ElementNotFound, "Could not find a window identified by #{locator}"
332
- end
333
-
334
340
  def insert_modal_handlers(accept, response_text)
335
341
  prompt_response = if accept
336
342
  if response_text.nil?
@@ -386,7 +392,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
386
392
  end
387
393
 
388
394
  def within_given_window(handle)
389
- original_handle = self.current_window_handle
395
+ original_handle = current_window_handle
390
396
  if handle == original_handle
391
397
  yield
392
398
  else
@@ -397,39 +403,41 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
397
403
  end
398
404
  end
399
405
 
400
- def find_modal(options={})
406
+ def find_modal(text: nil, **options)
401
407
  # Selenium has its own built in wait (2 seconds)for a modal to show up, so this wait is really the minimum time
402
408
  # Actual wait time may be longer than specified
403
409
  wait = Selenium::WebDriver::Wait.new(
404
- timeout: options.fetch(:wait, session_options.default_max_wait_time) || 0 ,
405
- ignore: modal_error)
410
+ timeout: options.fetch(:wait, session_options.default_max_wait_time) || 0,
411
+ ignore: modal_error
412
+ )
406
413
  begin
407
414
  wait.until do
408
415
  alert = @browser.switch_to.alert
409
- regexp = options[:text].is_a?(Regexp) ? options[:text] : Regexp.escape(options[:text].to_s)
416
+ regexp = text.is_a?(Regexp) ? text : Regexp.escape(text.to_s)
410
417
  alert.text.match(regexp) ? alert : nil
411
418
  end
412
419
  rescue Selenium::WebDriver::Error::TimeOutError
413
- raise Capybara::ModalNotFound.new("Unable to find modal dialog#{" with #{options[:text]}" if options[:text]}")
420
+ raise Capybara::ModalNotFound, "Unable to find modal dialog#{" with #{text}" if text}"
414
421
  end
415
422
  end
416
423
 
417
- def find_headless_modal(options={})
424
+ def find_headless_modal(text: nil, **options)
418
425
  # Selenium has its own built in wait (2 seconds)for a modal to show up, so this wait is really the minimum time
419
426
  # Actual wait time may be longer than specified
420
427
  wait = Selenium::WebDriver::Wait.new(
421
- timeout: options.fetch(:wait, session_options.default_max_wait_time) || 0 ,
422
- ignore: modal_error)
428
+ timeout: options.fetch(:wait, session_options.default_max_wait_time) || 0,
429
+ ignore: modal_error
430
+ )
423
431
  begin
424
432
  wait.until do
425
433
  called, alert_text = evaluate_script('window.capybara && window.capybara.current_modal_status()')
426
434
  if called
427
435
  execute_script('window.capybara && window.capybara.modal_handlers.shift()')
428
- regexp = options[:text].is_a?(Regexp) ? options[:text] : Regexp.escape(options[:text].to_s)
436
+ regexp = text.is_a?(Regexp) ? text : Regexp.escape(text.to_s)
429
437
  if alert_text.match(regexp)
430
438
  alert_text
431
439
  else
432
- raise Capybara::ModalNotFound.new("Unable to find modal dialog#{" with #{options[:text]}" if options[:text]}")
440
+ raise Capybara::ModalNotFound, "Unable to find modal dialog#{" with #{text}" if text}"
433
441
  end
434
442
  elsif called.nil?
435
443
  # page changed so modal_handler data has gone away
@@ -440,7 +448,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
440
448
  end
441
449
  end
442
450
  rescue Selenium::WebDriver::Error::TimeOutError
443
- raise Capybara::ModalNotFound.new("Unable to find modal dialog#{" with #{options[:text]}" if options[:text]}")
451
+ raise Capybara::ModalNotFound, "Unable to find modal dialog#{" with #{options[:text]}" if options[:text]}"
444
452
  end
445
453
  end
446
454
 
@@ -449,7 +457,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
449
457
  end
450
458
 
451
459
  def silenced_unknown_error_messages
452
- [ /Error communicating with the remote browser/ ]
460
+ [/Error communicating with the remote browser/]
453
461
  end
454
462
 
455
463
  def unwrap_script_result(arg)
@@ -466,21 +474,19 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
466
474
  end
467
475
 
468
476
  def load_selenium
469
- begin
470
- require 'selenium-webdriver'
471
- # Fix for selenium-webdriver 3.4.0 which misnamed these
472
- if !defined?(::Selenium::WebDriver::Error::ElementNotInteractableError)
473
- ::Selenium::WebDriver::Error.const_set('ElementNotInteractableError', Class.new(::Selenium::WebDriver::Error::WebDriverError))
474
- end
475
- if !defined?(::Selenium::WebDriver::Error::ElementClickInterceptedError)
476
- ::Selenium::WebDriver::Error.const_set('ElementClickInterceptedError', Class.new(::Selenium::WebDriver::Error::WebDriverError))
477
- end
478
- rescue LoadError => e
479
- if e.message =~ /selenium-webdriver/
480
- raise LoadError, "Capybara's selenium driver is unable to load `selenium-webdriver`, please install the gem and add `gem 'selenium-webdriver'` to your Gemfile if you are using bundler."
481
- else
482
- raise e
483
- end
477
+ require 'selenium-webdriver'
478
+ # Fix for selenium-webdriver 3.4.0 which misnamed these
479
+ unless defined?(::Selenium::WebDriver::Error::ElementNotInteractableError)
480
+ ::Selenium::WebDriver::Error.const_set('ElementNotInteractableError', Class.new(::Selenium::WebDriver::Error::WebDriverError))
481
+ end
482
+ unless defined?(::Selenium::WebDriver::Error::ElementClickInterceptedError)
483
+ ::Selenium::WebDriver::Error.const_set('ElementClickInterceptedError', Class.new(::Selenium::WebDriver::Error::WebDriverError))
484
+ end
485
+ rescue LoadError => e
486
+ if e.message =~ /selenium-webdriver/
487
+ raise LoadError, "Capybara's selenium driver is unable to load `selenium-webdriver`, please install the gem and add `gem 'selenium-webdriver'` to your Gemfile if you are using bundler."
488
+ else
489
+ raise e
484
490
  end
485
491
  end
486
492
  end