capybara 3.3.0 → 3.40.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardopts +1 -0
- data/History.md +803 -13
- data/License.txt +1 -1
- data/README.md +257 -84
- data/lib/capybara/config.rb +25 -9
- data/lib/capybara/cucumber.rb +1 -1
- data/lib/capybara/driver/base.rb +17 -3
- data/lib/capybara/driver/node.rb +31 -6
- data/lib/capybara/dsl.rb +9 -7
- data/lib/capybara/helpers.rb +31 -7
- data/lib/capybara/minitest/spec.rb +180 -88
- data/lib/capybara/minitest.rb +262 -149
- data/lib/capybara/node/actions.rb +202 -116
- data/lib/capybara/node/base.rb +34 -19
- data/lib/capybara/node/document.rb +14 -2
- data/lib/capybara/node/document_matchers.rb +10 -12
- data/lib/capybara/node/element.rb +269 -115
- data/lib/capybara/node/finders.rb +99 -77
- data/lib/capybara/node/matchers.rb +327 -151
- data/lib/capybara/node/simple.rb +48 -13
- 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 +8 -9
- data/lib/capybara/queries/base_query.rb +23 -16
- data/lib/capybara/queries/current_path_query.rb +16 -6
- data/lib/capybara/queries/match_query.rb +1 -0
- data/lib/capybara/queries/selector_query.rb +587 -130
- data/lib/capybara/queries/sibling_query.rb +8 -6
- data/lib/capybara/queries/style_query.rb +6 -2
- data/lib/capybara/queries/text_query.rb +28 -14
- data/lib/capybara/queries/title_query.rb +2 -2
- data/lib/capybara/rack_test/browser.rb +92 -25
- data/lib/capybara/rack_test/driver.rb +16 -7
- data/lib/capybara/rack_test/errors.rb +6 -0
- data/lib/capybara/rack_test/form.rb +68 -41
- data/lib/capybara/rack_test/node.rb +106 -39
- data/lib/capybara/rails.rb +1 -1
- 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 +75 -52
- data/lib/capybara/rspec/features.rb +7 -7
- data/lib/capybara/rspec/matcher_proxies.rb +39 -18
- 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 +141 -339
- data/lib/capybara/rspec.rb +2 -0
- 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 +27 -25
- 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 +1 -0
- data/lib/capybara/selector/filter_set.rb +73 -25
- data/lib/capybara/selector/filters/base.rb +24 -5
- data/lib/capybara/selector/filters/expression_filter.rb +3 -3
- data/lib/capybara/selector/filters/locator_filter.rb +29 -0
- data/lib/capybara/selector/filters/node_filter.rb +16 -2
- data/lib/capybara/selector/regexp_disassembler.rb +211 -0
- data/lib/capybara/selector/selector.rb +85 -348
- data/lib/capybara/selector/xpath_extensions.rb +17 -0
- data/lib/capybara/selector.rb +474 -447
- 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 +255 -143
- data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +93 -11
- 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 +436 -134
- 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 +56 -19
- data/lib/capybara/server/checker.rb +9 -3
- data/lib/capybara/server/middleware.rb +28 -12
- data/lib/capybara/server.rb +33 -10
- data/lib/capybara/session/config.rb +34 -10
- data/lib/capybara/session/matchers.rb +23 -16
- data/lib/capybara/session.rb +230 -170
- 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 +121 -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 +127 -40
- 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_spec.rb +21 -18
- data/lib/capybara/spec/session/assert_selector_spec.rb +52 -58
- data/lib/capybara/spec/session/assert_style_spec.rb +7 -7
- data/lib/capybara/spec/session/assert_text_spec.rb +74 -50
- data/lib/capybara/spec/session/assert_title_spec.rb +12 -12
- data/lib/capybara/spec/session/attach_file_spec.rb +126 -72
- data/lib/capybara/spec/session/body_spec.rb +6 -6
- data/lib/capybara/spec/session/check_spec.rb +102 -47
- data/lib/capybara/spec/session/choose_spec.rb +58 -32
- data/lib/capybara/spec/session/click_button_spec.rb +219 -163
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +49 -23
- data/lib/capybara/spec/session/click_link_spec.rb +77 -54
- data/lib/capybara/spec/session/current_scope_spec.rb +8 -8
- data/lib/capybara/spec/session/current_url_spec.rb +38 -29
- 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_spec.rb +8 -8
- data/lib/capybara/spec/session/element/match_css_spec.rb +16 -10
- data/lib/capybara/spec/session/element/match_xpath_spec.rb +6 -6
- data/lib/capybara/spec/session/element/matches_selector_spec.rb +68 -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 +101 -46
- data/lib/capybara/spec/session/find_button_spec.rb +23 -23
- data/lib/capybara/spec/session/find_by_id_spec.rb +7 -7
- data/lib/capybara/spec/session/find_field_spec.rb +32 -30
- data/lib/capybara/spec/session/find_link_spec.rb +31 -21
- data/lib/capybara/spec/session/find_spec.rb +244 -141
- data/lib/capybara/spec/session/first_spec.rb +43 -43
- data/lib/capybara/spec/session/frame/frame_title_spec.rb +5 -5
- data/lib/capybara/spec/session/frame/frame_url_spec.rb +5 -5
- data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +30 -18
- data/lib/capybara/spec/session/frame/within_frame_spec.rb +45 -18
- 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 +23 -23
- 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 +94 -13
- data/lib/capybara/spec/session/has_css_spec.rb +272 -132
- data/lib/capybara/spec/session/has_current_path_spec.rb +50 -35
- data/lib/capybara/spec/session/has_element_spec.rb +47 -0
- data/lib/capybara/spec/session/has_field_spec.rb +137 -58
- data/lib/capybara/spec/session/has_link_spec.rb +44 -4
- data/lib/capybara/spec/session/has_none_selectors_spec.rb +31 -31
- data/lib/capybara/spec/session/has_select_spec.rb +84 -50
- data/lib/capybara/spec/session/has_selector_spec.rb +111 -71
- data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
- data/lib/capybara/spec/session/has_table_spec.rb +181 -4
- data/lib/capybara/spec/session/has_text_spec.rb +101 -53
- 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_spec.rb +1 -1
- data/lib/capybara/spec/session/html_spec.rb +13 -6
- data/lib/capybara/spec/session/matches_style_spec.rb +37 -0
- data/lib/capybara/spec/session/node_spec.rb +894 -142
- data/lib/capybara/spec/session/node_wrapper_spec.rb +10 -7
- data/lib/capybara/spec/session/refresh_spec.rb +9 -7
- data/lib/capybara/spec/session/reset_session_spec.rb +63 -35
- data/lib/capybara/spec/session/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 +2 -2
- data/lib/capybara/spec/session/save_page_spec.rb +37 -37
- data/lib/capybara/spec/session/save_screenshot_spec.rb +10 -10
- 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 +85 -85
- data/lib/capybara/spec/session/selectors_spec.rb +49 -18
- data/lib/capybara/spec/session/sibling_spec.rb +9 -9
- data/lib/capybara/spec/session/text_spec.rb +25 -24
- data/lib/capybara/spec/session/title_spec.rb +7 -6
- data/lib/capybara/spec/session/uncheck_spec.rb +33 -21
- data/lib/capybara/spec/session/unselect_spec.rb +37 -37
- data/lib/capybara/spec/session/visit_spec.rb +68 -49
- data/lib/capybara/spec/session/window/become_closed_spec.rb +20 -17
- data/lib/capybara/spec/session/window/current_window_spec.rb +1 -1
- data/lib/capybara/spec/session/window/switch_to_window_spec.rb +20 -16
- data/lib/capybara/spec/session/window/window_opened_by_spec.rb +6 -2
- data/lib/capybara/spec/session/window/window_spec.rb +62 -63
- data/lib/capybara/spec/session/window/windows_spec.rb +5 -1
- data/lib/capybara/spec/session/window/within_window_spec.rb +14 -14
- data/lib/capybara/spec/session/within_spec.rb +79 -42
- data/lib/capybara/spec/spec_helper.rb +41 -53
- data/lib/capybara/spec/test_app.rb +132 -43
- data/lib/capybara/spec/views/animated.erb +49 -0
- data/lib/capybara/spec/views/form.erb +139 -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 +67 -0
- data/lib/capybara/spec/views/with_animation.erb +39 -4
- 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 +37 -9
- 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 +26 -5
- data/lib/capybara/spec/views/with_jstree.erb +26 -0
- data/lib/capybara/spec/views/with_namespace.erb +1 -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 +1 -1
- data/lib/capybara/version.rb +1 -1
- data/lib/capybara/window.rb +19 -25
- data/lib/capybara.rb +126 -111
- data/spec/basic_node_spec.rb +59 -34
- data/spec/capybara_spec.rb +56 -44
- data/spec/counter_spec.rb +35 -0
- data/spec/css_builder_spec.rb +101 -0
- data/spec/css_splitter_spec.rb +8 -8
- data/spec/dsl_spec.rb +79 -52
- data/spec/filter_set_spec.rb +9 -9
- 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 +45 -7
- data/spec/minitest_spec_spec.rb +87 -64
- data/spec/per_session_config_spec.rb +6 -6
- data/spec/rack_test_spec.rb +172 -116
- data/spec/regexp_dissassembler_spec.rb +250 -0
- data/spec/result_spec.rb +80 -72
- data/spec/rspec/features_spec.rb +21 -16
- data/spec/rspec/scenarios_spec.rb +10 -6
- data/spec/rspec/shared_spec_matchers.rb +407 -365
- data/spec/rspec/views_spec.rb +3 -3
- data/spec/rspec_matchers_spec.rb +35 -10
- data/spec/rspec_spec.rb +63 -41
- data/spec/sauce_spec_chrome.rb +43 -0
- data/spec/selector_spec.rb +334 -89
- data/spec/selenium_spec_chrome.rb +176 -62
- data/spec/selenium_spec_chrome_remote.rb +54 -14
- data/spec/selenium_spec_edge.rb +41 -8
- data/spec/selenium_spec_firefox.rb +228 -0
- data/spec/selenium_spec_firefox_remote.rb +94 -0
- data/spec/selenium_spec_ie.rb +129 -11
- data/spec/selenium_spec_safari.rb +162 -0
- data/spec/server_spec.rb +171 -97
- data/spec/session_spec.rb +34 -18
- data/spec/shared_selenium_node.rb +79 -0
- data/spec/shared_selenium_session.rb +344 -80
- data/spec/spec_helper.rb +124 -2
- data/spec/whitespace_normalizer_spec.rb +54 -0
- data/spec/xpath_builder_spec.rb +93 -0
- metadata +326 -28
- data/lib/capybara/rspec/compound.rb +0 -94
- data/lib/capybara/selenium/driver_specializations/marionette_driver.rb +0 -31
- data/lib/capybara/selenium/nodes/marionette_node.rb +0 -31
- data/lib/capybara/spec/session/has_style_spec.rb +0 -25
- 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 -167
data/lib/capybara/node/simple.rb
CHANGED
@@ -28,8 +28,9 @@ module Capybara
|
|
28
28
|
#
|
29
29
|
# @return [String] The text of the element
|
30
30
|
#
|
31
|
-
def text(_type = nil)
|
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
|
##
|
@@ -78,11 +79,11 @@ module Capybara
|
|
78
79
|
if tag_name == 'textarea'
|
79
80
|
native['_capybara_raw_value']
|
80
81
|
elsif tag_name == 'select'
|
82
|
+
selected_options = find_xpath('.//option[@selected]')
|
81
83
|
if multiple?
|
82
|
-
|
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
88
|
elsif tag_name == 'input' && %w[radio checkbox].include?(native[:type])
|
88
89
|
native[:value] || 'on'
|
@@ -99,14 +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
|
-
!
|
108
|
+
!find_xpath(VISIBILITY_XPATH)
|
107
109
|
else
|
108
110
|
# No need for an xpath if only checking the current element
|
109
|
-
!(native.
|
111
|
+
!(native.key?('hidden') ||
|
112
|
+
/display:\s?none/.match?(native[:style] || '') ||
|
113
|
+
%w[script head style].include?(tag_name))
|
110
114
|
end
|
111
115
|
end
|
112
116
|
|
@@ -126,7 +130,8 @@ module Capybara
|
|
126
130
|
#
|
127
131
|
# @return [Boolean] Whether the element is disabled
|
128
132
|
def disabled?
|
129
|
-
native.has_attribute?('disabled')
|
133
|
+
native.has_attribute?('disabled') &&
|
134
|
+
%w[button input select textarea optgroup option menuitem fieldset].include?(tag_name)
|
130
135
|
end
|
131
136
|
|
132
137
|
##
|
@@ -143,11 +148,15 @@ module Capybara
|
|
143
148
|
native.has_attribute?('multiple')
|
144
149
|
end
|
145
150
|
|
151
|
+
def readonly?
|
152
|
+
native.has_attribute?('readonly')
|
153
|
+
end
|
154
|
+
|
146
155
|
def synchronize(_seconds = nil)
|
147
156
|
yield # simple nodes don't need to wait
|
148
157
|
end
|
149
158
|
|
150
|
-
def allow_reload!
|
159
|
+
def allow_reload!(*)
|
151
160
|
# no op
|
152
161
|
end
|
153
162
|
|
@@ -163,12 +172,12 @@ module Capybara
|
|
163
172
|
end
|
164
173
|
|
165
174
|
# @api private
|
166
|
-
def find_css(css)
|
175
|
+
def find_css(css, **_options)
|
167
176
|
native.css(css)
|
168
177
|
end
|
169
178
|
|
170
179
|
# @api private
|
171
|
-
def find_xpath(xpath)
|
180
|
+
def find_xpath(xpath, **_options)
|
172
181
|
native.xpath(xpath)
|
173
182
|
end
|
174
183
|
|
@@ -176,6 +185,32 @@ module Capybara
|
|
176
185
|
def session_options
|
177
186
|
Capybara.session_options
|
178
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
|
179
214
|
end
|
180
215
|
end
|
181
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
|
@@ -6,24 +6,23 @@ module Capybara
|
|
6
6
|
# @api private
|
7
7
|
def resolve_for(node, exact = nil)
|
8
8
|
@child_node = node
|
9
|
+
|
9
10
|
node.synchronize do
|
10
|
-
|
11
|
-
|
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)
|
12
17
|
end
|
13
18
|
end
|
14
19
|
|
15
|
-
def description
|
20
|
+
def description(applied = false) # rubocop:disable Style/OptionalBooleanParameter
|
16
21
|
child_query = @child_node&.instance_variable_get(:@query)
|
17
22
|
desc = super
|
18
23
|
desc += " that is an ancestor of #{child_query.description}" if child_query
|
19
24
|
desc
|
20
25
|
end
|
21
|
-
|
22
|
-
private
|
23
|
-
|
24
|
-
def valid_keys
|
25
|
-
super - COUNT_KEYS
|
26
|
-
end
|
27
26
|
end
|
28
27
|
end
|
29
28
|
end
|
@@ -23,9 +23,9 @@ module Capybara
|
|
23
23
|
|
24
24
|
def self.wait(options, default = Capybara.default_max_wait_time)
|
25
25
|
# if no value or nil for the :wait option is passed it should default to the default
|
26
|
-
|
27
|
-
|
28
|
-
|
26
|
+
wait = options.fetch(:wait, nil)
|
27
|
+
wait = default if wait.nil?
|
28
|
+
wait || 0
|
29
29
|
end
|
30
30
|
|
31
31
|
##
|
@@ -51,6 +51,7 @@ module Capybara
|
|
51
51
|
return false if options[:maximum] && (Integer(options[:maximum]) < count)
|
52
52
|
return false if options[:minimum] && (Integer(options[:minimum]) > count)
|
53
53
|
return false if options[:between] && !options[:between].include?(count)
|
54
|
+
|
54
55
|
true
|
55
56
|
end
|
56
57
|
|
@@ -69,30 +70,36 @@ module Capybara
|
|
69
70
|
private
|
70
71
|
|
71
72
|
def count_specified?
|
72
|
-
COUNT_KEYS.any? { |
|
73
|
+
COUNT_KEYS.any? { |key| options.key? key }
|
73
74
|
end
|
74
75
|
|
75
76
|
def count_message
|
76
|
-
message = +
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
elsif
|
84
|
-
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}"
|
85
88
|
end
|
86
89
|
message
|
87
90
|
end
|
88
91
|
|
92
|
+
def occurrences(count)
|
93
|
+
"#{count} #{Capybara::Helpers.declension('time', 'times', count)}"
|
94
|
+
end
|
95
|
+
|
89
96
|
def assert_valid_keys
|
90
97
|
invalid_keys = @options.keys - valid_keys
|
91
98
|
return if invalid_keys.empty?
|
92
99
|
|
93
|
-
invalid_names = invalid_keys.map(&:inspect).join(
|
94
|
-
valid_names = valid_keys.map(&:inspect).join(
|
95
|
-
raise ArgumentError, "
|
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}"
|
96
103
|
end
|
97
104
|
end
|
98
105
|
end
|
@@ -6,26 +6,30 @@ module Capybara
|
|
6
6
|
# @api private
|
7
7
|
module Queries
|
8
8
|
class CurrentPathQuery < BaseQuery
|
9
|
-
def initialize(expected_path, **options)
|
9
|
+
def initialize(expected_path, **options, &optional_filter_block)
|
10
10
|
super(options)
|
11
11
|
@expected_path = expected_path
|
12
12
|
@options = {
|
13
|
-
url: !@expected_path.is_a?(Regexp) && !::Addressable::URI.parse(@expected_path ||
|
13
|
+
url: !@expected_path.is_a?(Regexp) && !::Addressable::URI.parse(@expected_path || '').hostname.nil?,
|
14
14
|
ignore_query: false
|
15
15
|
}.merge(options)
|
16
|
+
@filter_block = optional_filter_block
|
16
17
|
assert_valid_keys
|
17
18
|
end
|
18
19
|
|
19
20
|
def resolves_for?(session)
|
20
21
|
uri = ::Addressable::URI.parse(session.current_url)
|
21
|
-
|
22
|
-
|
22
|
+
@actual_path = (options[:ignore_query] ? uri&.omit(:query) : uri).then do |u|
|
23
|
+
options[:url] ? u&.to_s : u&.request_uri
|
24
|
+
end
|
23
25
|
|
24
|
-
if @expected_path.is_a? Regexp
|
25
|
-
@actual_path.to_s.match(@expected_path)
|
26
|
+
res = if @expected_path.is_a? Regexp
|
27
|
+
@actual_path.to_s.match?(@expected_path)
|
26
28
|
else
|
27
29
|
::Addressable::URI.parse(@expected_path) == ::Addressable::URI.parse(@actual_path)
|
28
30
|
end
|
31
|
+
|
32
|
+
res && matches_filter_block?(uri)
|
29
33
|
end
|
30
34
|
|
31
35
|
def failure_message
|
@@ -38,6 +42,12 @@ module Capybara
|
|
38
42
|
|
39
43
|
private
|
40
44
|
|
45
|
+
def matches_filter_block?(url)
|
46
|
+
return true unless @filter_block
|
47
|
+
|
48
|
+
@filter_block.call(url)
|
49
|
+
end
|
50
|
+
|
41
51
|
def failure_message_helper(negated = '')
|
42
52
|
verb = @expected_path.is_a?(Regexp) ? 'match' : 'equal'
|
43
53
|
"expected #{@actual_path.inspect}#{negated} to #{verb} #{@expected_path.inspect}"
|