capybara 2.7.0 → 3.35.3
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 +5 -5
- data/.yardopts +1 -0
- data/History.md +1147 -11
- data/License.txt +1 -1
- data/README.md +252 -131
- data/lib/capybara/config.rb +92 -0
- data/lib/capybara/cucumber.rb +3 -3
- data/lib/capybara/driver/base.rb +52 -21
- data/lib/capybara/driver/node.rb +48 -14
- data/lib/capybara/dsl.rb +16 -9
- data/lib/capybara/helpers.rb +72 -81
- data/lib/capybara/minitest/spec.rb +267 -0
- data/lib/capybara/minitest.rb +385 -0
- data/lib/capybara/node/actions.rb +337 -89
- data/lib/capybara/node/base.rb +50 -32
- data/lib/capybara/node/document.rb +19 -3
- data/lib/capybara/node/document_matchers.rb +22 -24
- data/lib/capybara/node/element.rb +388 -125
- data/lib/capybara/node/finders.rb +231 -121
- data/lib/capybara/node/matchers.rb +503 -217
- data/lib/capybara/node/simple.rb +64 -27
- data/lib/capybara/queries/ancestor_query.rb +27 -0
- data/lib/capybara/queries/base_query.rb +87 -11
- data/lib/capybara/queries/current_path_query.rb +24 -24
- data/lib/capybara/queries/match_query.rb +15 -10
- data/lib/capybara/queries/selector_query.rb +675 -81
- data/lib/capybara/queries/sibling_query.rb +26 -0
- data/lib/capybara/queries/style_query.rb +45 -0
- data/lib/capybara/queries/text_query.rb +88 -20
- data/lib/capybara/queries/title_query.rb +9 -11
- data/lib/capybara/rack_test/browser.rb +63 -39
- data/lib/capybara/rack_test/css_handlers.rb +6 -4
- data/lib/capybara/rack_test/driver.rb +26 -16
- data/lib/capybara/rack_test/errors.rb +6 -0
- data/lib/capybara/rack_test/form.rb +73 -58
- data/lib/capybara/rack_test/node.rb +187 -67
- data/lib/capybara/rails.rb +4 -8
- data/lib/capybara/registration_container.rb +44 -0
- data/lib/capybara/registrations/drivers.rb +42 -0
- data/lib/capybara/registrations/patches/puma_ssl.rb +29 -0
- data/lib/capybara/registrations/servers.rb +45 -0
- data/lib/capybara/result.rb +142 -14
- data/lib/capybara/rspec/features.rb +17 -42
- data/lib/capybara/rspec/matcher_proxies.rb +82 -0
- data/lib/capybara/rspec/matchers/base.rb +111 -0
- data/lib/capybara/rspec/matchers/become_closed.rb +33 -0
- data/lib/capybara/rspec/matchers/compound.rb +88 -0
- data/lib/capybara/rspec/matchers/count_sugar.rb +37 -0
- data/lib/capybara/rspec/matchers/have_ancestor.rb +28 -0
- data/lib/capybara/rspec/matchers/have_current_path.rb +29 -0
- data/lib/capybara/rspec/matchers/have_selector.rb +77 -0
- data/lib/capybara/rspec/matchers/have_sibling.rb +27 -0
- data/lib/capybara/rspec/matchers/have_text.rb +33 -0
- data/lib/capybara/rspec/matchers/have_title.rb +29 -0
- data/lib/capybara/rspec/matchers/match_selector.rb +27 -0
- data/lib/capybara/rspec/matchers/match_style.rb +43 -0
- data/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
- data/lib/capybara/rspec/matchers.rb +143 -244
- data/lib/capybara/rspec.rb +10 -12
- 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 +102 -0
- data/lib/capybara/selector/definition/button.rb +63 -0
- data/lib/capybara/selector/definition/checkbox.rb +26 -0
- data/lib/capybara/selector/definition/css.rb +10 -0
- data/lib/capybara/selector/definition/datalist_input.rb +35 -0
- data/lib/capybara/selector/definition/datalist_option.rb +25 -0
- data/lib/capybara/selector/definition/element.rb +28 -0
- data/lib/capybara/selector/definition/field.rb +40 -0
- data/lib/capybara/selector/definition/fieldset.rb +14 -0
- data/lib/capybara/selector/definition/file_field.rb +13 -0
- data/lib/capybara/selector/definition/fillable_field.rb +33 -0
- data/lib/capybara/selector/definition/frame.rb +17 -0
- data/lib/capybara/selector/definition/id.rb +6 -0
- data/lib/capybara/selector/definition/label.rb +62 -0
- data/lib/capybara/selector/definition/link.rb +54 -0
- data/lib/capybara/selector/definition/link_or_button.rb +16 -0
- data/lib/capybara/selector/definition/option.rb +27 -0
- data/lib/capybara/selector/definition/radio_button.rb +27 -0
- data/lib/capybara/selector/definition/select.rb +81 -0
- data/lib/capybara/selector/definition/table.rb +109 -0
- data/lib/capybara/selector/definition/table_row.rb +21 -0
- data/lib/capybara/selector/definition/xpath.rb +5 -0
- data/lib/capybara/selector/definition.rb +278 -0
- data/lib/capybara/selector/filter.rb +3 -46
- data/lib/capybara/selector/filter_set.rb +124 -0
- data/lib/capybara/selector/filters/base.rb +77 -0
- data/lib/capybara/selector/filters/expression_filter.rb +22 -0
- data/lib/capybara/selector/filters/locator_filter.rb +29 -0
- data/lib/capybara/selector/filters/node_filter.rb +31 -0
- data/lib/capybara/selector/regexp_disassembler.rb +214 -0
- data/lib/capybara/selector/selector.rb +155 -0
- data/lib/capybara/selector/xpath_extensions.rb +17 -0
- data/lib/capybara/selector.rb +232 -369
- 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 +380 -142
- data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +117 -0
- data/lib/capybara/selenium/driver_specializations/edge_driver.rb +124 -0
- data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +89 -0
- data/lib/capybara/selenium/driver_specializations/internet_explorer_driver.rb +26 -0
- data/lib/capybara/selenium/driver_specializations/safari_driver.rb +24 -0
- data/lib/capybara/selenium/extensions/file_input_click_emulation.rb +34 -0
- data/lib/capybara/selenium/extensions/find.rb +110 -0
- data/lib/capybara/selenium/extensions/html5_drag.rb +228 -0
- data/lib/capybara/selenium/extensions/modifier_keys_stack.rb +28 -0
- data/lib/capybara/selenium/extensions/scroll.rb +76 -0
- data/lib/capybara/selenium/logger_suppressor.rb +40 -0
- data/lib/capybara/selenium/node.rb +528 -97
- data/lib/capybara/selenium/nodes/chrome_node.rb +137 -0
- data/lib/capybara/selenium/nodes/edge_node.rb +104 -0
- data/lib/capybara/selenium/nodes/firefox_node.rb +136 -0
- data/lib/capybara/selenium/nodes/ie_node.rb +22 -0
- data/lib/capybara/selenium/nodes/safari_node.rb +118 -0
- data/lib/capybara/selenium/patches/action_pauser.rb +26 -0
- data/lib/capybara/selenium/patches/atoms.rb +18 -0
- data/lib/capybara/selenium/patches/is_displayed.rb +16 -0
- data/lib/capybara/selenium/patches/logs.rb +45 -0
- data/lib/capybara/selenium/patches/pause_duration_fix.rb +9 -0
- data/lib/capybara/selenium/patches/persistent_client.rb +20 -0
- data/lib/capybara/server/animation_disabler.rb +63 -0
- data/lib/capybara/server/checker.rb +44 -0
- data/lib/capybara/server/middleware.rb +71 -0
- data/lib/capybara/server.rb +74 -71
- data/lib/capybara/session/config.rb +126 -0
- data/lib/capybara/session/matchers.rb +44 -27
- data/lib/capybara/session.rb +500 -297
- data/lib/capybara/spec/fixtures/no_extension +1 -0
- 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 +168 -14
- data/lib/capybara/spec/session/accept_alert_spec.rb +37 -14
- data/lib/capybara/spec/session/accept_confirm_spec.rb +7 -6
- data/lib/capybara/spec/session/accept_prompt_spec.rb +38 -10
- data/lib/capybara/spec/session/all_spec.rb +179 -59
- data/lib/capybara/spec/session/ancestor_spec.rb +88 -0
- data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +140 -0
- data/lib/capybara/spec/session/assert_current_path_spec.rb +75 -0
- data/lib/capybara/spec/session/assert_selector_spec.rb +143 -0
- data/lib/capybara/spec/session/assert_style_spec.rb +26 -0
- data/lib/capybara/spec/session/assert_text_spec.rb +258 -0
- data/lib/capybara/spec/session/assert_title_spec.rb +93 -0
- data/lib/capybara/spec/session/attach_file_spec.rb +154 -48
- data/lib/capybara/spec/session/body_spec.rb +12 -13
- data/lib/capybara/spec/session/check_spec.rb +168 -41
- data/lib/capybara/spec/session/choose_spec.rb +75 -23
- data/lib/capybara/spec/session/click_button_spec.rb +243 -175
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +57 -32
- data/lib/capybara/spec/session/click_link_spec.rb +100 -53
- data/lib/capybara/spec/session/current_scope_spec.rb +11 -10
- data/lib/capybara/spec/session/current_url_spec.rb +61 -35
- data/lib/capybara/spec/session/dismiss_confirm_spec.rb +7 -7
- data/lib/capybara/spec/session/dismiss_prompt_spec.rb +5 -4
- data/lib/capybara/spec/session/element/{assert_match_selector.rb → assert_match_selector_spec.rb} +13 -6
- data/lib/capybara/spec/session/element/match_css_spec.rb +21 -7
- data/lib/capybara/spec/session/element/match_xpath_spec.rb +9 -7
- data/lib/capybara/spec/session/element/matches_selector_spec.rb +91 -34
- data/lib/capybara/spec/session/evaluate_async_script_spec.rb +23 -0
- data/lib/capybara/spec/session/evaluate_script_spec.rb +45 -3
- data/lib/capybara/spec/session/execute_script_spec.rb +24 -4
- data/lib/capybara/spec/session/fill_in_spec.rb +166 -64
- data/lib/capybara/spec/session/find_button_spec.rb +37 -18
- data/lib/capybara/spec/session/find_by_id_spec.rb +10 -9
- data/lib/capybara/spec/session/find_field_spec.rb +57 -34
- data/lib/capybara/spec/session/find_link_spec.rb +47 -10
- data/lib/capybara/spec/session/find_spec.rb +290 -144
- data/lib/capybara/spec/session/first_spec.rb +91 -48
- data/lib/capybara/spec/session/frame/frame_title_spec.rb +23 -0
- data/lib/capybara/spec/session/frame/frame_url_spec.rb +23 -0
- data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +116 -0
- data/lib/capybara/spec/session/frame/within_frame_spec.rb +112 -0
- data/lib/capybara/spec/session/go_back_spec.rb +3 -2
- data/lib/capybara/spec/session/go_forward_spec.rb +3 -2
- data/lib/capybara/spec/session/has_all_selectors_spec.rb +69 -0
- data/lib/capybara/spec/session/has_ancestor_spec.rb +46 -0
- data/lib/capybara/spec/session/has_any_selectors_spec.rb +25 -0
- data/lib/capybara/spec/session/has_button_spec.rb +76 -19
- data/lib/capybara/spec/session/has_css_spec.rb +277 -131
- data/lib/capybara/spec/session/has_current_path_spec.rb +98 -26
- data/lib/capybara/spec/session/has_field_spec.rb +177 -107
- data/lib/capybara/spec/session/has_link_spec.rb +13 -12
- data/lib/capybara/spec/session/has_none_selectors_spec.rb +78 -0
- data/lib/capybara/spec/session/has_select_spec.rb +191 -95
- data/lib/capybara/spec/session/has_selector_spec.rb +128 -64
- data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
- data/lib/capybara/spec/session/has_table_spec.rb +172 -5
- data/lib/capybara/spec/session/has_text_spec.rb +126 -60
- data/lib/capybara/spec/session/has_title_spec.rb +35 -12
- data/lib/capybara/spec/session/has_xpath_spec.rb +74 -53
- 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 +35 -0
- data/lib/capybara/spec/session/node_spec.rb +1028 -131
- data/lib/capybara/spec/session/node_wrapper_spec.rb +39 -0
- data/lib/capybara/spec/session/refresh_spec.rb +34 -0
- data/lib/capybara/spec/session/reset_session_spec.rb +75 -34
- 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 +11 -15
- 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 +117 -0
- data/lib/capybara/spec/session/select_spec.rb +112 -85
- data/lib/capybara/spec/session/selectors_spec.rb +71 -8
- data/lib/capybara/spec/session/sibling_spec.rb +52 -0
- data/lib/capybara/spec/session/text_spec.rb +38 -23
- data/lib/capybara/spec/session/title_spec.rb +17 -5
- data/lib/capybara/spec/session/uncheck_spec.rb +71 -12
- data/lib/capybara/spec/session/unselect_spec.rb +44 -43
- data/lib/capybara/spec/session/visit_spec.rb +99 -32
- data/lib/capybara/spec/session/window/become_closed_spec.rb +33 -29
- 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 +39 -30
- data/lib/capybara/spec/session/window/window_opened_by_spec.rb +17 -10
- data/lib/capybara/spec/session/window/window_spec.rb +121 -73
- data/lib/capybara/spec/session/window/windows_spec.rb +12 -10
- data/lib/capybara/spec/session/window/within_window_spec.rb +52 -82
- data/lib/capybara/spec/session/within_spec.rb +76 -43
- data/lib/capybara/spec/spec_helper.rb +67 -33
- data/lib/capybara/spec/test_app.rb +85 -36
- data/lib/capybara/spec/views/animated.erb +49 -0
- data/lib/capybara/spec/views/buttons.erb +1 -1
- data/lib/capybara/spec/views/fieldsets.erb +1 -1
- data/lib/capybara/spec/views/form.erb +227 -20
- data/lib/capybara/spec/views/frame_child.erb +10 -2
- data/lib/capybara/spec/views/frame_one.erb +2 -1
- data/lib/capybara/spec/views/frame_parent.erb +2 -2
- data/lib/capybara/spec/views/frame_two.erb +1 -1
- data/lib/capybara/spec/views/header_links.erb +1 -1
- data/lib/capybara/spec/views/host_links.erb +1 -1
- data/lib/capybara/spec/views/initial_alert.erb +10 -0
- data/lib/capybara/spec/views/obscured.erb +47 -0
- data/lib/capybara/spec/views/offset.erb +32 -0
- data/lib/capybara/spec/views/path.erb +1 -1
- 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/postback.erb +1 -1
- data/lib/capybara/spec/views/react.erb +45 -0
- data/lib/capybara/spec/views/scroll.erb +20 -0
- data/lib/capybara/spec/views/spatial.erb +31 -0
- data/lib/capybara/spec/views/tables.erb +69 -2
- data/lib/capybara/spec/views/with_animation.erb +82 -0
- data/lib/capybara/spec/views/with_base_tag.erb +1 -1
- data/lib/capybara/spec/views/with_count.erb +1 -1
- data/lib/capybara/spec/views/with_dragula.erb +24 -0
- data/lib/capybara/spec/views/with_fixed_header_footer.erb +17 -0
- data/lib/capybara/spec/views/with_hover.erb +7 -1
- data/lib/capybara/spec/views/with_hover1.erb +10 -0
- data/lib/capybara/spec/views/with_html.erb +100 -10
- data/lib/capybara/spec/views/with_html5_svg.erb +20 -0
- data/lib/capybara/spec/views/with_html_entities.erb +1 -1
- data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
- data/lib/capybara/spec/views/with_js.erb +49 -3
- data/lib/capybara/spec/views/with_jstree.erb +26 -0
- data/lib/capybara/spec/views/with_namespace.erb +20 -0
- data/lib/capybara/spec/views/with_scope.erb +1 -1
- data/lib/capybara/spec/views/with_scope_other.erb +6 -0
- data/lib/capybara/spec/views/with_simple_html.erb +1 -1
- data/lib/capybara/spec/views/with_sortable_js.erb +21 -0
- data/lib/capybara/spec/views/with_title.erb +1 -1
- data/lib/capybara/spec/views/with_unload_alert.erb +3 -1
- data/lib/capybara/spec/views/with_windows.erb +7 -1
- data/lib/capybara/spec/views/within_frames.erb +6 -3
- data/lib/capybara/version.rb +2 -1
- data/lib/capybara/window.rb +39 -21
- data/lib/capybara.rb +208 -186
- data/spec/basic_node_spec.rb +52 -39
- data/spec/capybara_spec.rb +72 -50
- data/spec/css_builder_spec.rb +101 -0
- data/spec/css_splitter_spec.rb +38 -0
- data/spec/dsl_spec.rb +81 -61
- data/spec/filter_set_spec.rb +46 -0
- data/spec/fixtures/capybara.csv +1 -0
- data/spec/fixtures/certificate.pem +25 -0
- data/spec/fixtures/key.pem +27 -0
- data/spec/fixtures/selenium_driver_rspec_failure.rb +7 -3
- data/spec/fixtures/selenium_driver_rspec_success.rb +7 -3
- data/spec/minitest_spec.rb +164 -0
- data/spec/minitest_spec_spec.rb +162 -0
- data/spec/per_session_config_spec.rb +68 -0
- data/spec/rack_test_spec.rb +189 -96
- data/spec/regexp_dissassembler_spec.rb +250 -0
- data/spec/result_spec.rb +143 -13
- data/spec/rspec/features_spec.rb +38 -32
- data/spec/rspec/scenarios_spec.rb +9 -7
- data/spec/rspec/shared_spec_matchers.rb +959 -0
- data/spec/rspec/views_spec.rb +9 -3
- data/spec/rspec_matchers_spec.rb +62 -0
- data/spec/rspec_spec.rb +127 -30
- data/spec/sauce_spec_chrome.rb +43 -0
- data/spec/selector_spec.rb +458 -37
- data/spec/selenium_spec_chrome.rb +196 -9
- data/spec/selenium_spec_chrome_remote.rb +100 -0
- data/spec/selenium_spec_edge.rb +47 -0
- data/spec/selenium_spec_firefox.rb +210 -0
- data/spec/selenium_spec_firefox_remote.rb +80 -0
- data/spec/selenium_spec_ie.rb +150 -0
- data/spec/selenium_spec_safari.rb +148 -0
- data/spec/server_spec.rb +200 -101
- data/spec/session_spec.rb +91 -0
- data/spec/shared_selenium_node.rb +83 -0
- data/spec/shared_selenium_session.rb +558 -0
- data/spec/spec_helper.rb +94 -2
- data/spec/xpath_builder_spec.rb +93 -0
- metadata +420 -60
- data/lib/capybara/query.rb +0 -7
- data/lib/capybara/spec/session/assert_current_path.rb +0 -60
- data/lib/capybara/spec/session/assert_selector.rb +0 -148
- data/lib/capybara/spec/session/assert_text.rb +0 -196
- data/lib/capybara/spec/session/assert_title.rb +0 -70
- data/lib/capybara/spec/session/source_spec.rb +0 -0
- data/lib/capybara/spec/session/within_frame_spec.rb +0 -53
- data/spec/rspec/matchers_spec.rb +0 -827
- data/spec/selenium_spec.rb +0 -151
|
@@ -1,85 +1,50 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
class Capybara::RackTest::Form < Capybara::RackTest::Node
|
|
3
4
|
# This only needs to inherit from Rack::Test::UploadedFile because Rack::Test checks for
|
|
4
5
|
# the class specifically when determining whether to construct the request as multipart.
|
|
5
6
|
# That check should be based solely on the form element's 'enctype' attribute value,
|
|
6
7
|
# which should probably be provided to Rack::Test in its non-GET request methods.
|
|
7
8
|
class NilUploadedFile < Rack::Test::UploadedFile
|
|
8
|
-
def initialize
|
|
9
|
-
@empty_file = Tempfile.new(
|
|
9
|
+
def initialize # rubocop:disable Lint/MissingSuper
|
|
10
|
+
@empty_file = Tempfile.new('nil_uploaded_file')
|
|
10
11
|
@empty_file.close
|
|
11
12
|
end
|
|
12
13
|
|
|
13
|
-
def original_filename;
|
|
14
|
-
def content_type;
|
|
14
|
+
def original_filename; ''; end
|
|
15
|
+
def content_type; 'application/octet-stream'; end
|
|
15
16
|
def path; @empty_file.path; end
|
|
17
|
+
def size; 0; end
|
|
18
|
+
def read; ''; end
|
|
16
19
|
end
|
|
17
20
|
|
|
18
21
|
def params(button)
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
xpath
|
|
24
|
-
xpath=xpath.union(x.anywhere(*form_element_types).where(x.attr(:form) == native[:id])) if native[:id]
|
|
25
|
-
xpath.where(~x.attr(:disabled))
|
|
22
|
+
form_element_types = %i[input select textarea button]
|
|
23
|
+
form_elements_xpath = XPath.generate do |xp|
|
|
24
|
+
xpath = xp.descendant(*form_element_types).where(!xp.attr(:form))
|
|
25
|
+
xpath += xp.anywhere(*form_element_types).where(xp.attr(:form) == native[:id]) if native[:id]
|
|
26
|
+
xpath.where(!xp.attr(:disabled))
|
|
26
27
|
end.to_s
|
|
27
28
|
|
|
28
|
-
native.xpath(form_elements_xpath).
|
|
29
|
+
form_elements = native.xpath(form_elements_xpath).reject { |el| submitter?(el) && (el != button.native) }
|
|
30
|
+
|
|
31
|
+
form_elements.each_with_object(make_params) do |field, params|
|
|
29
32
|
case field.name
|
|
30
|
-
when 'input'
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
node=Capybara::RackTest::Node.new(self.driver, field)
|
|
34
|
-
merge_param!(params, field['name'].to_s, node.value.to_s)
|
|
35
|
-
end
|
|
36
|
-
elsif %w(submit image).include? field['type']
|
|
37
|
-
# TO DO identify the click button here (in document order, rather
|
|
38
|
-
# than leaving until the end of the params)
|
|
39
|
-
elsif field['type'] =='file'
|
|
40
|
-
if multipart?
|
|
41
|
-
file = \
|
|
42
|
-
if (value = field['value']).to_s.empty?
|
|
43
|
-
NilUploadedFile.new
|
|
44
|
-
else
|
|
45
|
-
content_type = MIME::Types.type_for(value).first.to_s
|
|
46
|
-
Rack::Test::UploadedFile.new(value, content_type)
|
|
47
|
-
end
|
|
48
|
-
merge_param!(params, field['name'].to_s, file)
|
|
49
|
-
else
|
|
50
|
-
merge_param!(params, field['name'].to_s, File.basename(field['value'].to_s))
|
|
51
|
-
end
|
|
52
|
-
else
|
|
53
|
-
merge_param!(params, field['name'].to_s, field['value'].to_s)
|
|
54
|
-
end
|
|
55
|
-
when 'select'
|
|
56
|
-
if field['multiple'] == 'multiple'
|
|
57
|
-
options = field.xpath(".//option[@selected]")
|
|
58
|
-
options.each do |option|
|
|
59
|
-
merge_param!(params, field['name'].to_s, (option['value'] || option.text).to_s)
|
|
60
|
-
end
|
|
61
|
-
else
|
|
62
|
-
option = field.xpath(".//option[@selected]").first
|
|
63
|
-
option ||= field.xpath('.//option').first
|
|
64
|
-
merge_param!(params, field['name'].to_s, (option['value'] || option.text).to_s) if option
|
|
65
|
-
end
|
|
66
|
-
when 'textarea'
|
|
67
|
-
merge_param!(params, field['name'].to_s, field.text.to_s.gsub(/\n/, "\r\n"))
|
|
33
|
+
when 'input', 'button' then add_input_param(field, params)
|
|
34
|
+
when 'select' then add_select_param(field, params)
|
|
35
|
+
when 'textarea' then add_textarea_param(field, params)
|
|
68
36
|
end
|
|
69
|
-
end
|
|
70
|
-
merge_param!(params, button[:name], button[:value] || "") if button[:name]
|
|
71
|
-
|
|
72
|
-
params.to_params_hash
|
|
37
|
+
end.to_params_hash
|
|
73
38
|
end
|
|
74
39
|
|
|
75
40
|
def submit(button)
|
|
76
|
-
action =
|
|
77
|
-
method =
|
|
41
|
+
action = button&.[]('formaction') || native['action']
|
|
42
|
+
method = button&.[]('formmethod') || request_method
|
|
78
43
|
driver.submit(method, action.to_s, params(button))
|
|
79
44
|
end
|
|
80
45
|
|
|
81
46
|
def multipart?
|
|
82
|
-
self[:enctype] ==
|
|
47
|
+
self[:enctype] == 'multipart/form-data'
|
|
83
48
|
end
|
|
84
49
|
|
|
85
50
|
private
|
|
@@ -91,10 +56,11 @@ private
|
|
|
91
56
|
end
|
|
92
57
|
|
|
93
58
|
def request_method
|
|
94
|
-
self[:method]
|
|
59
|
+
/post/i.match?(self[:method] || '') ? :post : :get
|
|
95
60
|
end
|
|
96
61
|
|
|
97
62
|
def merge_param!(params, key, value)
|
|
63
|
+
key = key.to_s
|
|
98
64
|
if Rack::Utils.respond_to?(:default_query_parser)
|
|
99
65
|
Rack::Utils.default_query_parser.normalize_params(params, key, value, Rack::Utils.param_depth_limit)
|
|
100
66
|
else
|
|
@@ -109,4 +75,53 @@ private
|
|
|
109
75
|
ParamsHash.new
|
|
110
76
|
end
|
|
111
77
|
end
|
|
78
|
+
|
|
79
|
+
def add_input_param(field, params)
|
|
80
|
+
name, value = field['name'].to_s, field['value'].to_s
|
|
81
|
+
return if name.empty?
|
|
82
|
+
|
|
83
|
+
value = case field['type']
|
|
84
|
+
when 'radio', 'checkbox'
|
|
85
|
+
return unless field['checked']
|
|
86
|
+
|
|
87
|
+
Capybara::RackTest::Node.new(driver, field).value.to_s
|
|
88
|
+
when 'file'
|
|
89
|
+
if multipart?
|
|
90
|
+
file_to_upload(value)
|
|
91
|
+
else
|
|
92
|
+
File.basename(value)
|
|
93
|
+
end
|
|
94
|
+
else
|
|
95
|
+
value
|
|
96
|
+
end
|
|
97
|
+
merge_param!(params, name, value)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def file_to_upload(filename)
|
|
101
|
+
if filename.empty?
|
|
102
|
+
NilUploadedFile.new
|
|
103
|
+
else
|
|
104
|
+
mime_info = MiniMime.lookup_by_filename(filename)
|
|
105
|
+
Rack::Test::UploadedFile.new(filename, mime_info&.content_type&.to_s)
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def add_select_param(field, params)
|
|
110
|
+
if field.has_attribute?('multiple')
|
|
111
|
+
field.xpath('.//option[@selected]').each do |option|
|
|
112
|
+
merge_param!(params, field['name'], (option['value'] || option.text).to_s)
|
|
113
|
+
end
|
|
114
|
+
else
|
|
115
|
+
option = field.xpath('.//option[@selected]').first || field.xpath('.//option').first
|
|
116
|
+
merge_param!(params, field['name'], (option['value'] || option.text).to_s) if option
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def add_textarea_param(field, params)
|
|
121
|
+
merge_param!(params, field['name'], field['_capybara_raw_value'].to_s.gsub(/\n/, "\r\n"))
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def submitter?(el)
|
|
125
|
+
(%w[submit image].include? el['type']) || (el.name == 'button')
|
|
126
|
+
end
|
|
112
127
|
end
|
|
@@ -1,65 +1,84 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'capybara/rack_test/errors'
|
|
4
|
+
|
|
2
5
|
class Capybara::RackTest::Node < Capybara::Driver::Node
|
|
6
|
+
BLOCK_ELEMENTS = %w[p h1 h2 h3 h4 h5 h6 ol ul pre address blockquote dl div fieldset form hr noscript table].freeze
|
|
7
|
+
|
|
3
8
|
def all_text
|
|
4
|
-
|
|
9
|
+
native.text
|
|
10
|
+
.gsub(/[\u200b\u200e\u200f]/, '')
|
|
11
|
+
.gsub(/[\ \n\f\t\v\u2028\u2029]+/, ' ')
|
|
12
|
+
.gsub(/\A[[:space:]&&[^\u00a0]]+/, '')
|
|
13
|
+
.gsub(/[[:space:]&&[^\u00a0]]+\z/, '')
|
|
14
|
+
.tr("\u00a0", ' ')
|
|
5
15
|
end
|
|
6
16
|
|
|
7
17
|
def visible_text
|
|
8
|
-
|
|
18
|
+
displayed_text.squeeze(' ')
|
|
19
|
+
.gsub(/[\ \n]*\n[\ \n]*/, "\n")
|
|
20
|
+
.gsub(/\A[[:space:]&&[^\u00a0]]+/, '')
|
|
21
|
+
.gsub(/[[:space:]&&[^\u00a0]]+\z/, '')
|
|
22
|
+
.tr("\u00a0", ' ')
|
|
9
23
|
end
|
|
10
24
|
|
|
11
25
|
def [](name)
|
|
12
26
|
string_node[name]
|
|
13
27
|
end
|
|
14
28
|
|
|
29
|
+
def style(_styles)
|
|
30
|
+
raise NotImplementedError, 'The rack_test driver does not process CSS'
|
|
31
|
+
end
|
|
32
|
+
|
|
15
33
|
def value
|
|
16
34
|
string_node.value
|
|
17
35
|
end
|
|
18
36
|
|
|
19
|
-
def set(value)
|
|
20
|
-
if
|
|
21
|
-
|
|
37
|
+
def set(value, **options)
|
|
38
|
+
return if disabled? || readonly?
|
|
39
|
+
|
|
40
|
+
warn "Options passed to Node#set but the RackTest driver doesn't support any - ignoring" unless options.empty?
|
|
41
|
+
|
|
42
|
+
if value.is_a?(Array) && !multiple?
|
|
43
|
+
raise TypeError, "Value cannot be an Array when 'multiple' attribute is not present. Not a #{value.class}"
|
|
22
44
|
end
|
|
23
45
|
|
|
24
|
-
if radio?
|
|
25
|
-
|
|
26
|
-
elsif
|
|
27
|
-
|
|
28
|
-
elsif
|
|
29
|
-
set_input(value)
|
|
30
|
-
elsif textarea?
|
|
31
|
-
if self[:readonly]
|
|
32
|
-
warn "Attempt to set readonly element with value: #{value} \n * This will raise an exception in a future version of Capybara"
|
|
33
|
-
else
|
|
34
|
-
native.content = value.to_s
|
|
35
|
-
end
|
|
46
|
+
if radio? then set_radio(value)
|
|
47
|
+
elsif checkbox? then set_checkbox(value)
|
|
48
|
+
elsif range? then set_range(value)
|
|
49
|
+
elsif input_field? then set_input(value)
|
|
50
|
+
elsif textarea? then native['_capybara_raw_value'] = value.to_s
|
|
36
51
|
end
|
|
37
52
|
end
|
|
38
53
|
|
|
39
54
|
def select_option
|
|
40
55
|
return if disabled?
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
native["selected"] = 'selected'
|
|
56
|
+
|
|
57
|
+
deselect_options unless select_node.multiple?
|
|
58
|
+
native['selected'] = 'selected'
|
|
45
59
|
end
|
|
46
60
|
|
|
47
61
|
def unselect_option
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
end
|
|
62
|
+
raise Capybara::UnselectNotAllowed, 'Cannot unselect option from single select box.' unless select_node.multiple?
|
|
63
|
+
|
|
51
64
|
native.remove_attribute('selected')
|
|
52
65
|
end
|
|
53
66
|
|
|
54
|
-
def click
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
67
|
+
def click(keys = [], **options)
|
|
68
|
+
options.delete(:offset)
|
|
69
|
+
raise ArgumentError, 'The RackTest driver does not support click options' unless keys.empty? && options.empty?
|
|
70
|
+
|
|
71
|
+
if link?
|
|
72
|
+
follow_link
|
|
73
|
+
elsif submits?
|
|
61
74
|
associated_form = form
|
|
62
75
|
Capybara::RackTest::Form.new(driver, associated_form).submit(self) if associated_form
|
|
76
|
+
elsif checkable?
|
|
77
|
+
set(!checked?)
|
|
78
|
+
elsif tag_name == 'label'
|
|
79
|
+
click_label
|
|
80
|
+
elsif (details = native.xpath('.//ancestor-or-self::details').last)
|
|
81
|
+
toggle_details(details)
|
|
63
82
|
end
|
|
64
83
|
end
|
|
65
84
|
|
|
@@ -80,10 +99,12 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
|
|
|
80
99
|
end
|
|
81
100
|
|
|
82
101
|
def disabled?
|
|
83
|
-
if
|
|
84
|
-
|
|
102
|
+
return true if string_node.disabled?
|
|
103
|
+
|
|
104
|
+
if %w[option optgroup].include? tag_name
|
|
105
|
+
find_xpath(OPTION_OWNER_XPATH)[0].disabled?
|
|
85
106
|
else
|
|
86
|
-
|
|
107
|
+
!find_xpath(DISABLED_BY_FIELDSET_XPATH).empty?
|
|
87
108
|
end
|
|
88
109
|
end
|
|
89
110
|
|
|
@@ -91,12 +112,31 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
|
|
|
91
112
|
native.path
|
|
92
113
|
end
|
|
93
114
|
|
|
94
|
-
def find_xpath(locator)
|
|
95
|
-
native.xpath(locator).map { |
|
|
115
|
+
def find_xpath(locator, **_hints)
|
|
116
|
+
native.xpath(locator).map { |el| self.class.new(driver, el) }
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def find_css(locator, **_hints)
|
|
120
|
+
native.css(locator, Capybara::RackTest::CSSHandlers.new).map { |el| self.class.new(driver, el) }
|
|
96
121
|
end
|
|
97
122
|
|
|
98
|
-
|
|
99
|
-
|
|
123
|
+
public_instance_methods(false).each do |meth_name|
|
|
124
|
+
alias_method "unchecked_#{meth_name}", meth_name
|
|
125
|
+
private "unchecked_#{meth_name}" # rubocop:disable Style/AccessModifierDeclarations
|
|
126
|
+
|
|
127
|
+
if RUBY_VERSION >= '2.7'
|
|
128
|
+
class_eval <<~METHOD, __FILE__, __LINE__ + 1
|
|
129
|
+
def #{meth_name}(...)
|
|
130
|
+
stale_check
|
|
131
|
+
method(:"unchecked_#{meth_name}").call(...)
|
|
132
|
+
end
|
|
133
|
+
METHOD
|
|
134
|
+
else
|
|
135
|
+
define_method meth_name do |*args|
|
|
136
|
+
stale_check
|
|
137
|
+
send("unchecked_#{meth_name}", *args)
|
|
138
|
+
end
|
|
139
|
+
end
|
|
100
140
|
end
|
|
101
141
|
|
|
102
142
|
def ==(other)
|
|
@@ -105,15 +145,20 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
|
|
|
105
145
|
|
|
106
146
|
protected
|
|
107
147
|
|
|
108
|
-
|
|
109
|
-
|
|
148
|
+
# @api private
|
|
149
|
+
def displayed_text(check_ancestor: true)
|
|
150
|
+
if !string_node.visible?(check_ancestor)
|
|
110
151
|
''
|
|
111
152
|
elsif native.text?
|
|
112
153
|
native.text
|
|
154
|
+
.gsub(/[\u200b\u200e\u200f]/, '')
|
|
155
|
+
.gsub(/[\ \n\f\t\v\u2028\u2029]+/, ' ')
|
|
113
156
|
elsif native.element?
|
|
114
|
-
native.children.map do |child|
|
|
115
|
-
Capybara::RackTest::Node.new(driver, child).
|
|
116
|
-
end.join
|
|
157
|
+
text = native.children.map do |child|
|
|
158
|
+
Capybara::RackTest::Node.new(driver, child).displayed_text(check_ancestor: false)
|
|
159
|
+
end.join || ''
|
|
160
|
+
text = "\n#{text}\n" if BLOCK_ELEMENTS.include?(tag_name)
|
|
161
|
+
text
|
|
117
162
|
else
|
|
118
163
|
''
|
|
119
164
|
end
|
|
@@ -121,13 +166,21 @@ protected
|
|
|
121
166
|
|
|
122
167
|
private
|
|
123
168
|
|
|
169
|
+
def stale_check
|
|
170
|
+
raise Capybara::RackTest::Errors::StaleElementReferenceError unless native.document == driver.dom
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def deselect_options
|
|
174
|
+
select_node.find_xpath('.//option[@selected]').each { |node| node.native.remove_attribute('selected') }
|
|
175
|
+
end
|
|
176
|
+
|
|
124
177
|
def string_node
|
|
125
178
|
@string_node ||= Capybara::Node::Simple.new(native)
|
|
126
179
|
end
|
|
127
180
|
|
|
128
181
|
# a reference to the select node if this is an option node
|
|
129
182
|
def select_node
|
|
130
|
-
find_xpath('./ancestor::select').first
|
|
183
|
+
find_xpath('./ancestor::select[1]').first
|
|
131
184
|
end
|
|
132
185
|
|
|
133
186
|
def type
|
|
@@ -136,19 +189,19 @@ private
|
|
|
136
189
|
|
|
137
190
|
def form
|
|
138
191
|
if native[:form]
|
|
139
|
-
native.xpath("//form[@id='#{native[:form]}']")
|
|
192
|
+
native.xpath("//form[@id='#{native[:form]}']")
|
|
140
193
|
else
|
|
141
|
-
native.ancestors('form')
|
|
142
|
-
end
|
|
194
|
+
native.ancestors('form')
|
|
195
|
+
end.first
|
|
143
196
|
end
|
|
144
197
|
|
|
145
|
-
def set_radio(
|
|
146
|
-
other_radios_xpath = XPath.generate { |
|
|
147
|
-
driver.dom.xpath(other_radios_xpath).each { |node| node.remove_attribute(
|
|
198
|
+
def set_radio(_value) # rubocop:disable Naming/AccessorMethodName
|
|
199
|
+
other_radios_xpath = XPath.generate { |xp| xp.anywhere(:input)[xp.attr(:name) == self[:name]] }.to_s
|
|
200
|
+
driver.dom.xpath(other_radios_xpath).each { |node| node.remove_attribute('checked') }
|
|
148
201
|
native['checked'] = 'checked'
|
|
149
202
|
end
|
|
150
203
|
|
|
151
|
-
def set_checkbox(value)
|
|
204
|
+
def set_checkbox(value) # rubocop:disable Naming/AccessorMethodName
|
|
152
205
|
if value && !native['checked']
|
|
153
206
|
native['checked'] = 'checked'
|
|
154
207
|
elsif !value && native['checked']
|
|
@@ -156,26 +209,30 @@ private
|
|
|
156
209
|
end
|
|
157
210
|
end
|
|
158
211
|
|
|
159
|
-
def
|
|
212
|
+
def set_range(value) # rubocop:disable Naming/AccessorMethodName
|
|
213
|
+
min, max, step = (native['min'] || 0).to_f, (native['max'] || 100).to_f, (native['step'] || 1).to_f
|
|
214
|
+
value = value.to_f
|
|
215
|
+
value = value.clamp(min, max)
|
|
216
|
+
value = ((value - min) / step).round * step + min
|
|
217
|
+
native['value'] = value.clamp(min, max)
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def set_input(value) # rubocop:disable Naming/AccessorMethodName
|
|
160
221
|
if text_or_password? && attribute_is_not_blank?(:maxlength)
|
|
161
222
|
# Browser behavior for maxlength="0" is inconsistent, so we stick with
|
|
162
223
|
# Firefox, allowing no input
|
|
163
224
|
value = value.to_s[0...self[:maxlength].to_i]
|
|
164
225
|
end
|
|
165
|
-
if Array
|
|
166
|
-
value.each do |
|
|
226
|
+
if value.is_a?(Array) # Assert multiple attribute is present
|
|
227
|
+
value.each do |val|
|
|
167
228
|
new_native = native.clone
|
|
168
229
|
new_native.remove_attribute('value')
|
|
169
230
|
native.add_next_sibling(new_native)
|
|
170
|
-
new_native['value'] =
|
|
231
|
+
new_native['value'] = val.to_s
|
|
171
232
|
end
|
|
172
233
|
native.remove
|
|
173
234
|
else
|
|
174
|
-
|
|
175
|
-
warn "Attempt to set readonly element with value: #{value} \n *This will raise an exception in a future version of Capybara"
|
|
176
|
-
else
|
|
177
|
-
native['value'] = value.to_s
|
|
178
|
-
end
|
|
235
|
+
native['value'] = value.to_s
|
|
179
236
|
end
|
|
180
237
|
end
|
|
181
238
|
|
|
@@ -183,23 +240,86 @@ private
|
|
|
183
240
|
self[attribute] && !self[attribute].empty?
|
|
184
241
|
end
|
|
185
242
|
|
|
186
|
-
def
|
|
187
|
-
|
|
243
|
+
def follow_link
|
|
244
|
+
method = self['data-method'] if driver.options[:respect_data_method]
|
|
245
|
+
method ||= :get
|
|
246
|
+
driver.follow(method, self[:href].to_s)
|
|
188
247
|
end
|
|
189
248
|
|
|
190
|
-
def
|
|
191
|
-
|
|
249
|
+
def click_label
|
|
250
|
+
labelled_control = if native[:for]
|
|
251
|
+
find_xpath("//input[@id='#{native[:for]}']")
|
|
252
|
+
else
|
|
253
|
+
find_xpath('.//input')
|
|
254
|
+
end.first
|
|
255
|
+
|
|
256
|
+
labelled_control.set(!labelled_control.checked?) if checkbox_or_radio?(labelled_control)
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def toggle_details(details = nil)
|
|
260
|
+
details ||= native.xpath('.//ancestor-or-self::details').last
|
|
261
|
+
return unless details
|
|
262
|
+
|
|
263
|
+
if details.has_attribute?('open')
|
|
264
|
+
details.remove_attribute('open')
|
|
265
|
+
else
|
|
266
|
+
details.set_attribute('open', 'open')
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
def link?
|
|
271
|
+
tag_name == 'a' && !self[:href].nil?
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
def submits?
|
|
275
|
+
(tag_name == 'input' && %w[submit image].include?(type)) || (tag_name == 'button' && [nil, 'submit'].include?(type))
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
def checkable?
|
|
279
|
+
tag_name == 'input' && %w[checkbox radio].include?(type)
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
protected
|
|
283
|
+
|
|
284
|
+
def checkbox_or_radio?(field = self)
|
|
285
|
+
field&.checkbox? || field&.radio?
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
def checkbox?
|
|
289
|
+
input_field? && type == 'checkbox'
|
|
192
290
|
end
|
|
193
291
|
|
|
194
292
|
def radio?
|
|
195
293
|
input_field? && type == 'radio'
|
|
196
294
|
end
|
|
197
295
|
|
|
296
|
+
def text_or_password?
|
|
297
|
+
input_field? && (type == 'text' || type == 'password')
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
def input_field?
|
|
301
|
+
tag_name == 'input'
|
|
302
|
+
end
|
|
303
|
+
|
|
198
304
|
def textarea?
|
|
199
|
-
tag_name ==
|
|
305
|
+
tag_name == 'textarea'
|
|
200
306
|
end
|
|
201
307
|
|
|
202
|
-
def
|
|
203
|
-
input_field? &&
|
|
308
|
+
def range?
|
|
309
|
+
input_field? && type == 'range'
|
|
204
310
|
end
|
|
311
|
+
|
|
312
|
+
OPTION_OWNER_XPATH = XPath.parent(:optgroup, :select, :datalist).to_s.freeze
|
|
313
|
+
DISABLED_BY_FIELDSET_XPATH = XPath.generate do |x|
|
|
314
|
+
x.parent(:fieldset)[
|
|
315
|
+
XPath.attr(:disabled)
|
|
316
|
+
] + x.ancestor[
|
|
317
|
+
~x.self(:legend) |
|
|
318
|
+
x.preceding_sibling(:legend)
|
|
319
|
+
][
|
|
320
|
+
x.parent(:fieldset)[
|
|
321
|
+
x.attr(:disabled)
|
|
322
|
+
]
|
|
323
|
+
]
|
|
324
|
+
end.to_s.freeze
|
|
205
325
|
end
|