capybara 3.3.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 -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
|
@@ -1,385 +1,131 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# rubocop:disable Style/AsciiComments
|
|
4
|
-
|
|
5
|
-
require 'capybara/selector/filter_set'
|
|
6
|
-
require 'capybara/selector/css'
|
|
7
|
-
|
|
8
3
|
module Capybara
|
|
9
|
-
|
|
10
|
-
# ## Built-in Selectors
|
|
11
|
-
#
|
|
12
|
-
# * **:xpath** - Select elements by XPath expression
|
|
13
|
-
# * Locator: An XPath expression
|
|
14
|
-
#
|
|
15
|
-
# * **:css** - Select elements by CSS selector
|
|
16
|
-
# * Locator: A CSS selector
|
|
17
|
-
#
|
|
18
|
-
# * **:id** - Select element by id
|
|
19
|
-
# * Locator: The id of the element to match
|
|
20
|
-
#
|
|
21
|
-
# * **:field** - Select field elements (input [not of type submit, image, or hidden], textarea, select)
|
|
22
|
-
# * Locator: Matches against the id, name, or placeholder
|
|
23
|
-
# * Filters:
|
|
24
|
-
# * :id (String) — Matches the id attribute
|
|
25
|
-
# * :name (String) — Matches the name attribute
|
|
26
|
-
# * :placeholder (String) — Matches the placeholder attribute
|
|
27
|
-
# * :type (String) — Matches the type attribute of the field or element type for 'textarea' and 'select'
|
|
28
|
-
# * :readonly (Boolean)
|
|
29
|
-
# * :with (String) — Matches the current value of the field
|
|
30
|
-
# * :class (String, Array<String>) — Matches the class(es) provided
|
|
31
|
-
# * :checked (Boolean) — Match checked fields?
|
|
32
|
-
# * :unchecked (Boolean) — Match unchecked fields?
|
|
33
|
-
# * :disabled (Boolean) — Match disabled field?
|
|
34
|
-
# * :multiple (Boolean) — Match fields that accept multiple values
|
|
35
|
-
#
|
|
36
|
-
# * **:fieldset** - Select fieldset elements
|
|
37
|
-
# * Locator: Matches id or contents of wrapped legend
|
|
38
|
-
# * Filters:
|
|
39
|
-
# * :id (String) — Matches id attribute
|
|
40
|
-
# * :legend (String) — Matches contents of wrapped legend
|
|
41
|
-
# * :class (String, Array<String>) — Matches the class(es) provided
|
|
42
|
-
#
|
|
43
|
-
# * **:link** - Find links ( <a> elements with an href attribute )
|
|
44
|
-
# * Locator: Matches the id or title attributes, or the string content of the link, or the alt attribute of a contained img element
|
|
45
|
-
# * Filters:
|
|
46
|
-
# * :id (String) — Matches the id attribute
|
|
47
|
-
# * :title (String) — Matches the title attribute
|
|
48
|
-
# * :alt (String) — Matches the alt attribute of a contained img element
|
|
49
|
-
# * :class (String) — Matches the class(es) provided
|
|
50
|
-
# * :href (String, Regexp, nil) — Matches the normalized href of the link, if nil will find <a> elements with no href attribute
|
|
51
|
-
#
|
|
52
|
-
# * **:button** - Find buttons ( input [of type submit, reset, image, button] or button elements )
|
|
53
|
-
# * Locator: Matches the id, value, or title attributes, string content of a button, or the alt attribute of an image type button or of a descendant image of a button
|
|
54
|
-
# * Filters:
|
|
55
|
-
# * :id (String) — Matches the id attribute
|
|
56
|
-
# * :title (String) — Matches the title attribute
|
|
57
|
-
# * :class (String) — Matches the class(es) provided
|
|
58
|
-
# * :value (String) — Matches the value of an input button
|
|
59
|
-
# * :type
|
|
60
|
-
#
|
|
61
|
-
# * **:link_or_button** - Find links or buttons
|
|
62
|
-
# * Locator: See :link and :button selectors
|
|
63
|
-
#
|
|
64
|
-
# * **:fillable_field** - Find text fillable fields ( textarea, input [not of type submit, image, radio, checkbox, hidden, file] )
|
|
65
|
-
# * Locator: Matches against the id, name, or placeholder
|
|
66
|
-
# * Filters:
|
|
67
|
-
# * :id (String) — Matches the id attribute
|
|
68
|
-
# * :name (String) — Matches the name attribute
|
|
69
|
-
# * :placeholder (String) — Matches the placeholder attribute
|
|
70
|
-
# * :with (String) — Matches the current value of the field
|
|
71
|
-
# * :type (String) — Matches the type attribute of the field or element type for 'textarea'
|
|
72
|
-
# * :class (String, Array<String>) — Matches the class(es) provided
|
|
73
|
-
# * :disabled (Boolean) — Match disabled field?
|
|
74
|
-
# * :multiple (Boolean) — Match fields that accept multiple values
|
|
75
|
-
#
|
|
76
|
-
# * **:radio_button** - Find radio buttons
|
|
77
|
-
# * Locator: Match id, name, or associated label text
|
|
78
|
-
# * Filters:
|
|
79
|
-
# * :id (String) — Matches the id attribute
|
|
80
|
-
# * :name (String) — Matches the name attribute
|
|
81
|
-
# * :class (String, Array<String>) — Matches the class(es) provided
|
|
82
|
-
# * :checked (Boolean) — Match checked fields?
|
|
83
|
-
# * :unchecked (Boolean) — Match unchecked fields?
|
|
84
|
-
# * :disabled (Boolean) — Match disabled field?
|
|
85
|
-
# * :option (String) — Match the value
|
|
86
|
-
#
|
|
87
|
-
# * **:checkbox** - Find checkboxes
|
|
88
|
-
# * Locator: Match id, name, or associated label text
|
|
89
|
-
# * Filters:
|
|
90
|
-
# * *:id (String) — Matches the id attribute
|
|
91
|
-
# * *:name (String) — Matches the name attribute
|
|
92
|
-
# * *:class (String, Array<String>) — Matches the class(es) provided
|
|
93
|
-
# * *:checked (Boolean) — Match checked fields?
|
|
94
|
-
# * *:unchecked (Boolean) — Match unchecked fields?
|
|
95
|
-
# * *:disabled (Boolean) — Match disabled field?
|
|
96
|
-
# * *:option (String) — Match the value
|
|
97
|
-
#
|
|
98
|
-
# * **:select** - Find select elements
|
|
99
|
-
# * Locator: Match id, name, placeholder, or associated label text
|
|
100
|
-
# * Filters:
|
|
101
|
-
# * :id (String) — Matches the id attribute
|
|
102
|
-
# * :name (String) — Matches the name attribute
|
|
103
|
-
# * :placeholder (String) — Matches the placeholder attribute
|
|
104
|
-
# * :class (String, Array<String>) — Matches the class(es) provided
|
|
105
|
-
# * :disabled (Boolean) — Match disabled field?
|
|
106
|
-
# * :multiple (Boolean) — Match fields that accept multiple values
|
|
107
|
-
# * :options (Array<String>) — Exact match options
|
|
108
|
-
# * :with_options (Array<String>) — Partial match options
|
|
109
|
-
# * :selected (String, Array<String>) — Match the selection(s)
|
|
110
|
-
# * :with_selected (String, Array<String>) — Partial match the selection(s)
|
|
111
|
-
#
|
|
112
|
-
# * **:option** - Find option elements
|
|
113
|
-
# * Locator: Match text of option
|
|
114
|
-
# * Filters:
|
|
115
|
-
# * :disabled (Boolean) — Match disabled option
|
|
116
|
-
# * :selected (Boolean) — Match selected option
|
|
117
|
-
#
|
|
118
|
-
# * **:datalist_input**
|
|
119
|
-
# * Locator:
|
|
120
|
-
# * Filters:
|
|
121
|
-
# * :disabled
|
|
122
|
-
# * :name
|
|
123
|
-
# * :placeholder
|
|
124
|
-
#
|
|
125
|
-
# * **:datalist_option**
|
|
126
|
-
# * Locator:
|
|
127
|
-
#
|
|
128
|
-
# * **:file_field** - Find file input elements
|
|
129
|
-
# * Locator: Match id, name, or associated label text
|
|
130
|
-
# * Filters:
|
|
131
|
-
# * :id (String) — Matches the id attribute
|
|
132
|
-
# * :name (String) — Matches the name attribute
|
|
133
|
-
# * :class (String, Array<String>) — Matches the class(es) provided
|
|
134
|
-
# * :disabled (Boolean) — Match disabled field?
|
|
135
|
-
# * :multiple (Boolean) — Match field that accepts multiple values
|
|
136
|
-
#
|
|
137
|
-
# * **:label** - Find label elements
|
|
138
|
-
# * Locator: Match id or text contents
|
|
139
|
-
# * Filters:
|
|
140
|
-
# * :for (Element, String) — The element or id of the element associated with the label
|
|
141
|
-
#
|
|
142
|
-
# * **:table** - Find table elements
|
|
143
|
-
# * Locator: id or caption text of table
|
|
144
|
-
# * Filters:
|
|
145
|
-
# * :id (String) — Match id attribute of table
|
|
146
|
-
# * :caption (String) — Match text of associated caption
|
|
147
|
-
# * :class (String, Array<String>) — Matches the class(es) provided
|
|
148
|
-
#
|
|
149
|
-
# * **:frame** - Find frame/iframe elements
|
|
150
|
-
# * Locator: Match id or name
|
|
151
|
-
# * Filters:
|
|
152
|
-
# * :id (String) — Match id attribute
|
|
153
|
-
# * :name (String) — Match name attribute
|
|
154
|
-
# * :class (String, Array<String>) — Matches the class(es) provided
|
|
155
|
-
#
|
|
156
|
-
# * **:element**
|
|
157
|
-
# * Locator: Type of element ('div', 'a', etc) - if not specified defaults to '*'
|
|
158
|
-
# * Filters: Matches on any element attribute
|
|
159
|
-
#
|
|
160
|
-
class Selector
|
|
161
|
-
attr_reader :name, :format
|
|
162
|
-
extend Forwardable
|
|
163
|
-
|
|
4
|
+
class Selector < SimpleDelegator
|
|
164
5
|
class << self
|
|
165
6
|
def all
|
|
166
|
-
@
|
|
7
|
+
@definitions ||= {} # rubocop:disable Naming/MemoizedInstanceVariableName
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def [](name)
|
|
11
|
+
all.fetch(name.to_sym) { |sel_type| raise ArgumentError, "Unknown selector type (:#{sel_type})" }
|
|
167
12
|
end
|
|
168
13
|
|
|
169
|
-
def add(name, &block)
|
|
170
|
-
all[name.to_sym] =
|
|
14
|
+
def add(name, **options, &block)
|
|
15
|
+
all[name.to_sym] = Definition.new(name.to_sym, **options, &block)
|
|
171
16
|
end
|
|
172
17
|
|
|
173
18
|
def update(name, &block)
|
|
174
|
-
|
|
19
|
+
self[name].instance_eval(&block)
|
|
175
20
|
end
|
|
176
21
|
|
|
177
22
|
def remove(name)
|
|
178
23
|
all.delete(name.to_sym)
|
|
179
24
|
end
|
|
180
|
-
end
|
|
181
|
-
|
|
182
|
-
def initialize(name, &block)
|
|
183
|
-
@name = name
|
|
184
|
-
@filter_set = FilterSet.add(name) {}
|
|
185
|
-
@match = nil
|
|
186
|
-
@label = nil
|
|
187
|
-
@failure_message = nil
|
|
188
|
-
@description = nil
|
|
189
|
-
@format = nil
|
|
190
|
-
@expression = nil
|
|
191
|
-
@expression_filters = {}
|
|
192
|
-
@default_visibility = nil
|
|
193
|
-
instance_eval(&block)
|
|
194
|
-
end
|
|
195
25
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
26
|
+
def for(locator)
|
|
27
|
+
all.values.find { |sel| sel.match?(locator) }
|
|
28
|
+
end
|
|
199
29
|
end
|
|
200
30
|
|
|
201
|
-
|
|
202
|
-
@filter_set.node_filters
|
|
203
|
-
end
|
|
31
|
+
attr_reader :errors
|
|
204
32
|
|
|
205
|
-
def
|
|
206
|
-
|
|
33
|
+
def initialize(definition, config:, format:)
|
|
34
|
+
definition = self.class[definition] unless definition.is_a? Definition
|
|
35
|
+
super(definition)
|
|
36
|
+
@definition = definition
|
|
37
|
+
@config = config
|
|
38
|
+
@format = format
|
|
39
|
+
@errors = []
|
|
207
40
|
end
|
|
208
41
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
# Define a selector by an xpath expression
|
|
212
|
-
#
|
|
213
|
-
# @overload xpath(*expression_filters, &block)
|
|
214
|
-
# @param [Array<Symbol>] expression_filters ([]) Names of filters that can be implemented via this expression
|
|
215
|
-
# @yield [locator, options] The block to use to generate the XPath expression
|
|
216
|
-
# @yieldparam [String] locator The locator string passed to the query
|
|
217
|
-
# @yieldparam [Hash] options The options hash passed to the query
|
|
218
|
-
# @yieldreturn [#to_xpath, #to_s] An object that can produce an xpath expression
|
|
219
|
-
#
|
|
220
|
-
# @overload xpath()
|
|
221
|
-
# @return [#call] The block that will be called to generate the XPath expression
|
|
222
|
-
#
|
|
223
|
-
def xpath(*allowed_filters, &block)
|
|
224
|
-
if block
|
|
225
|
-
@format, @expression = :xpath, block
|
|
226
|
-
allowed_filters.flatten.each { |ef| expression_filters[ef] = Filters::IdentityExpressionFilter.new(ef) }
|
|
227
|
-
end
|
|
228
|
-
format == :xpath ? @expression : nil
|
|
42
|
+
def format
|
|
43
|
+
@format || @definition.default_format
|
|
229
44
|
end
|
|
45
|
+
alias_method :current_format, :format
|
|
230
46
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
# Define a selector by a CSS selector
|
|
234
|
-
#
|
|
235
|
-
# @overload css(*expression_filters, &block)
|
|
236
|
-
# @param [Array<Symbol>] expression_filters ([]) Names of filters that can be implemented via this CSS selector
|
|
237
|
-
# @yield [locator, options] The block to use to generate the CSS selector
|
|
238
|
-
# @yieldparam [String] locator The locator string passed to the query
|
|
239
|
-
# @yieldparam [Hash] options The options hash passed to the query
|
|
240
|
-
# @yieldreturn [#to_s] An object that can produce a CSS selector
|
|
241
|
-
#
|
|
242
|
-
# @overload css()
|
|
243
|
-
# @return [#call] The block that will be called to generate the CSS selector
|
|
244
|
-
#
|
|
245
|
-
def css(*allowed_filters, &block)
|
|
246
|
-
if block
|
|
247
|
-
@format, @expression = :css, block
|
|
248
|
-
allowed_filters.flatten.each { |ef| expression_filters[ef] = nil }
|
|
249
|
-
end
|
|
250
|
-
format == :css ? @expression : nil
|
|
47
|
+
def enable_aria_label
|
|
48
|
+
@config[:enable_aria_label]
|
|
251
49
|
end
|
|
252
50
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
# Automatic selector detection
|
|
256
|
-
#
|
|
257
|
-
# @yield [locator] This block takes the passed in locator string and returns whether or not it matches the selector
|
|
258
|
-
# @yieldparam [String], locator The locator string used to determin if it matches the selector
|
|
259
|
-
# @yieldreturn [Boolean] Whether this selector matches the locator string
|
|
260
|
-
# @return [#call] The block that will be used to detect selector match
|
|
261
|
-
#
|
|
262
|
-
def match(&block)
|
|
263
|
-
@match = block if block
|
|
264
|
-
@match
|
|
51
|
+
def enable_aria_role
|
|
52
|
+
@config[:enable_aria_role]
|
|
265
53
|
end
|
|
266
54
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
# Set/get a descriptive label for the selector
|
|
270
|
-
#
|
|
271
|
-
# @overload label(label)
|
|
272
|
-
# @param [String] label A descriptive label for this selector - used in error messages
|
|
273
|
-
# @overload label()
|
|
274
|
-
# @return [String] The currently set label
|
|
275
|
-
#
|
|
276
|
-
def label(label = nil)
|
|
277
|
-
@label = label if label
|
|
278
|
-
@label
|
|
55
|
+
def test_id
|
|
56
|
+
@config[:test_id]
|
|
279
57
|
end
|
|
280
58
|
|
|
281
|
-
##
|
|
282
|
-
#
|
|
283
|
-
# Description of the selector
|
|
284
|
-
#
|
|
285
|
-
# @!method description(options)
|
|
286
|
-
# @param [Hash] options The options of the query used to generate the description
|
|
287
|
-
# @return [String] Description of the selector when used with the options passed
|
|
288
|
-
def_delegator :@filter_set, :description
|
|
289
|
-
|
|
290
59
|
def call(locator, **options)
|
|
291
60
|
if format
|
|
292
|
-
@
|
|
61
|
+
raise ArgumentError, "Selector #{@name} does not support #{format}" unless expressions.key?(format)
|
|
62
|
+
|
|
63
|
+
instance_exec(locator, **options, &expressions[format])
|
|
293
64
|
else
|
|
294
|
-
warn
|
|
65
|
+
warn 'Selector has no format'
|
|
66
|
+
end
|
|
67
|
+
ensure
|
|
68
|
+
unless locator_valid?(locator)
|
|
69
|
+
Capybara::Helpers.warn(
|
|
70
|
+
"Locator #{locator.class}:#{locator.inspect} for selector #{name.inspect} must #{locator_description}. " \
|
|
71
|
+
'This will raise an error in a future version of Capybara. ' \
|
|
72
|
+
"Called from: #{Capybara::Helpers.filter_backtrace(caller)}"
|
|
73
|
+
)
|
|
295
74
|
end
|
|
296
75
|
end
|
|
297
76
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
# Should this selector be used for the passed in locator
|
|
301
|
-
#
|
|
302
|
-
# This is used by the automatic selector selection mechanism when no selector type is passed to a selector query
|
|
303
|
-
#
|
|
304
|
-
# @param [String] locator The locator passed to the query
|
|
305
|
-
# @return [Boolean] Whether or not to use this selector
|
|
306
|
-
#
|
|
307
|
-
def match?(locator)
|
|
308
|
-
@match&.call(locator)
|
|
77
|
+
def add_error(error_msg)
|
|
78
|
+
errors << error_msg
|
|
309
79
|
end
|
|
310
80
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
#
|
|
315
|
-
# @!method node_filter(name, *types, options={}, &block)
|
|
316
|
-
# @param [Symbol, Regexp] name The filter name
|
|
317
|
-
# @param [Array<Symbol>] types The types of the filter - currently valid types are [:boolean]
|
|
318
|
-
# @param [Hash] options ({}) Options of the filter
|
|
319
|
-
# @option options [Array<>] :valid_values Valid values for this filter
|
|
320
|
-
# @option options :default The default value of the filter (if any)
|
|
321
|
-
# @option options :skip_if Value of the filter that will cause it to be skipped
|
|
322
|
-
# @option options [Regexp] :matcher (nil) A Regexp used to check whether a specific option is handled by this filter. If not provided the filter will be used for options matching the filter name.
|
|
323
|
-
#
|
|
324
|
-
# If a Symbol is passed for the name the block should accept | node, option_value |, while if a Regexp
|
|
325
|
-
# is passed for the name the block should accept | node, option_name, option_value |. In either case
|
|
326
|
-
# the block should return `true` if the node passes the filer or `false` if it doesn't
|
|
327
|
-
|
|
328
|
-
# @!method filter
|
|
329
|
-
# See {Selector#node_filter}
|
|
330
|
-
|
|
331
|
-
##
|
|
332
|
-
#
|
|
333
|
-
# Define an expression filter for use with this selector
|
|
334
|
-
#
|
|
335
|
-
# @!method expression_filter(name, *types, options={}, &block)
|
|
336
|
-
# @param [Symbol, Regexp] name The filter name
|
|
337
|
-
# @param [Regexp] matcher (nil) A Regexp used to check whether a specific option is handled by this filter
|
|
338
|
-
# @param [Array<Symbol>] types The types of the filter - currently valid types are [:boolean]
|
|
339
|
-
# @param [Hash] options ({}) Options of the filter
|
|
340
|
-
# @option options [Array<>] :valid_values Valid values for this filter
|
|
341
|
-
# @option options :default The default value of the filter (if any)
|
|
342
|
-
# @option options :skip_if Value of the filter that will cause it to be skipped
|
|
343
|
-
# @option options [Regexp] :matcher (nil) A Regexp used to check whether a specific option is handled by this filter. If not provided the filter will be used for options matching the filter name.
|
|
344
|
-
#
|
|
345
|
-
# If a Symbol is passed for the name the block should accept | current_expression, option_value |, while if a Regexp
|
|
346
|
-
# is passed for the name the block should accept | current_expression, option_name, option_value |. In either case
|
|
347
|
-
# the block should return the modified expression
|
|
81
|
+
def expression_for(name, locator, config: @config, format: current_format, **options)
|
|
82
|
+
Selector.new(name, config: config, format: format).call(locator, **options)
|
|
83
|
+
end
|
|
348
84
|
|
|
349
|
-
|
|
85
|
+
# @api private
|
|
86
|
+
def with_filter_errors(errors)
|
|
87
|
+
old_errors = @errors
|
|
88
|
+
@errors = errors
|
|
89
|
+
yield
|
|
90
|
+
ensure
|
|
91
|
+
@errors = old_errors
|
|
92
|
+
end
|
|
350
93
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
94
|
+
# @api private
|
|
95
|
+
def builder(expr = nil)
|
|
96
|
+
case format
|
|
97
|
+
when :css
|
|
98
|
+
Capybara::Selector::CSSBuilder
|
|
99
|
+
when :xpath
|
|
100
|
+
Capybara::Selector::XPathBuilder
|
|
101
|
+
else
|
|
102
|
+
raise NotImplementedError, "No builder exists for selector of type #{default_format}"
|
|
103
|
+
end.new(expr)
|
|
357
104
|
end
|
|
358
105
|
|
|
359
|
-
|
|
106
|
+
private
|
|
360
107
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
# * :visible - only finds visible elements.
|
|
370
|
-
def visible(default_visibility)
|
|
371
|
-
@default_visibility = default_visibility
|
|
108
|
+
def locator_description
|
|
109
|
+
locator_types.group_by { |lt| lt.is_a? Symbol }.map do |symbol, types_or_methods|
|
|
110
|
+
if symbol
|
|
111
|
+
"respond to #{types_or_methods.join(' or ')}"
|
|
112
|
+
else
|
|
113
|
+
"be an instance of #{types_or_methods.join(' or ')}"
|
|
114
|
+
end
|
|
115
|
+
end.join(' or ')
|
|
372
116
|
end
|
|
373
117
|
|
|
374
|
-
def
|
|
375
|
-
return
|
|
376
|
-
fallback
|
|
377
|
-
end
|
|
118
|
+
def locator_valid?(locator)
|
|
119
|
+
return true unless locator && locator_types
|
|
378
120
|
|
|
379
|
-
|
|
121
|
+
locator_types&.any? do |type_or_method|
|
|
122
|
+
type_or_method.is_a?(Symbol) ? locator.respond_to?(type_or_method) : type_or_method === locator # rubocop:disable Style/CaseEquality
|
|
123
|
+
end
|
|
124
|
+
end
|
|
380
125
|
|
|
381
|
-
def locate_field(xpath, locator,
|
|
126
|
+
def locate_field(xpath, locator, **_options)
|
|
382
127
|
return xpath if locator.nil?
|
|
128
|
+
|
|
383
129
|
locate_xpath = xpath # Need to save original xpath for the label wrap
|
|
384
130
|
locator = locator.to_s
|
|
385
131
|
attr_matchers = [XPath.attr(:id) == locator,
|
|
@@ -387,21 +133,14 @@ module Capybara
|
|
|
387
133
|
XPath.attr(:placeholder) == locator,
|
|
388
134
|
XPath.attr(:id) == XPath.anywhere(:label)[XPath.string.n.is(locator)].attr(:for)].reduce(:|)
|
|
389
135
|
attr_matchers |= XPath.attr(:'aria-label').is(locator) if enable_aria_label
|
|
136
|
+
attr_matchers |= XPath.attr(test_id) == locator if test_id
|
|
390
137
|
|
|
391
138
|
locate_xpath = locate_xpath[attr_matchers]
|
|
392
|
-
locate_xpath +
|
|
139
|
+
locate_xpath + locate_label(locator).descendant(xpath)
|
|
393
140
|
end
|
|
394
141
|
|
|
395
|
-
def
|
|
396
|
-
|
|
397
|
-
if ef.matcher?
|
|
398
|
-
opts.keys.map do |k|
|
|
399
|
-
" with #{ef_name}[#{k} => #{opts[k]}]" if ef.handles_option?(k) && !::Capybara::Queries::SelectorQuery::VALID_KEYS.include?(k)
|
|
400
|
-
end.join
|
|
401
|
-
elsif opts.key?(ef_name)
|
|
402
|
-
" with #{ef_name} #{opts[ef_name]}"
|
|
403
|
-
end
|
|
404
|
-
end.join
|
|
142
|
+
def locate_label(locator)
|
|
143
|
+
XPath.descendant(:label)[XPath.string.n.is(locator)]
|
|
405
144
|
end
|
|
406
145
|
|
|
407
146
|
def find_by_attr(attribute, value)
|
|
@@ -418,5 +157,3 @@ module Capybara
|
|
|
418
157
|
end
|
|
419
158
|
end
|
|
420
159
|
end
|
|
421
|
-
|
|
422
|
-
# rubocop:enable Style/AsciiComments
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module XPath
|
|
4
|
+
class Renderer
|
|
5
|
+
def join(*expressions)
|
|
6
|
+
expressions.join('/')
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
module XPath
|
|
12
|
+
module DSL
|
|
13
|
+
def join(*expressions)
|
|
14
|
+
XPath::Expression.new(:join, *[self, expressions].flatten)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|