capybara 2.18.0 → 3.40.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 +945 -12
- data/License.txt +1 -1
- data/README.md +264 -90
- data/lib/capybara/config.rb +29 -57
- data/lib/capybara/cucumber.rb +2 -3
- data/lib/capybara/driver/base.rb +35 -18
- data/lib/capybara/driver/node.rb +40 -10
- data/lib/capybara/dsl.rb +10 -7
- data/lib/capybara/helpers.rb +70 -31
- data/lib/capybara/minitest/spec.rb +185 -83
- data/lib/capybara/minitest.rb +232 -112
- data/lib/capybara/node/actions.rb +274 -171
- data/lib/capybara/node/base.rb +42 -34
- data/lib/capybara/node/document.rb +15 -3
- data/lib/capybara/node/document_matchers.rb +19 -21
- data/lib/capybara/node/element.rb +362 -135
- data/lib/capybara/node/finders.rb +151 -137
- data/lib/capybara/node/matchers.rb +394 -209
- data/lib/capybara/node/simple.rb +59 -26
- data/lib/capybara/node/whitespace_normalizer.rb +81 -0
- data/lib/capybara/queries/active_element_query.rb +18 -0
- data/lib/capybara/queries/ancestor_query.rb +12 -9
- data/lib/capybara/queries/base_query.rb +39 -28
- data/lib/capybara/queries/current_path_query.rb +21 -27
- data/lib/capybara/queries/match_query.rb +14 -7
- data/lib/capybara/queries/selector_query.rb +659 -149
- data/lib/capybara/queries/sibling_query.rb +11 -9
- data/lib/capybara/queries/style_query.rb +45 -0
- data/lib/capybara/queries/text_query.rb +56 -38
- data/lib/capybara/queries/title_query.rb +8 -11
- data/lib/capybara/rack_test/browser.rb +114 -42
- data/lib/capybara/rack_test/css_handlers.rb +6 -4
- data/lib/capybara/rack_test/driver.rb +22 -17
- data/lib/capybara/rack_test/errors.rb +6 -0
- data/lib/capybara/rack_test/form.rb +93 -58
- data/lib/capybara/rack_test/node.rb +184 -81
- data/lib/capybara/rails.rb +3 -7
- data/lib/capybara/registration_container.rb +41 -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 +66 -0
- data/lib/capybara/result.rb +97 -63
- data/lib/capybara/rspec/features.rb +17 -50
- data/lib/capybara/rspec/matcher_proxies.rb +52 -15
- data/lib/capybara/rspec/matchers/base.rb +113 -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 +69 -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 +146 -310
- data/lib/capybara/rspec.rb +7 -11
- 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 +85 -13
- 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 +55 -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 +280 -0
- data/lib/capybara/selector/filter.rb +2 -17
- data/lib/capybara/selector/filter_set.rb +80 -33
- data/lib/capybara/selector/filters/base.rb +50 -6
- data/lib/capybara/selector/filters/expression_filter.rb +8 -26
- data/lib/capybara/selector/filters/locator_filter.rb +29 -0
- data/lib/capybara/selector/filters/node_filter.rb +16 -12
- data/lib/capybara/selector/regexp_disassembler.rb +211 -0
- data/lib/capybara/selector/selector.rb +93 -210
- data/lib/capybara/selector/xpath_extensions.rb +17 -0
- data/lib/capybara/selector.rb +475 -523
- 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 +298 -267
- data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +117 -0
- data/lib/capybara/selenium/driver_specializations/edge_driver.rb +128 -0
- data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +84 -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 +229 -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/node.rb +517 -145
- data/lib/capybara/selenium/nodes/chrome_node.rb +125 -0
- data/lib/capybara/selenium/nodes/edge_node.rb +110 -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/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 +80 -0
- data/lib/capybara/server/checker.rb +44 -0
- data/lib/capybara/server/middleware.rb +71 -0
- data/lib/capybara/server.rb +59 -67
- data/lib/capybara/session/config.rb +81 -67
- data/lib/capybara/session/matchers.rb +28 -20
- data/lib/capybara/session.rb +337 -365
- 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 +151 -12
- data/lib/capybara/spec/session/accept_alert_spec.rb +12 -11
- data/lib/capybara/spec/session/accept_confirm_spec.rb +6 -5
- data/lib/capybara/spec/session/accept_prompt_spec.rb +10 -10
- data/lib/capybara/spec/session/active_element_spec.rb +31 -0
- data/lib/capybara/spec/session/all_spec.rb +161 -57
- data/lib/capybara/spec/session/ancestor_spec.rb +27 -24
- data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +68 -38
- 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.rb → assert_title_spec.rb} +22 -12
- data/lib/capybara/spec/session/attach_file_spec.rb +144 -69
- data/lib/capybara/spec/session/body_spec.rb +12 -13
- data/lib/capybara/spec/session/check_spec.rb +117 -55
- data/lib/capybara/spec/session/choose_spec.rb +64 -31
- data/lib/capybara/spec/session/click_button_spec.rb +231 -173
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +55 -35
- data/lib/capybara/spec/session/click_link_spec.rb +93 -58
- data/lib/capybara/spec/session/current_scope_spec.rb +12 -11
- data/lib/capybara/spec/session/current_url_spec.rb +57 -39
- data/lib/capybara/spec/session/dismiss_confirm_spec.rb +4 -4
- data/lib/capybara/spec/session/dismiss_prompt_spec.rb +3 -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 +9 -7
- data/lib/capybara/spec/session/element/matches_selector_spec.rb +71 -57
- data/lib/capybara/spec/session/evaluate_async_script_spec.rb +8 -7
- data/lib/capybara/spec/session/evaluate_script_spec.rb +29 -8
- data/lib/capybara/spec/session/execute_script_spec.rb +10 -8
- data/lib/capybara/spec/session/fill_in_spec.rb +134 -43
- data/lib/capybara/spec/session/find_button_spec.rb +25 -24
- data/lib/capybara/spec/session/find_by_id_spec.rb +10 -9
- data/lib/capybara/spec/session/find_field_spec.rb +37 -41
- data/lib/capybara/spec/session/find_link_spec.rb +46 -17
- data/lib/capybara/spec/session/find_spec.rb +260 -145
- data/lib/capybara/spec/session/first_spec.rb +80 -52
- 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 +33 -20
- data/lib/capybara/spec/session/frame/within_frame_spec.rb +52 -32
- data/lib/capybara/spec/session/go_back_spec.rb +2 -1
- data/lib/capybara/spec/session/go_forward_spec.rb +2 -1
- data/lib/capybara/spec/session/has_all_selectors_spec.rb +31 -31
- 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 +100 -13
- data/lib/capybara/spec/session/has_css_spec.rb +272 -137
- data/lib/capybara/spec/session/has_current_path_spec.rb +60 -61
- data/lib/capybara/spec/session/has_element_spec.rb +47 -0
- data/lib/capybara/spec/session/has_field_spec.rb +139 -59
- data/lib/capybara/spec/session/has_link_spec.rb +47 -6
- data/lib/capybara/spec/session/has_none_selectors_spec.rb +42 -40
- data/lib/capybara/spec/session/has_select_spec.rb +107 -72
- data/lib/capybara/spec/session/has_selector_spec.rb +120 -71
- data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
- data/lib/capybara/spec/session/has_table_spec.rb +183 -5
- data/lib/capybara/spec/session/has_text_spec.rb +106 -62
- data/lib/capybara/spec/session/has_title_spec.rb +20 -14
- data/lib/capybara/spec/session/has_xpath_spec.rb +57 -38
- data/lib/capybara/spec/session/{headers.rb → headers_spec.rb} +3 -2
- data/lib/capybara/spec/session/html_spec.rb +14 -6
- data/lib/capybara/spec/session/matches_style_spec.rb +37 -0
- data/lib/capybara/spec/session/node_spec.rb +1024 -153
- data/lib/capybara/spec/session/node_wrapper_spec.rb +39 -0
- data/lib/capybara/spec/session/refresh_spec.rb +12 -6
- data/lib/capybara/spec/session/reset_session_spec.rb +82 -35
- data/lib/capybara/spec/session/{response_code.rb → response_code_spec.rb} +2 -1
- data/lib/capybara/spec/session/save_and_open_page_spec.rb +3 -2
- data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +8 -12
- data/lib/capybara/spec/session/save_page_spec.rb +42 -55
- data/lib/capybara/spec/session/save_screenshot_spec.rb +16 -14
- data/lib/capybara/spec/session/screenshot_spec.rb +2 -2
- data/lib/capybara/spec/session/scroll_spec.rb +119 -0
- data/lib/capybara/spec/session/select_spec.rb +107 -81
- data/lib/capybara/spec/session/selectors_spec.rb +52 -19
- data/lib/capybara/spec/session/sibling_spec.rb +10 -10
- data/lib/capybara/spec/session/text_spec.rb +37 -21
- data/lib/capybara/spec/session/title_spec.rb +17 -5
- data/lib/capybara/spec/session/uncheck_spec.rb +43 -23
- data/lib/capybara/spec/session/unselect_spec.rb +39 -38
- data/lib/capybara/spec/session/visit_spec.rb +85 -53
- data/lib/capybara/spec/session/window/become_closed_spec.rb +24 -20
- data/lib/capybara/spec/session/window/current_window_spec.rb +5 -3
- data/lib/capybara/spec/session/window/open_new_window_spec.rb +5 -3
- data/lib/capybara/spec/session/window/switch_to_window_spec.rb +27 -22
- data/lib/capybara/spec/session/window/window_opened_by_spec.rb +12 -6
- data/lib/capybara/spec/session/window/window_spec.rb +97 -63
- data/lib/capybara/spec/session/window/windows_spec.rb +12 -10
- data/lib/capybara/spec/session/window/within_window_spec.rb +31 -86
- data/lib/capybara/spec/session/within_spec.rb +83 -44
- data/lib/capybara/spec/spec_helper.rb +54 -44
- data/lib/capybara/spec/test_app.rb +158 -43
- data/lib/capybara/spec/views/animated.erb +49 -0
- data/lib/capybara/spec/views/form.erb +163 -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 +69 -12
- 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.erb +2 -2
- data/lib/capybara/spec/views/with_scope_other.erb +6 -0
- data/lib/capybara/spec/views/with_shadow.erb +31 -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 +5 -2
- data/lib/capybara/version.rb +2 -1
- data/lib/capybara/window.rb +36 -34
- data/lib/capybara.rb +134 -107
- data/spec/basic_node_spec.rb +60 -34
- data/spec/capybara_spec.rb +63 -88
- data/spec/counter_spec.rb +35 -0
- data/spec/css_builder_spec.rb +101 -0
- data/spec/css_splitter_spec.rb +38 -0
- data/spec/dsl_spec.rb +85 -64
- data/spec/filter_set_spec.rb +27 -9
- data/spec/fixtures/certificate.pem +25 -0
- data/spec/fixtures/key.pem +27 -0
- data/spec/fixtures/selenium_driver_rspec_failure.rb +6 -5
- data/spec/fixtures/selenium_driver_rspec_success.rb +6 -5
- data/spec/minitest_spec.rb +52 -7
- data/spec/minitest_spec_spec.rb +94 -63
- data/spec/per_session_config_spec.rb +14 -13
- data/spec/rack_test_spec.rb +194 -125
- data/spec/regexp_dissassembler_spec.rb +250 -0
- data/spec/result_spec.rb +111 -50
- data/spec/rspec/features_spec.rb +37 -31
- data/spec/rspec/scenarios_spec.rb +10 -8
- data/spec/rspec/shared_spec_matchers.rb +473 -422
- data/spec/rspec/views_spec.rb +5 -3
- data/spec/rspec_matchers_spec.rb +52 -11
- data/spec/rspec_spec.rb +109 -89
- data/spec/sauce_spec_chrome.rb +43 -0
- data/spec/selector_spec.rb +397 -68
- data/spec/selenium_spec_chrome.rb +187 -40
- data/spec/selenium_spec_chrome_remote.rb +96 -0
- data/spec/selenium_spec_edge.rb +60 -0
- data/spec/selenium_spec_firefox.rb +201 -41
- data/spec/selenium_spec_firefox_remote.rb +94 -0
- data/spec/selenium_spec_ie.rb +149 -0
- data/spec/selenium_spec_safari.rb +162 -0
- data/spec/server_spec.rb +213 -102
- data/spec/session_spec.rb +53 -16
- data/spec/shared_selenium_node.rb +79 -0
- data/spec/shared_selenium_session.rb +473 -122
- data/spec/spec_helper.rb +126 -7
- data/spec/whitespace_normalizer_spec.rb +54 -0
- data/spec/xpath_builder_spec.rb +93 -0
- metadata +355 -73
- 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/query.rb +0 -7
- data/lib/capybara/rspec/compound.rb +0 -95
- data/lib/capybara/spec/session/assert_current_path.rb +0 -72
- data/lib/capybara/spec/session/assert_selector.rb +0 -148
- data/lib/capybara/spec/session/assert_text.rb +0 -234
- 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 -127
data/lib/capybara/node/simple.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
module Capybara
|
|
3
4
|
module Node
|
|
4
|
-
|
|
5
5
|
##
|
|
6
6
|
#
|
|
7
7
|
# A {Capybara::Node::Simple} is a simpler version of {Capybara::Node::Base} which
|
|
@@ -28,8 +28,9 @@ module Capybara
|
|
|
28
28
|
#
|
|
29
29
|
# @return [String] The text of the element
|
|
30
30
|
#
|
|
31
|
-
def text(
|
|
32
|
-
native.text
|
|
31
|
+
def text(_type = nil, normalize_ws: false)
|
|
32
|
+
txt = native.text
|
|
33
|
+
normalize_ws ? txt.gsub(/[[:space:]]+/, ' ').strip : txt
|
|
33
34
|
end
|
|
34
35
|
|
|
35
36
|
##
|
|
@@ -45,7 +46,7 @@ module Capybara
|
|
|
45
46
|
attr_name = name.to_s
|
|
46
47
|
if attr_name == 'value'
|
|
47
48
|
value
|
|
48
|
-
elsif
|
|
49
|
+
elsif (tag_name == 'input') && (native[:type] == 'checkbox') && (attr_name == 'checked')
|
|
49
50
|
native['checked'] == 'checked'
|
|
50
51
|
else
|
|
51
52
|
native[attr_name]
|
|
@@ -78,13 +79,13 @@ module Capybara
|
|
|
78
79
|
if tag_name == 'textarea'
|
|
79
80
|
native['_capybara_raw_value']
|
|
80
81
|
elsif tag_name == 'select'
|
|
81
|
-
|
|
82
|
-
|
|
82
|
+
selected_options = find_xpath('.//option[@selected]')
|
|
83
|
+
if multiple?
|
|
84
|
+
selected_options.map(&method(:option_value))
|
|
83
85
|
else
|
|
84
|
-
|
|
85
|
-
option[:value] || option.content if option
|
|
86
|
+
option_value(selected_options.first || find_xpath('.//option').first)
|
|
86
87
|
end
|
|
87
|
-
elsif tag_name == 'input' && %w
|
|
88
|
+
elsif tag_name == 'input' && %w[radio checkbox].include?(native[:type])
|
|
88
89
|
native[:value] || 'on'
|
|
89
90
|
else
|
|
90
91
|
native[:value]
|
|
@@ -99,15 +100,17 @@ module Capybara
|
|
|
99
100
|
# @param [Boolean] check_ancestors Whether to inherit visibility from ancestors
|
|
100
101
|
# @return [Boolean] Whether the element is visible
|
|
101
102
|
#
|
|
102
|
-
def visible?(check_ancestors = true)
|
|
103
|
-
return false if (tag_name == 'input') && (native[:type]==
|
|
103
|
+
def visible?(check_ancestors = true) # rubocop:disable Style/OptionalBooleanParameter
|
|
104
|
+
return false if (tag_name == 'input') && (native[:type] == 'hidden')
|
|
105
|
+
return false if tag_name == 'template'
|
|
104
106
|
|
|
105
107
|
if check_ancestors
|
|
106
|
-
|
|
107
|
-
native.xpath("./ancestor-or-self::*[contains(@style, 'display:none') or contains(@style, 'display: none') or @hidden or name()='script' or name()='head']").size() == 0
|
|
108
|
+
!find_xpath(VISIBILITY_XPATH)
|
|
108
109
|
else
|
|
109
|
-
#
|
|
110
|
-
!(native.
|
|
110
|
+
# No need for an xpath if only checking the current element
|
|
111
|
+
!(native.key?('hidden') ||
|
|
112
|
+
/display:\s?none/.match?(native[:style] || '') ||
|
|
113
|
+
%w[script head style].include?(tag_name))
|
|
111
114
|
end
|
|
112
115
|
end
|
|
113
116
|
|
|
@@ -127,7 +130,8 @@ module Capybara
|
|
|
127
130
|
#
|
|
128
131
|
# @return [Boolean] Whether the element is disabled
|
|
129
132
|
def disabled?
|
|
130
|
-
native.has_attribute?('disabled')
|
|
133
|
+
native.has_attribute?('disabled') &&
|
|
134
|
+
%w[button input select textarea optgroup option menuitem fieldset].include?(tag_name)
|
|
131
135
|
end
|
|
132
136
|
|
|
133
137
|
##
|
|
@@ -140,11 +144,19 @@ module Capybara
|
|
|
140
144
|
native.has_attribute?('selected')
|
|
141
145
|
end
|
|
142
146
|
|
|
143
|
-
def
|
|
147
|
+
def multiple?
|
|
148
|
+
native.has_attribute?('multiple')
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def readonly?
|
|
152
|
+
native.has_attribute?('readonly')
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def synchronize(_seconds = nil)
|
|
144
156
|
yield # simple nodes don't need to wait
|
|
145
157
|
end
|
|
146
158
|
|
|
147
|
-
def allow_reload!
|
|
159
|
+
def allow_reload!(*)
|
|
148
160
|
# no op
|
|
149
161
|
end
|
|
150
162
|
|
|
@@ -152,12 +164,7 @@ module Capybara
|
|
|
152
164
|
#
|
|
153
165
|
# @return [String] The title of the document
|
|
154
166
|
def title
|
|
155
|
-
|
|
156
|
-
native.title
|
|
157
|
-
else
|
|
158
|
-
#old versions of nokogiri don't have #title - remove in 3.0
|
|
159
|
-
native.xpath('/html/head/title | /html/title').first.text
|
|
160
|
-
end
|
|
167
|
+
native.title
|
|
161
168
|
end
|
|
162
169
|
|
|
163
170
|
def inspect
|
|
@@ -165,12 +172,12 @@ module Capybara
|
|
|
165
172
|
end
|
|
166
173
|
|
|
167
174
|
# @api private
|
|
168
|
-
def find_css(css)
|
|
175
|
+
def find_css(css, **_options)
|
|
169
176
|
native.css(css)
|
|
170
177
|
end
|
|
171
178
|
|
|
172
179
|
# @api private
|
|
173
|
-
def find_xpath(xpath)
|
|
180
|
+
def find_xpath(xpath, **_options)
|
|
174
181
|
native.xpath(xpath)
|
|
175
182
|
end
|
|
176
183
|
|
|
@@ -178,6 +185,32 @@ module Capybara
|
|
|
178
185
|
def session_options
|
|
179
186
|
Capybara.session_options
|
|
180
187
|
end
|
|
188
|
+
|
|
189
|
+
# @api private
|
|
190
|
+
def initial_cache
|
|
191
|
+
{}
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def ==(other)
|
|
195
|
+
eql?(other) || (other.respond_to?(:native) && native == other.native)
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
private
|
|
199
|
+
|
|
200
|
+
def option_value(option)
|
|
201
|
+
return nil if option.nil?
|
|
202
|
+
|
|
203
|
+
option[:value] || option.content
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
VISIBILITY_XPATH = XPath.generate do |x|
|
|
207
|
+
x.ancestor_or_self[
|
|
208
|
+
x.attr(:style)[x.contains('display:none') | x.contains('display: none')] |
|
|
209
|
+
x.attr(:hidden) |
|
|
210
|
+
x.qname.one_of('script', 'head') |
|
|
211
|
+
(~x.self(:summary) & XPath.parent(:details)[!XPath.attr(:open)])
|
|
212
|
+
].boolean
|
|
213
|
+
end.to_s.freeze
|
|
181
214
|
end
|
|
182
215
|
end
|
|
183
216
|
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Capybara
|
|
4
|
+
module Node
|
|
5
|
+
##
|
|
6
|
+
#
|
|
7
|
+
# {Capybara::Node::WhitespaceNormalizer} provides methods that
|
|
8
|
+
# help to normalize the spacing of text content inside of
|
|
9
|
+
# {Capybara::Node::Element}s by removing various unicode
|
|
10
|
+
# spacing and directional markings.
|
|
11
|
+
#
|
|
12
|
+
module WhitespaceNormalizer
|
|
13
|
+
# Unicode for NBSP, or
|
|
14
|
+
NON_BREAKING_SPACE = "\u00a0"
|
|
15
|
+
LINE_SEPERATOR = "\u2028"
|
|
16
|
+
PARAGRAPH_SEPERATOR = "\u2029"
|
|
17
|
+
|
|
18
|
+
# All spaces except for NBSP
|
|
19
|
+
BREAKING_SPACES = "[[:space:]&&[^#{NON_BREAKING_SPACE}]]".freeze
|
|
20
|
+
|
|
21
|
+
# Whitespace we want to substitute with plain spaces
|
|
22
|
+
SQUEEZED_SPACES = " \n\f\t\v#{LINE_SEPERATOR}#{PARAGRAPH_SEPERATOR}".freeze
|
|
23
|
+
|
|
24
|
+
# Any whitespace at the front of text
|
|
25
|
+
LEADING_SPACES = /\A#{BREAKING_SPACES}+/
|
|
26
|
+
|
|
27
|
+
# Any whitespace at the end of text
|
|
28
|
+
TRAILING_SPACES = /#{BREAKING_SPACES}+\z/
|
|
29
|
+
|
|
30
|
+
# "Invisible" space character
|
|
31
|
+
ZERO_WIDTH_SPACE = "\u200b"
|
|
32
|
+
|
|
33
|
+
# Signifies text is read left to right
|
|
34
|
+
LEFT_TO_RIGHT_MARK = "\u200e"
|
|
35
|
+
|
|
36
|
+
# Signifies text is read right to left
|
|
37
|
+
RIGHT_TO_LEFT_MARK = "\u200f"
|
|
38
|
+
|
|
39
|
+
# Characters we want to truncate from text
|
|
40
|
+
REMOVED_CHARACTERS = [ZERO_WIDTH_SPACE, LEFT_TO_RIGHT_MARK, RIGHT_TO_LEFT_MARK].join
|
|
41
|
+
|
|
42
|
+
# Matches multiple empty lines
|
|
43
|
+
EMPTY_LINES = /[\ \n]*\n[\ \n]*/
|
|
44
|
+
|
|
45
|
+
##
|
|
46
|
+
#
|
|
47
|
+
# Normalizes the spacing of a node's text to be similar to
|
|
48
|
+
# what matchers might expect.
|
|
49
|
+
#
|
|
50
|
+
# @param text [String]
|
|
51
|
+
# @return [String]
|
|
52
|
+
#
|
|
53
|
+
def normalize_spacing(text)
|
|
54
|
+
text
|
|
55
|
+
.delete(REMOVED_CHARACTERS)
|
|
56
|
+
.tr(SQUEEZED_SPACES, ' ')
|
|
57
|
+
.squeeze(' ')
|
|
58
|
+
.sub(LEADING_SPACES, '')
|
|
59
|
+
.sub(TRAILING_SPACES, '')
|
|
60
|
+
.tr(NON_BREAKING_SPACE, ' ')
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
##
|
|
64
|
+
#
|
|
65
|
+
# Variant on {Capybara::Node::Normalizer#normalize_spacing} that
|
|
66
|
+
# targets the whitespace of visible elements only.
|
|
67
|
+
#
|
|
68
|
+
# @param text [String]
|
|
69
|
+
# @return [String]
|
|
70
|
+
#
|
|
71
|
+
def normalize_visible_spacing(text)
|
|
72
|
+
text
|
|
73
|
+
.squeeze(' ')
|
|
74
|
+
.gsub(EMPTY_LINES, "\n")
|
|
75
|
+
.sub(LEADING_SPACES, '')
|
|
76
|
+
.sub(TRAILING_SPACES, '')
|
|
77
|
+
.tr(NON_BREAKING_SPACE, ' ')
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Capybara
|
|
4
|
+
# @api private
|
|
5
|
+
module Queries
|
|
6
|
+
class ActiveElementQuery < BaseQuery
|
|
7
|
+
def initialize(**options)
|
|
8
|
+
@options = options
|
|
9
|
+
super(@options)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def resolve_for(session)
|
|
13
|
+
node = session.driver.active_element
|
|
14
|
+
[Capybara::Node::Element.new(session, node, nil, self)]
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -1,23 +1,26 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
module Capybara
|
|
3
4
|
module Queries
|
|
4
|
-
class AncestorQuery <
|
|
5
|
+
class AncestorQuery < Capybara::Queries::SelectorQuery
|
|
5
6
|
# @api private
|
|
6
7
|
def resolve_for(node, exact = nil)
|
|
7
8
|
@child_node = node
|
|
9
|
+
|
|
8
10
|
node.synchronize do
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
scope = node.respond_to?(:session) ? node.session.current_scope : node.find(:xpath, '/*')
|
|
12
|
+
match_results = super(scope, exact)
|
|
13
|
+
ancestors = node.find_xpath(XPath.ancestor.to_s)
|
|
14
|
+
.map(&method(:to_element))
|
|
15
|
+
.select { |el| match_results.include?(el) }
|
|
16
|
+
Capybara::Result.new(ordered_results(ancestors), self)
|
|
13
17
|
end
|
|
14
18
|
end
|
|
15
19
|
|
|
16
|
-
def description
|
|
20
|
+
def description(applied = false) # rubocop:disable Style/OptionalBooleanParameter
|
|
21
|
+
child_query = @child_node&.instance_variable_get(:@query)
|
|
17
22
|
desc = super
|
|
18
|
-
|
|
19
|
-
desc += " that is an ancestor of #{child_query.description}"
|
|
20
|
-
end
|
|
23
|
+
desc += " that is an ancestor of #{child_query.description}" if child_query
|
|
21
24
|
desc
|
|
22
25
|
end
|
|
23
26
|
end
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
module Capybara
|
|
3
4
|
# @api private
|
|
4
5
|
module Queries
|
|
5
6
|
class BaseQuery
|
|
6
|
-
COUNT_KEYS = [
|
|
7
|
+
COUNT_KEYS = %i[count minimum maximum between].freeze
|
|
7
8
|
|
|
8
9
|
attr_reader :options
|
|
9
10
|
attr_writer :session_options
|
|
@@ -20,8 +21,11 @@ module Capybara
|
|
|
20
21
|
self.class.wait(options, session_options.default_max_wait_time)
|
|
21
22
|
end
|
|
22
23
|
|
|
23
|
-
def self.wait(options, default=Capybara.default_max_wait_time)
|
|
24
|
-
|
|
24
|
+
def self.wait(options, default = Capybara.default_max_wait_time)
|
|
25
|
+
# if no value or nil for the :wait option is passed it should default to the default
|
|
26
|
+
wait = options.fetch(:wait, nil)
|
|
27
|
+
wait = default if wait.nil?
|
|
28
|
+
wait || 0
|
|
25
29
|
end
|
|
26
30
|
|
|
27
31
|
##
|
|
@@ -30,11 +34,7 @@ module Capybara
|
|
|
30
34
|
# Returns false if query does not have any count options specified.
|
|
31
35
|
#
|
|
32
36
|
def expects_none?
|
|
33
|
-
|
|
34
|
-
matches_count?(0)
|
|
35
|
-
else
|
|
36
|
-
false
|
|
37
|
-
end
|
|
37
|
+
count_specified? ? matches_count?(0) : false
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
##
|
|
@@ -47,11 +47,12 @@ module Capybara
|
|
|
47
47
|
# @param [Integer] count The actual number. Should be coercible via Integer()
|
|
48
48
|
#
|
|
49
49
|
def matches_count?(count)
|
|
50
|
-
return (Integer(options[:count]) == count)
|
|
50
|
+
return (Integer(options[:count]) == count) if options[:count]
|
|
51
51
|
return false if options[:maximum] && (Integer(options[:maximum]) < count)
|
|
52
52
|
return false if options[:minimum] && (Integer(options[:minimum]) > count)
|
|
53
|
-
return false if options[:between] && !
|
|
54
|
-
|
|
53
|
+
return false if options[:between] && !options[:between].include?(count)
|
|
54
|
+
|
|
55
|
+
true
|
|
55
56
|
end
|
|
56
57
|
|
|
57
58
|
##
|
|
@@ -59,36 +60,46 @@ module Capybara
|
|
|
59
60
|
# Generates a failure message from the query description and count options.
|
|
60
61
|
#
|
|
61
62
|
def failure_message
|
|
62
|
-
|
|
63
|
+
+"expected to find #{description}" << count_message
|
|
63
64
|
end
|
|
64
65
|
|
|
65
66
|
def negative_failure_message
|
|
66
|
-
|
|
67
|
+
+"expected not to find #{description}" << count_message
|
|
67
68
|
end
|
|
68
69
|
|
|
69
|
-
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
def count_specified?
|
|
73
|
+
COUNT_KEYS.any? { |key| options.key? key }
|
|
74
|
+
end
|
|
70
75
|
|
|
71
76
|
def count_message
|
|
72
|
-
message =
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
elsif
|
|
80
|
-
message << " at
|
|
77
|
+
message = +''
|
|
78
|
+
count, between, maximum, minimum = options.values_at(:count, :between, :maximum, :minimum)
|
|
79
|
+
if count
|
|
80
|
+
message << " #{occurrences count}"
|
|
81
|
+
elsif between
|
|
82
|
+
message << " between #{between.begin ? between.first : 1} and " \
|
|
83
|
+
"#{between.end ? between.last : 'infinite'} times"
|
|
84
|
+
elsif maximum
|
|
85
|
+
message << " at most #{occurrences maximum}"
|
|
86
|
+
elsif minimum
|
|
87
|
+
message << " at least #{occurrences minimum}"
|
|
81
88
|
end
|
|
82
89
|
message
|
|
83
90
|
end
|
|
84
91
|
|
|
92
|
+
def occurrences(count)
|
|
93
|
+
"#{count} #{Capybara::Helpers.declension('time', 'times', count)}"
|
|
94
|
+
end
|
|
95
|
+
|
|
85
96
|
def assert_valid_keys
|
|
86
97
|
invalid_keys = @options.keys - valid_keys
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
98
|
+
return if invalid_keys.empty?
|
|
99
|
+
|
|
100
|
+
invalid_names = invalid_keys.map(&:inspect).join(', ')
|
|
101
|
+
valid_names = valid_keys.map(&:inspect).join(', ')
|
|
102
|
+
raise ArgumentError, "Invalid option(s) #{invalid_names}, should be one of #{valid_names}"
|
|
92
103
|
end
|
|
93
104
|
end
|
|
94
105
|
end
|
|
@@ -1,40 +1,35 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
require 'addressable/uri'
|
|
3
4
|
|
|
4
5
|
module Capybara
|
|
5
6
|
# @api private
|
|
6
7
|
module Queries
|
|
7
8
|
class CurrentPathQuery < BaseQuery
|
|
8
|
-
def initialize(expected_path, options
|
|
9
|
+
def initialize(expected_path, **options, &optional_filter_block)
|
|
9
10
|
super(options)
|
|
10
11
|
@expected_path = expected_path
|
|
11
|
-
warn "DEPRECATED: The :only_path option is deprecated in favor of the :ignore_query option" if options.has_key?(:only_path)
|
|
12
|
-
|
|
13
12
|
@options = {
|
|
14
|
-
url: !@expected_path.is_a?(Regexp) && !::Addressable::URI.parse(@expected_path ||
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
url: !@expected_path.is_a?(Regexp) && !::Addressable::URI.parse(@expected_path || '').hostname.nil?,
|
|
14
|
+
ignore_query: false
|
|
15
|
+
}.merge(options)
|
|
16
|
+
@filter_block = optional_filter_block
|
|
17
17
|
assert_valid_keys
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
def resolves_for?(session)
|
|
21
21
|
uri = ::Addressable::URI.parse(session.current_url)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
uri.to_s
|
|
25
|
-
else
|
|
26
|
-
if options[:only_path]
|
|
27
|
-
uri && uri.path
|
|
28
|
-
else
|
|
29
|
-
uri && uri.request_uri
|
|
30
|
-
end
|
|
22
|
+
@actual_path = (options[:ignore_query] ? uri&.omit(:query) : uri).then do |u|
|
|
23
|
+
options[:url] ? u&.to_s : u&.request_uri
|
|
31
24
|
end
|
|
32
25
|
|
|
33
|
-
if @expected_path.is_a? Regexp
|
|
34
|
-
@actual_path.to_s.match(@expected_path)
|
|
26
|
+
res = if @expected_path.is_a? Regexp
|
|
27
|
+
@actual_path.to_s.match?(@expected_path)
|
|
35
28
|
else
|
|
36
29
|
::Addressable::URI.parse(@expected_path) == ::Addressable::URI.parse(@actual_path)
|
|
37
30
|
end
|
|
31
|
+
|
|
32
|
+
res && matches_filter_block?(uri)
|
|
38
33
|
end
|
|
39
34
|
|
|
40
35
|
def failure_message
|
|
@@ -45,22 +40,21 @@ module Capybara
|
|
|
45
40
|
failure_message_helper(' not')
|
|
46
41
|
end
|
|
47
42
|
|
|
48
|
-
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def matches_filter_block?(url)
|
|
46
|
+
return true unless @filter_block
|
|
47
|
+
|
|
48
|
+
@filter_block.call(url)
|
|
49
|
+
end
|
|
49
50
|
|
|
50
51
|
def failure_message_helper(negated = '')
|
|
51
|
-
verb =
|
|
52
|
+
verb = @expected_path.is_a?(Regexp) ? 'match' : 'equal'
|
|
52
53
|
"expected #{@actual_path.inspect}#{negated} to #{verb} #{@expected_path.inspect}"
|
|
53
54
|
end
|
|
54
55
|
|
|
55
56
|
def valid_keys
|
|
56
|
-
[
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def assert_valid_keys
|
|
60
|
-
super
|
|
61
|
-
if options[:url] && options[:only_path]
|
|
62
|
-
raise ArgumentError, "the :url and :only_path options cannot both be true"
|
|
63
|
-
end
|
|
57
|
+
%i[wait url ignore_query]
|
|
64
58
|
end
|
|
65
59
|
end
|
|
66
60
|
end
|
|
@@ -1,19 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Capybara
|
|
2
4
|
module Queries
|
|
3
5
|
class MatchQuery < Capybara::Queries::SelectorQuery
|
|
4
6
|
def visible
|
|
5
|
-
|
|
6
|
-
super
|
|
7
|
-
else
|
|
8
|
-
:all
|
|
9
|
-
end
|
|
7
|
+
options.key?(:visible) ? super : :all
|
|
10
8
|
end
|
|
11
9
|
|
|
12
|
-
|
|
10
|
+
private
|
|
11
|
+
|
|
12
|
+
def assert_valid_keys
|
|
13
|
+
invalid_options = @options.keys & COUNT_KEYS
|
|
14
|
+
unless invalid_options.empty?
|
|
15
|
+
raise ArgumentError, "Match queries don't support quantity options. Invalid keys - #{invalid_options.join(', ')}"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
super
|
|
19
|
+
end
|
|
13
20
|
|
|
14
21
|
def valid_keys
|
|
15
22
|
super - COUNT_KEYS
|
|
16
23
|
end
|
|
17
24
|
end
|
|
18
25
|
end
|
|
19
|
-
end
|
|
26
|
+
end
|