capybara 2.18.0 → 3.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.yardopts +1 -1
- data/History.md +945 -12
- data/License.txt +1 -1
- data/README.md +264 -90
- data/lib/capybara/config.rb +29 -57
- data/lib/capybara/cucumber.rb +2 -3
- data/lib/capybara/driver/base.rb +35 -18
- data/lib/capybara/driver/node.rb +40 -10
- data/lib/capybara/dsl.rb +10 -7
- data/lib/capybara/helpers.rb +70 -31
- data/lib/capybara/minitest/spec.rb +185 -83
- data/lib/capybara/minitest.rb +232 -112
- data/lib/capybara/node/actions.rb +274 -171
- data/lib/capybara/node/base.rb +42 -34
- data/lib/capybara/node/document.rb +15 -3
- data/lib/capybara/node/document_matchers.rb +19 -21
- data/lib/capybara/node/element.rb +362 -135
- data/lib/capybara/node/finders.rb +151 -137
- data/lib/capybara/node/matchers.rb +394 -209
- data/lib/capybara/node/simple.rb +59 -26
- data/lib/capybara/node/whitespace_normalizer.rb +81 -0
- data/lib/capybara/queries/active_element_query.rb +18 -0
- data/lib/capybara/queries/ancestor_query.rb +12 -9
- data/lib/capybara/queries/base_query.rb +39 -28
- data/lib/capybara/queries/current_path_query.rb +21 -27
- data/lib/capybara/queries/match_query.rb +14 -7
- data/lib/capybara/queries/selector_query.rb +659 -149
- data/lib/capybara/queries/sibling_query.rb +11 -9
- data/lib/capybara/queries/style_query.rb +45 -0
- data/lib/capybara/queries/text_query.rb +56 -38
- data/lib/capybara/queries/title_query.rb +8 -11
- data/lib/capybara/rack_test/browser.rb +114 -42
- data/lib/capybara/rack_test/css_handlers.rb +6 -4
- data/lib/capybara/rack_test/driver.rb +22 -17
- data/lib/capybara/rack_test/errors.rb +6 -0
- data/lib/capybara/rack_test/form.rb +93 -58
- data/lib/capybara/rack_test/node.rb +184 -81
- data/lib/capybara/rails.rb +3 -7
- data/lib/capybara/registration_container.rb +41 -0
- data/lib/capybara/registrations/drivers.rb +42 -0
- data/lib/capybara/registrations/patches/puma_ssl.rb +29 -0
- data/lib/capybara/registrations/servers.rb +66 -0
- data/lib/capybara/result.rb +97 -63
- data/lib/capybara/rspec/features.rb +17 -50
- data/lib/capybara/rspec/matcher_proxies.rb +52 -15
- data/lib/capybara/rspec/matchers/base.rb +113 -0
- data/lib/capybara/rspec/matchers/become_closed.rb +33 -0
- data/lib/capybara/rspec/matchers/compound.rb +88 -0
- data/lib/capybara/rspec/matchers/count_sugar.rb +37 -0
- data/lib/capybara/rspec/matchers/have_ancestor.rb +28 -0
- data/lib/capybara/rspec/matchers/have_current_path.rb +29 -0
- data/lib/capybara/rspec/matchers/have_selector.rb +69 -0
- data/lib/capybara/rspec/matchers/have_sibling.rb +27 -0
- data/lib/capybara/rspec/matchers/have_text.rb +33 -0
- data/lib/capybara/rspec/matchers/have_title.rb +29 -0
- data/lib/capybara/rspec/matchers/match_selector.rb +27 -0
- data/lib/capybara/rspec/matchers/match_style.rb +43 -0
- data/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
- data/lib/capybara/rspec/matchers.rb +146 -310
- data/lib/capybara/rspec.rb +7 -11
- data/lib/capybara/selector/builders/css_builder.rb +84 -0
- data/lib/capybara/selector/builders/xpath_builder.rb +71 -0
- data/lib/capybara/selector/css.rb +85 -13
- data/lib/capybara/selector/definition/button.rb +68 -0
- data/lib/capybara/selector/definition/checkbox.rb +26 -0
- data/lib/capybara/selector/definition/css.rb +10 -0
- data/lib/capybara/selector/definition/datalist_input.rb +35 -0
- data/lib/capybara/selector/definition/datalist_option.rb +25 -0
- data/lib/capybara/selector/definition/element.rb +28 -0
- data/lib/capybara/selector/definition/field.rb +40 -0
- data/lib/capybara/selector/definition/fieldset.rb +14 -0
- data/lib/capybara/selector/definition/file_field.rb +13 -0
- data/lib/capybara/selector/definition/fillable_field.rb +33 -0
- data/lib/capybara/selector/definition/frame.rb +17 -0
- data/lib/capybara/selector/definition/id.rb +6 -0
- data/lib/capybara/selector/definition/label.rb +62 -0
- data/lib/capybara/selector/definition/link.rb +55 -0
- data/lib/capybara/selector/definition/link_or_button.rb +16 -0
- data/lib/capybara/selector/definition/option.rb +27 -0
- data/lib/capybara/selector/definition/radio_button.rb +27 -0
- data/lib/capybara/selector/definition/select.rb +81 -0
- data/lib/capybara/selector/definition/table.rb +109 -0
- data/lib/capybara/selector/definition/table_row.rb +21 -0
- data/lib/capybara/selector/definition/xpath.rb +5 -0
- data/lib/capybara/selector/definition.rb +280 -0
- data/lib/capybara/selector/filter.rb +2 -17
- data/lib/capybara/selector/filter_set.rb +80 -33
- data/lib/capybara/selector/filters/base.rb +50 -6
- data/lib/capybara/selector/filters/expression_filter.rb +8 -26
- data/lib/capybara/selector/filters/locator_filter.rb +29 -0
- data/lib/capybara/selector/filters/node_filter.rb +16 -12
- data/lib/capybara/selector/regexp_disassembler.rb +211 -0
- data/lib/capybara/selector/selector.rb +93 -210
- data/lib/capybara/selector/xpath_extensions.rb +17 -0
- data/lib/capybara/selector.rb +475 -523
- data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -0
- data/lib/capybara/selenium/atoms/isDisplayed.min.js +1 -0
- data/lib/capybara/selenium/atoms/src/getAttribute.js +161 -0
- data/lib/capybara/selenium/atoms/src/isDisplayed.js +454 -0
- data/lib/capybara/selenium/driver.rb +298 -267
- data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +117 -0
- data/lib/capybara/selenium/driver_specializations/edge_driver.rb +128 -0
- data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +84 -0
- data/lib/capybara/selenium/driver_specializations/internet_explorer_driver.rb +26 -0
- data/lib/capybara/selenium/driver_specializations/safari_driver.rb +24 -0
- data/lib/capybara/selenium/extensions/file_input_click_emulation.rb +34 -0
- data/lib/capybara/selenium/extensions/find.rb +110 -0
- data/lib/capybara/selenium/extensions/html5_drag.rb +229 -0
- data/lib/capybara/selenium/extensions/modifier_keys_stack.rb +28 -0
- data/lib/capybara/selenium/extensions/scroll.rb +76 -0
- data/lib/capybara/selenium/node.rb +517 -145
- data/lib/capybara/selenium/nodes/chrome_node.rb +125 -0
- data/lib/capybara/selenium/nodes/edge_node.rb +110 -0
- data/lib/capybara/selenium/nodes/firefox_node.rb +136 -0
- data/lib/capybara/selenium/nodes/ie_node.rb +22 -0
- data/lib/capybara/selenium/nodes/safari_node.rb +118 -0
- data/lib/capybara/selenium/patches/atoms.rb +18 -0
- data/lib/capybara/selenium/patches/is_displayed.rb +16 -0
- data/lib/capybara/selenium/patches/logs.rb +45 -0
- data/lib/capybara/selenium/patches/pause_duration_fix.rb +9 -0
- data/lib/capybara/selenium/patches/persistent_client.rb +20 -0
- data/lib/capybara/server/animation_disabler.rb +80 -0
- data/lib/capybara/server/checker.rb +44 -0
- data/lib/capybara/server/middleware.rb +71 -0
- data/lib/capybara/server.rb +59 -67
- data/lib/capybara/session/config.rb +81 -67
- data/lib/capybara/session/matchers.rb +28 -20
- data/lib/capybara/session.rb +337 -365
- data/lib/capybara/spec/public/jquery.js +5 -5
- data/lib/capybara/spec/public/offset.js +6 -0
- data/lib/capybara/spec/public/test.js +151 -12
- data/lib/capybara/spec/session/accept_alert_spec.rb +12 -11
- data/lib/capybara/spec/session/accept_confirm_spec.rb +6 -5
- data/lib/capybara/spec/session/accept_prompt_spec.rb +10 -10
- data/lib/capybara/spec/session/active_element_spec.rb +31 -0
- data/lib/capybara/spec/session/all_spec.rb +161 -57
- data/lib/capybara/spec/session/ancestor_spec.rb +27 -24
- data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +68 -38
- data/lib/capybara/spec/session/assert_current_path_spec.rb +75 -0
- data/lib/capybara/spec/session/assert_selector_spec.rb +143 -0
- data/lib/capybara/spec/session/assert_style_spec.rb +26 -0
- data/lib/capybara/spec/session/assert_text_spec.rb +258 -0
- data/lib/capybara/spec/session/{assert_title.rb → assert_title_spec.rb} +22 -12
- data/lib/capybara/spec/session/attach_file_spec.rb +144 -69
- data/lib/capybara/spec/session/body_spec.rb +12 -13
- data/lib/capybara/spec/session/check_spec.rb +117 -55
- data/lib/capybara/spec/session/choose_spec.rb +64 -31
- data/lib/capybara/spec/session/click_button_spec.rb +231 -173
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +55 -35
- data/lib/capybara/spec/session/click_link_spec.rb +93 -58
- data/lib/capybara/spec/session/current_scope_spec.rb +12 -11
- data/lib/capybara/spec/session/current_url_spec.rb +57 -39
- data/lib/capybara/spec/session/dismiss_confirm_spec.rb +4 -4
- data/lib/capybara/spec/session/dismiss_prompt_spec.rb +3 -2
- data/lib/capybara/spec/session/element/{assert_match_selector.rb → assert_match_selector_spec.rb} +11 -9
- data/lib/capybara/spec/session/element/match_css_spec.rb +18 -10
- data/lib/capybara/spec/session/element/match_xpath_spec.rb +9 -7
- data/lib/capybara/spec/session/element/matches_selector_spec.rb +71 -57
- data/lib/capybara/spec/session/evaluate_async_script_spec.rb +8 -7
- data/lib/capybara/spec/session/evaluate_script_spec.rb +29 -8
- data/lib/capybara/spec/session/execute_script_spec.rb +10 -8
- data/lib/capybara/spec/session/fill_in_spec.rb +134 -43
- data/lib/capybara/spec/session/find_button_spec.rb +25 -24
- data/lib/capybara/spec/session/find_by_id_spec.rb +10 -9
- data/lib/capybara/spec/session/find_field_spec.rb +37 -41
- data/lib/capybara/spec/session/find_link_spec.rb +46 -17
- data/lib/capybara/spec/session/find_spec.rb +260 -145
- data/lib/capybara/spec/session/first_spec.rb +80 -52
- data/lib/capybara/spec/session/frame/frame_title_spec.rb +23 -0
- data/lib/capybara/spec/session/frame/frame_url_spec.rb +23 -0
- data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +33 -20
- data/lib/capybara/spec/session/frame/within_frame_spec.rb +52 -32
- data/lib/capybara/spec/session/go_back_spec.rb +2 -1
- data/lib/capybara/spec/session/go_forward_spec.rb +2 -1
- data/lib/capybara/spec/session/has_all_selectors_spec.rb +31 -31
- data/lib/capybara/spec/session/has_ancestor_spec.rb +46 -0
- data/lib/capybara/spec/session/has_any_selectors_spec.rb +29 -0
- data/lib/capybara/spec/session/has_button_spec.rb +100 -13
- data/lib/capybara/spec/session/has_css_spec.rb +272 -137
- data/lib/capybara/spec/session/has_current_path_spec.rb +60 -61
- data/lib/capybara/spec/session/has_element_spec.rb +47 -0
- data/lib/capybara/spec/session/has_field_spec.rb +139 -59
- data/lib/capybara/spec/session/has_link_spec.rb +47 -6
- data/lib/capybara/spec/session/has_none_selectors_spec.rb +42 -40
- data/lib/capybara/spec/session/has_select_spec.rb +107 -72
- data/lib/capybara/spec/session/has_selector_spec.rb +120 -71
- data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
- data/lib/capybara/spec/session/has_table_spec.rb +183 -5
- data/lib/capybara/spec/session/has_text_spec.rb +106 -62
- data/lib/capybara/spec/session/has_title_spec.rb +20 -14
- data/lib/capybara/spec/session/has_xpath_spec.rb +57 -38
- data/lib/capybara/spec/session/{headers.rb → headers_spec.rb} +3 -2
- data/lib/capybara/spec/session/html_spec.rb +14 -6
- data/lib/capybara/spec/session/matches_style_spec.rb +37 -0
- data/lib/capybara/spec/session/node_spec.rb +1024 -153
- data/lib/capybara/spec/session/node_wrapper_spec.rb +39 -0
- data/lib/capybara/spec/session/refresh_spec.rb +12 -6
- data/lib/capybara/spec/session/reset_session_spec.rb +82 -35
- data/lib/capybara/spec/session/{response_code.rb → response_code_spec.rb} +2 -1
- data/lib/capybara/spec/session/save_and_open_page_spec.rb +3 -2
- data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +8 -12
- data/lib/capybara/spec/session/save_page_spec.rb +42 -55
- data/lib/capybara/spec/session/save_screenshot_spec.rb +16 -14
- data/lib/capybara/spec/session/screenshot_spec.rb +2 -2
- data/lib/capybara/spec/session/scroll_spec.rb +119 -0
- data/lib/capybara/spec/session/select_spec.rb +107 -81
- data/lib/capybara/spec/session/selectors_spec.rb +52 -19
- data/lib/capybara/spec/session/sibling_spec.rb +10 -10
- data/lib/capybara/spec/session/text_spec.rb +37 -21
- data/lib/capybara/spec/session/title_spec.rb +17 -5
- data/lib/capybara/spec/session/uncheck_spec.rb +43 -23
- data/lib/capybara/spec/session/unselect_spec.rb +39 -38
- data/lib/capybara/spec/session/visit_spec.rb +85 -53
- data/lib/capybara/spec/session/window/become_closed_spec.rb +24 -20
- data/lib/capybara/spec/session/window/current_window_spec.rb +5 -3
- data/lib/capybara/spec/session/window/open_new_window_spec.rb +5 -3
- data/lib/capybara/spec/session/window/switch_to_window_spec.rb +27 -22
- data/lib/capybara/spec/session/window/window_opened_by_spec.rb +12 -6
- data/lib/capybara/spec/session/window/window_spec.rb +97 -63
- data/lib/capybara/spec/session/window/windows_spec.rb +12 -10
- data/lib/capybara/spec/session/window/within_window_spec.rb +31 -86
- data/lib/capybara/spec/session/within_spec.rb +83 -44
- data/lib/capybara/spec/spec_helper.rb +54 -44
- data/lib/capybara/spec/test_app.rb +158 -43
- data/lib/capybara/spec/views/animated.erb +49 -0
- data/lib/capybara/spec/views/form.erb +163 -42
- data/lib/capybara/spec/views/frame_child.erb +4 -3
- data/lib/capybara/spec/views/frame_one.erb +2 -1
- data/lib/capybara/spec/views/frame_parent.erb +1 -1
- data/lib/capybara/spec/views/frame_two.erb +1 -1
- data/lib/capybara/spec/views/initial_alert.erb +2 -1
- data/lib/capybara/spec/views/layout.erb +10 -0
- data/lib/capybara/spec/views/obscured.erb +47 -0
- data/lib/capybara/spec/views/offset.erb +33 -0
- data/lib/capybara/spec/views/path.erb +2 -2
- data/lib/capybara/spec/views/popup_one.erb +1 -1
- data/lib/capybara/spec/views/popup_two.erb +1 -1
- data/lib/capybara/spec/views/react.erb +45 -0
- data/lib/capybara/spec/views/scroll.erb +21 -0
- data/lib/capybara/spec/views/spatial.erb +31 -0
- data/lib/capybara/spec/views/tables.erb +68 -1
- data/lib/capybara/spec/views/with_animation.erb +81 -0
- data/lib/capybara/spec/views/with_base_tag.erb +2 -2
- data/lib/capybara/spec/views/with_dragula.erb +24 -0
- data/lib/capybara/spec/views/with_fixed_header_footer.erb +2 -1
- data/lib/capybara/spec/views/with_hover.erb +3 -2
- data/lib/capybara/spec/views/with_hover1.erb +10 -0
- data/lib/capybara/spec/views/with_html.erb +69 -12
- data/lib/capybara/spec/views/with_html5_svg.erb +20 -0
- data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
- data/lib/capybara/spec/views/with_js.erb +30 -5
- data/lib/capybara/spec/views/with_jstree.erb +26 -0
- data/lib/capybara/spec/views/with_namespace.erb +21 -0
- data/lib/capybara/spec/views/with_scope.erb +2 -2
- data/lib/capybara/spec/views/with_scope_other.erb +6 -0
- data/lib/capybara/spec/views/with_shadow.erb +31 -0
- data/lib/capybara/spec/views/with_slow_unload.erb +2 -1
- data/lib/capybara/spec/views/with_sortable_js.erb +21 -0
- data/lib/capybara/spec/views/with_unload_alert.erb +1 -0
- data/lib/capybara/spec/views/with_windows.erb +1 -1
- data/lib/capybara/spec/views/within_frames.erb +5 -2
- data/lib/capybara/version.rb +2 -1
- data/lib/capybara/window.rb +36 -34
- data/lib/capybara.rb +134 -107
- data/spec/basic_node_spec.rb +60 -34
- data/spec/capybara_spec.rb +63 -88
- data/spec/counter_spec.rb +35 -0
- data/spec/css_builder_spec.rb +101 -0
- data/spec/css_splitter_spec.rb +38 -0
- data/spec/dsl_spec.rb +85 -64
- data/spec/filter_set_spec.rb +27 -9
- data/spec/fixtures/certificate.pem +25 -0
- data/spec/fixtures/key.pem +27 -0
- data/spec/fixtures/selenium_driver_rspec_failure.rb +6 -5
- data/spec/fixtures/selenium_driver_rspec_success.rb +6 -5
- data/spec/minitest_spec.rb +52 -7
- data/spec/minitest_spec_spec.rb +94 -63
- data/spec/per_session_config_spec.rb +14 -13
- data/spec/rack_test_spec.rb +194 -125
- data/spec/regexp_dissassembler_spec.rb +250 -0
- data/spec/result_spec.rb +111 -50
- data/spec/rspec/features_spec.rb +37 -31
- data/spec/rspec/scenarios_spec.rb +10 -8
- data/spec/rspec/shared_spec_matchers.rb +473 -422
- data/spec/rspec/views_spec.rb +5 -3
- data/spec/rspec_matchers_spec.rb +52 -11
- data/spec/rspec_spec.rb +109 -89
- data/spec/sauce_spec_chrome.rb +43 -0
- data/spec/selector_spec.rb +397 -68
- data/spec/selenium_spec_chrome.rb +187 -40
- data/spec/selenium_spec_chrome_remote.rb +96 -0
- data/spec/selenium_spec_edge.rb +60 -0
- data/spec/selenium_spec_firefox.rb +201 -41
- data/spec/selenium_spec_firefox_remote.rb +94 -0
- data/spec/selenium_spec_ie.rb +149 -0
- data/spec/selenium_spec_safari.rb +162 -0
- data/spec/server_spec.rb +213 -102
- data/spec/session_spec.rb +53 -16
- data/spec/shared_selenium_node.rb +79 -0
- data/spec/shared_selenium_session.rb +473 -122
- data/spec/spec_helper.rb +126 -7
- data/spec/whitespace_normalizer_spec.rb +54 -0
- data/spec/xpath_builder_spec.rb +93 -0
- metadata +355 -73
- data/.yard/templates_custom/default/class/html/selectors.erb +0 -38
- data/.yard/templates_custom/default/class/html/setup.rb +0 -17
- data/.yard/yard_extensions.rb +0 -78
- data/lib/capybara/query.rb +0 -7
- data/lib/capybara/rspec/compound.rb +0 -95
- data/lib/capybara/spec/session/assert_current_path.rb +0 -72
- data/lib/capybara/spec/session/assert_selector.rb +0 -148
- data/lib/capybara/spec/session/assert_text.rb +0 -234
- data/lib/capybara/spec/session/source_spec.rb +0 -0
- data/lib/capybara/spec/views/with_title.erb +0 -5
- data/spec/selenium_spec_marionette.rb +0 -127
|
@@ -1,257 +1,146 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
-
require 'capybara/selector/filter_set'
|
|
3
|
-
require 'capybara/selector/css'
|
|
4
|
-
require 'xpath'
|
|
5
|
-
|
|
6
|
-
#Patch XPath to allow a nil condition in where
|
|
7
|
-
module XPath
|
|
8
|
-
class Renderer
|
|
9
|
-
undef :where if method_defined?(:where)
|
|
10
|
-
def where(on, condition)
|
|
11
|
-
condition = condition.to_s
|
|
12
|
-
if !condition.empty?
|
|
13
|
-
"#{on}[#{condition}]"
|
|
14
|
-
else
|
|
15
|
-
"#{on}"
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
2
|
|
|
21
3
|
module Capybara
|
|
22
|
-
class Selector
|
|
23
|
-
|
|
24
|
-
attr_reader :name, :format
|
|
25
|
-
|
|
4
|
+
class Selector < SimpleDelegator
|
|
26
5
|
class << self
|
|
27
6
|
def all
|
|
28
|
-
@
|
|
7
|
+
@definitions ||= {} # rubocop:disable Naming/MemoizedInstanceVariableName
|
|
29
8
|
end
|
|
30
9
|
|
|
31
|
-
def
|
|
32
|
-
all
|
|
10
|
+
def [](name)
|
|
11
|
+
all.fetch(name.to_sym) { |sel_type| raise ArgumentError, "Unknown selector type (:#{sel_type})" }
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def add(name, **options, &block)
|
|
15
|
+
all[name.to_sym] = Definition.new(name.to_sym, **options, &block)
|
|
33
16
|
end
|
|
34
17
|
|
|
35
18
|
def update(name, &block)
|
|
36
|
-
|
|
19
|
+
self[name].instance_eval(&block)
|
|
37
20
|
end
|
|
38
21
|
|
|
39
22
|
def remove(name)
|
|
40
23
|
all.delete(name.to_sym)
|
|
41
24
|
end
|
|
42
|
-
end
|
|
43
25
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
@match = nil
|
|
48
|
-
@label = nil
|
|
49
|
-
@failure_message = nil
|
|
50
|
-
@description = nil
|
|
51
|
-
@format = nil
|
|
52
|
-
@expression = nil
|
|
53
|
-
@expression_filters = {}
|
|
54
|
-
@default_visibility = nil
|
|
55
|
-
instance_eval(&block)
|
|
26
|
+
def for(locator)
|
|
27
|
+
all.values.find { |sel| sel.match?(locator) }
|
|
28
|
+
end
|
|
56
29
|
end
|
|
57
30
|
|
|
58
|
-
|
|
59
|
-
@filter_set.filters
|
|
60
|
-
end
|
|
31
|
+
attr_reader :errors
|
|
61
32
|
|
|
62
|
-
def
|
|
63
|
-
|
|
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 = []
|
|
64
40
|
end
|
|
65
41
|
|
|
66
|
-
def
|
|
67
|
-
@
|
|
42
|
+
def format
|
|
43
|
+
@format || @definition.default_format
|
|
68
44
|
end
|
|
45
|
+
alias_method :current_format, :format
|
|
69
46
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
# Define a selector by an xpath expression
|
|
73
|
-
#
|
|
74
|
-
# @overload xpath(*expression_filters, &block)
|
|
75
|
-
# @param [Array<Symbol>] expression_filters ([]) Names of filters that can be implemented via this expression
|
|
76
|
-
# @yield [locator, options] The block to use to generate the XPath expression
|
|
77
|
-
# @yieldparam [String] locator The locator string passed to the query
|
|
78
|
-
# @yieldparam [Hash] options The options hash passed to the query
|
|
79
|
-
# @yieldreturn [#to_xpath, #to_s] An object that can produce an xpath expression
|
|
80
|
-
#
|
|
81
|
-
# @overload xpath()
|
|
82
|
-
# @return [#call] The block that will be called to generate the XPath expression
|
|
83
|
-
#
|
|
84
|
-
def xpath(*expression_filters, &block)
|
|
85
|
-
if block
|
|
86
|
-
@format, @expression = :xpath, block
|
|
87
|
-
expression_filters.flatten.each { |ef| custom_filters[ef] = Filters::IdentityExpressionFilter.new }
|
|
88
|
-
end
|
|
89
|
-
format == :xpath ? @expression : nil
|
|
47
|
+
def enable_aria_label
|
|
48
|
+
@config[:enable_aria_label]
|
|
90
49
|
end
|
|
91
50
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
# Define a selector by a CSS selector
|
|
95
|
-
#
|
|
96
|
-
# @overload css(*expression_filters, &block)
|
|
97
|
-
# @param [Array<Symbol>] expression_filters ([]) Names of filters that can be implemented via this CSS selector
|
|
98
|
-
# @yield [locator, options] The block to use to generate the CSS selector
|
|
99
|
-
# @yieldparam [String] locator The locator string passed to the query
|
|
100
|
-
# @yieldparam [Hash] options The options hash passed to the query
|
|
101
|
-
# @yieldreturn [#to_s] An object that can produce a CSS selector
|
|
102
|
-
#
|
|
103
|
-
# @overload css()
|
|
104
|
-
# @return [#call] The block that will be called to generate the CSS selector
|
|
105
|
-
#
|
|
106
|
-
def css(*expression_filters, &block)
|
|
107
|
-
if block
|
|
108
|
-
@format, @expression = :css, block
|
|
109
|
-
expression_filters.flatten.each { |ef| custom_filters[ef] = nil }
|
|
110
|
-
end
|
|
111
|
-
format == :css ? @expression : nil
|
|
51
|
+
def enable_aria_role
|
|
52
|
+
@config[:enable_aria_role]
|
|
112
53
|
end
|
|
113
54
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
# Automatic selector detection
|
|
117
|
-
#
|
|
118
|
-
# @yield [locator] This block takes the passed in locator string and returns whether or not it matches the selector
|
|
119
|
-
# @yieldparam [String], locator The locator string used to determin if it matches the selector
|
|
120
|
-
# @yieldreturn [Boolean] Whether this selector matches the locator string
|
|
121
|
-
# @return [#call] The block that will be used to detect selector match
|
|
122
|
-
#
|
|
123
|
-
def match(&block)
|
|
124
|
-
@match = block if block
|
|
125
|
-
@match
|
|
55
|
+
def test_id
|
|
56
|
+
@config[:test_id]
|
|
126
57
|
end
|
|
127
58
|
|
|
128
|
-
|
|
129
|
-
#
|
|
130
|
-
# Set/get a descriptive label for the selector
|
|
131
|
-
#
|
|
132
|
-
# @overload label(label)
|
|
133
|
-
# @param [String] label A descriptive label for this selector - used in error messages
|
|
134
|
-
# @overload label()
|
|
135
|
-
# @return [String] The currently set label
|
|
136
|
-
#
|
|
137
|
-
def label(label=nil)
|
|
138
|
-
@label = label if label
|
|
139
|
-
@label
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
##
|
|
143
|
-
#
|
|
144
|
-
# Description of the selector
|
|
145
|
-
#
|
|
146
|
-
# @param [Hash] options The options of the query used to generate the description
|
|
147
|
-
# @return [String] Description of the selector when used with the options passed
|
|
148
|
-
#
|
|
149
|
-
def description(options={})
|
|
150
|
-
@filter_set.description(options)
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
def call(locator, options={})
|
|
59
|
+
def call(locator, **options)
|
|
154
60
|
if format
|
|
155
|
-
|
|
156
|
-
|
|
61
|
+
raise ArgumentError, "Selector #{@name} does not support #{format}" unless expressions.key?(format)
|
|
62
|
+
|
|
63
|
+
instance_exec(locator, **options, &expressions[format])
|
|
157
64
|
else
|
|
158
|
-
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
|
+
)
|
|
159
74
|
end
|
|
160
75
|
end
|
|
161
76
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
# Should this selector be used for the passed in locator
|
|
165
|
-
#
|
|
166
|
-
# This is used by the automatic selector selection mechanism when no selector type is passed to a selector query
|
|
167
|
-
#
|
|
168
|
-
# @param [String] locator The locator passed to the query
|
|
169
|
-
# @return [Boolean] Whether or not to use this selector
|
|
170
|
-
#
|
|
171
|
-
def match?(locator)
|
|
172
|
-
@match and @match.call(locator)
|
|
77
|
+
def add_error(error_msg)
|
|
78
|
+
errors << error_msg
|
|
173
79
|
end
|
|
174
80
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
# Define a non-expression filter for use with this selector
|
|
178
|
-
#
|
|
179
|
-
# @overload filter(name, *types, options={}, &block)
|
|
180
|
-
# @param [Symbol] name The filter name
|
|
181
|
-
# @param [Array<Symbol>] types The types of the filter - currently valid types are [:boolean]
|
|
182
|
-
# @param [Hash] options ({}) Options of the filter
|
|
183
|
-
# @option options [Array<>] :valid_values Valid values for this filter
|
|
184
|
-
# @option options :default The default value of the filter (if any)
|
|
185
|
-
# @option options :skip_if Value of the filter that will cause it to be skipped
|
|
186
|
-
#
|
|
187
|
-
def filter(name, *types_and_options, &block)
|
|
188
|
-
options = types_and_options.last.is_a?(Hash) ? types_and_options.pop.dup : {}
|
|
189
|
-
types_and_options.each { |k| options[k] = true }
|
|
190
|
-
custom_filters[name] = Filters::NodeFilter.new(name, block, options)
|
|
81
|
+
def expression_for(name, locator, config: @config, format: current_format, **options)
|
|
82
|
+
Selector.new(name, config: config, format: format).call(locator, **options)
|
|
191
83
|
end
|
|
192
84
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
85
|
+
# @api private
|
|
86
|
+
def with_filter_errors(errors)
|
|
87
|
+
old_errors = @errors
|
|
88
|
+
@errors = errors
|
|
89
|
+
yield
|
|
90
|
+
ensure
|
|
91
|
+
@errors = old_errors
|
|
197
92
|
end
|
|
198
93
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
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)
|
|
206
104
|
end
|
|
207
105
|
|
|
208
|
-
|
|
209
|
-
@filter_set.describe(&block)
|
|
210
|
-
end
|
|
106
|
+
private
|
|
211
107
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
# * :visible - only finds visible elements.
|
|
221
|
-
def visible(default_visibility)
|
|
222
|
-
@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 ')
|
|
223
116
|
end
|
|
224
117
|
|
|
225
|
-
def
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
118
|
+
def locator_valid?(locator)
|
|
119
|
+
return true unless locator && locator_types
|
|
120
|
+
|
|
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
|
|
230
123
|
end
|
|
231
124
|
end
|
|
232
125
|
|
|
233
|
-
|
|
126
|
+
def locate_field(xpath, locator, **_options)
|
|
127
|
+
return xpath if locator.nil?
|
|
234
128
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
attr_matchers = attr_matchers.or XPath.attr(:'aria-label').is(locator) if options[:enable_aria_label]
|
|
129
|
+
locate_xpath = xpath # Need to save original xpath for the label wrap
|
|
130
|
+
locator = locator.to_s
|
|
131
|
+
attr_matchers = [XPath.attr(:id) == locator,
|
|
132
|
+
XPath.attr(:name) == locator,
|
|
133
|
+
XPath.attr(:placeholder) == locator,
|
|
134
|
+
XPath.attr(:id) == XPath.anywhere(:label)[XPath.string.n.is(locator)].attr(:for)].reduce(:|)
|
|
135
|
+
attr_matchers |= XPath.attr(:'aria-label').is(locator) if enable_aria_label
|
|
136
|
+
attr_matchers |= XPath.attr(test_id) == locator if test_id
|
|
244
137
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
end
|
|
248
|
-
|
|
249
|
-
# locate_xpath = [:name, :placeholder].inject(locate_xpath) { |memo, ef| memo[find_by_attr(ef, options[ef])] }
|
|
250
|
-
locate_xpath
|
|
138
|
+
locate_xpath = locate_xpath[attr_matchers]
|
|
139
|
+
locate_xpath + locate_label(locator).descendant(xpath)
|
|
251
140
|
end
|
|
252
141
|
|
|
253
|
-
def
|
|
254
|
-
|
|
142
|
+
def locate_label(locator)
|
|
143
|
+
XPath.descendant(:label)[XPath.string.n.is(locator)]
|
|
255
144
|
end
|
|
256
145
|
|
|
257
146
|
def find_by_attr(attribute, value)
|
|
@@ -259,18 +148,12 @@ module Capybara
|
|
|
259
148
|
if respond_to?(finder_name, true)
|
|
260
149
|
send(finder_name, value)
|
|
261
150
|
else
|
|
262
|
-
value ? XPath.attr(attribute)
|
|
151
|
+
value ? XPath.attr(attribute) == value : nil
|
|
263
152
|
end
|
|
264
153
|
end
|
|
265
154
|
|
|
266
155
|
def find_by_class_attr(classes)
|
|
267
|
-
|
|
268
|
-
Array(classes).map do |klass|
|
|
269
|
-
"contains(concat(' ',normalize-space(@class),' '),' #{klass} ')"
|
|
270
|
-
end.join(" and ").to_sym
|
|
271
|
-
else
|
|
272
|
-
nil
|
|
273
|
-
end
|
|
156
|
+
Array(classes).map { |klass| XPath.attr(:class).contains_word(klass) }.reduce(:&)
|
|
274
157
|
end
|
|
275
158
|
end
|
|
276
159
|
end
|
|
@@ -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
|