capybara 3.0.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 +891 -12
- data/License.txt +1 -1
- data/README.md +257 -84
- data/lib/capybara/config.rb +29 -10
- data/lib/capybara/cucumber.rb +1 -1
- data/lib/capybara/driver/base.rb +22 -4
- data/lib/capybara/driver/node.rb +38 -9
- data/lib/capybara/dsl.rb +9 -7
- data/lib/capybara/helpers.rb +57 -8
- data/lib/capybara/minitest/spec.rb +185 -84
- data/lib/capybara/minitest.rb +264 -145
- data/lib/capybara/node/actions.rb +248 -124
- data/lib/capybara/node/base.rb +35 -20
- data/lib/capybara/node/document.rb +14 -2
- data/lib/capybara/node/document_matchers.rb +13 -15
- data/lib/capybara/node/element.rb +350 -113
- data/lib/capybara/node/finders.rb +104 -82
- data/lib/capybara/node/matchers.rb +363 -157
- data/lib/capybara/node/simple.rb +54 -15
- 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 +9 -10
- data/lib/capybara/queries/base_query.rb +25 -18
- data/lib/capybara/queries/current_path_query.rb +16 -6
- data/lib/capybara/queries/match_query.rb +11 -0
- data/lib/capybara/queries/selector_query.rb +617 -104
- data/lib/capybara/queries/sibling_query.rb +9 -7
- data/lib/capybara/queries/style_query.rb +45 -0
- data/lib/capybara/queries/text_query.rb +40 -22
- data/lib/capybara/queries/title_query.rb +2 -2
- data/lib/capybara/rack_test/browser.rb +106 -31
- 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 +74 -49
- data/lib/capybara/rack_test/node.rb +120 -47
- 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 +87 -53
- data/lib/capybara/rspec/features.rb +8 -10
- 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 +142 -315
- data/lib/capybara/rspec.rb +3 -2
- data/lib/capybara/selector/builders/css_builder.rb +84 -0
- data/lib/capybara/selector/builders/xpath_builder.rb +71 -0
- data/lib/capybara/selector/css.rb +85 -8
- 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 +72 -28
- data/lib/capybara/selector/filters/base.rb +45 -2
- data/lib/capybara/selector/filters/expression_filter.rb +5 -6
- data/lib/capybara/selector/filters/locator_filter.rb +29 -0
- data/lib/capybara/selector/filters/node_filter.rb +18 -4
- data/lib/capybara/selector/regexp_disassembler.rb +211 -0
- data/lib/capybara/selector/selector.rb +89 -200
- data/lib/capybara/selector/xpath_extensions.rb +17 -0
- data/lib/capybara/selector.rb +474 -534
- 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 +270 -245
- 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 +460 -170
- 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 +58 -67
- data/lib/capybara/session/config.rb +40 -6
- data/lib/capybara/session/matchers.rb +26 -19
- data/lib/capybara/session.rb +252 -194
- 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 +126 -8
- data/lib/capybara/spec/session/accept_alert_spec.rb +11 -11
- data/lib/capybara/spec/session/accept_confirm_spec.rb +3 -3
- data/lib/capybara/spec/session/accept_prompt_spec.rb +9 -10
- data/lib/capybara/spec/session/active_element_spec.rb +31 -0
- data/lib/capybara/spec/session/all_spec.rb +135 -44
- data/lib/capybara/spec/session/ancestor_spec.rb +24 -19
- data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +67 -38
- data/lib/capybara/spec/session/{assert_current_path.rb → assert_current_path_spec.rb} +20 -18
- data/lib/capybara/spec/session/assert_selector_spec.rb +143 -0
- data/lib/capybara/spec/session/assert_style_spec.rb +26 -0
- data/lib/capybara/spec/session/{assert_text.rb → assert_text_spec.rb} +76 -52
- data/lib/capybara/spec/session/{assert_title.rb → 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 +11 -13
- data/lib/capybara/spec/session/check_spec.rb +112 -51
- data/lib/capybara/spec/session/choose_spec.rb +62 -30
- data/lib/capybara/spec/session/click_button_spec.rb +227 -161
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +49 -30
- data/lib/capybara/spec/session/click_link_spec.rb +89 -55
- data/lib/capybara/spec/session/current_scope_spec.rb +8 -8
- data/lib/capybara/spec/session/current_url_spec.rb +44 -37
- data/lib/capybara/spec/session/dismiss_confirm_spec.rb +3 -3
- data/lib/capybara/spec/session/dismiss_prompt_spec.rb +2 -2
- data/lib/capybara/spec/session/element/{assert_match_selector.rb → assert_match_selector_spec.rb} +11 -9
- data/lib/capybara/spec/session/element/match_css_spec.rb +18 -10
- data/lib/capybara/spec/session/element/match_xpath_spec.rb +8 -6
- data/lib/capybara/spec/session/element/matches_selector_spec.rb +70 -56
- data/lib/capybara/spec/session/evaluate_async_script_spec.rb +7 -7
- data/lib/capybara/spec/session/evaluate_script_spec.rb +28 -8
- data/lib/capybara/spec/session/execute_script_spec.rb +8 -7
- data/lib/capybara/spec/session/fill_in_spec.rb +110 -44
- data/lib/capybara/spec/session/find_button_spec.rb +23 -23
- data/lib/capybara/spec/session/find_by_id_spec.rb +8 -8
- data/lib/capybara/spec/session/find_field_spec.rb +33 -31
- data/lib/capybara/spec/session/find_link_spec.rb +42 -14
- data/lib/capybara/spec/session/find_spec.rb +251 -142
- data/lib/capybara/spec/session/first_spec.rb +45 -44
- data/lib/capybara/spec/session/frame/frame_title_spec.rb +6 -6
- data/lib/capybara/spec/session/frame/frame_url_spec.rb +6 -6
- data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +32 -20
- data/lib/capybara/spec/session/frame/within_frame_spec.rb +46 -19
- data/lib/capybara/spec/session/go_back_spec.rb +1 -1
- data/lib/capybara/spec/session/go_forward_spec.rb +1 -1
- data/lib/capybara/spec/session/has_all_selectors_spec.rb +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 +98 -12
- data/lib/capybara/spec/session/has_css_spec.rb +271 -137
- 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 +46 -6
- data/lib/capybara/spec/session/has_none_selectors_spec.rb +33 -31
- data/lib/capybara/spec/session/has_select_spec.rb +84 -50
- data/lib/capybara/spec/session/has_selector_spec.rb +117 -69
- 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.rb → headers_spec.rb} +1 -1
- data/lib/capybara/spec/session/html_spec.rb +13 -6
- data/lib/capybara/spec/session/matches_style_spec.rb +37 -0
- data/lib/capybara/spec/session/node_spec.rb +958 -122
- data/lib/capybara/spec/session/node_wrapper_spec.rb +15 -12
- data/lib/capybara/spec/session/refresh_spec.rb +9 -7
- data/lib/capybara/spec/session/reset_session_spec.rb +65 -37
- data/lib/capybara/spec/session/{response_code.rb → response_code_spec.rb} +1 -1
- data/lib/capybara/spec/session/save_and_open_page_spec.rb +2 -2
- data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +5 -4
- data/lib/capybara/spec/session/save_page_spec.rb +41 -38
- data/lib/capybara/spec/session/save_screenshot_spec.rb +13 -11
- data/lib/capybara/spec/session/screenshot_spec.rb +2 -2
- data/lib/capybara/spec/session/scroll_spec.rb +119 -0
- data/lib/capybara/spec/session/select_spec.rb +102 -76
- data/lib/capybara/spec/session/selectors_spec.rb +51 -18
- data/lib/capybara/spec/session/sibling_spec.rb +9 -9
- data/lib/capybara/spec/session/text_spec.rb +26 -24
- data/lib/capybara/spec/session/title_spec.rb +8 -6
- data/lib/capybara/spec/session/uncheck_spec.rb +41 -22
- data/lib/capybara/spec/session/unselect_spec.rb +37 -37
- data/lib/capybara/spec/session/visit_spec.rb +79 -53
- data/lib/capybara/spec/session/window/become_closed_spec.rb +22 -19
- data/lib/capybara/spec/session/window/current_window_spec.rb +4 -3
- data/lib/capybara/spec/session/window/open_new_window_spec.rb +4 -3
- data/lib/capybara/spec/session/window/switch_to_window_spec.rb +25 -21
- data/lib/capybara/spec/session/window/window_opened_by_spec.rb +10 -5
- data/lib/capybara/spec/session/window/window_spec.rb +88 -54
- data/lib/capybara/spec/session/window/windows_spec.rb +11 -8
- data/lib/capybara/spec/session/window/within_window_spec.rb +17 -16
- data/lib/capybara/spec/session/within_spec.rb +82 -44
- data/lib/capybara/spec/spec_helper.rb +46 -52
- data/lib/capybara/spec/test_app.rb +148 -41
- data/lib/capybara/spec/views/animated.erb +49 -0
- data/lib/capybara/spec/views/form.erb +156 -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 +46 -11
- 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 +1 -1
- data/lib/capybara/version.rb +1 -1
- data/lib/capybara/window.rb +32 -26
- data/lib/capybara.rb +128 -104
- data/spec/basic_node_spec.rb +59 -34
- data/spec/capybara_spec.rb +65 -51
- 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 +84 -55
- data/spec/filter_set_spec.rb +24 -7
- data/spec/fixtures/certificate.pem +25 -0
- data/spec/fixtures/key.pem +27 -0
- data/spec/fixtures/selenium_driver_rspec_failure.rb +5 -5
- data/spec/fixtures/selenium_driver_rspec_success.rb +5 -5
- data/spec/minitest_spec.rb +49 -5
- data/spec/minitest_spec_spec.rb +92 -62
- data/spec/per_session_config_spec.rb +6 -6
- data/spec/rack_test_spec.rb +183 -115
- data/spec/regexp_dissassembler_spec.rb +250 -0
- data/spec/result_spec.rb +99 -39
- data/spec/rspec/features_spec.rb +28 -25
- data/spec/rspec/scenarios_spec.rb +10 -6
- data/spec/rspec/shared_spec_matchers.rb +418 -364
- data/spec/rspec/views_spec.rb +4 -3
- data/spec/rspec_matchers_spec.rb +35 -10
- data/spec/rspec_spec.rb +109 -85
- data/spec/sauce_spec_chrome.rb +43 -0
- data/spec/selector_spec.rb +392 -62
- data/spec/selenium_spec_chrome.rb +183 -41
- data/spec/selenium_spec_chrome_remote.rb +96 -0
- 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 +192 -81
- data/spec/session_spec.rb +52 -16
- data/spec/shared_selenium_node.rb +79 -0
- data/spec/shared_selenium_session.rb +460 -123
- data/spec/spec_helper.rb +124 -2
- data/spec/whitespace_normalizer_spec.rb +54 -0
- data/spec/xpath_builder_spec.rb +93 -0
- metadata +344 -45
- data/.yard/templates_custom/default/class/html/selectors.erb +0 -38
- data/.yard/templates_custom/default/class/html/setup.rb +0 -17
- data/.yard/yard_extensions.rb +0 -78
- data/lib/capybara/rspec/compound.rb +0 -90
- data/lib/capybara/spec/session/assert_selector.rb +0 -149
- data/lib/capybara/spec/session/source_spec.rb +0 -0
- data/lib/capybara/spec/views/with_title.erb +0 -5
- data/spec/selenium_spec_marionette.rb +0 -143
@@ -1,29 +1,29 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'capybara/rack_test/errors'
|
4
|
+
require 'capybara/node/whitespace_normalizer'
|
5
|
+
|
3
6
|
class Capybara::RackTest::Node < Capybara::Driver::Node
|
7
|
+
include Capybara::Node::WhitespaceNormalizer
|
8
|
+
|
4
9
|
BLOCK_ELEMENTS = %w[p h1 h2 h3 h4 h5 h6 ol ul pre address blockquote dl div fieldset form hr noscript table].freeze
|
5
10
|
|
6
11
|
def all_text
|
7
|
-
native.text
|
8
|
-
.gsub(/[\u200b\u200e\u200f]/, '')
|
9
|
-
.gsub(/[\ \n\f\t\v\u2028\u2029]+/, ' ')
|
10
|
-
.gsub(/\A[[:space:]&&[^\u00a0]]+/, "")
|
11
|
-
.gsub(/[[:space:]&&[^\u00a0]]+\z/, "")
|
12
|
-
.tr("\u00a0", ' ')
|
12
|
+
normalize_spacing(native.text)
|
13
13
|
end
|
14
14
|
|
15
15
|
def visible_text
|
16
|
-
displayed_text
|
17
|
-
.gsub(/[\ \n]*\n[\ \n]*/, "\n")
|
18
|
-
.gsub(/\A[[:space:]&&[^\u00a0]]+/, "")
|
19
|
-
.gsub(/[[:space:]&&[^\u00a0]]+\z/, "")
|
20
|
-
.tr("\u00a0", ' ')
|
16
|
+
normalize_visible_spacing(displayed_text)
|
21
17
|
end
|
22
18
|
|
23
19
|
def [](name)
|
24
20
|
string_node[name]
|
25
21
|
end
|
26
22
|
|
23
|
+
def style(_styles)
|
24
|
+
raise NotImplementedError, 'The rack_test driver does not process CSS'
|
25
|
+
end
|
26
|
+
|
27
27
|
def value
|
28
28
|
string_node.value
|
29
29
|
end
|
@@ -39,6 +39,7 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
|
|
39
39
|
|
40
40
|
if radio? then set_radio(value)
|
41
41
|
elsif checkbox? then set_checkbox(value)
|
42
|
+
elsif range? then set_range(value)
|
42
43
|
elsif input_field? then set_input(value)
|
43
44
|
elsif textarea? then native['_capybara_raw_value'] = value.to_s
|
44
45
|
end
|
@@ -46,17 +47,20 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
|
|
46
47
|
|
47
48
|
def select_option
|
48
49
|
return if disabled?
|
50
|
+
|
49
51
|
deselect_options unless select_node.multiple?
|
50
|
-
native[
|
52
|
+
native['selected'] = 'selected'
|
51
53
|
end
|
52
54
|
|
53
55
|
def unselect_option
|
54
|
-
raise Capybara::UnselectNotAllowed,
|
56
|
+
raise Capybara::UnselectNotAllowed, 'Cannot unselect option from single select box.' unless select_node.multiple?
|
57
|
+
|
55
58
|
native.remove_attribute('selected')
|
56
59
|
end
|
57
60
|
|
58
|
-
def click(keys = [],
|
59
|
-
|
61
|
+
def click(keys = [], **options)
|
62
|
+
options.delete(:offset)
|
63
|
+
raise ArgumentError, 'The RackTest driver does not support click options' unless keys.empty? && options.empty?
|
60
64
|
|
61
65
|
if link?
|
62
66
|
follow_link
|
@@ -67,6 +71,8 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
|
|
67
71
|
set(!checked?)
|
68
72
|
elsif tag_name == 'label'
|
69
73
|
click_label
|
74
|
+
elsif (details = native.xpath('.//ancestor-or-self::details').last)
|
75
|
+
toggle_details(details)
|
70
76
|
end
|
71
77
|
end
|
72
78
|
|
@@ -90,26 +96,41 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
|
|
90
96
|
return true if string_node.disabled?
|
91
97
|
|
92
98
|
if %w[option optgroup].include? tag_name
|
93
|
-
find_xpath(
|
99
|
+
find_xpath(OPTION_OWNER_XPATH)[0].disabled?
|
94
100
|
else
|
95
|
-
!find_xpath(
|
101
|
+
!find_xpath(DISABLED_BY_FIELDSET_XPATH).empty?
|
96
102
|
end
|
97
103
|
end
|
98
104
|
|
105
|
+
def readonly?
|
106
|
+
# readonly attribute not valid on these input types
|
107
|
+
return false if input_field? && %w[hidden range color checkbox radio file submit image reset button].include?(type)
|
108
|
+
|
109
|
+
super
|
110
|
+
end
|
111
|
+
|
99
112
|
def path
|
100
113
|
native.path
|
101
114
|
end
|
102
115
|
|
103
|
-
def find_xpath(locator)
|
104
|
-
native.xpath(locator).map { |
|
116
|
+
def find_xpath(locator, **_hints)
|
117
|
+
native.xpath(locator).map { |el| self.class.new(driver, el) }
|
105
118
|
end
|
106
119
|
|
107
|
-
def find_css(locator)
|
108
|
-
native.css(locator, Capybara::RackTest::CSSHandlers.new).map { |
|
120
|
+
def find_css(locator, **_hints)
|
121
|
+
native.css(locator, Capybara::RackTest::CSSHandlers.new).map { |el| self.class.new(driver, el) }
|
109
122
|
end
|
110
123
|
|
111
|
-
|
112
|
-
|
124
|
+
public_instance_methods(false).each do |meth_name|
|
125
|
+
alias_method "unchecked_#{meth_name}", meth_name
|
126
|
+
private "unchecked_#{meth_name}" # rubocop:disable Style/AccessModifierDeclarations
|
127
|
+
|
128
|
+
class_eval <<~METHOD, __FILE__, __LINE__ + 1
|
129
|
+
def #{meth_name}(...)
|
130
|
+
stale_check
|
131
|
+
method(:"unchecked_#{meth_name}").call(...)
|
132
|
+
end
|
133
|
+
METHOD
|
113
134
|
end
|
114
135
|
|
115
136
|
protected
|
@@ -119,24 +140,30 @@ protected
|
|
119
140
|
if !string_node.visible?(check_ancestor)
|
120
141
|
''
|
121
142
|
elsif native.text?
|
122
|
-
native
|
123
|
-
|
124
|
-
|
143
|
+
native
|
144
|
+
.text
|
145
|
+
.delete(REMOVED_CHARACTERS)
|
146
|
+
.tr(SQUEEZED_SPACES, ' ')
|
147
|
+
.squeeze(' ')
|
125
148
|
elsif native.element?
|
126
149
|
text = native.children.map do |child|
|
127
150
|
Capybara::RackTest::Node.new(driver, child).displayed_text(check_ancestor: false)
|
128
151
|
end.join || ''
|
129
152
|
text = "\n#{text}\n" if BLOCK_ELEMENTS.include?(tag_name)
|
130
153
|
text
|
131
|
-
else
|
154
|
+
else # rubocop:disable Lint/DuplicateBranch
|
132
155
|
''
|
133
156
|
end
|
134
157
|
end
|
135
158
|
|
136
159
|
private
|
137
160
|
|
161
|
+
def stale_check
|
162
|
+
raise Capybara::RackTest::Errors::StaleElementReferenceError unless native.document == driver.dom
|
163
|
+
end
|
164
|
+
|
138
165
|
def deselect_options
|
139
|
-
select_node.find_xpath(
|
166
|
+
select_node.find_xpath('.//option[@selected]').each { |node| node.native.remove_attribute('selected') }
|
140
167
|
end
|
141
168
|
|
142
169
|
def string_node
|
@@ -161,8 +188,8 @@ private
|
|
161
188
|
end
|
162
189
|
|
163
190
|
def set_radio(_value) # rubocop:disable Naming/AccessorMethodName
|
164
|
-
other_radios_xpath = XPath.generate { |
|
165
|
-
driver.dom.xpath(other_radios_xpath).each { |node| node.remove_attribute(
|
191
|
+
other_radios_xpath = XPath.generate { |xp| xp.anywhere(:input)[xp.attr(:name) == self[:name]] }.to_s
|
192
|
+
driver.dom.xpath(other_radios_xpath).each { |node| node.remove_attribute('checked') }
|
166
193
|
native['checked'] = 'checked'
|
167
194
|
end
|
168
195
|
|
@@ -174,6 +201,14 @@ private
|
|
174
201
|
end
|
175
202
|
end
|
176
203
|
|
204
|
+
def set_range(value) # rubocop:disable Naming/AccessorMethodName
|
205
|
+
min, max, step = (native['min'] || 0).to_f, (native['max'] || 100).to_f, (native['step'] || 1).to_f
|
206
|
+
value = value.to_f
|
207
|
+
value = value.clamp(min, max)
|
208
|
+
value = (((value - min) / step).round * step) + min
|
209
|
+
native['value'] = value.clamp(min, max)
|
210
|
+
end
|
211
|
+
|
177
212
|
def set_input(value) # rubocop:disable Naming/AccessorMethodName
|
178
213
|
if text_or_password? && attribute_is_not_blank?(:maxlength)
|
179
214
|
# Browser behavior for maxlength="0" is inconsistent, so we stick with
|
@@ -181,15 +216,22 @@ private
|
|
181
216
|
value = value.to_s[0...self[:maxlength].to_i]
|
182
217
|
end
|
183
218
|
if value.is_a?(Array) # Assert multiple attribute is present
|
184
|
-
value.each do |
|
219
|
+
value.each do |val|
|
185
220
|
new_native = native.clone
|
186
221
|
new_native.remove_attribute('value')
|
187
222
|
native.add_next_sibling(new_native)
|
188
|
-
new_native['value'] =
|
223
|
+
new_native['value'] = val.to_s
|
189
224
|
end
|
190
225
|
native.remove
|
191
226
|
else
|
192
|
-
|
227
|
+
value.to_s.tap do |set_value|
|
228
|
+
if set_value.end_with?("\n") && form&.css('input, textarea')&.count == 1
|
229
|
+
native['value'] = set_value.to_s.chop
|
230
|
+
Capybara::RackTest::Form.new(driver, form).submit(self)
|
231
|
+
else
|
232
|
+
native['value'] = set_value
|
233
|
+
end
|
234
|
+
end
|
193
235
|
end
|
194
236
|
end
|
195
237
|
|
@@ -198,7 +240,7 @@ private
|
|
198
240
|
end
|
199
241
|
|
200
242
|
def follow_link
|
201
|
-
method = self[
|
243
|
+
method = self['data-method'] || self['data-turbo-method'] if driver.options[:respect_data_method]
|
202
244
|
method ||= :get
|
203
245
|
driver.follow(method, self[:href].to_s)
|
204
246
|
end
|
@@ -207,11 +249,20 @@ private
|
|
207
249
|
labelled_control = if native[:for]
|
208
250
|
find_xpath("//input[@id='#{native[:for]}']")
|
209
251
|
else
|
210
|
-
find_xpath(
|
252
|
+
find_xpath('.//input')
|
211
253
|
end.first
|
212
254
|
|
213
|
-
|
214
|
-
|
255
|
+
labelled_control.set(!labelled_control.checked?) if checkbox_or_radio?(labelled_control)
|
256
|
+
end
|
257
|
+
|
258
|
+
def toggle_details(details = nil)
|
259
|
+
details ||= native.xpath('.//ancestor-or-self::details').last
|
260
|
+
return unless details
|
261
|
+
|
262
|
+
if details.has_attribute?('open')
|
263
|
+
details.remove_attribute('open')
|
264
|
+
else
|
265
|
+
details.set_attribute('open', 'open')
|
215
266
|
end
|
216
267
|
end
|
217
268
|
|
@@ -220,32 +271,54 @@ private
|
|
220
271
|
end
|
221
272
|
|
222
273
|
def submits?
|
223
|
-
(tag_name == 'input'
|
274
|
+
(tag_name == 'input' && %w[submit image].include?(type)) || (tag_name == 'button' && [nil, 'submit'].include?(type))
|
224
275
|
end
|
225
276
|
|
226
277
|
def checkable?
|
227
|
-
tag_name == 'input'
|
278
|
+
tag_name == 'input' && %w[checkbox radio].include?(type)
|
228
279
|
end
|
229
280
|
|
230
281
|
protected
|
231
282
|
|
232
|
-
def
|
233
|
-
|
283
|
+
def checkbox_or_radio?(field = self)
|
284
|
+
field&.checkbox? || field&.radio?
|
234
285
|
end
|
235
286
|
|
236
|
-
def
|
237
|
-
|
287
|
+
def checkbox?
|
288
|
+
input_field? && type == 'checkbox'
|
238
289
|
end
|
239
290
|
|
240
291
|
def radio?
|
241
292
|
input_field? && type == 'radio'
|
242
293
|
end
|
243
294
|
|
244
|
-
def textarea?
|
245
|
-
tag_name == "textarea"
|
246
|
-
end
|
247
|
-
|
248
295
|
def text_or_password?
|
249
296
|
input_field? && (type == 'text' || type == 'password')
|
250
297
|
end
|
298
|
+
|
299
|
+
def input_field?
|
300
|
+
tag_name == 'input'
|
301
|
+
end
|
302
|
+
|
303
|
+
def textarea?
|
304
|
+
tag_name == 'textarea'
|
305
|
+
end
|
306
|
+
|
307
|
+
def range?
|
308
|
+
input_field? && type == 'range'
|
309
|
+
end
|
310
|
+
|
311
|
+
OPTION_OWNER_XPATH = XPath.parent(:optgroup, :select, :datalist).to_s.freeze
|
312
|
+
DISABLED_BY_FIELDSET_XPATH = XPath.generate do |x|
|
313
|
+
x.parent(:fieldset)[
|
314
|
+
XPath.attr(:disabled)
|
315
|
+
] + x.ancestor[
|
316
|
+
~x.self(:legend) |
|
317
|
+
x.preceding_sibling(:legend)
|
318
|
+
][
|
319
|
+
x.parent(:fieldset)[
|
320
|
+
x.attr(:disabled)
|
321
|
+
]
|
322
|
+
]
|
323
|
+
end.to_s.freeze
|
251
324
|
end
|
data/lib/capybara/rails.rb
CHANGED
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Capybara
|
4
|
+
# @api private
|
5
|
+
class RegistrationContainer
|
6
|
+
def names
|
7
|
+
@registered.keys
|
8
|
+
end
|
9
|
+
|
10
|
+
def [](name)
|
11
|
+
@registered[name]
|
12
|
+
end
|
13
|
+
|
14
|
+
def []=(name, value)
|
15
|
+
Capybara::Helpers.warn 'DEPRECATED: Directly setting drivers/servers is deprecated, please use Capybara.register_driver/register_server instead'
|
16
|
+
@registered[name] = value
|
17
|
+
end
|
18
|
+
|
19
|
+
def method_missing(method_name, ...)
|
20
|
+
if @registered.respond_to?(method_name)
|
21
|
+
Capybara::Helpers.warn "DEPRECATED: Calling '#{method_name}' on the drivers/servers container is deprecated without replacement"
|
22
|
+
return @registered.public_send(method_name, ...)
|
23
|
+
end
|
24
|
+
super
|
25
|
+
end
|
26
|
+
|
27
|
+
def respond_to_missing?(method_name, include_all)
|
28
|
+
@registered.respond_to?(method_name) || super
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def initialize
|
34
|
+
@registered = {}
|
35
|
+
end
|
36
|
+
|
37
|
+
def register(name, block)
|
38
|
+
@registered[name] = block
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Capybara.register_driver :rack_test do |app|
|
4
|
+
Capybara::RackTest::Driver.new(app)
|
5
|
+
end
|
6
|
+
|
7
|
+
Capybara.register_driver :selenium do |app|
|
8
|
+
Capybara::Selenium::Driver.new(app)
|
9
|
+
end
|
10
|
+
|
11
|
+
Capybara.register_driver :selenium_headless do |app|
|
12
|
+
version = Capybara::Selenium::Driver.load_selenium
|
13
|
+
options_key = Capybara::Selenium::Driver::CAPS_VERSION.satisfied_by?(version) ? :capabilities : :options
|
14
|
+
browser_options = Selenium::WebDriver::Firefox::Options.new.tap do |opts|
|
15
|
+
opts.add_argument '-headless'
|
16
|
+
end
|
17
|
+
Capybara::Selenium::Driver.new(app, **{ :browser => :firefox, options_key => browser_options })
|
18
|
+
end
|
19
|
+
|
20
|
+
Capybara.register_driver :selenium_chrome do |app|
|
21
|
+
version = Capybara::Selenium::Driver.load_selenium
|
22
|
+
options_key = Capybara::Selenium::Driver::CAPS_VERSION.satisfied_by?(version) ? :capabilities : :options
|
23
|
+
browser_options = Selenium::WebDriver::Chrome::Options.new.tap do |opts|
|
24
|
+
# Workaround https://bugs.chromium.org/p/chromedriver/issues/detail?id=2650&q=load&sort=-id&colspec=ID%20Status%20Pri%20Owner%20Summary
|
25
|
+
opts.add_argument('--disable-site-isolation-trials')
|
26
|
+
end
|
27
|
+
|
28
|
+
Capybara::Selenium::Driver.new(app, **{ :browser => :chrome, options_key => browser_options })
|
29
|
+
end
|
30
|
+
|
31
|
+
Capybara.register_driver :selenium_chrome_headless do |app|
|
32
|
+
version = Capybara::Selenium::Driver.load_selenium
|
33
|
+
options_key = Capybara::Selenium::Driver::CAPS_VERSION.satisfied_by?(version) ? :capabilities : :options
|
34
|
+
browser_options = Selenium::WebDriver::Chrome::Options.new.tap do |opts|
|
35
|
+
opts.add_argument('--headless=new')
|
36
|
+
opts.add_argument('--disable-gpu') if Gem.win_platform?
|
37
|
+
# Workaround https://bugs.chromium.org/p/chromedriver/issues/detail?id=2650&q=load&sort=-id&colspec=ID%20Status%20Pri%20Owner%20Summary
|
38
|
+
opts.add_argument('--disable-site-isolation-trials')
|
39
|
+
end
|
40
|
+
|
41
|
+
Capybara::Selenium::Driver.new(app, **{ :browser => :chrome, options_key => browser_options })
|
42
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Puma
|
4
|
+
module MiniSSL
|
5
|
+
class Socket
|
6
|
+
def read_nonblock(size, *_)
|
7
|
+
wait_states = %i[wait_readable wait_writable]
|
8
|
+
|
9
|
+
loop do
|
10
|
+
output = engine_read_all
|
11
|
+
return output if output
|
12
|
+
|
13
|
+
data = @socket.read_nonblock(size, exception: false)
|
14
|
+
raise IO::EAGAINWaitReadable if wait_states.include? data
|
15
|
+
return nil if data.nil?
|
16
|
+
|
17
|
+
@engine.inject(data)
|
18
|
+
output = engine_read_all
|
19
|
+
|
20
|
+
return output if output
|
21
|
+
|
22
|
+
while (neg_data = @engine.extract)
|
23
|
+
@socket.write neg_data
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Capybara.register_server :default do |app, port, _host|
|
4
|
+
Capybara.run_default_server(app, port)
|
5
|
+
end
|
6
|
+
|
7
|
+
Capybara.register_server :webrick do |app, port, host, **options|
|
8
|
+
base_class = begin
|
9
|
+
require 'rack/handler/webrick'
|
10
|
+
Rack
|
11
|
+
rescue LoadError
|
12
|
+
# Rack 3 separated out the webrick handle - no way test currently in Capybaras automated
|
13
|
+
# tests due to Sinatra not yet supporting Rack 3 - experimental
|
14
|
+
require 'rackup/handler/webrick'
|
15
|
+
Rackup
|
16
|
+
end
|
17
|
+
options = { Host: host, Port: port, AccessLog: [], Logger: WEBrick::Log.new(nil, 0) }.merge(options)
|
18
|
+
base_class::Handler::WEBrick.run(app, **options)
|
19
|
+
end
|
20
|
+
|
21
|
+
Capybara.register_server :puma do |app, port, host, **options| # rubocop:disable Metrics/BlockLength
|
22
|
+
begin
|
23
|
+
require 'rackup'
|
24
|
+
rescue LoadError # rubocop:disable Lint/SuppressedException
|
25
|
+
end
|
26
|
+
begin
|
27
|
+
require 'rack/handler/puma'
|
28
|
+
rescue LoadError
|
29
|
+
raise LoadError, 'Capybara is unable to load `puma` for its server, please add `puma` to your project or specify a different server via something like `Capybara.server = :webrick`.'
|
30
|
+
end
|
31
|
+
puma_rack_handler = defined?(Rackup::Handler::Puma) ? Rackup::Handler::Puma : Rack::Handler::Puma
|
32
|
+
|
33
|
+
unless puma_rack_handler.respond_to?(:config)
|
34
|
+
raise LoadError, 'Capybara requires `puma` version 3.8.0 or higher, please upgrade `puma` or register and specify your own server block'
|
35
|
+
end
|
36
|
+
|
37
|
+
# If we just run the Puma Rack handler it installs signal handlers which prevent us from being able to interrupt tests.
|
38
|
+
# Therefore construct and run the Server instance ourselves.
|
39
|
+
# puma_rack_handler.run(app, { Host: host, Port: port, Threads: "0:4", workers: 0, daemon: false }.merge(options))
|
40
|
+
default_options = { Host: host, Port: port, Threads: '0:4', workers: 0, daemon: false }
|
41
|
+
options = default_options.merge(options)
|
42
|
+
|
43
|
+
conf = puma_rack_handler.config(app, options)
|
44
|
+
conf.clamp
|
45
|
+
|
46
|
+
puma_ver = Gem::Version.new(Puma::Const::PUMA_VERSION)
|
47
|
+
require_relative 'patches/puma_ssl' if Gem::Requirement.new('>=4.0.0', '< 4.1.0').satisfied_by?(puma_ver)
|
48
|
+
|
49
|
+
logger = (defined?(Puma::LogWriter) ? Puma::LogWriter : Puma::Events).then do |cls|
|
50
|
+
conf.options[:Silent] ? cls.strings : cls.stdio
|
51
|
+
end
|
52
|
+
conf.options[:log_writer] = logger
|
53
|
+
|
54
|
+
logger.log 'Capybara starting Puma...'
|
55
|
+
logger.log "* Version #{Puma::Const::PUMA_VERSION}, codename: #{Puma::Const::CODE_NAME}"
|
56
|
+
logger.log "* Min threads: #{conf.options[:min_threads]}, max threads: #{conf.options[:max_threads]}"
|
57
|
+
|
58
|
+
Puma::Server.new(
|
59
|
+
conf.app,
|
60
|
+
defined?(Puma::LogWriter) ? nil : logger,
|
61
|
+
conf.options
|
62
|
+
).tap do |s|
|
63
|
+
s.binder.parse conf.options[:binds], (s.log_writer rescue s.events) # rubocop:disable Style/RescueModifier
|
64
|
+
s.min_threads, s.max_threads = conf.options[:min_threads], conf.options[:max_threads] if s.respond_to? :min_threads=
|
65
|
+
end.run.join
|
66
|
+
end
|