capybara 3.32.2
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 +7 -0
- data/.yardopts +1 -0
- data/History.md +1813 -0
- data/License.txt +22 -0
- data/README.md +1099 -0
- data/lib/capybara.rb +511 -0
- data/lib/capybara/config.rb +94 -0
- data/lib/capybara/cucumber.rb +27 -0
- data/lib/capybara/driver/base.rb +170 -0
- data/lib/capybara/driver/node.rb +139 -0
- data/lib/capybara/dsl.rb +65 -0
- data/lib/capybara/helpers.rb +108 -0
- data/lib/capybara/minitest.rb +386 -0
- data/lib/capybara/minitest/spec.rb +264 -0
- data/lib/capybara/node/actions.rb +420 -0
- data/lib/capybara/node/base.rb +143 -0
- data/lib/capybara/node/document.rb +48 -0
- data/lib/capybara/node/document_matchers.rb +67 -0
- data/lib/capybara/node/element.rb +606 -0
- data/lib/capybara/node/finders.rb +325 -0
- data/lib/capybara/node/matchers.rb +883 -0
- data/lib/capybara/node/simple.rb +208 -0
- data/lib/capybara/queries/ancestor_query.rb +27 -0
- data/lib/capybara/queries/base_query.rb +106 -0
- data/lib/capybara/queries/current_path_query.rb +51 -0
- data/lib/capybara/queries/match_query.rb +26 -0
- data/lib/capybara/queries/selector_query.rb +710 -0
- data/lib/capybara/queries/sibling_query.rb +26 -0
- data/lib/capybara/queries/style_query.rb +45 -0
- data/lib/capybara/queries/text_query.rb +110 -0
- data/lib/capybara/queries/title_query.rb +39 -0
- data/lib/capybara/rack_test/browser.rb +140 -0
- data/lib/capybara/rack_test/css_handlers.rb +13 -0
- data/lib/capybara/rack_test/driver.rb +109 -0
- data/lib/capybara/rack_test/errors.rb +6 -0
- data/lib/capybara/rack_test/form.rb +127 -0
- data/lib/capybara/rack_test/node.rb +325 -0
- data/lib/capybara/rails.rb +16 -0
- data/lib/capybara/registrations/drivers.rb +36 -0
- data/lib/capybara/registrations/patches/puma_ssl.rb +27 -0
- data/lib/capybara/registrations/servers.rb +44 -0
- data/lib/capybara/result.rb +190 -0
- data/lib/capybara/rspec.rb +29 -0
- data/lib/capybara/rspec/features.rb +23 -0
- data/lib/capybara/rspec/matcher_proxies.rb +82 -0
- data/lib/capybara/rspec/matchers.rb +201 -0
- 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 +38 -0
- data/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
- data/lib/capybara/selector.rb +233 -0
- data/lib/capybara/selector/builders/css_builder.rb +84 -0
- data/lib/capybara/selector/builders/xpath_builder.rb +69 -0
- data/lib/capybara/selector/css.rb +102 -0
- data/lib/capybara/selector/definition.rb +276 -0
- data/lib/capybara/selector/definition/button.rb +51 -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 +27 -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 +46 -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/filter.rb +5 -0
- data/lib/capybara/selector/filter_set.rb +124 -0
- data/lib/capybara/selector/filters/base.rb +77 -0
- data/lib/capybara/selector/filters/expression_filter.rb +22 -0
- data/lib/capybara/selector/filters/locator_filter.rb +29 -0
- data/lib/capybara/selector/filters/node_filter.rb +31 -0
- data/lib/capybara/selector/regexp_disassembler.rb +214 -0
- data/lib/capybara/selector/selector.rb +147 -0
- data/lib/capybara/selector/xpath_extensions.rb +17 -0
- 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 +496 -0
- data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +119 -0
- data/lib/capybara/selenium/driver_specializations/edge_driver.rb +126 -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 +78 -0
- data/lib/capybara/selenium/logger_suppressor.rb +34 -0
- data/lib/capybara/selenium/node.rb +610 -0
- data/lib/capybara/selenium/nodes/chrome_node.rb +119 -0
- data/lib/capybara/selenium/nodes/edge_node.rb +104 -0
- data/lib/capybara/selenium/nodes/firefox_node.rb +131 -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 +47 -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.rb +126 -0
- data/lib/capybara/server/animation_disabler.rb +58 -0
- data/lib/capybara/server/checker.rb +44 -0
- data/lib/capybara/server/middleware.rb +69 -0
- data/lib/capybara/session.rb +942 -0
- data/lib/capybara/session/config.rb +124 -0
- data/lib/capybara/session/matchers.rb +87 -0
- data/lib/capybara/spec/fixtures/another_test_file.txt +1 -0
- data/lib/capybara/spec/fixtures/capybara.jpg +3 -0
- data/lib/capybara/spec/fixtures/no_extension +1 -0
- data/lib/capybara/spec/fixtures/test_file.txt +1 -0
- data/lib/capybara/spec/public/jquery-ui.js +13 -0
- data/lib/capybara/spec/public/jquery.js +5 -0
- data/lib/capybara/spec/public/offset.js +6 -0
- data/lib/capybara/spec/public/test.js +268 -0
- data/lib/capybara/spec/session/accept_alert_spec.rb +81 -0
- data/lib/capybara/spec/session/accept_confirm_spec.rb +32 -0
- data/lib/capybara/spec/session/accept_prompt_spec.rb +78 -0
- data/lib/capybara/spec/session/all_spec.rb +278 -0
- data/lib/capybara/spec/session/ancestor_spec.rb +88 -0
- data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +140 -0
- data/lib/capybara/spec/session/assert_current_path_spec.rb +75 -0
- 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_spec.rb +258 -0
- data/lib/capybara/spec/session/assert_title_spec.rb +93 -0
- data/lib/capybara/spec/session/attach_file_spec.rb +216 -0
- data/lib/capybara/spec/session/body_spec.rb +23 -0
- data/lib/capybara/spec/session/check_spec.rb +235 -0
- data/lib/capybara/spec/session/choose_spec.rb +121 -0
- data/lib/capybara/spec/session/click_button_spec.rb +506 -0
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +129 -0
- data/lib/capybara/spec/session/click_link_spec.rb +229 -0
- data/lib/capybara/spec/session/current_scope_spec.rb +31 -0
- data/lib/capybara/spec/session/current_url_spec.rb +115 -0
- data/lib/capybara/spec/session/dismiss_confirm_spec.rb +36 -0
- data/lib/capybara/spec/session/dismiss_prompt_spec.rb +21 -0
- data/lib/capybara/spec/session/element/assert_match_selector_spec.rb +38 -0
- data/lib/capybara/spec/session/element/match_css_spec.rb +31 -0
- data/lib/capybara/spec/session/element/match_xpath_spec.rb +25 -0
- data/lib/capybara/spec/session/element/matches_selector_spec.rb +120 -0
- data/lib/capybara/spec/session/evaluate_async_script_spec.rb +23 -0
- data/lib/capybara/spec/session/evaluate_script_spec.rb +49 -0
- data/lib/capybara/spec/session/execute_script_spec.rb +28 -0
- data/lib/capybara/spec/session/fill_in_spec.rb +286 -0
- data/lib/capybara/spec/session/find_button_spec.rb +74 -0
- data/lib/capybara/spec/session/find_by_id_spec.rb +33 -0
- data/lib/capybara/spec/session/find_field_spec.rb +113 -0
- data/lib/capybara/spec/session/find_link_spec.rb +70 -0
- data/lib/capybara/spec/session/find_spec.rb +531 -0
- data/lib/capybara/spec/session/first_spec.rb +156 -0
- 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 +116 -0
- data/lib/capybara/spec/session/frame/within_frame_spec.rb +112 -0
- data/lib/capybara/spec/session/go_back_spec.rb +12 -0
- data/lib/capybara/spec/session/go_forward_spec.rb +14 -0
- data/lib/capybara/spec/session/has_all_selectors_spec.rb +69 -0
- data/lib/capybara/spec/session/has_ancestor_spec.rb +46 -0
- data/lib/capybara/spec/session/has_any_selectors_spec.rb +25 -0
- data/lib/capybara/spec/session/has_button_spec.rb +69 -0
- data/lib/capybara/spec/session/has_css_spec.rb +374 -0
- data/lib/capybara/spec/session/has_current_path_spec.rb +138 -0
- data/lib/capybara/spec/session/has_field_spec.rb +349 -0
- data/lib/capybara/spec/session/has_link_spec.rb +39 -0
- data/lib/capybara/spec/session/has_none_selectors_spec.rb +78 -0
- data/lib/capybara/spec/session/has_select_spec.rb +310 -0
- data/lib/capybara/spec/session/has_selector_spec.rb +202 -0
- data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
- data/lib/capybara/spec/session/has_table_spec.rb +198 -0
- data/lib/capybara/spec/session/has_text_spec.rb +394 -0
- data/lib/capybara/spec/session/has_title_spec.rb +71 -0
- data/lib/capybara/spec/session/has_xpath_spec.rb +149 -0
- data/lib/capybara/spec/session/headers_spec.rb +8 -0
- data/lib/capybara/spec/session/html_spec.rb +47 -0
- data/lib/capybara/spec/session/matches_style_spec.rb +35 -0
- data/lib/capybara/spec/session/node_spec.rb +1292 -0
- data/lib/capybara/spec/session/node_wrapper_spec.rb +39 -0
- data/lib/capybara/spec/session/refresh_spec.rb +33 -0
- data/lib/capybara/spec/session/reset_session_spec.rb +148 -0
- data/lib/capybara/spec/session/response_code_spec.rb +8 -0
- data/lib/capybara/spec/session/save_and_open_page_spec.rb +21 -0
- data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +43 -0
- data/lib/capybara/spec/session/save_page_spec.rb +110 -0
- data/lib/capybara/spec/session/save_screenshot_spec.rb +55 -0
- data/lib/capybara/spec/session/screenshot_spec.rb +18 -0
- data/lib/capybara/spec/session/scroll_spec.rb +117 -0
- data/lib/capybara/spec/session/select_spec.rb +229 -0
- data/lib/capybara/spec/session/selectors_spec.rb +98 -0
- data/lib/capybara/spec/session/sibling_spec.rb +52 -0
- data/lib/capybara/spec/session/source_spec.rb +0 -0
- data/lib/capybara/spec/session/text_spec.rb +74 -0
- data/lib/capybara/spec/session/title_spec.rb +29 -0
- data/lib/capybara/spec/session/uncheck_spec.rb +100 -0
- data/lib/capybara/spec/session/unselect_spec.rb +116 -0
- data/lib/capybara/spec/session/visit_spec.rb +204 -0
- data/lib/capybara/spec/session/window/become_closed_spec.rb +89 -0
- data/lib/capybara/spec/session/window/current_window_spec.rb +28 -0
- data/lib/capybara/spec/session/window/open_new_window_spec.rb +31 -0
- data/lib/capybara/spec/session/window/switch_to_window_spec.rb +132 -0
- data/lib/capybara/spec/session/window/window_opened_by_spec.rb +99 -0
- data/lib/capybara/spec/session/window/window_spec.rb +203 -0
- data/lib/capybara/spec/session/window/windows_spec.rb +34 -0
- data/lib/capybara/spec/session/window/within_window_spec.rb +157 -0
- data/lib/capybara/spec/session/within_spec.rb +199 -0
- data/lib/capybara/spec/spec_helper.rb +134 -0
- data/lib/capybara/spec/test_app.rb +226 -0
- data/lib/capybara/spec/views/animated.erb +49 -0
- data/lib/capybara/spec/views/buttons.erb +5 -0
- data/lib/capybara/spec/views/fieldsets.erb +30 -0
- data/lib/capybara/spec/views/form.erb +685 -0
- data/lib/capybara/spec/views/frame_child.erb +18 -0
- data/lib/capybara/spec/views/frame_one.erb +10 -0
- data/lib/capybara/spec/views/frame_parent.erb +9 -0
- data/lib/capybara/spec/views/frame_two.erb +9 -0
- data/lib/capybara/spec/views/header_links.erb +8 -0
- data/lib/capybara/spec/views/host_links.erb +13 -0
- data/lib/capybara/spec/views/initial_alert.erb +10 -0
- data/lib/capybara/spec/views/obscured.erb +47 -0
- data/lib/capybara/spec/views/offset.erb +32 -0
- data/lib/capybara/spec/views/path.erb +13 -0
- data/lib/capybara/spec/views/popup_one.erb +9 -0
- data/lib/capybara/spec/views/popup_two.erb +9 -0
- data/lib/capybara/spec/views/postback.erb +14 -0
- data/lib/capybara/spec/views/react.erb +45 -0
- data/lib/capybara/spec/views/scroll.erb +20 -0
- data/lib/capybara/spec/views/spatial.erb +31 -0
- data/lib/capybara/spec/views/tables.erb +130 -0
- data/lib/capybara/spec/views/with_animation.erb +74 -0
- data/lib/capybara/spec/views/with_base_tag.erb +11 -0
- data/lib/capybara/spec/views/with_count.erb +8 -0
- data/lib/capybara/spec/views/with_dragula.erb +22 -0
- data/lib/capybara/spec/views/with_fixed_header_footer.erb +17 -0
- data/lib/capybara/spec/views/with_hover.erb +24 -0
- data/lib/capybara/spec/views/with_hover1.erb +10 -0
- data/lib/capybara/spec/views/with_html.erb +208 -0
- data/lib/capybara/spec/views/with_html5_svg.erb +20 -0
- data/lib/capybara/spec/views/with_html_entities.erb +2 -0
- data/lib/capybara/spec/views/with_js.erb +160 -0
- data/lib/capybara/spec/views/with_jstree.erb +26 -0
- data/lib/capybara/spec/views/with_namespace.erb +20 -0
- data/lib/capybara/spec/views/with_scope.erb +42 -0
- data/lib/capybara/spec/views/with_scope_other.erb +6 -0
- data/lib/capybara/spec/views/with_simple_html.erb +2 -0
- data/lib/capybara/spec/views/with_slow_unload.erb +17 -0
- data/lib/capybara/spec/views/with_sortable_js.erb +21 -0
- data/lib/capybara/spec/views/with_title.erb +5 -0
- data/lib/capybara/spec/views/with_unload_alert.erb +14 -0
- data/lib/capybara/spec/views/with_windows.erb +54 -0
- data/lib/capybara/spec/views/within_frames.erb +15 -0
- data/lib/capybara/version.rb +5 -0
- data/lib/capybara/window.rb +146 -0
- data/spec/basic_node_spec.rb +154 -0
- data/spec/capybara_spec.rb +112 -0
- data/spec/css_builder_spec.rb +101 -0
- data/spec/css_splitter_spec.rb +38 -0
- data/spec/dsl_spec.rb +276 -0
- data/spec/filter_set_spec.rb +46 -0
- data/spec/fixtures/capybara.csv +1 -0
- data/spec/fixtures/certificate.pem +25 -0
- data/spec/fixtures/key.pem +27 -0
- data/spec/fixtures/selenium_driver_rspec_failure.rb +13 -0
- data/spec/fixtures/selenium_driver_rspec_success.rb +13 -0
- data/spec/minitest_spec.rb +163 -0
- data/spec/minitest_spec_spec.rb +162 -0
- data/spec/per_session_config_spec.rb +68 -0
- data/spec/rack_test_spec.rb +268 -0
- data/spec/regexp_dissassembler_spec.rb +250 -0
- data/spec/result_spec.rb +196 -0
- data/spec/rspec/features_spec.rb +99 -0
- data/spec/rspec/scenarios_spec.rb +19 -0
- data/spec/rspec/shared_spec_matchers.rb +947 -0
- data/spec/rspec/views_spec.rb +14 -0
- data/spec/rspec_matchers_spec.rb +62 -0
- data/spec/rspec_spec.rb +145 -0
- data/spec/sauce_spec_chrome.rb +43 -0
- data/spec/selector_spec.rb +513 -0
- data/spec/selenium_spec_chrome.rb +188 -0
- data/spec/selenium_spec_chrome_remote.rb +96 -0
- data/spec/selenium_spec_edge.rb +47 -0
- data/spec/selenium_spec_firefox.rb +208 -0
- data/spec/selenium_spec_firefox_remote.rb +80 -0
- data/spec/selenium_spec_ie.rb +150 -0
- data/spec/selenium_spec_safari.rb +148 -0
- data/spec/server_spec.rb +292 -0
- data/spec/session_spec.rb +91 -0
- data/spec/shared_selenium_node.rb +83 -0
- data/spec/shared_selenium_session.rb +476 -0
- data/spec/spec_helper.rb +100 -0
- data/spec/xpath_builder_spec.rb +93 -0
- metadata +753 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'capybara/selenium/extensions/html5_drag'
|
|
4
|
+
require 'capybara/selenium/extensions/file_input_click_emulation'
|
|
5
|
+
|
|
6
|
+
class Capybara::Selenium::ChromeNode < Capybara::Selenium::Node
|
|
7
|
+
include Html5Drag
|
|
8
|
+
include FileInputClickEmulation
|
|
9
|
+
|
|
10
|
+
def set_text(value, clear: nil, **_unused)
|
|
11
|
+
super.tap do
|
|
12
|
+
# React doesn't see the chromedriver element clear
|
|
13
|
+
send_keys(:space, :backspace) if value.to_s.empty? && clear.nil?
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def set_file(value) # rubocop:disable Naming/AccessorMethodName
|
|
18
|
+
# In Chrome 75+ files are appended (due to WebDriver spec - why?) so we have to clear here if its multiple and already set
|
|
19
|
+
if browser_version >= 75.0
|
|
20
|
+
driver.execute_script(<<~JS, self)
|
|
21
|
+
if (arguments[0].multiple && arguments[0].files.length){
|
|
22
|
+
arguments[0].value = null;
|
|
23
|
+
}
|
|
24
|
+
JS
|
|
25
|
+
end
|
|
26
|
+
super
|
|
27
|
+
rescue *file_errors => e
|
|
28
|
+
if e.message.match?(/File not found : .+\n.+/m)
|
|
29
|
+
raise ArgumentError, "Selenium < 3.14 with remote Chrome doesn't support multiple file upload"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
raise
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def drop(*args)
|
|
36
|
+
html5_drop(*args)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def click(*, **)
|
|
40
|
+
super
|
|
41
|
+
rescue ::Selenium::WebDriver::Error::ElementClickInterceptedError
|
|
42
|
+
raise
|
|
43
|
+
rescue ::Selenium::WebDriver::Error::WebDriverError => e
|
|
44
|
+
# chromedriver 74 (at least on mac) raises the wrong error for this
|
|
45
|
+
if e.message.match?(/element click intercepted/)
|
|
46
|
+
raise ::Selenium::WebDriver::Error::ElementClickInterceptedError, e.message
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
raise
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def disabled?
|
|
53
|
+
driver.evaluate_script("arguments[0].matches(':disabled, select:disabled *')", self)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def select_option
|
|
57
|
+
# To optimize to only one check and then click
|
|
58
|
+
selected_or_disabled = driver.evaluate_script(<<~JS, self)
|
|
59
|
+
arguments[0].matches(':disabled, select:disabled *, :checked')
|
|
60
|
+
JS
|
|
61
|
+
click unless selected_or_disabled
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def visible?
|
|
65
|
+
return super unless native_displayed?
|
|
66
|
+
|
|
67
|
+
begin
|
|
68
|
+
bridge.send(:execute, :is_element_displayed, id: native.ref)
|
|
69
|
+
rescue Selenium::WebDriver::Error::UnknownCommandError
|
|
70
|
+
# If the is_element_displayed command is unknown, no point in trying again
|
|
71
|
+
driver.options[:native_displayed] = false
|
|
72
|
+
super
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
|
|
78
|
+
def perform_legacy_drag(element, drop_modifiers)
|
|
79
|
+
return super if chromedriver_fixed_actions_key_state? || !w3c? || element.obscured?
|
|
80
|
+
|
|
81
|
+
raise ArgumentError, 'Modifier keys are not supported while dragging in this version of Chrome.' unless drop_modifiers.empty?
|
|
82
|
+
|
|
83
|
+
# W3C Chrome/chromedriver < 77 doesn't maintain mouse button state across actions API performs
|
|
84
|
+
# https://bugs.chromium.org/p/chromedriver/issues/detail?id=2981
|
|
85
|
+
browser_action.release.perform
|
|
86
|
+
browser_action.click_and_hold(native).move_to(element.native).release.perform
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def file_errors
|
|
90
|
+
@file_errors = ::Selenium::WebDriver.logger.suppress_deprecations do
|
|
91
|
+
[::Selenium::WebDriver::Error::ExpectedError]
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def browser_version(to_float = true)
|
|
96
|
+
caps = capabilities
|
|
97
|
+
ver = (caps[:browser_version] || caps[:version])
|
|
98
|
+
ver = ver.to_f if to_float
|
|
99
|
+
ver
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def chromedriver_fixed_actions_key_state?
|
|
103
|
+
Gem::Version.new(chromedriver_version) >= Gem::Version.new('76.0.3809.68')
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def chromedriver_supports_displayed_endpoint?
|
|
107
|
+
Gem::Version.new(chromedriver_version) >= Gem::Version.new('76.0.3809.25')
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def chromedriver_version
|
|
111
|
+
capabilities['chrome']['chromedriverVersion'].split(' ')[0]
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def native_displayed?
|
|
115
|
+
(driver.options[:native_displayed] != false) &&
|
|
116
|
+
(w3c? && chromedriver_supports_displayed_endpoint?) &&
|
|
117
|
+
(!ENV['DISABLE_CAPYBARA_SELENIUM_OPTIMIZATIONS'])
|
|
118
|
+
end
|
|
119
|
+
end
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'capybara/selenium/extensions/html5_drag'
|
|
4
|
+
|
|
5
|
+
class Capybara::Selenium::EdgeNode < Capybara::Selenium::Node
|
|
6
|
+
include Html5Drag
|
|
7
|
+
|
|
8
|
+
def set_text(value, clear: nil, **_unused)
|
|
9
|
+
return super unless chrome_edge?
|
|
10
|
+
|
|
11
|
+
super.tap do
|
|
12
|
+
# React doesn't see the chromedriver element clear
|
|
13
|
+
send_keys(:space, :backspace) if value.to_s.empty? && clear.nil?
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def set_file(value) # rubocop:disable Naming/AccessorMethodName
|
|
18
|
+
# In Chrome 75+ files are appended (due to WebDriver spec - why?) so we have to clear here if its multiple and already set
|
|
19
|
+
if chrome_edge?
|
|
20
|
+
driver.execute_script(<<~JS, self)
|
|
21
|
+
if (arguments[0].multiple && arguments[0].files.length){
|
|
22
|
+
arguments[0].value = null;
|
|
23
|
+
}
|
|
24
|
+
JS
|
|
25
|
+
end
|
|
26
|
+
super
|
|
27
|
+
rescue *file_errors => e
|
|
28
|
+
if e.message.match?(/File not found : .+\n.+/m)
|
|
29
|
+
raise ArgumentError, "Selenium < 3.14 with remote Chrome doesn't support multiple file upload"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
raise
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def drop(*args)
|
|
36
|
+
return super unless chrome_edge?
|
|
37
|
+
|
|
38
|
+
html5_drop(*args)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def click(*)
|
|
42
|
+
super
|
|
43
|
+
rescue Selenium::WebDriver::Error::InvalidArgumentError => e
|
|
44
|
+
tag_name, type = attrs(:tagName, :type).map { |val| val&.downcase }
|
|
45
|
+
if tag_name == 'input' && type == 'file'
|
|
46
|
+
raise Selenium::WebDriver::Error::InvalidArgumentError, "EdgeChrome can't click on file inputs.\n#{e.message}"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
raise
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def disabled?
|
|
53
|
+
return super unless chrome_edge?
|
|
54
|
+
|
|
55
|
+
driver.evaluate_script("arguments[0].matches(':disabled, select:disabled *')", self)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def select_option
|
|
59
|
+
return super unless chrome_edge?
|
|
60
|
+
|
|
61
|
+
# To optimize to only one check and then click
|
|
62
|
+
selected_or_disabled = driver.evaluate_script(<<~JS, self)
|
|
63
|
+
arguments[0].matches(':disabled, select:disabled *, :checked')
|
|
64
|
+
JS
|
|
65
|
+
click unless selected_or_disabled
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def visible?
|
|
69
|
+
return super unless chrome_edge? && native_displayed?
|
|
70
|
+
|
|
71
|
+
begin
|
|
72
|
+
bridge.send(:execute, :is_element_displayed, id: native.ref)
|
|
73
|
+
rescue Selenium::WebDriver::Error::UnknownCommandError
|
|
74
|
+
# If the is_element_displayed command is unknown, no point in trying again
|
|
75
|
+
driver.options[:native_displayed] = false
|
|
76
|
+
super
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
private
|
|
81
|
+
|
|
82
|
+
def file_errors
|
|
83
|
+
@file_errors = ::Selenium::WebDriver.logger.suppress_deprecations do
|
|
84
|
+
[::Selenium::WebDriver::Error::ExpectedError]
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def browser_version
|
|
89
|
+
@browser_version ||= begin
|
|
90
|
+
caps = driver.browser.capabilities
|
|
91
|
+
(caps[:browser_version] || caps[:version]).to_f
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def chrome_edge?
|
|
96
|
+
browser_version >= 75
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def native_displayed?
|
|
100
|
+
(driver.options[:native_displayed] != false) &&
|
|
101
|
+
# chromedriver_supports_displayed_endpoint? &&
|
|
102
|
+
(!ENV['DISABLE_CAPYBARA_SELENIUM_OPTIMIZATIONS'])
|
|
103
|
+
end
|
|
104
|
+
end
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'capybara/selenium/extensions/html5_drag'
|
|
4
|
+
require 'capybara/selenium/extensions/file_input_click_emulation'
|
|
5
|
+
|
|
6
|
+
class Capybara::Selenium::FirefoxNode < Capybara::Selenium::Node
|
|
7
|
+
include Html5Drag
|
|
8
|
+
include FileInputClickEmulation
|
|
9
|
+
|
|
10
|
+
def click(keys = [], **options)
|
|
11
|
+
super
|
|
12
|
+
rescue ::Selenium::WebDriver::Error::ElementNotInteractableError
|
|
13
|
+
if tag_name == 'tr'
|
|
14
|
+
warn 'You are attempting to click a table row which has issues in geckodriver/marionette - '\
|
|
15
|
+
'see https://github.com/mozilla/geckodriver/issues/1228. Your test should probably be '\
|
|
16
|
+
'clicking on a table cell like a user would. Clicking the first cell in the row instead.'
|
|
17
|
+
return find_css('th:first-child,td:first-child')[0].click(keys, **options)
|
|
18
|
+
end
|
|
19
|
+
raise
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def disabled?
|
|
23
|
+
driver.evaluate_script("arguments[0].matches(':disabled, select:disabled *')", self)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def set_file(value) # rubocop:disable Naming/AccessorMethodName
|
|
27
|
+
# By default files are appended so we have to clear here if its multiple and already set
|
|
28
|
+
driver.execute_script(<<~JS, self)
|
|
29
|
+
if (arguments[0].multiple && arguments[0].files.length){
|
|
30
|
+
arguments[0].value = null;
|
|
31
|
+
}
|
|
32
|
+
JS
|
|
33
|
+
return super if browser_version >= 62.0
|
|
34
|
+
|
|
35
|
+
# Workaround lack of support for multiple upload by uploading one at a time
|
|
36
|
+
path_names = value.to_s.empty? ? [] : Array(value)
|
|
37
|
+
if (fd = bridge.file_detector) && !driver.browser.respond_to?(:upload)
|
|
38
|
+
path_names.map! { |path| upload(fd.call([path])) || path }
|
|
39
|
+
end
|
|
40
|
+
path_names.each { |path| native.send_keys(path) }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def send_keys(*args)
|
|
44
|
+
# https://github.com/mozilla/geckodriver/issues/846
|
|
45
|
+
return super(*args.map { |arg| arg == :space ? ' ' : arg }) if args.none? { |arg| arg.is_a? Array }
|
|
46
|
+
|
|
47
|
+
native.click
|
|
48
|
+
_send_keys(args).perform
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def drop(*args)
|
|
52
|
+
html5_drop(*args)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def hover
|
|
56
|
+
return super unless browser_version >= 65.0
|
|
57
|
+
|
|
58
|
+
# work around issue 2156 - https://github.com/teamcapybara/capybara/issues/2156
|
|
59
|
+
scroll_if_needed { browser_action.move_to(native, 0, 0).move_to(native).perform }
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def select_option
|
|
63
|
+
# To optimize to only one check and then click
|
|
64
|
+
selected_or_disabled = driver.evaluate_script(<<~JS, self)
|
|
65
|
+
arguments[0].matches(':disabled, select:disabled *, :checked')
|
|
66
|
+
JS
|
|
67
|
+
click unless selected_or_disabled
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def visible?
|
|
71
|
+
return super unless native_displayed?
|
|
72
|
+
|
|
73
|
+
begin
|
|
74
|
+
bridge.send(:execute, :is_element_displayed, id: native.ref)
|
|
75
|
+
rescue Selenium::WebDriver::Error::UnknownCommandError
|
|
76
|
+
# If the is_element_displayed command is unknown, no point in trying again
|
|
77
|
+
driver.options[:native_displayed] = false
|
|
78
|
+
super
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
private
|
|
83
|
+
|
|
84
|
+
def native_displayed?
|
|
85
|
+
(driver.options[:native_displayed] != false) && !ENV['DISABLE_CAPYBARA_SELENIUM_OPTIMIZATIONS']
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def perform_with_options(click_options)
|
|
89
|
+
# Firefox/marionette has an issue clicking with offset near viewport edge
|
|
90
|
+
# scroll element to middle just in case
|
|
91
|
+
scroll_to_center if click_options.coords?
|
|
92
|
+
super
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def _send_keys(keys, actions = browser_action, down_keys = ModifierKeysStack.new)
|
|
96
|
+
case keys
|
|
97
|
+
when :control, :left_control, :right_control,
|
|
98
|
+
:alt, :left_alt, :right_alt,
|
|
99
|
+
:shift, :left_shift, :right_shift,
|
|
100
|
+
:meta, :left_meta, :right_meta,
|
|
101
|
+
:command
|
|
102
|
+
down_keys.press(keys)
|
|
103
|
+
actions.key_down(keys)
|
|
104
|
+
when String
|
|
105
|
+
# https://bugzilla.mozilla.org/show_bug.cgi?id=1405370
|
|
106
|
+
keys = keys.upcase if (browser_version < 64.0) && down_keys&.include?(:shift)
|
|
107
|
+
actions.send_keys(keys)
|
|
108
|
+
when Symbol
|
|
109
|
+
actions.send_keys(keys)
|
|
110
|
+
when Array
|
|
111
|
+
down_keys.push
|
|
112
|
+
keys.each { |sub_keys| _send_keys(sub_keys, actions, down_keys) }
|
|
113
|
+
down_keys.pop.reverse_each { |key| actions.key_up(key) }
|
|
114
|
+
else
|
|
115
|
+
raise ArgumentError, 'Unknown keys type'
|
|
116
|
+
end
|
|
117
|
+
actions
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def upload(local_file)
|
|
121
|
+
return nil unless local_file
|
|
122
|
+
raise ArgumentError, "You may only upload files: #{local_file.inspect}" unless File.file?(local_file)
|
|
123
|
+
|
|
124
|
+
file = ::Selenium::WebDriver::Zipper.zip_file(local_file)
|
|
125
|
+
bridge.http.call(:post, "session/#{bridge.session_id}/file", file: file)['value']
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def browser_version
|
|
129
|
+
driver.browser.capabilities[:browser_version].to_f
|
|
130
|
+
end
|
|
131
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'capybara/selenium/extensions/html5_drag'
|
|
4
|
+
|
|
5
|
+
class Capybara::Selenium::IENode < Capybara::Selenium::Node
|
|
6
|
+
def disabled?
|
|
7
|
+
# super
|
|
8
|
+
# optimize to one script call
|
|
9
|
+
driver.evaluate_script <<~JS.delete("\n"), self
|
|
10
|
+
arguments[0].msMatchesSelector('
|
|
11
|
+
:disabled,
|
|
12
|
+
select:disabled *,
|
|
13
|
+
optgroup:disabled *,
|
|
14
|
+
fieldset[disabled],
|
|
15
|
+
fieldset[disabled] > *:not(legend),
|
|
16
|
+
fieldset[disabled] > *:not(legend) *,
|
|
17
|
+
fieldset[disabled] > legend:nth-of-type(n+2),
|
|
18
|
+
fieldset[disabled] > legend:nth-of-type(n+2) *
|
|
19
|
+
')
|
|
20
|
+
JS
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# require 'capybara/selenium/extensions/html5_drag'
|
|
4
|
+
require 'capybara/selenium/extensions/modifier_keys_stack'
|
|
5
|
+
|
|
6
|
+
class Capybara::Selenium::SafariNode < Capybara::Selenium::Node
|
|
7
|
+
# include Html5Drag
|
|
8
|
+
|
|
9
|
+
def click(keys = [], **options)
|
|
10
|
+
# driver.execute_script('arguments[0].scrollIntoViewIfNeeded({block: "center"})', self)
|
|
11
|
+
super
|
|
12
|
+
rescue ::Selenium::WebDriver::Error::ElementNotInteractableError
|
|
13
|
+
if tag_name == 'tr'
|
|
14
|
+
warn 'You are attempting to click a table row which has issues in safaridriver - '\
|
|
15
|
+
'Your test should probably be clicking on a table cell like a user would. '\
|
|
16
|
+
'Clicking the first cell in the row instead.'
|
|
17
|
+
return find_css('th:first-child,td:first-child')[0].click(keys, options)
|
|
18
|
+
end
|
|
19
|
+
raise
|
|
20
|
+
rescue ::Selenium::WebDriver::Error::WebDriverError => e
|
|
21
|
+
raise unless e.instance_of? ::Selenium::WebDriver::Error::WebDriverError
|
|
22
|
+
|
|
23
|
+
# Safari doesn't return a specific error here - assume it's an ElementNotInteractableError
|
|
24
|
+
raise ::Selenium::WebDriver::Error::ElementNotInteractableError,
|
|
25
|
+
'Non distinct error raised in #click, translated to ElementNotInteractableError for retry'
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def select_option
|
|
29
|
+
# To optimize to only one check and then click
|
|
30
|
+
selected_or_disabled = driver.execute_script(<<~JS, self)
|
|
31
|
+
arguments[0].closest('select').scrollIntoView();
|
|
32
|
+
return arguments[0].matches(':disabled, select:disabled *, :checked');
|
|
33
|
+
JS
|
|
34
|
+
click unless selected_or_disabled
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def unselect_option
|
|
38
|
+
driver.execute_script("arguments[0].closest('select').scrollIntoView()", self)
|
|
39
|
+
super
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def visible_text
|
|
43
|
+
return '' unless visible?
|
|
44
|
+
|
|
45
|
+
vis_text = driver.execute_script('return arguments[0].innerText', self)
|
|
46
|
+
vis_text.gsub(/\ +/, ' ')
|
|
47
|
+
.gsub(/[\ \n]*\n[\ \n]*/, "\n")
|
|
48
|
+
.gsub(/\A[[:space:]&&[^\u00a0]]+/, '')
|
|
49
|
+
.gsub(/[[:space:]&&[^\u00a0]]+\z/, '')
|
|
50
|
+
.tr("\u00a0", ' ')
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def disabled?
|
|
54
|
+
driver.evaluate_script("arguments[0].matches(':disabled, select:disabled *')", self)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def set_file(value) # rubocop:disable Naming/AccessorMethodName
|
|
58
|
+
# By default files are appended so we have to clear here if its multiple and already set
|
|
59
|
+
native.clear if multiple? && driver.evaluate_script('arguments[0].files', self).any?
|
|
60
|
+
super
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def send_keys(*args)
|
|
64
|
+
if args.none? { |arg| arg.is_a?(Array) || (arg.is_a?(Symbol) && MODIFIER_KEYS.include?(arg)) }
|
|
65
|
+
return super(*args.map { |arg| arg == :space ? ' ' : arg })
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
native.click
|
|
69
|
+
_send_keys(args).perform
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def set_text(value, clear: nil, **_unused)
|
|
73
|
+
value = value.to_s
|
|
74
|
+
if clear == :backspace
|
|
75
|
+
# Clear field by sending the correct number of backspace keys.
|
|
76
|
+
backspaces = [:backspace] * self.value.to_s.length
|
|
77
|
+
send_keys(*([[:control, 'e']] + backspaces + [value]))
|
|
78
|
+
else
|
|
79
|
+
super.tap do
|
|
80
|
+
# React doesn't see the safaridriver element clear
|
|
81
|
+
send_keys(:space, :backspace) if value.to_s.empty? && clear.nil?
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def hover
|
|
87
|
+
# Workaround issue where hover would sometimes fail - possibly due to mouse not having moved
|
|
88
|
+
scroll_if_needed { browser_action.move_to(native, 0, 0).move_to(native).perform }
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
private
|
|
92
|
+
|
|
93
|
+
def _send_keys(keys, actions = browser_action, down_keys = ModifierKeysStack.new)
|
|
94
|
+
case keys
|
|
95
|
+
when *MODIFIER_KEYS
|
|
96
|
+
down_keys.press(keys)
|
|
97
|
+
actions.key_down(keys)
|
|
98
|
+
when String
|
|
99
|
+
keys = keys.upcase if down_keys&.include?(:shift)
|
|
100
|
+
actions.send_keys(keys)
|
|
101
|
+
when Symbol
|
|
102
|
+
actions.send_keys(keys)
|
|
103
|
+
when Array
|
|
104
|
+
down_keys.push
|
|
105
|
+
keys.each { |sub_keys| _send_keys(sub_keys, actions, down_keys) }
|
|
106
|
+
down_keys.pop.reverse_each { |key| actions.key_up(key) }
|
|
107
|
+
else
|
|
108
|
+
raise ArgumentError, 'Unknown keys type'
|
|
109
|
+
end
|
|
110
|
+
actions
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
MODIFIER_KEYS = %i[control left_control right_control
|
|
114
|
+
alt left_alt right_alt
|
|
115
|
+
shift left_shift right_shift
|
|
116
|
+
meta left_meta right_meta
|
|
117
|
+
command].freeze
|
|
118
|
+
end
|