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.
- checksums.yaml +4 -4
- data/History.md +55 -1
- data/README.md +18 -17
- data/lib/capybara/config.rb +11 -58
- data/lib/capybara/cucumber.rb +2 -3
- data/lib/capybara/driver/base.rb +15 -16
- data/lib/capybara/driver/node.rb +5 -4
- data/lib/capybara/dsl.rb +1 -0
- data/lib/capybara/helpers.rb +19 -29
- data/lib/capybara/minitest/spec.rb +15 -14
- data/lib/capybara/minitest.rb +139 -138
- data/lib/capybara/node/actions.rb +60 -81
- data/lib/capybara/node/base.rb +11 -18
- data/lib/capybara/node/document.rb +2 -2
- data/lib/capybara/node/document_matchers.rb +8 -8
- data/lib/capybara/node/element.rb +30 -40
- data/lib/capybara/node/finders.rb +62 -70
- data/lib/capybara/node/matchers.rb +50 -71
- data/lib/capybara/node/simple.rb +11 -17
- data/lib/capybara/queries/ancestor_query.rb +11 -7
- data/lib/capybara/queries/base_query.rb +22 -18
- data/lib/capybara/queries/current_path_query.rb +8 -24
- data/lib/capybara/queries/match_query.rb +3 -7
- data/lib/capybara/queries/selector_query.rb +92 -95
- data/lib/capybara/queries/sibling_query.rb +4 -4
- data/lib/capybara/queries/text_query.rb +35 -35
- data/lib/capybara/queries/title_query.rb +8 -11
- data/lib/capybara/rack_test/browser.rb +15 -18
- data/lib/capybara/rack_test/css_handlers.rb +6 -4
- data/lib/capybara/rack_test/driver.rb +6 -10
- data/lib/capybara/rack_test/form.rb +50 -40
- data/lib/capybara/rack_test/node.rb +93 -63
- data/lib/capybara/rails.rb +2 -6
- data/lib/capybara/result.rb +22 -22
- data/lib/capybara/rspec/compound.rb +5 -10
- data/lib/capybara/rspec/features.rb +17 -48
- data/lib/capybara/rspec/matcher_proxies.rb +31 -15
- data/lib/capybara/rspec/matchers.rb +70 -61
- data/lib/capybara/rspec.rb +5 -10
- data/lib/capybara/selector/css.rb +6 -11
- data/lib/capybara/selector/filter.rb +1 -17
- data/lib/capybara/selector/filter_set.rb +18 -15
- data/lib/capybara/selector/filters/base.rb +7 -6
- data/lib/capybara/selector/filters/expression_filter.rb +6 -23
- data/lib/capybara/selector/filters/node_filter.rb +2 -12
- data/lib/capybara/selector/selector.rb +28 -34
- data/lib/capybara/selector.rb +129 -117
- data/lib/capybara/selenium/driver.rb +131 -125
- data/lib/capybara/selenium/node.rb +197 -115
- data/lib/capybara/server.rb +3 -2
- data/lib/capybara/session/config.rb +47 -67
- data/lib/capybara/session/matchers.rb +8 -7
- data/lib/capybara/session.rb +138 -224
- data/lib/capybara/spec/public/test.js +25 -4
- data/lib/capybara/spec/session/accept_alert_spec.rb +1 -0
- data/lib/capybara/spec/session/accept_confirm_spec.rb +3 -2
- data/lib/capybara/spec/session/accept_prompt_spec.rb +1 -0
- data/lib/capybara/spec/session/all_spec.rb +31 -18
- data/lib/capybara/spec/session/ancestor_spec.rb +6 -8
- data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +6 -5
- data/lib/capybara/spec/session/assert_current_path.rb +12 -11
- data/lib/capybara/spec/session/assert_selector.rb +1 -0
- data/lib/capybara/spec/session/assert_text.rb +23 -23
- data/lib/capybara/spec/session/assert_title.rb +13 -3
- data/lib/capybara/spec/session/attach_file_spec.rb +51 -30
- data/lib/capybara/spec/session/body_spec.rb +1 -0
- data/lib/capybara/spec/session/check_spec.rb +7 -6
- data/lib/capybara/spec/session/choose_spec.rb +5 -4
- data/lib/capybara/spec/session/click_button_spec.rb +24 -32
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +8 -7
- data/lib/capybara/spec/session/click_link_spec.rb +8 -7
- data/lib/capybara/spec/session/current_scope_spec.rb +4 -3
- data/lib/capybara/spec/session/current_url_spec.rb +17 -6
- data/lib/capybara/spec/session/dismiss_confirm_spec.rb +1 -1
- data/lib/capybara/spec/session/dismiss_prompt_spec.rb +1 -0
- data/lib/capybara/spec/session/element/assert_match_selector.rb +1 -1
- data/lib/capybara/spec/session/element/match_xpath_spec.rb +1 -1
- data/lib/capybara/spec/session/element/matches_selector_spec.rb +5 -5
- data/lib/capybara/spec/session/evaluate_async_script_spec.rb +3 -2
- data/lib/capybara/spec/session/evaluate_script_spec.rb +4 -3
- data/lib/capybara/spec/session/execute_script_spec.rb +4 -3
- data/lib/capybara/spec/session/fill_in_spec.rb +30 -5
- data/lib/capybara/spec/session/find_button_spec.rb +4 -3
- data/lib/capybara/spec/session/find_by_id_spec.rb +2 -1
- data/lib/capybara/spec/session/find_field_spec.rb +9 -15
- data/lib/capybara/spec/session/find_link_spec.rb +6 -5
- data/lib/capybara/spec/session/find_spec.rb +37 -31
- data/lib/capybara/spec/session/first_spec.rb +60 -33
- data/lib/capybara/spec/session/frame/frame_title_spec.rb +23 -0
- data/lib/capybara/spec/session/frame/frame_url_spec.rb +23 -0
- data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +2 -1
- data/lib/capybara/spec/session/frame/within_frame_spec.rb +9 -16
- data/lib/capybara/spec/session/go_back_spec.rb +1 -0
- data/lib/capybara/spec/session/go_forward_spec.rb +1 -0
- data/lib/capybara/spec/session/has_all_selectors_spec.rb +15 -15
- data/lib/capybara/spec/session/has_button_spec.rb +2 -1
- data/lib/capybara/spec/session/has_css_spec.rb +3 -2
- data/lib/capybara/spec/session/has_current_path_spec.rb +12 -28
- data/lib/capybara/spec/session/has_field_spec.rb +4 -3
- data/lib/capybara/spec/session/has_link_spec.rb +1 -0
- data/lib/capybara/spec/session/has_none_selectors_spec.rb +17 -17
- data/lib/capybara/spec/session/has_select_spec.rb +30 -29
- data/lib/capybara/spec/session/has_selector_spec.rb +5 -4
- data/lib/capybara/spec/session/has_table_spec.rb +2 -1
- data/lib/capybara/spec/session/has_text_spec.rb +9 -13
- data/lib/capybara/spec/session/has_title_spec.rb +1 -0
- data/lib/capybara/spec/session/has_xpath_spec.rb +1 -0
- data/lib/capybara/spec/session/headers.rb +2 -1
- data/lib/capybara/spec/session/html_spec.rb +1 -0
- data/lib/capybara/spec/session/node_spec.rb +91 -56
- data/lib/capybara/spec/session/node_wrapper_spec.rb +36 -0
- data/lib/capybara/spec/session/refresh_spec.rb +6 -2
- data/lib/capybara/spec/session/reset_session_spec.rb +19 -0
- data/lib/capybara/spec/session/response_code.rb +1 -0
- data/lib/capybara/spec/session/save_and_open_page_spec.rb +1 -0
- data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +6 -11
- data/lib/capybara/spec/session/save_page_spec.rb +1 -17
- data/lib/capybara/spec/session/save_screenshot_spec.rb +3 -3
- data/lib/capybara/spec/session/select_spec.rb +20 -20
- data/lib/capybara/spec/session/selectors_spec.rb +2 -2
- data/lib/capybara/spec/session/sibling_spec.rb +1 -1
- data/lib/capybara/spec/session/text_spec.rb +17 -3
- data/lib/capybara/spec/session/title_spec.rb +11 -1
- data/lib/capybara/spec/session/uncheck_spec.rb +4 -3
- data/lib/capybara/spec/session/unselect_spec.rb +6 -5
- data/lib/capybara/spec/session/visit_spec.rb +9 -3
- data/lib/capybara/spec/session/window/become_closed_spec.rb +2 -1
- data/lib/capybara/spec/session/window/current_window_spec.rb +1 -0
- data/lib/capybara/spec/session/window/open_new_window_spec.rb +1 -0
- data/lib/capybara/spec/session/window/switch_to_window_spec.rb +2 -1
- data/lib/capybara/spec/session/window/window_opened_by_spec.rb +2 -1
- data/lib/capybara/spec/session/window/window_spec.rb +12 -12
- data/lib/capybara/spec/session/window/windows_spec.rb +2 -3
- data/lib/capybara/spec/session/window/within_window_spec.rb +15 -71
- data/lib/capybara/spec/session/within_spec.rb +1 -0
- data/lib/capybara/spec/spec_helper.rb +34 -18
- data/lib/capybara/spec/test_app.rb +17 -9
- data/lib/capybara/spec/views/form.erb +7 -0
- data/lib/capybara/spec/views/with_html.erb +23 -1
- data/lib/capybara/spec/views/within_frames.erb +4 -1
- data/lib/capybara/version.rb +2 -1
- data/lib/capybara/window.rb +6 -10
- data/lib/capybara.rb +28 -25
- data/spec/basic_node_spec.rb +1 -0
- data/spec/capybara_spec.rb +11 -50
- data/spec/dsl_spec.rb +5 -13
- data/spec/filter_set_spec.rb +5 -4
- data/spec/fixtures/selenium_driver_rspec_failure.rb +2 -1
- data/spec/fixtures/selenium_driver_rspec_success.rb +3 -2
- data/spec/minitest_spec.rb +4 -3
- data/spec/minitest_spec_spec.rb +3 -2
- data/spec/per_session_config_spec.rb +9 -8
- data/spec/rack_test_spec.rb +21 -20
- data/spec/result_spec.rb +17 -16
- data/spec/rspec/features_spec.rb +17 -14
- data/spec/rspec/scenarios_spec.rb +5 -7
- data/spec/rspec/shared_spec_matchers.rb +96 -99
- data/spec/rspec/views_spec.rb +2 -1
- data/spec/rspec_matchers_spec.rb +18 -2
- data/spec/rspec_spec.rb +11 -15
- data/spec/selector_spec.rb +5 -6
- data/spec/selenium_spec_chrome.rb +9 -4
- data/spec/selenium_spec_edge.rb +27 -0
- data/spec/selenium_spec_ie.rb +31 -0
- data/spec/selenium_spec_marionette.rb +28 -12
- data/spec/server_spec.rb +33 -33
- data/spec/session_spec.rb +2 -1
- data/spec/shared_selenium_session.rb +36 -22
- data/spec/spec_helper.rb +3 -6
- metadata +68 -85
- data/lib/capybara/query.rb +0 -7
- 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
|
-
:
|
8
|
+
browser: :firefox,
|
8
9
|
clear_local_storage: false,
|
9
10
|
clear_session_storage: false
|
10
|
-
}
|
11
|
-
SPECIAL_OPTIONS = [
|
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]
|
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 =
|
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
|
-
|
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) ?
|
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
|
-
|
112
|
-
|
113
|
-
|
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
|
-
|
116
|
-
|
117
|
-
|
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
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
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
|
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
|
-
[
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
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
|
-
# @
|
298
|
-
def
|
299
|
-
|
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 =
|
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 =
|
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
|
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 =
|
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
|
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
|
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
|
-
[
|
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
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
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
|