capybara 3.0.0 → 3.36.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/.yardopts +1 -1
- data/History.md +777 -10
- data/License.txt +1 -1
- data/README.md +75 -58
- data/lib/capybara/config.rb +29 -10
- data/lib/capybara/cucumber.rb +1 -1
- data/lib/capybara/driver/base.rb +22 -4
- data/lib/capybara/driver/node.rb +34 -9
- data/lib/capybara/dsl.rb +14 -6
- data/lib/capybara/helpers.rb +52 -7
- data/lib/capybara/minitest/spec.rb +173 -84
- data/lib/capybara/minitest.rb +250 -144
- data/lib/capybara/node/actions.rb +248 -124
- data/lib/capybara/node/base.rb +34 -20
- data/lib/capybara/node/document.rb +14 -2
- data/lib/capybara/node/document_matchers.rb +13 -15
- data/lib/capybara/node/element.rb +339 -113
- data/lib/capybara/node/finders.rb +95 -82
- data/lib/capybara/node/matchers.rb +338 -157
- data/lib/capybara/node/simple.rb +54 -15
- data/lib/capybara/queries/active_element_query.rb +18 -0
- data/lib/capybara/queries/ancestor_query.rb +9 -10
- data/lib/capybara/queries/base_query.rb +25 -18
- data/lib/capybara/queries/current_path_query.rb +16 -6
- data/lib/capybara/queries/match_query.rb +11 -0
- data/lib/capybara/queries/selector_query.rb +600 -103
- data/lib/capybara/queries/sibling_query.rb +9 -7
- data/lib/capybara/queries/style_query.rb +45 -0
- data/lib/capybara/queries/text_query.rb +40 -22
- data/lib/capybara/queries/title_query.rb +2 -2
- data/lib/capybara/rack_test/browser.rb +47 -28
- data/lib/capybara/rack_test/driver.rb +12 -3
- data/lib/capybara/rack_test/errors.rb +6 -0
- data/lib/capybara/rack_test/form.rb +53 -50
- data/lib/capybara/rack_test/node.rb +114 -37
- data/lib/capybara/rails.rb +1 -1
- data/lib/capybara/registration_container.rb +44 -0
- data/lib/capybara/registrations/drivers.rb +42 -0
- data/lib/capybara/registrations/patches/puma_ssl.rb +29 -0
- data/lib/capybara/registrations/servers.rb +45 -0
- data/lib/capybara/result.rb +86 -52
- data/lib/capybara/rspec/features.rb +8 -10
- data/lib/capybara/rspec/matcher_proxies.rb +39 -18
- data/lib/capybara/rspec/matchers/base.rb +111 -0
- data/lib/capybara/rspec/matchers/become_closed.rb +33 -0
- data/lib/capybara/rspec/matchers/compound.rb +88 -0
- data/lib/capybara/rspec/matchers/count_sugar.rb +37 -0
- data/lib/capybara/rspec/matchers/have_ancestor.rb +28 -0
- data/lib/capybara/rspec/matchers/have_current_path.rb +29 -0
- data/lib/capybara/rspec/matchers/have_selector.rb +77 -0
- data/lib/capybara/rspec/matchers/have_sibling.rb +27 -0
- data/lib/capybara/rspec/matchers/have_text.rb +33 -0
- data/lib/capybara/rspec/matchers/have_title.rb +29 -0
- data/lib/capybara/rspec/matchers/match_selector.rb +27 -0
- data/lib/capybara/rspec/matchers/match_style.rb +43 -0
- data/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
- data/lib/capybara/rspec/matchers.rb +138 -316
- data/lib/capybara/rspec.rb +3 -2
- data/lib/capybara/selector/builders/css_builder.rb +84 -0
- data/lib/capybara/selector/builders/xpath_builder.rb +71 -0
- data/lib/capybara/selector/css.rb +89 -12
- data/lib/capybara/selector/definition/button.rb +68 -0
- data/lib/capybara/selector/definition/checkbox.rb +26 -0
- data/lib/capybara/selector/definition/css.rb +10 -0
- data/lib/capybara/selector/definition/datalist_input.rb +35 -0
- data/lib/capybara/selector/definition/datalist_option.rb +25 -0
- data/lib/capybara/selector/definition/element.rb +28 -0
- data/lib/capybara/selector/definition/field.rb +40 -0
- data/lib/capybara/selector/definition/fieldset.rb +14 -0
- data/lib/capybara/selector/definition/file_field.rb +13 -0
- data/lib/capybara/selector/definition/fillable_field.rb +33 -0
- data/lib/capybara/selector/definition/frame.rb +17 -0
- data/lib/capybara/selector/definition/id.rb +6 -0
- data/lib/capybara/selector/definition/label.rb +62 -0
- data/lib/capybara/selector/definition/link.rb +54 -0
- data/lib/capybara/selector/definition/link_or_button.rb +16 -0
- data/lib/capybara/selector/definition/option.rb +27 -0
- data/lib/capybara/selector/definition/radio_button.rb +27 -0
- data/lib/capybara/selector/definition/select.rb +81 -0
- data/lib/capybara/selector/definition/table.rb +109 -0
- data/lib/capybara/selector/definition/table_row.rb +21 -0
- data/lib/capybara/selector/definition/xpath.rb +5 -0
- data/lib/capybara/selector/definition.rb +279 -0
- data/lib/capybara/selector/filter.rb +1 -0
- data/lib/capybara/selector/filter_set.rb +72 -27
- data/lib/capybara/selector/filters/base.rb +45 -2
- data/lib/capybara/selector/filters/expression_filter.rb +5 -6
- data/lib/capybara/selector/filters/locator_filter.rb +29 -0
- data/lib/capybara/selector/filters/node_filter.rb +18 -4
- data/lib/capybara/selector/regexp_disassembler.rb +214 -0
- data/lib/capybara/selector/selector.rb +85 -200
- data/lib/capybara/selector/xpath_extensions.rb +17 -0
- data/lib/capybara/selector.rb +226 -537
- data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -0
- data/lib/capybara/selenium/atoms/isDisplayed.min.js +1 -0
- data/lib/capybara/selenium/atoms/src/getAttribute.js +161 -0
- data/lib/capybara/selenium/atoms/src/isDisplayed.js +454 -0
- data/lib/capybara/selenium/driver.rb +296 -238
- data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +117 -0
- data/lib/capybara/selenium/driver_specializations/edge_driver.rb +124 -0
- data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +89 -0
- data/lib/capybara/selenium/driver_specializations/internet_explorer_driver.rb +26 -0
- data/lib/capybara/selenium/driver_specializations/safari_driver.rb +24 -0
- data/lib/capybara/selenium/extensions/file_input_click_emulation.rb +34 -0
- data/lib/capybara/selenium/extensions/find.rb +110 -0
- data/lib/capybara/selenium/extensions/html5_drag.rb +228 -0
- data/lib/capybara/selenium/extensions/modifier_keys_stack.rb +28 -0
- data/lib/capybara/selenium/extensions/scroll.rb +76 -0
- data/lib/capybara/selenium/logger_suppressor.rb +40 -0
- data/lib/capybara/selenium/node.rb +436 -166
- data/lib/capybara/selenium/nodes/chrome_node.rb +137 -0
- data/lib/capybara/selenium/nodes/edge_node.rb +104 -0
- data/lib/capybara/selenium/nodes/firefox_node.rb +136 -0
- data/lib/capybara/selenium/nodes/ie_node.rb +22 -0
- data/lib/capybara/selenium/nodes/safari_node.rb +118 -0
- data/lib/capybara/selenium/patches/action_pauser.rb +26 -0
- data/lib/capybara/selenium/patches/atoms.rb +18 -0
- data/lib/capybara/selenium/patches/is_displayed.rb +16 -0
- data/lib/capybara/selenium/patches/logs.rb +45 -0
- data/lib/capybara/selenium/patches/pause_duration_fix.rb +9 -0
- data/lib/capybara/selenium/patches/persistent_client.rb +20 -0
- data/lib/capybara/server/animation_disabler.rb +69 -0
- data/lib/capybara/server/checker.rb +44 -0
- data/lib/capybara/server/middleware.rb +71 -0
- data/lib/capybara/server.rb +58 -67
- data/lib/capybara/session/config.rb +38 -6
- data/lib/capybara/session/matchers.rb +26 -19
- data/lib/capybara/session.rb +258 -190
- data/lib/capybara/spec/public/jquery.js +5 -5
- data/lib/capybara/spec/public/offset.js +6 -0
- data/lib/capybara/spec/public/test.js +122 -8
- data/lib/capybara/spec/session/accept_alert_spec.rb +11 -11
- data/lib/capybara/spec/session/accept_confirm_spec.rb +3 -3
- data/lib/capybara/spec/session/accept_prompt_spec.rb +9 -10
- data/lib/capybara/spec/session/active_element_spec.rb +31 -0
- data/lib/capybara/spec/session/all_spec.rb +135 -42
- data/lib/capybara/spec/session/ancestor_spec.rb +24 -19
- data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +67 -38
- data/lib/capybara/spec/session/{assert_current_path.rb → assert_current_path_spec.rb} +20 -18
- data/lib/capybara/spec/session/assert_selector_spec.rb +143 -0
- data/lib/capybara/spec/session/assert_style_spec.rb +26 -0
- data/lib/capybara/spec/session/{assert_text.rb → assert_text_spec.rb} +62 -38
- data/lib/capybara/spec/session/{assert_title.rb → assert_title_spec.rb} +12 -12
- data/lib/capybara/spec/session/attach_file_spec.rb +120 -72
- data/lib/capybara/spec/session/body_spec.rb +11 -13
- data/lib/capybara/spec/session/check_spec.rb +111 -51
- data/lib/capybara/spec/session/choose_spec.rb +62 -30
- data/lib/capybara/spec/session/click_button_spec.rb +227 -161
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +49 -30
- data/lib/capybara/spec/session/click_link_spec.rb +78 -55
- data/lib/capybara/spec/session/current_scope_spec.rb +7 -7
- data/lib/capybara/spec/session/current_url_spec.rb +44 -37
- data/lib/capybara/spec/session/dismiss_confirm_spec.rb +3 -3
- data/lib/capybara/spec/session/dismiss_prompt_spec.rb +2 -2
- data/lib/capybara/spec/session/element/{assert_match_selector.rb → assert_match_selector_spec.rb} +11 -9
- data/lib/capybara/spec/session/element/match_css_spec.rb +18 -10
- data/lib/capybara/spec/session/element/match_xpath_spec.rb +8 -6
- data/lib/capybara/spec/session/element/matches_selector_spec.rb +70 -56
- data/lib/capybara/spec/session/evaluate_async_script_spec.rb +7 -7
- data/lib/capybara/spec/session/evaluate_script_spec.rb +28 -8
- data/lib/capybara/spec/session/execute_script_spec.rb +8 -7
- data/lib/capybara/spec/session/fill_in_spec.rb +104 -44
- data/lib/capybara/spec/session/find_button_spec.rb +23 -23
- data/lib/capybara/spec/session/find_by_id_spec.rb +8 -8
- data/lib/capybara/spec/session/find_field_spec.rb +33 -31
- data/lib/capybara/spec/session/find_link_spec.rb +32 -14
- data/lib/capybara/spec/session/find_spec.rb +236 -141
- data/lib/capybara/spec/session/first_spec.rb +44 -43
- data/lib/capybara/spec/session/frame/frame_title_spec.rb +6 -6
- data/lib/capybara/spec/session/frame/frame_url_spec.rb +6 -6
- data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +32 -20
- data/lib/capybara/spec/session/frame/within_frame_spec.rb +44 -19
- data/lib/capybara/spec/session/go_back_spec.rb +1 -1
- data/lib/capybara/spec/session/go_forward_spec.rb +1 -1
- data/lib/capybara/spec/session/has_all_selectors_spec.rb +18 -18
- data/lib/capybara/spec/session/has_ancestor_spec.rb +46 -0
- data/lib/capybara/spec/session/has_any_selectors_spec.rb +29 -0
- data/lib/capybara/spec/session/has_button_spec.rb +92 -12
- data/lib/capybara/spec/session/has_css_spec.rb +271 -137
- data/lib/capybara/spec/session/has_current_path_spec.rb +48 -33
- data/lib/capybara/spec/session/has_field_spec.rb +137 -58
- data/lib/capybara/spec/session/has_link_spec.rb +30 -6
- data/lib/capybara/spec/session/has_none_selectors_spec.rb +26 -24
- data/lib/capybara/spec/session/has_select_spec.rb +75 -47
- data/lib/capybara/spec/session/has_selector_spec.rb +102 -69
- data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
- data/lib/capybara/spec/session/has_table_spec.rb +170 -4
- data/lib/capybara/spec/session/has_text_spec.rb +108 -52
- data/lib/capybara/spec/session/has_title_spec.rb +19 -14
- data/lib/capybara/spec/session/has_xpath_spec.rb +56 -38
- data/lib/capybara/spec/session/{headers.rb → headers_spec.rb} +1 -1
- data/lib/capybara/spec/session/html_spec.rb +13 -6
- data/lib/capybara/spec/session/matches_style_spec.rb +35 -0
- data/lib/capybara/spec/session/node_spec.rb +871 -122
- data/lib/capybara/spec/session/node_wrapper_spec.rb +15 -12
- data/lib/capybara/spec/session/refresh_spec.rb +9 -7
- data/lib/capybara/spec/session/reset_session_spec.rb +52 -37
- data/lib/capybara/spec/session/{response_code.rb → response_code_spec.rb} +1 -1
- data/lib/capybara/spec/session/save_and_open_page_spec.rb +2 -2
- data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +5 -4
- data/lib/capybara/spec/session/save_page_spec.rb +41 -38
- data/lib/capybara/spec/session/save_screenshot_spec.rb +13 -11
- data/lib/capybara/spec/session/screenshot_spec.rb +2 -2
- data/lib/capybara/spec/session/scroll_spec.rb +117 -0
- data/lib/capybara/spec/session/select_spec.rb +102 -76
- data/lib/capybara/spec/session/selectors_spec.rb +51 -18
- data/lib/capybara/spec/session/sibling_spec.rb +9 -9
- data/lib/capybara/spec/session/text_spec.rb +26 -24
- data/lib/capybara/spec/session/title_spec.rb +8 -6
- data/lib/capybara/spec/session/uncheck_spec.rb +40 -21
- data/lib/capybara/spec/session/unselect_spec.rb +37 -37
- data/lib/capybara/spec/session/visit_spec.rb +59 -53
- data/lib/capybara/spec/session/window/become_closed_spec.rb +22 -19
- data/lib/capybara/spec/session/window/current_window_spec.rb +4 -3
- data/lib/capybara/spec/session/window/open_new_window_spec.rb +4 -3
- data/lib/capybara/spec/session/window/switch_to_window_spec.rb +25 -21
- data/lib/capybara/spec/session/window/window_opened_by_spec.rb +10 -5
- data/lib/capybara/spec/session/window/window_spec.rb +88 -54
- data/lib/capybara/spec/session/window/windows_spec.rb +10 -7
- data/lib/capybara/spec/session/window/within_window_spec.rb +17 -16
- data/lib/capybara/spec/session/within_spec.rb +69 -44
- data/lib/capybara/spec/spec_helper.rb +41 -53
- data/lib/capybara/spec/test_app.rb +79 -40
- data/lib/capybara/spec/views/animated.erb +49 -0
- data/lib/capybara/spec/views/form.erb +134 -42
- data/lib/capybara/spec/views/frame_child.erb +4 -3
- data/lib/capybara/spec/views/frame_one.erb +2 -1
- data/lib/capybara/spec/views/frame_parent.erb +1 -1
- data/lib/capybara/spec/views/frame_two.erb +1 -1
- data/lib/capybara/spec/views/initial_alert.erb +2 -1
- data/lib/capybara/spec/views/layout.erb +10 -0
- data/lib/capybara/spec/views/obscured.erb +47 -0
- data/lib/capybara/spec/views/offset.erb +33 -0
- data/lib/capybara/spec/views/path.erb +2 -2
- data/lib/capybara/spec/views/popup_one.erb +1 -1
- data/lib/capybara/spec/views/popup_two.erb +1 -1
- data/lib/capybara/spec/views/react.erb +45 -0
- data/lib/capybara/spec/views/scroll.erb +21 -0
- data/lib/capybara/spec/views/spatial.erb +31 -0
- data/lib/capybara/spec/views/tables.erb +68 -1
- data/lib/capybara/spec/views/with_animation.erb +81 -0
- data/lib/capybara/spec/views/with_base_tag.erb +2 -2
- data/lib/capybara/spec/views/with_dragula.erb +24 -0
- data/lib/capybara/spec/views/with_fixed_header_footer.erb +2 -1
- data/lib/capybara/spec/views/with_hover.erb +3 -2
- data/lib/capybara/spec/views/with_hover1.erb +10 -0
- data/lib/capybara/spec/views/with_html.erb +43 -10
- data/lib/capybara/spec/views/with_html5_svg.erb +20 -0
- data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
- data/lib/capybara/spec/views/with_js.erb +30 -5
- data/lib/capybara/spec/views/with_jstree.erb +26 -0
- data/lib/capybara/spec/views/with_namespace.erb +21 -0
- data/lib/capybara/spec/views/with_scope_other.erb +6 -0
- data/lib/capybara/spec/views/with_slow_unload.erb +2 -1
- data/lib/capybara/spec/views/with_sortable_js.erb +21 -0
- data/lib/capybara/spec/views/with_unload_alert.erb +1 -0
- data/lib/capybara/spec/views/with_windows.erb +1 -1
- data/lib/capybara/spec/views/within_frames.erb +1 -1
- data/lib/capybara/version.rb +1 -1
- data/lib/capybara/window.rb +31 -25
- data/lib/capybara.rb +120 -100
- data/spec/basic_node_spec.rb +59 -34
- data/spec/capybara_spec.rb +54 -52
- data/spec/css_builder_spec.rb +101 -0
- data/spec/css_splitter_spec.rb +38 -0
- data/spec/dsl_spec.rb +80 -53
- data/spec/filter_set_spec.rb +24 -7
- data/spec/fixtures/certificate.pem +25 -0
- data/spec/fixtures/key.pem +27 -0
- data/spec/fixtures/selenium_driver_rspec_failure.rb +4 -4
- data/spec/fixtures/selenium_driver_rspec_success.rb +4 -4
- data/spec/minitest_spec.rb +38 -5
- data/spec/minitest_spec_spec.rb +88 -62
- data/spec/per_session_config_spec.rb +5 -5
- data/spec/rack_test_spec.rb +169 -115
- data/spec/regexp_dissassembler_spec.rb +250 -0
- data/spec/result_spec.rb +86 -33
- data/spec/rspec/features_spec.rb +26 -23
- data/spec/rspec/scenarios_spec.rb +8 -4
- data/spec/rspec/shared_spec_matchers.rb +393 -363
- data/spec/rspec/views_spec.rb +4 -3
- data/spec/rspec_matchers_spec.rb +10 -10
- data/spec/rspec_spec.rb +109 -85
- data/spec/sauce_spec_chrome.rb +43 -0
- data/spec/selector_spec.rb +391 -61
- data/spec/selenium_spec_chrome.rb +180 -41
- data/spec/selenium_spec_chrome_remote.rb +101 -0
- data/spec/selenium_spec_edge.rb +28 -8
- data/spec/selenium_spec_firefox.rb +211 -0
- data/spec/selenium_spec_firefox_remote.rb +80 -0
- data/spec/selenium_spec_ie.rb +127 -11
- data/spec/selenium_spec_safari.rb +156 -0
- data/spec/server_spec.rb +177 -78
- data/spec/session_spec.rb +52 -16
- data/spec/shared_selenium_node.rb +79 -0
- data/spec/shared_selenium_session.rb +455 -123
- data/spec/spec_helper.rb +91 -2
- data/spec/xpath_builder_spec.rb +93 -0
- metadata +343 -42
- data/.yard/templates_custom/default/class/html/selectors.erb +0 -38
- data/.yard/templates_custom/default/class/html/setup.rb +0 -17
- data/.yard/yard_extensions.rb +0 -78
- data/lib/capybara/rspec/compound.rb +0 -90
- data/lib/capybara/spec/session/assert_selector.rb +0 -149
- data/lib/capybara/spec/session/source_spec.rb +0 -0
- data/lib/capybara/spec/views/with_title.erb +0 -5
- data/spec/selenium_spec_marionette.rb +0 -143
|
@@ -1,50 +1,103 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
3
|
+
require 'uri'
|
|
4
|
+
require 'English'
|
|
5
5
|
|
|
6
6
|
class Capybara::Selenium::Driver < Capybara::Driver::Base
|
|
7
|
+
include Capybara::Selenium::Find
|
|
8
|
+
|
|
7
9
|
DEFAULT_OPTIONS = {
|
|
8
10
|
browser: :firefox,
|
|
9
|
-
clear_local_storage:
|
|
10
|
-
clear_session_storage:
|
|
11
|
+
clear_local_storage: nil,
|
|
12
|
+
clear_session_storage: nil
|
|
11
13
|
}.freeze
|
|
12
|
-
SPECIAL_OPTIONS = %i[browser clear_local_storage clear_session_storage].freeze
|
|
14
|
+
SPECIAL_OPTIONS = %i[browser clear_local_storage clear_session_storage timeout native_displayed].freeze
|
|
15
|
+
CAPS_VERSION = Gem::Requirement.new('~> 4.0.0.alpha6')
|
|
13
16
|
|
|
14
17
|
attr_reader :app, :options
|
|
15
18
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
class << self
|
|
20
|
+
attr_reader :selenium_webdriver_version
|
|
21
|
+
|
|
22
|
+
def load_selenium
|
|
23
|
+
require 'selenium-webdriver'
|
|
24
|
+
require 'capybara/selenium/logger_suppressor'
|
|
25
|
+
require 'capybara/selenium/patches/atoms'
|
|
26
|
+
require 'capybara/selenium/patches/is_displayed'
|
|
27
|
+
require 'capybara/selenium/patches/action_pauser'
|
|
28
|
+
|
|
29
|
+
# Look up the version of `selenium-webdriver` to
|
|
30
|
+
# see if it's a version we support.
|
|
31
|
+
#
|
|
32
|
+
# By default, we use Gem.loaded_specs to determine
|
|
33
|
+
# the version number. However, in some cases, such
|
|
34
|
+
# as when loading `selenium-webdriver` outside of
|
|
35
|
+
# Rubygems, we fall back to referencing
|
|
36
|
+
# Selenium::WebDriver::VERSION. Ideally we'd
|
|
37
|
+
# use the constant in all cases, but earlier versions
|
|
38
|
+
# of `selenium-webdriver` didn't provide the constant.
|
|
39
|
+
@selenium_webdriver_version =
|
|
40
|
+
if Gem.loaded_specs['selenium-webdriver']
|
|
41
|
+
Gem.loaded_specs['selenium-webdriver'].version
|
|
42
|
+
else
|
|
43
|
+
Gem::Version.new(Selenium::WebDriver::VERSION)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
unless Gem::Requirement.new('>= 3.142.7').satisfied_by? @selenium_webdriver_version
|
|
47
|
+
warn "Warning: You're using an unsupported version of selenium-webdriver, please upgrade."
|
|
21
48
|
end
|
|
22
49
|
|
|
23
|
-
@
|
|
24
|
-
|
|
50
|
+
@selenium_webdriver_version
|
|
51
|
+
rescue LoadError => e
|
|
52
|
+
raise e unless e.message.include?('selenium-webdriver')
|
|
25
53
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
main = Process.pid
|
|
54
|
+
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."
|
|
55
|
+
end
|
|
29
56
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
57
|
+
attr_reader :specializations
|
|
58
|
+
|
|
59
|
+
def register_specialization(browser_name, specialization)
|
|
60
|
+
@specializations ||= {}
|
|
61
|
+
@specializations[browser_name] = specialization
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def browser
|
|
66
|
+
unless @browser
|
|
67
|
+
options[:http_client] ||= begin
|
|
68
|
+
require 'capybara/selenium/patches/persistent_client'
|
|
69
|
+
if options[:timeout]
|
|
70
|
+
::Capybara::Selenium::PersistentClient.new(read_timeout: options[:timeout])
|
|
71
|
+
else
|
|
72
|
+
::Capybara::Selenium::PersistentClient.new
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
processed_options = options.reject { |key, _val| SPECIAL_OPTIONS.include?(key) }
|
|
76
|
+
|
|
77
|
+
@browser = if options[:browser] == :firefox &&
|
|
78
|
+
RUBY_VERSION >= '3.0' &&
|
|
79
|
+
Capybara::Selenium::Driver.selenium_webdriver_version <= Gem::Version.new('4.0.0.alpha1')
|
|
80
|
+
# selenium-webdriver 3.x doesn't correctly pass options through for Firefox with Ruby 3 so workaround that
|
|
81
|
+
Selenium::WebDriver::Firefox::Driver.new(**processed_options)
|
|
82
|
+
else
|
|
83
|
+
Selenium::WebDriver.for(options[:browser], processed_options)
|
|
35
84
|
end
|
|
85
|
+
|
|
86
|
+
specialize_driver
|
|
87
|
+
setup_exit_handler
|
|
36
88
|
end
|
|
37
89
|
@browser
|
|
38
90
|
end
|
|
39
91
|
|
|
40
92
|
def initialize(app, **options)
|
|
41
|
-
|
|
42
|
-
|
|
93
|
+
super()
|
|
94
|
+
self.class.load_selenium
|
|
43
95
|
@app = app
|
|
44
96
|
@browser = nil
|
|
45
97
|
@exit_status = nil
|
|
46
|
-
@frame_handles = {}
|
|
98
|
+
@frame_handles = Hash.new { |hash, handle| hash[handle] = [] }
|
|
47
99
|
@options = DEFAULT_OPTIONS.merge(options)
|
|
100
|
+
@node_class = ::Capybara::Selenium::Node
|
|
48
101
|
end
|
|
49
102
|
|
|
50
103
|
def visit(path)
|
|
@@ -65,6 +118,8 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
|
|
|
65
118
|
|
|
66
119
|
def html
|
|
67
120
|
browser.page_source
|
|
121
|
+
rescue Selenium::WebDriver::Error::JavascriptError => e
|
|
122
|
+
raise unless e.message.include?('documentElement is null')
|
|
68
123
|
end
|
|
69
124
|
|
|
70
125
|
def title
|
|
@@ -75,19 +130,11 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
|
|
|
75
130
|
browser.current_url
|
|
76
131
|
end
|
|
77
132
|
|
|
78
|
-
def find_xpath(selector)
|
|
79
|
-
browser.find_elements(:xpath, selector).map { |node| Capybara::Selenium::Node.new(self, node) }
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def find_css(selector)
|
|
83
|
-
browser.find_elements(:css, selector).map { |node| Capybara::Selenium::Node.new(self, node) }
|
|
84
|
-
end
|
|
85
|
-
|
|
86
133
|
def wait?; true; end
|
|
87
134
|
def needs_server?; true; end
|
|
88
135
|
|
|
89
136
|
def execute_script(script, *args)
|
|
90
|
-
browser.execute_script(script, *args
|
|
137
|
+
browser.execute_script(script, *native_args(args))
|
|
91
138
|
end
|
|
92
139
|
|
|
93
140
|
def evaluate_script(script, *args)
|
|
@@ -97,10 +144,19 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
|
|
|
97
144
|
|
|
98
145
|
def evaluate_async_script(script, *args)
|
|
99
146
|
browser.manage.timeouts.script_timeout = Capybara.default_max_wait_time
|
|
100
|
-
result = browser.execute_async_script(script, *args
|
|
147
|
+
result = browser.execute_async_script(script, *native_args(args))
|
|
101
148
|
unwrap_script_result(result)
|
|
102
149
|
end
|
|
103
150
|
|
|
151
|
+
def active_element
|
|
152
|
+
build_node(native_active_element)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def send_keys(*args)
|
|
156
|
+
# Should this call the specialized nodes rather than native???
|
|
157
|
+
native_active_element.send_keys(*args)
|
|
158
|
+
end
|
|
159
|
+
|
|
104
160
|
def save_screenshot(path, **_options)
|
|
105
161
|
browser.save_screenshot(path)
|
|
106
162
|
end
|
|
@@ -109,74 +165,48 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
|
|
|
109
165
|
# Use instance variable directly so we avoid starting the browser just to reset the session
|
|
110
166
|
return unless @browser
|
|
111
167
|
|
|
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
168
|
navigated = false
|
|
118
|
-
|
|
169
|
+
timer = Capybara::Helpers.timer(expire_in: 10)
|
|
119
170
|
begin
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
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
|
|
171
|
+
# Only trigger a navigation if we haven't done it already, otherwise it
|
|
172
|
+
# can trigger an endless series of unload modals
|
|
173
|
+
reset_browser_state unless navigated
|
|
133
174
|
navigated = true
|
|
134
|
-
|
|
135
175
|
# Ensure the page is empty and trigger an UnhandledAlertError for any modals that appear during unload
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
sleep 0.05
|
|
139
|
-
end
|
|
140
|
-
rescue Selenium::WebDriver::Error::UnhandledAlertError, Selenium::WebDriver::Error::UnexpectedAlertOpenError
|
|
176
|
+
wait_for_empty_page(timer)
|
|
177
|
+
rescue *unhandled_alert_errors
|
|
141
178
|
# This error is thrown if an unhandled alert is on the page
|
|
142
179
|
# Firefox appears to automatically dismiss this alert, chrome does not
|
|
143
180
|
# We'll try to accept it
|
|
144
|
-
|
|
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"
|
|
150
|
-
begin
|
|
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
|
|
158
|
-
end
|
|
159
|
-
end
|
|
160
|
-
end
|
|
181
|
+
accept_unhandled_reset_alert
|
|
161
182
|
# try cleaning up the browser again
|
|
162
183
|
retry
|
|
163
184
|
end
|
|
164
185
|
end
|
|
165
186
|
|
|
187
|
+
def frame_obscured_at?(x:, y:)
|
|
188
|
+
frame = @frame_handles[current_window_handle].last
|
|
189
|
+
return false unless frame
|
|
190
|
+
|
|
191
|
+
switch_to_frame(:parent)
|
|
192
|
+
begin
|
|
193
|
+
frame.base.obscured?(x: x, y: y)
|
|
194
|
+
ensure
|
|
195
|
+
switch_to_frame(frame)
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
166
199
|
def switch_to_frame(frame)
|
|
200
|
+
handles = @frame_handles[current_window_handle]
|
|
167
201
|
case frame
|
|
168
202
|
when :top
|
|
169
|
-
|
|
203
|
+
handles.clear
|
|
170
204
|
browser.switch_to.default_content
|
|
171
205
|
when :parent
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
@frame_handles[browser.window_handle].pop
|
|
175
|
-
browser.switch_to.default_content
|
|
176
|
-
@frame_handles[browser.window_handle].each { |fh| browser.switch_to.frame(fh) }
|
|
206
|
+
handles.pop
|
|
207
|
+
browser.switch_to.parent_frame
|
|
177
208
|
else
|
|
178
|
-
|
|
179
|
-
@frame_handles[browser.window_handle] << frame.native
|
|
209
|
+
handles << frame
|
|
180
210
|
browser.switch_to.frame(frame.native)
|
|
181
211
|
end
|
|
182
212
|
end
|
|
@@ -194,12 +224,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
|
|
|
194
224
|
|
|
195
225
|
def resize_window_to(handle, width, height)
|
|
196
226
|
within_given_window(handle) do
|
|
197
|
-
|
|
198
|
-
if marionette? && (window_size(handle) == [width, height])
|
|
199
|
-
{}
|
|
200
|
-
else
|
|
201
|
-
browser.manage.window.resize_to(width, height)
|
|
202
|
-
end
|
|
227
|
+
browser.manage.window.resize_to(width, height)
|
|
203
228
|
end
|
|
204
229
|
end
|
|
205
230
|
|
|
@@ -210,8 +235,15 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
|
|
|
210
235
|
sleep 0.1 # work around for https://code.google.com/p/selenium/issues/detail?id=7405
|
|
211
236
|
end
|
|
212
237
|
|
|
238
|
+
def fullscreen_window(handle)
|
|
239
|
+
within_given_window(handle) do
|
|
240
|
+
browser.manage.window.full_screen
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
|
|
213
244
|
def close_window(handle)
|
|
214
|
-
raise ArgumentError,
|
|
245
|
+
raise ArgumentError, 'Not allowed to close the primary window' if handle == window_handles.first
|
|
246
|
+
|
|
215
247
|
within_given_window(handle) do
|
|
216
248
|
browser.close
|
|
217
249
|
end
|
|
@@ -221,7 +253,16 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
|
|
|
221
253
|
browser.window_handles
|
|
222
254
|
end
|
|
223
255
|
|
|
224
|
-
def open_new_window
|
|
256
|
+
def open_new_window(kind = :tab)
|
|
257
|
+
if browser.switch_to.respond_to?(:new_window)
|
|
258
|
+
handle = current_window_handle
|
|
259
|
+
browser.switch_to.new_window(kind)
|
|
260
|
+
switch_to_window(handle)
|
|
261
|
+
else
|
|
262
|
+
browser.manage.new_window(kind)
|
|
263
|
+
end
|
|
264
|
+
rescue NoMethodError, Selenium::WebDriver::Error::WebDriverError
|
|
265
|
+
# If not supported by the driver or browser default to using JS
|
|
225
266
|
browser.execute_script('window.open();')
|
|
226
267
|
end
|
|
227
268
|
|
|
@@ -231,7 +272,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
|
|
|
231
272
|
|
|
232
273
|
def accept_modal(_type, **options)
|
|
233
274
|
yield if block_given?
|
|
234
|
-
modal = find_modal(options)
|
|
275
|
+
modal = find_modal(**options)
|
|
235
276
|
|
|
236
277
|
modal.send_keys options[:with] if options[:with]
|
|
237
278
|
|
|
@@ -242,15 +283,16 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
|
|
|
242
283
|
|
|
243
284
|
def dismiss_modal(_type, **options)
|
|
244
285
|
yield if block_given?
|
|
245
|
-
modal = find_modal(options)
|
|
286
|
+
modal = find_modal(**options)
|
|
246
287
|
message = modal.text
|
|
247
288
|
modal.dismiss
|
|
248
289
|
message
|
|
249
290
|
end
|
|
250
291
|
|
|
251
292
|
def quit
|
|
252
|
-
@browser
|
|
253
|
-
rescue Selenium::WebDriver::Error::SessionNotCreatedError, Errno::ECONNREFUSED
|
|
293
|
+
@browser&.quit
|
|
294
|
+
rescue Selenium::WebDriver::Error::SessionNotCreatedError, Errno::ECONNREFUSED,
|
|
295
|
+
Selenium::WebDriver::Error::InvalidSessionIdError
|
|
254
296
|
# Browser must have already gone
|
|
255
297
|
rescue Selenium::WebDriver::Error::UnknownError => e
|
|
256
298
|
unless silenced_unknown_error_message?(e.message) # Most likely already gone
|
|
@@ -262,133 +304,115 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
|
|
|
262
304
|
end
|
|
263
305
|
|
|
264
306
|
def invalid_element_errors
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
307
|
+
@invalid_element_errors ||=
|
|
308
|
+
[
|
|
309
|
+
::Selenium::WebDriver::Error::StaleElementReferenceError,
|
|
310
|
+
::Selenium::WebDriver::Error::ElementNotInteractableError,
|
|
311
|
+
::Selenium::WebDriver::Error::InvalidSelectorError, # Work around chromedriver go_back/go_forward race condition
|
|
312
|
+
::Selenium::WebDriver::Error::ElementClickInterceptedError,
|
|
313
|
+
::Selenium::WebDriver::Error::NoSuchElementError, # IE
|
|
314
|
+
::Selenium::WebDriver::Error::InvalidArgumentError # IE
|
|
315
|
+
].tap do |errors|
|
|
316
|
+
unless selenium_4?
|
|
317
|
+
::Selenium::WebDriver.logger.suppress_deprecations do
|
|
318
|
+
errors.concat [
|
|
319
|
+
::Selenium::WebDriver::Error::UnhandledError,
|
|
320
|
+
::Selenium::WebDriver::Error::ElementNotVisibleError,
|
|
321
|
+
::Selenium::WebDriver::Error::InvalidElementStateError,
|
|
322
|
+
::Selenium::WebDriver::Error::ElementNotSelectableError
|
|
323
|
+
]
|
|
324
|
+
end
|
|
325
|
+
end
|
|
326
|
+
end
|
|
278
327
|
end
|
|
279
328
|
|
|
280
329
|
def no_such_window_error
|
|
281
330
|
Selenium::WebDriver::Error::NoSuchWindowError
|
|
282
331
|
end
|
|
283
332
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
333
|
+
private
|
|
334
|
+
|
|
335
|
+
def selenium_4?
|
|
336
|
+
defined?(Selenium::WebDriver::VERSION) && (Selenium::WebDriver::VERSION.to_f >= 4)
|
|
287
337
|
end
|
|
288
338
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
browser_name == "firefox"
|
|
339
|
+
def native_args(args)
|
|
340
|
+
args.map { |arg| arg.is_a?(Capybara::Selenium::Node) ? arg.native : arg }
|
|
292
341
|
end
|
|
293
342
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
browser_name == "chrome"
|
|
343
|
+
def native_active_element
|
|
344
|
+
browser.switch_to.active_element
|
|
297
345
|
end
|
|
298
346
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
347
|
+
def clear_browser_state
|
|
348
|
+
delete_all_cookies
|
|
349
|
+
clear_storage
|
|
350
|
+
rescue *clear_browser_state_errors
|
|
351
|
+
# delete_all_cookies fails when we've previously gone
|
|
352
|
+
# to about:blank, so we rescue this error and do nothing
|
|
353
|
+
# instead.
|
|
302
354
|
end
|
|
303
355
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
browser_name == "ie"
|
|
356
|
+
def clear_browser_state_errors
|
|
357
|
+
@clear_browser_state_errors ||= [Selenium::WebDriver::Error::UnknownError]
|
|
307
358
|
end
|
|
308
359
|
|
|
309
|
-
|
|
360
|
+
def unhandled_alert_errors
|
|
361
|
+
@unhandled_alert_errors ||= with_legacy_error(
|
|
362
|
+
[Selenium::WebDriver::Error::UnexpectedAlertOpenError],
|
|
363
|
+
'UnhandledAlertError'
|
|
364
|
+
)
|
|
365
|
+
end
|
|
310
366
|
|
|
311
|
-
def
|
|
312
|
-
|
|
367
|
+
def delete_all_cookies
|
|
368
|
+
@browser.manage.delete_all_cookies
|
|
313
369
|
end
|
|
314
370
|
|
|
315
371
|
def clear_storage
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
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
|
|
372
|
+
clear_session_storage unless options[:clear_session_storage] == false
|
|
373
|
+
clear_local_storage unless options[:clear_local_storage] == false
|
|
374
|
+
rescue Selenium::WebDriver::Error::JavascriptError
|
|
375
|
+
# session/local storage may not be available if on non-http pages (e.g. about:blank)
|
|
330
376
|
end
|
|
331
377
|
|
|
332
|
-
def
|
|
333
|
-
if
|
|
334
|
-
|
|
378
|
+
def clear_session_storage
|
|
379
|
+
if @browser.respond_to? :session_storage
|
|
380
|
+
@browser.session_storage.clear
|
|
335
381
|
else
|
|
336
|
-
|
|
382
|
+
begin
|
|
383
|
+
@browser&.execute_script('window.sessionStorage.clear()')
|
|
384
|
+
rescue # rubocop:disable Style/RescueStandardError
|
|
385
|
+
unless options[:clear_session_storage].nil?
|
|
386
|
+
warn 'sessionStorage clear requested but is not supported by this driver'
|
|
387
|
+
end
|
|
388
|
+
end
|
|
337
389
|
end
|
|
338
390
|
end
|
|
339
391
|
|
|
340
|
-
def
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
"default_text"
|
|
344
|
-
else
|
|
345
|
-
"'#{response_text.gsub("\\", "\\\\\\").gsub("'", "\\\\'")}'"
|
|
346
|
-
end
|
|
392
|
+
def clear_local_storage
|
|
393
|
+
if @browser.respond_to? :local_storage
|
|
394
|
+
@browser.local_storage.clear
|
|
347
395
|
else
|
|
348
|
-
|
|
396
|
+
begin
|
|
397
|
+
@browser&.execute_script('window.localStorage.clear()')
|
|
398
|
+
rescue # rubocop:disable Style/RescueStandardError
|
|
399
|
+
unless options[:clear_local_storage].nil?
|
|
400
|
+
warn 'localStorage clear requested but is not supported by this driver'
|
|
401
|
+
end
|
|
402
|
+
end
|
|
349
403
|
end
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
def navigate_with_accept(url)
|
|
407
|
+
@browser.navigate.to(url)
|
|
408
|
+
sleep 0.1 # slight wait for alert
|
|
409
|
+
@browser.switch_to.alert.accept
|
|
410
|
+
rescue modal_error
|
|
411
|
+
# alert now gone, should mean navigation happened
|
|
412
|
+
end
|
|
350
413
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
window.capybara = {
|
|
354
|
-
modal_handlers: [],
|
|
355
|
-
current_modal_status: function() {
|
|
356
|
-
return [this.modal_handlers[0].called, this.modal_handlers[0].modal_text];
|
|
357
|
-
},
|
|
358
|
-
add_handler: function(handler) {
|
|
359
|
-
this.modal_handlers.unshift(handler);
|
|
360
|
-
},
|
|
361
|
-
remove_handler: function(handler) {
|
|
362
|
-
window.alert = handler.alert;
|
|
363
|
-
window.confirm = handler.confirm;
|
|
364
|
-
window.prompt = handler.prompt;
|
|
365
|
-
},
|
|
366
|
-
handler_called: function(handler, str) {
|
|
367
|
-
handler.called = true;
|
|
368
|
-
handler.modal_text = str;
|
|
369
|
-
this.remove_handler(handler);
|
|
370
|
-
}
|
|
371
|
-
};
|
|
372
|
-
};
|
|
373
|
-
|
|
374
|
-
var modal_handler = {
|
|
375
|
-
prompt: window.prompt,
|
|
376
|
-
confirm: window.confirm,
|
|
377
|
-
alert: window.alert,
|
|
378
|
-
called: false
|
|
379
|
-
}
|
|
380
|
-
window.capybara.add_handler(modal_handler);
|
|
381
|
-
|
|
382
|
-
window.alert = window.confirm = function(str = "") {
|
|
383
|
-
window.capybara.handler_called(modal_handler, str.toString());
|
|
384
|
-
return #{accept ? 'true' : 'false'};
|
|
385
|
-
}
|
|
386
|
-
window.prompt = function(str = "", default_text = "") {
|
|
387
|
-
window.capybara.handler_called(modal_handler, str.toString());
|
|
388
|
-
return #{prompt_response};
|
|
389
|
-
}
|
|
390
|
-
JS
|
|
391
|
-
execute_script script
|
|
414
|
+
def modal_error
|
|
415
|
+
Selenium::WebDriver::Error::NoSuchAlertError
|
|
392
416
|
end
|
|
393
417
|
|
|
394
418
|
def within_given_window(handle)
|
|
@@ -413,47 +437,35 @@ private
|
|
|
413
437
|
begin
|
|
414
438
|
wait.until do
|
|
415
439
|
alert = @browser.switch_to.alert
|
|
416
|
-
regexp = text.is_a?(Regexp) ? text : Regexp.escape(text.to_s)
|
|
417
|
-
alert.text.match(regexp)
|
|
440
|
+
regexp = text.is_a?(Regexp) ? text : Regexp.new(Regexp.escape(text.to_s))
|
|
441
|
+
matched = alert.text.match?(regexp)
|
|
442
|
+
unless matched
|
|
443
|
+
raise Capybara::ModalNotFound, "Unable to find modal dialog with #{text} - found '#{alert.text}' instead."
|
|
444
|
+
end
|
|
445
|
+
|
|
446
|
+
alert
|
|
418
447
|
end
|
|
419
|
-
rescue
|
|
448
|
+
rescue *find_modal_errors
|
|
420
449
|
raise Capybara::ModalNotFound, "Unable to find modal dialog#{" with #{text}" if text}"
|
|
421
450
|
end
|
|
422
451
|
end
|
|
423
452
|
|
|
424
|
-
def
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
called, alert_text = evaluate_script('window.capybara && window.capybara.current_modal_status()')
|
|
434
|
-
if called
|
|
435
|
-
execute_script('window.capybara && window.capybara.modal_handlers.shift()')
|
|
436
|
-
regexp = text.is_a?(Regexp) ? text : Regexp.escape(text.to_s)
|
|
437
|
-
if alert_text.match(regexp)
|
|
438
|
-
alert_text
|
|
439
|
-
else
|
|
440
|
-
raise Capybara::ModalNotFound, "Unable to find modal dialog#{" with #{text}" if text}"
|
|
441
|
-
end
|
|
442
|
-
elsif called.nil?
|
|
443
|
-
# page changed so modal_handler data has gone away
|
|
444
|
-
warn "Can't verify modal text when page change occurs - ignoring" if options[:text]
|
|
445
|
-
""
|
|
446
|
-
else
|
|
447
|
-
nil
|
|
453
|
+
def find_modal_errors
|
|
454
|
+
@find_modal_errors ||= with_legacy_error([Selenium::WebDriver::Error::TimeoutError], 'TimeOutError')
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
def with_legacy_error(errors, legacy_error)
|
|
458
|
+
errors.tap do |errs|
|
|
459
|
+
unless selenium_4?
|
|
460
|
+
::Selenium::WebDriver.logger.suppress_deprecations do
|
|
461
|
+
errs << Selenium::WebDriver::Error.const_get(legacy_error)
|
|
448
462
|
end
|
|
449
463
|
end
|
|
450
|
-
rescue Selenium::WebDriver::Error::TimeOutError
|
|
451
|
-
raise Capybara::ModalNotFound, "Unable to find modal dialog#{" with #{options[:text]}" if options[:text]}"
|
|
452
464
|
end
|
|
453
465
|
end
|
|
454
466
|
|
|
455
467
|
def silenced_unknown_error_message?(msg)
|
|
456
|
-
silenced_unknown_error_messages.any? { |
|
|
468
|
+
silenced_unknown_error_messages.any? { |regex| msg.match? regex }
|
|
457
469
|
end
|
|
458
470
|
|
|
459
471
|
def silenced_unknown_error_messages
|
|
@@ -463,30 +475,76 @@ private
|
|
|
463
475
|
def unwrap_script_result(arg)
|
|
464
476
|
case arg
|
|
465
477
|
when Array
|
|
466
|
-
arg.map { |
|
|
478
|
+
arg.map { |arr| unwrap_script_result(arr) }
|
|
467
479
|
when Hash
|
|
468
|
-
arg.
|
|
480
|
+
arg.transform_values! { |value| unwrap_script_result(value) }
|
|
469
481
|
when Selenium::WebDriver::Element
|
|
470
|
-
|
|
482
|
+
build_node(arg)
|
|
471
483
|
else
|
|
472
484
|
arg
|
|
473
485
|
end
|
|
474
486
|
end
|
|
475
487
|
|
|
476
|
-
def
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
488
|
+
def find_context
|
|
489
|
+
browser
|
|
490
|
+
end
|
|
491
|
+
|
|
492
|
+
def build_node(native_node, initial_cache = {})
|
|
493
|
+
::Capybara::Selenium::Node.new(self, native_node, initial_cache)
|
|
494
|
+
end
|
|
495
|
+
|
|
496
|
+
def bridge
|
|
497
|
+
browser.send(:bridge)
|
|
498
|
+
end
|
|
499
|
+
|
|
500
|
+
def specialize_driver
|
|
501
|
+
browser_type = browser.browser
|
|
502
|
+
Capybara::Selenium::Driver.specializations.select { |k, _v| k === browser_type }.each_value do |specialization| # rubocop:disable Style/CaseEquality
|
|
503
|
+
extend specialization
|
|
481
504
|
end
|
|
482
|
-
|
|
483
|
-
|
|
505
|
+
end
|
|
506
|
+
|
|
507
|
+
def setup_exit_handler
|
|
508
|
+
main = Process.pid
|
|
509
|
+
at_exit do
|
|
510
|
+
# Store the exit status of the test run since it goes away after calling the at_exit proc...
|
|
511
|
+
@exit_status = $ERROR_INFO.status if $ERROR_INFO.is_a?(SystemExit)
|
|
512
|
+
quit if Process.pid == main
|
|
513
|
+
exit @exit_status if @exit_status # Force exit with stored status
|
|
484
514
|
end
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
515
|
+
end
|
|
516
|
+
|
|
517
|
+
def reset_browser_state
|
|
518
|
+
clear_browser_state
|
|
519
|
+
@browser.navigate.to('about:blank')
|
|
520
|
+
end
|
|
521
|
+
|
|
522
|
+
def wait_for_empty_page(timer)
|
|
523
|
+
until find_xpath('/html/body/*').empty?
|
|
524
|
+
raise Capybara::ExpectationNotMet, 'Timed out waiting for Selenium session reset' if timer.expired?
|
|
525
|
+
|
|
526
|
+
sleep 0.01
|
|
527
|
+
|
|
528
|
+
# It has been observed that it is possible that asynchronous JS code in
|
|
529
|
+
# the application under test can navigate the browser away from about:blank
|
|
530
|
+
# if the timing is just right. Ensure we are still at about:blank...
|
|
531
|
+
@browser.navigate.to('about:blank') unless current_url == 'about:blank'
|
|
490
532
|
end
|
|
491
533
|
end
|
|
534
|
+
|
|
535
|
+
def accept_unhandled_reset_alert
|
|
536
|
+
@browser.switch_to.alert.accept
|
|
537
|
+
sleep 0.25 # allow time for the modal to be handled
|
|
538
|
+
rescue modal_error
|
|
539
|
+
# The alert is now gone.
|
|
540
|
+
# If navigation has not occurred attempt again and accept alert
|
|
541
|
+
# since FF may have dismissed the alert at first attempt.
|
|
542
|
+
navigate_with_accept('about:blank') if current_url != 'about:blank'
|
|
543
|
+
end
|
|
492
544
|
end
|
|
545
|
+
|
|
546
|
+
require 'capybara/selenium/driver_specializations/chrome_driver'
|
|
547
|
+
require 'capybara/selenium/driver_specializations/firefox_driver'
|
|
548
|
+
require 'capybara/selenium/driver_specializations/internet_explorer_driver'
|
|
549
|
+
require 'capybara/selenium/driver_specializations/safari_driver'
|
|
550
|
+
require 'capybara/selenium/driver_specializations/edge_driver'
|