capybara 3.13.2 → 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 +587 -16
- data/README.md +240 -90
- data/lib/capybara/config.rb +24 -11
- data/lib/capybara/cucumber.rb +1 -1
- data/lib/capybara/driver/base.rb +8 -0
- data/lib/capybara/driver/node.rb +20 -4
- data/lib/capybara/dsl.rb +5 -3
- data/lib/capybara/helpers.rb +25 -4
- data/lib/capybara/minitest/spec.rb +174 -90
- data/lib/capybara/minitest.rb +256 -142
- data/lib/capybara/node/actions.rb +123 -77
- data/lib/capybara/node/base.rb +20 -12
- data/lib/capybara/node/document.rb +2 -2
- data/lib/capybara/node/document_matchers.rb +3 -3
- data/lib/capybara/node/element.rb +223 -117
- data/lib/capybara/node/finders.rb +81 -71
- data/lib/capybara/node/matchers.rb +271 -134
- data/lib/capybara/node/simple.rb +18 -5
- 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 +3 -2
- data/lib/capybara/queries/current_path_query.rb +15 -5
- data/lib/capybara/queries/selector_query.rb +364 -54
- data/lib/capybara/queries/sibling_query.rb +8 -6
- data/lib/capybara/queries/style_query.rb +2 -2
- data/lib/capybara/queries/text_query.rb +13 -1
- data/lib/capybara/queries/title_query.rb +1 -1
- data/lib/capybara/rack_test/browser.rb +76 -11
- data/lib/capybara/rack_test/driver.rb +10 -5
- data/lib/capybara/rack_test/errors.rb +6 -0
- data/lib/capybara/rack_test/form.rb +31 -9
- data/lib/capybara/rack_test/node.rb +74 -23
- 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 +44 -20
- data/lib/capybara/rspec/matcher_proxies.rb +13 -11
- data/lib/capybara/rspec/matchers/base.rb +31 -16
- data/lib/capybara/rspec/matchers/compound.rb +1 -1
- 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 +2 -2
- data/lib/capybara/rspec/matchers/have_selector.rb +21 -21
- data/lib/capybara/rspec/matchers/have_sibling.rb +27 -0
- data/lib/capybara/rspec/matchers/have_text.rb +4 -4
- data/lib/capybara/rspec/matchers/have_title.rb +2 -2
- data/lib/capybara/rspec/matchers/match_selector.rb +3 -3
- data/lib/capybara/rspec/matchers/match_style.rb +7 -2
- data/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
- data/lib/capybara/rspec/matchers.rb +111 -68
- data/lib/capybara/rspec.rb +2 -0
- data/lib/capybara/selector/builders/css_builder.rb +11 -7
- data/lib/capybara/selector/builders/xpath_builder.rb +5 -3
- data/lib/capybara/selector/css.rb +11 -9
- 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_set.rb +19 -18
- data/lib/capybara/selector/filters/base.rb +11 -2
- data/lib/capybara/selector/filters/locator_filter.rb +13 -3
- data/lib/capybara/selector/regexp_disassembler.rb +11 -7
- data/lib/capybara/selector/selector.rb +50 -440
- data/lib/capybara/selector/xpath_extensions.rb +17 -0
- data/lib/capybara/selector.rb +473 -482
- 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 +174 -62
- data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +74 -18
- data/lib/capybara/selenium/driver_specializations/edge_driver.rb +128 -0
- data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +37 -3
- data/lib/capybara/selenium/driver_specializations/internet_explorer_driver.rb +14 -1
- 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 +68 -45
- data/lib/capybara/selenium/extensions/html5_drag.rb +192 -22
- data/lib/capybara/selenium/extensions/modifier_keys_stack.rb +28 -0
- data/lib/capybara/selenium/extensions/scroll.rb +8 -10
- data/lib/capybara/selenium/node.rb +268 -72
- data/lib/capybara/selenium/nodes/chrome_node.rb +105 -9
- data/lib/capybara/selenium/nodes/edge_node.rb +110 -0
- data/lib/capybara/selenium/nodes/firefox_node.rb +51 -61
- 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 +1 -1
- data/lib/capybara/selenium/patches/persistent_client.rb +20 -0
- data/lib/capybara/server/animation_disabler.rb +43 -21
- data/lib/capybara/server/checker.rb +6 -2
- data/lib/capybara/server/middleware.rb +25 -13
- data/lib/capybara/server.rb +20 -4
- data/lib/capybara/session/config.rb +15 -11
- data/lib/capybara/session/matchers.rb +11 -11
- data/lib/capybara/session.rb +162 -131
- data/lib/capybara/spec/public/offset.js +6 -0
- data/lib/capybara/spec/public/test.js +105 -6
- data/lib/capybara/spec/session/accept_alert_spec.rb +1 -1
- data/lib/capybara/spec/session/active_element_spec.rb +31 -0
- data/lib/capybara/spec/session/all_spec.rb +89 -15
- data/lib/capybara/spec/session/ancestor_spec.rb +5 -0
- data/lib/capybara/spec/session/assert_current_path_spec.rb +5 -2
- data/lib/capybara/spec/session/assert_text_spec.rb +26 -22
- data/lib/capybara/spec/session/attach_file_spec.rb +64 -31
- data/lib/capybara/spec/session/check_spec.rb +26 -4
- data/lib/capybara/spec/session/choose_spec.rb +14 -2
- data/lib/capybara/spec/session/click_button_spec.rb +109 -61
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +9 -0
- data/lib/capybara/spec/session/click_link_spec.rb +23 -1
- data/lib/capybara/spec/session/current_scope_spec.rb +1 -1
- data/lib/capybara/spec/session/current_url_spec.rb +11 -1
- data/lib/capybara/spec/session/element/matches_selector_spec.rb +40 -39
- data/lib/capybara/spec/session/evaluate_script_spec.rb +12 -0
- data/lib/capybara/spec/session/fill_in_spec.rb +46 -5
- data/lib/capybara/spec/session/find_link_spec.rb +10 -0
- data/lib/capybara/spec/session/find_spec.rb +80 -7
- data/lib/capybara/spec/session/first_spec.rb +2 -2
- data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +14 -1
- data/lib/capybara/spec/session/frame/within_frame_spec.rb +14 -1
- data/lib/capybara/spec/session/has_all_selectors_spec.rb +5 -5
- data/lib/capybara/spec/session/has_ancestor_spec.rb +46 -0
- data/lib/capybara/spec/session/has_any_selectors_spec.rb +6 -2
- data/lib/capybara/spec/session/has_button_spec.rb +81 -0
- data/lib/capybara/spec/session/has_css_spec.rb +45 -8
- data/lib/capybara/spec/session/has_current_path_spec.rb +22 -7
- data/lib/capybara/spec/session/has_element_spec.rb +47 -0
- data/lib/capybara/spec/session/has_field_spec.rb +59 -1
- data/lib/capybara/spec/session/has_link_spec.rb +40 -0
- data/lib/capybara/spec/session/has_none_selectors_spec.rb +7 -7
- data/lib/capybara/spec/session/has_select_spec.rb +42 -8
- data/lib/capybara/spec/session/has_selector_spec.rb +19 -4
- data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
- data/lib/capybara/spec/session/has_table_spec.rb +177 -0
- data/lib/capybara/spec/session/has_text_spec.rb +31 -3
- data/lib/capybara/spec/session/html_spec.rb +1 -1
- data/lib/capybara/spec/session/matches_style_spec.rb +6 -4
- data/lib/capybara/spec/session/node_spec.rb +697 -23
- data/lib/capybara/spec/session/node_wrapper_spec.rb +1 -1
- data/lib/capybara/spec/session/refresh_spec.rb +2 -1
- data/lib/capybara/spec/session/reset_session_spec.rb +21 -7
- data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +2 -2
- data/lib/capybara/spec/session/save_page_spec.rb +4 -4
- data/lib/capybara/spec/session/save_screenshot_spec.rb +4 -4
- data/lib/capybara/spec/session/scroll_spec.rb +9 -7
- data/lib/capybara/spec/session/select_spec.rb +5 -10
- data/lib/capybara/spec/session/selectors_spec.rb +24 -3
- data/lib/capybara/spec/session/uncheck_spec.rb +3 -3
- data/lib/capybara/spec/session/unselect_spec.rb +1 -1
- data/lib/capybara/spec/session/visit_spec.rb +20 -0
- data/lib/capybara/spec/session/window/become_closed_spec.rb +20 -17
- data/lib/capybara/spec/session/window/switch_to_window_spec.rb +1 -1
- data/lib/capybara/spec/session/window/window_opened_by_spec.rb +1 -1
- data/lib/capybara/spec/session/window/window_spec.rb +54 -57
- data/lib/capybara/spec/session/window/windows_spec.rb +2 -2
- data/lib/capybara/spec/session/within_spec.rb +36 -0
- data/lib/capybara/spec/spec_helper.rb +30 -19
- data/lib/capybara/spec/test_app.rb +122 -34
- data/lib/capybara/spec/views/animated.erb +49 -0
- data/lib/capybara/spec/views/form.erb +86 -8
- data/lib/capybara/spec/views/frame_child.erb +3 -2
- 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 +10 -10
- 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 +2 -1
- 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 +34 -6
- data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
- data/lib/capybara/spec/views/with_js.erb +7 -4
- 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 +14 -18
- data/lib/capybara.rb +91 -126
- data/spec/basic_node_spec.rb +30 -16
- data/spec/capybara_spec.rb +40 -28
- data/spec/counter_spec.rb +35 -0
- data/spec/css_builder_spec.rb +3 -1
- data/spec/css_splitter_spec.rb +1 -1
- data/spec/dsl_spec.rb +33 -22
- data/spec/filter_set_spec.rb +5 -5
- data/spec/fixtures/selenium_driver_rspec_failure.rb +3 -3
- data/spec/fixtures/selenium_driver_rspec_success.rb +3 -3
- data/spec/minitest_spec.rb +24 -2
- data/spec/minitest_spec_spec.rb +60 -45
- data/spec/per_session_config_spec.rb +1 -1
- data/spec/rack_test_spec.rb +131 -98
- data/spec/regexp_dissassembler_spec.rb +53 -39
- data/spec/result_spec.rb +68 -66
- data/spec/rspec/features_spec.rb +9 -4
- data/spec/rspec/scenarios_spec.rb +6 -2
- data/spec/rspec/shared_spec_matchers.rb +137 -98
- data/spec/rspec_matchers_spec.rb +25 -0
- data/spec/rspec_spec.rb +23 -21
- data/spec/sauce_spec_chrome.rb +43 -0
- data/spec/selector_spec.rb +77 -21
- data/spec/selenium_spec_chrome.rb +141 -39
- data/spec/selenium_spec_chrome_remote.rb +32 -17
- data/spec/selenium_spec_edge.rb +36 -8
- data/spec/selenium_spec_firefox.rb +110 -68
- data/spec/selenium_spec_firefox_remote.rb +22 -15
- data/spec/selenium_spec_ie.rb +29 -22
- data/spec/selenium_spec_safari.rb +162 -0
- data/spec/server_spec.rb +153 -81
- data/spec/session_spec.rb +11 -4
- data/spec/shared_selenium_node.rb +79 -0
- data/spec/shared_selenium_session.rb +179 -74
- data/spec/spec_helper.rb +80 -5
- data/spec/whitespace_normalizer_spec.rb +54 -0
- data/spec/xpath_builder_spec.rb +3 -1
- metadata +218 -30
- data/lib/capybara/spec/session/source_spec.rb +0 -0
- data/lib/capybara/spec/views/with_title.erb +0 -5
@@ -1,183 +1,10 @@
|
|
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
|
-
require 'capybara/selector/regexp_disassembler'
|
8
|
-
require 'capybara/selector/builders/xpath_builder'
|
9
|
-
require 'capybara/selector/builders/css_builder'
|
10
|
-
|
11
3
|
module Capybara
|
12
|
-
|
13
|
-
# ## Built-in Selectors
|
14
|
-
#
|
15
|
-
# * **:xpath** - Select elements by XPath expression
|
16
|
-
# * Locator: An XPath expression
|
17
|
-
#
|
18
|
-
# * **:css** - Select elements by CSS selector
|
19
|
-
# * Locator: A CSS selector
|
20
|
-
#
|
21
|
-
# * **:id** - Select element by id
|
22
|
-
# * Locator: (String, Regexp, XPath::Expression) The id of the element to match
|
23
|
-
#
|
24
|
-
# * **:field** - Select field elements (input [not of type submit, image, or hidden], textarea, select)
|
25
|
-
# * Locator: Matches against the id, Capybara.test_id attribute, name, or placeholder
|
26
|
-
# * Filters:
|
27
|
-
# * :id (String, Regexp, XPath::Expression) — Matches the id attribute
|
28
|
-
# * :name (String) — Matches the name attribute
|
29
|
-
# * :placeholder (String) — Matches the placeholder attribute
|
30
|
-
# * :type (String) — Matches the type attribute of the field or element type for 'textarea' and 'select'
|
31
|
-
# * :readonly (Boolean)
|
32
|
-
# * :with (String) — Matches the current value of the field
|
33
|
-
# * :class (String, Array<String>, Regexp, XPath::Expression) — Matches the class(es) provided
|
34
|
-
# * :checked (Boolean) — Match checked fields?
|
35
|
-
# * :unchecked (Boolean) — Match unchecked fields?
|
36
|
-
# * :disabled (Boolean) — Match disabled field?
|
37
|
-
# * :multiple (Boolean) — Match fields that accept multiple values
|
38
|
-
# * :style (String, Regexp, Hash)
|
39
|
-
#
|
40
|
-
# * **:fieldset** - Select fieldset elements
|
41
|
-
# * Locator: Matches id or contents of wrapped legend
|
42
|
-
# * Filters:
|
43
|
-
# * :id (String, Regexp, XPath::Expression) — Matches id attribute
|
44
|
-
# * :legend (String) — Matches contents of wrapped legend
|
45
|
-
# * :class (String, Array<String>, Regexp, XPath::Expression) — Matches the class(es) provided
|
46
|
-
# * :style (String, Regexp, Hash)
|
47
|
-
#
|
48
|
-
# * **:link** - Find links ( <a> elements with an href attribute )
|
49
|
-
# * Locator: Matches the id or title attributes, or the string content of the link, or the alt attribute of a contained img element
|
50
|
-
# * Filters:
|
51
|
-
# * :id (String, Regexp, XPath::Expression) — Matches the id attribute
|
52
|
-
# * :title (String) — Matches the title attribute
|
53
|
-
# * :alt (String) — Matches the alt attribute of a contained img element
|
54
|
-
# * :class (String, Array<String>, Regexp, XPath::Expression) — Matches the class(es) provided
|
55
|
-
# * :href (String, Regexp, nil) — Matches the normalized href of the link, if nil will find <a> elements with no href attribute
|
56
|
-
# * :style (String, Regexp, Hash)
|
57
|
-
#
|
58
|
-
# * **:button** - Find buttons ( input [of type submit, reset, image, button] or button elements )
|
59
|
-
# * Locator: Matches the id, Capybara.test_id attribute, 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
|
60
|
-
# * Filters:
|
61
|
-
# * :id (String, Regexp, XPath::Expression) — Matches the id attribute
|
62
|
-
# * :title (String) — Matches the title attribute
|
63
|
-
# * :class (String, Array<String>, Regexp, XPath::Expression) — Matches the class(es) provided
|
64
|
-
# * :value (String) — Matches the value of an input button
|
65
|
-
# * :type
|
66
|
-
# * :style (String, Regexp, Hash)
|
67
|
-
#
|
68
|
-
# * **:link_or_button** - Find links or buttons
|
69
|
-
# * Locator: See :link and :button selectors
|
70
|
-
#
|
71
|
-
# * **:fillable_field** - Find text fillable fields ( textarea, input [not of type submit, image, radio, checkbox, hidden, file] )
|
72
|
-
# * Locator: Matches against the id, Capybara.test_id attribute, name, or placeholder
|
73
|
-
# * Filters:
|
74
|
-
# * :id (String, Regexp, XPath::Expression) — Matches the id attribute
|
75
|
-
# * :name (String) — Matches the name attribute
|
76
|
-
# * :placeholder (String) — Matches the placeholder attribute
|
77
|
-
# * :with (String) — Matches the current value of the field
|
78
|
-
# * :type (String) — Matches the type attribute of the field or element type for 'textarea'
|
79
|
-
# * :class (String, Array<String>, Regexp, XPath::Expression) — Matches the class(es) provided
|
80
|
-
# * :disabled (Boolean) — Match disabled field?
|
81
|
-
# * :multiple (Boolean) — Match fields that accept multiple values
|
82
|
-
# * :style (String, Regexp, Hash)
|
83
|
-
#
|
84
|
-
# * **:radio_button** - Find radio buttons
|
85
|
-
# * Locator: Match id, Capybara.test_id attribute, name, or associated label text
|
86
|
-
# * Filters:
|
87
|
-
# * :id (String, Regexp, XPath::Expression) — Matches the id attribute
|
88
|
-
# * :name (String) — Matches the name attribute
|
89
|
-
# * :class (String, Array<String>, Regexp, XPath::Expression) — Matches the class(es) provided
|
90
|
-
# * :checked (Boolean) — Match checked fields?
|
91
|
-
# * :unchecked (Boolean) — Match unchecked fields?
|
92
|
-
# * :disabled (Boolean) — Match disabled field?
|
93
|
-
# * :option (String) — Match the value
|
94
|
-
# * :style (String, Regexp, Hash)
|
95
|
-
#
|
96
|
-
# * **:checkbox** - Find checkboxes
|
97
|
-
# * Locator: Match id, Capybara.test_id attribute, name, or associated label text
|
98
|
-
# * Filters:
|
99
|
-
# * *:id (String, Regexp, XPath::Expression) — Matches the id attribute
|
100
|
-
# * *:name (String) — Matches the name attribute
|
101
|
-
# * *:class (String, Array<String>, Regexp, XPath::Expression) — Matches the class(es) provided
|
102
|
-
# * *:checked (Boolean) — Match checked fields?
|
103
|
-
# * *:unchecked (Boolean) — Match unchecked fields?
|
104
|
-
# * *:disabled (Boolean) — Match disabled field?
|
105
|
-
# * *:option (String) — Match the value
|
106
|
-
# * :style (String, Regexp, Hash)
|
107
|
-
#
|
108
|
-
# * **:select** - Find select elements
|
109
|
-
# * Locator: Match id, Capybara.test_id attribute, name, placeholder, or associated label text
|
110
|
-
# * Filters:
|
111
|
-
# * :id (String, Regexp, XPath::Expression) — Matches the id attribute
|
112
|
-
# * :name (String) — Matches the name attribute
|
113
|
-
# * :placeholder (String) — Matches the placeholder attribute
|
114
|
-
# * :class (String, Array<String>, Regexp, XPath::Expression) — Matches the class(es) provided
|
115
|
-
# * :disabled (Boolean) — Match disabled field?
|
116
|
-
# * :multiple (Boolean) — Match fields that accept multiple values
|
117
|
-
# * :options (Array<String>) — Exact match options
|
118
|
-
# * :with_options (Array<String>) — Partial match options
|
119
|
-
# * :selected (String, Array<String>) — Match the selection(s)
|
120
|
-
# * :with_selected (String, Array<String>) — Partial match the selection(s)
|
121
|
-
# * :style (String, Regexp, Hash)
|
122
|
-
#
|
123
|
-
# * **:option** - Find option elements
|
124
|
-
# * Locator: Match text of option
|
125
|
-
# * Filters:
|
126
|
-
# * :disabled (Boolean) — Match disabled option
|
127
|
-
# * :selected (Boolean) — Match selected option
|
128
|
-
#
|
129
|
-
# * **:datalist_input**
|
130
|
-
# * Locator:
|
131
|
-
# * Filters:
|
132
|
-
# * :disabled
|
133
|
-
# * :name
|
134
|
-
# * :placeholder
|
135
|
-
#
|
136
|
-
# * **:datalist_option**
|
137
|
-
# * Locator:
|
138
|
-
#
|
139
|
-
# * **:file_field** - Find file input elements
|
140
|
-
# * Locator: Match id, Capybara.test_id attribute, name, or associated label text
|
141
|
-
# * Filters:
|
142
|
-
# * :id (String, Regexp, XPath::Expression) — Matches the id attribute
|
143
|
-
# * :name (String) — Matches the name attribute
|
144
|
-
# * :class (String, Array<String>, Regexp, XPath::Expression) — Matches the class(es) provided
|
145
|
-
# * :disabled (Boolean) — Match disabled field?
|
146
|
-
# * :multiple (Boolean) — Match field that accepts multiple values
|
147
|
-
# * :style (String, Regexp, Hash)
|
148
|
-
#
|
149
|
-
# * **:label** - Find label elements
|
150
|
-
# * Locator: Match id or text contents
|
151
|
-
# * Filters:
|
152
|
-
# * :for (Element, String) — The element or id of the element associated with the label
|
153
|
-
#
|
154
|
-
# * **:table** - Find table elements
|
155
|
-
# * Locator: id or caption text of table
|
156
|
-
# * Filters:
|
157
|
-
# * :id (String, Regexp, XPath::Expression) — Match id attribute of table
|
158
|
-
# * :caption (String) — Match text of associated caption
|
159
|
-
# * :class ((String, Array<String>, Regexp, XPath::Expression) — Matches the class(es) provided
|
160
|
-
# * :style (String, Regexp, Hash)
|
161
|
-
#
|
162
|
-
# * **:frame** - Find frame/iframe elements
|
163
|
-
# * Locator: Match id or name
|
164
|
-
# * Filters:
|
165
|
-
# * :id (String, Regexp, XPath::Expression) — Match id attribute
|
166
|
-
# * :name (String) — Match name attribute
|
167
|
-
# * :class (String, Array<String>, Regexp, XPath::Expression) — Matches the class(es) provided
|
168
|
-
# * :style (String, Regexp, Hash)
|
169
|
-
#
|
170
|
-
# * **:element**
|
171
|
-
# * Locator: Type of element ('div', 'a', etc) - if not specified defaults to '*'
|
172
|
-
# * Filters: Matches on any element attribute
|
173
|
-
#
|
174
|
-
class Selector
|
175
|
-
attr_reader :name, :format
|
176
|
-
extend Forwardable
|
177
|
-
|
4
|
+
class Selector < SimpleDelegator
|
178
5
|
class << self
|
179
6
|
def all
|
180
|
-
@
|
7
|
+
@definitions ||= {} # rubocop:disable Naming/MemoizedInstanceVariableName
|
181
8
|
end
|
182
9
|
|
183
10
|
def [](name)
|
@@ -185,7 +12,7 @@ module Capybara
|
|
185
12
|
end
|
186
13
|
|
187
14
|
def add(name, **options, &block)
|
188
|
-
all[name.to_sym] =
|
15
|
+
all[name.to_sym] = Definition.new(name.to_sym, **options, &block)
|
189
16
|
end
|
190
17
|
|
191
18
|
def update(name, &block)
|
@@ -201,226 +28,67 @@ module Capybara
|
|
201
28
|
end
|
202
29
|
end
|
203
30
|
|
204
|
-
|
205
|
-
@name = name
|
206
|
-
@filter_set = FilterSet.add(name) {}
|
207
|
-
@match = nil
|
208
|
-
@label = nil
|
209
|
-
@failure_message = nil
|
210
|
-
@format = nil
|
211
|
-
@expression = nil
|
212
|
-
@expression_filters = {}
|
213
|
-
@locator_filter = nil
|
214
|
-
@default_visibility = nil
|
215
|
-
@locator_type = locator_type
|
216
|
-
@raw_locator = raw_locator
|
217
|
-
@config = {
|
218
|
-
enable_aria_label: false,
|
219
|
-
test_id: nil
|
220
|
-
}
|
221
|
-
instance_eval(&block)
|
222
|
-
end
|
223
|
-
|
224
|
-
def custom_filters
|
225
|
-
warn "Deprecated: Selector#custom_filters is not valid when same named expression and node filter exist - don't use"
|
226
|
-
node_filters.merge(expression_filters).freeze
|
227
|
-
end
|
31
|
+
attr_reader :errors
|
228
32
|
|
229
|
-
def
|
230
|
-
|
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 = []
|
231
40
|
end
|
232
41
|
|
233
|
-
def
|
234
|
-
@
|
42
|
+
def format
|
43
|
+
@format || @definition.default_format
|
235
44
|
end
|
45
|
+
alias_method :current_format, :format
|
236
46
|
|
237
|
-
|
238
|
-
|
239
|
-
# Define a selector by an xpath expression
|
240
|
-
#
|
241
|
-
# @overload xpath(*expression_filters, &block)
|
242
|
-
# @param [Array<Symbol>] expression_filters ([]) Names of filters that are implemented via this expression, if not specified the names of any keyword parameters in the block will be used
|
243
|
-
# @yield [locator, options] The block to use to generate the XPath expression
|
244
|
-
# @yieldparam [String] locator The locator string passed to the query
|
245
|
-
# @yieldparam [Hash] options The options hash passed to the query
|
246
|
-
# @yieldreturn [#to_xpath, #to_s] An object that can produce an xpath expression
|
247
|
-
#
|
248
|
-
# @overload xpath()
|
249
|
-
# @return [#call] The block that will be called to generate the XPath expression
|
250
|
-
#
|
251
|
-
def xpath(*allowed_filters, &block)
|
252
|
-
expression(:xpath, allowed_filters, &block)
|
253
|
-
end
|
254
|
-
|
255
|
-
##
|
256
|
-
#
|
257
|
-
# Define a selector by a CSS selector
|
258
|
-
#
|
259
|
-
# @overload css(*expression_filters, &block)
|
260
|
-
# @param [Array<Symbol>] expression_filters ([]) Names of filters that can be implemented via this CSS selector
|
261
|
-
# @yield [locator, options] The block to use to generate the CSS selector
|
262
|
-
# @yieldparam [String] locator The locator string passed to the query
|
263
|
-
# @yieldparam [Hash] options The options hash passed to the query
|
264
|
-
# @yieldreturn [#to_s] An object that can produce a CSS selector
|
265
|
-
#
|
266
|
-
# @overload css()
|
267
|
-
# @return [#call] The block that will be called to generate the CSS selector
|
268
|
-
#
|
269
|
-
def css(*allowed_filters, &block)
|
270
|
-
expression(:css, allowed_filters, &block)
|
47
|
+
def enable_aria_label
|
48
|
+
@config[:enable_aria_label]
|
271
49
|
end
|
272
50
|
|
273
|
-
|
274
|
-
|
275
|
-
# Automatic selector detection
|
276
|
-
#
|
277
|
-
# @yield [locator] This block takes the passed in locator string and returns whether or not it matches the selector
|
278
|
-
# @yieldparam [String], locator The locator string used to determin if it matches the selector
|
279
|
-
# @yieldreturn [Boolean] Whether this selector matches the locator string
|
280
|
-
# @return [#call] The block that will be used to detect selector match
|
281
|
-
#
|
282
|
-
def match(&block)
|
283
|
-
@match = block if block
|
284
|
-
@match
|
51
|
+
def enable_aria_role
|
52
|
+
@config[:enable_aria_role]
|
285
53
|
end
|
286
54
|
|
287
|
-
|
288
|
-
|
289
|
-
# Set/get a descriptive label for the selector
|
290
|
-
#
|
291
|
-
# @overload label(label)
|
292
|
-
# @param [String] label A descriptive label for this selector - used in error messages
|
293
|
-
# @overload label()
|
294
|
-
# @return [String] The currently set label
|
295
|
-
#
|
296
|
-
def label(label = nil)
|
297
|
-
@label = label if label
|
298
|
-
@label
|
55
|
+
def test_id
|
56
|
+
@config[:test_id]
|
299
57
|
end
|
300
58
|
|
301
|
-
|
302
|
-
#
|
303
|
-
# Description of the selector
|
304
|
-
#
|
305
|
-
# @!method description(options)
|
306
|
-
# @param [Hash] options The options of the query used to generate the description
|
307
|
-
# @return [String] Description of the selector when used with the options passed
|
308
|
-
def_delegator :@filter_set, :description
|
309
|
-
|
310
|
-
def call(locator, selector_config: {}, **options)
|
311
|
-
@config.merge! selector_config
|
59
|
+
def call(locator, **options)
|
312
60
|
if format
|
313
|
-
@
|
61
|
+
raise ArgumentError, "Selector #{@name} does not support #{format}" unless expressions.key?(format)
|
62
|
+
|
63
|
+
instance_exec(locator, **options, &expressions[format])
|
314
64
|
else
|
315
65
|
warn 'Selector has no format'
|
316
66
|
end
|
317
67
|
ensure
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
#
|
325
|
-
# This is used by the automatic selector selection mechanism when no selector type is passed to a selector query
|
326
|
-
#
|
327
|
-
# @param [String] locator The locator passed to the query
|
328
|
-
# @return [Boolean] Whether or not to use this selector
|
329
|
-
#
|
330
|
-
def match?(locator)
|
331
|
-
@match&.call(locator)
|
332
|
-
end
|
333
|
-
|
334
|
-
##
|
335
|
-
#
|
336
|
-
# Define a node filter for use with this selector
|
337
|
-
#
|
338
|
-
# @!method node_filter(name, *types, options={}, &block)
|
339
|
-
# @param [Symbol, Regexp] name The filter name
|
340
|
-
# @param [Array<Symbol>] types The types of the filter - currently valid types are [:boolean]
|
341
|
-
# @param [Hash] options ({}) Options of the filter
|
342
|
-
# @option options [Array<>] :valid_values Valid values for this filter
|
343
|
-
# @option options :default The default value of the filter (if any)
|
344
|
-
# @option options :skip_if Value of the filter that will cause it to be skipped
|
345
|
-
# @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.
|
346
|
-
#
|
347
|
-
# If a Symbol is passed for the name the block should accept | node, option_value |, while if a Regexp
|
348
|
-
# is passed for the name the block should accept | node, option_name, option_value |. In either case
|
349
|
-
# the block should return `true` if the node passes the filer or `false` if it doesn't
|
350
|
-
|
351
|
-
# @!method filter
|
352
|
-
# See {Selector#node_filter}
|
353
|
-
|
354
|
-
##
|
355
|
-
#
|
356
|
-
# Define an expression filter for use with this selector
|
357
|
-
#
|
358
|
-
# @!method expression_filter(name, *types, matcher: nil, **options, &block)
|
359
|
-
# @param [Symbol, Regexp] name The filter name
|
360
|
-
# @param [Regexp] matcher (nil) A Regexp used to check whether a specific option is handled by this filter
|
361
|
-
# @param [Array<Symbol>] types The types of the filter - currently valid types are [:boolean]
|
362
|
-
# @param [Hash] options ({}) Options of the filter
|
363
|
-
# @option options [Array<>] :valid_values Valid values for this filter
|
364
|
-
# @option options :default The default value of the filter (if any)
|
365
|
-
# @option options :skip_if Value of the filter that will cause it to be skipped
|
366
|
-
# @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.
|
367
|
-
#
|
368
|
-
# If a Symbol is passed for the name the block should accept | current_expression, option_value |, while if a Regexp
|
369
|
-
# is passed for the name the block should accept | current_expression, option_name, option_value |. In either case
|
370
|
-
# the block should return the modified expression
|
371
|
-
|
372
|
-
def_delegators :@filter_set, :node_filter, :expression_filter, :filter
|
373
|
-
|
374
|
-
def locator_filter(*types, **options, &block)
|
375
|
-
types.each { |type| options[type] = true }
|
376
|
-
@locator_filter = Filters::LocatorFilter.new(block, options) if block
|
377
|
-
@locator_filter
|
378
|
-
end
|
379
|
-
|
380
|
-
def filter_set(name, filters_to_use = nil)
|
381
|
-
@filter_set.import(name, filters_to_use)
|
382
|
-
end
|
383
|
-
|
384
|
-
def_delegator :@filter_set, :describe
|
385
|
-
|
386
|
-
def describe_expression_filters(&block)
|
387
|
-
if block_given?
|
388
|
-
describe(:expression_filters, &block)
|
389
|
-
else
|
390
|
-
describe(:expression_filters) do |**options|
|
391
|
-
describe_all_expression_filters(options)
|
392
|
-
end
|
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
|
+
)
|
393
74
|
end
|
394
75
|
end
|
395
76
|
|
396
|
-
def
|
397
|
-
|
398
|
-
end
|
399
|
-
|
400
|
-
##
|
401
|
-
#
|
402
|
-
# Set the default visibility mode that shouble be used if no visibile option is passed when using the selector.
|
403
|
-
# If not specified will default to the behavior indicated by Capybara.ignore_hidden_elements
|
404
|
-
#
|
405
|
-
# @param [Symbol] default_visibility Only find elements with the specified visibility:
|
406
|
-
# * :all - finds visible and invisible elements.
|
407
|
-
# * :hidden - only finds invisible elements.
|
408
|
-
# * :visible - only finds visible elements.
|
409
|
-
def visible(default_visibility = nil, &block)
|
410
|
-
@default_visibility = block || default_visibility
|
77
|
+
def add_error(error_msg)
|
78
|
+
errors << error_msg
|
411
79
|
end
|
412
80
|
|
413
|
-
def
|
414
|
-
|
415
|
-
@default_visibility.call(options)
|
416
|
-
else
|
417
|
-
@default_visibility
|
418
|
-
end
|
419
|
-
vis.nil? ? fallback : vis
|
81
|
+
def expression_for(name, locator, config: @config, format: current_format, **options)
|
82
|
+
Selector.new(name, config: config, format: format).call(locator, **options)
|
420
83
|
end
|
421
84
|
|
422
|
-
|
423
|
-
|
85
|
+
# @api private
|
86
|
+
def with_filter_errors(errors)
|
87
|
+
old_errors = @errors
|
88
|
+
@errors = errors
|
89
|
+
yield
|
90
|
+
ensure
|
91
|
+
@errors = old_errors
|
424
92
|
end
|
425
93
|
|
426
94
|
# @api private
|
@@ -431,39 +99,12 @@ module Capybara
|
|
431
99
|
when :xpath
|
432
100
|
Capybara::Selector::XPathBuilder
|
433
101
|
else
|
434
|
-
raise NotImplementedError, "No builder exists for selector of type #{
|
102
|
+
raise NotImplementedError, "No builder exists for selector of type #{default_format}"
|
435
103
|
end.new(expr)
|
436
104
|
end
|
437
105
|
|
438
|
-
# @api private
|
439
|
-
def with_filter_errors(errors)
|
440
|
-
Thread.current["capybara_#{object_id}_errors"] = errors
|
441
|
-
yield
|
442
|
-
ensure
|
443
|
-
Thread.current["capybara_#{object_id}_errors"] = nil
|
444
|
-
end
|
445
|
-
|
446
|
-
# @api private
|
447
|
-
def raw_locator?
|
448
|
-
!!@raw_locator
|
449
|
-
end
|
450
|
-
|
451
106
|
private
|
452
107
|
|
453
|
-
def locator_types
|
454
|
-
return nil unless @locator_type
|
455
|
-
|
456
|
-
Array(@locator_type)
|
457
|
-
end
|
458
|
-
|
459
|
-
def locator_valid?(locator)
|
460
|
-
return true unless locator && locator_types
|
461
|
-
|
462
|
-
locator_types&.any? do |type_or_method|
|
463
|
-
type_or_method.is_a?(Symbol) ? locator.respond_to?(type_or_method) : type_or_method === locator # rubocop:disable Style/CaseEquality
|
464
|
-
end
|
465
|
-
end
|
466
|
-
|
467
108
|
def locator_description
|
468
109
|
locator_types.group_by { |lt| lt.is_a? Symbol }.map do |symbol, types_or_methods|
|
469
110
|
if symbol
|
@@ -474,16 +115,12 @@ module Capybara
|
|
474
115
|
end.join(' or ')
|
475
116
|
end
|
476
117
|
|
477
|
-
def
|
478
|
-
|
479
|
-
end
|
480
|
-
|
481
|
-
def enable_aria_label
|
482
|
-
@config[:enable_aria_label]
|
483
|
-
end
|
118
|
+
def locator_valid?(locator)
|
119
|
+
return true unless locator && locator_types
|
484
120
|
|
485
|
-
|
486
|
-
|
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
|
487
124
|
end
|
488
125
|
|
489
126
|
def locate_field(xpath, locator, **_options)
|
@@ -499,23 +136,11 @@ module Capybara
|
|
499
136
|
attr_matchers |= XPath.attr(test_id) == locator if test_id
|
500
137
|
|
501
138
|
locate_xpath = locate_xpath[attr_matchers]
|
502
|
-
locate_xpath +
|
139
|
+
locate_xpath + locate_label(locator).descendant(xpath)
|
503
140
|
end
|
504
141
|
|
505
|
-
def
|
506
|
-
|
507
|
-
if ef.matcher?
|
508
|
-
handled_custom_keys(ef, opts.keys).map { |key| " with #{ef_name}[#{key} => #{opts[key]}]" }.join
|
509
|
-
elsif opts.key?(ef_name)
|
510
|
-
" with #{ef_name} #{opts[ef_name]}"
|
511
|
-
end
|
512
|
-
end.join
|
513
|
-
end
|
514
|
-
|
515
|
-
def handled_custom_keys(filter, keys)
|
516
|
-
keys.select do |key|
|
517
|
-
filter.handles_option?(key) && !::Capybara::Queries::SelectorQuery::VALID_KEYS.include?(key)
|
518
|
-
end
|
142
|
+
def locate_label(locator)
|
143
|
+
XPath.descendant(:label)[XPath.string.n.is(locator)]
|
519
144
|
end
|
520
145
|
|
521
146
|
def find_by_attr(attribute, value)
|
@@ -530,20 +155,5 @@ module Capybara
|
|
530
155
|
def find_by_class_attr(classes)
|
531
156
|
Array(classes).map { |klass| XPath.attr(:class).contains_word(klass) }.reduce(:&)
|
532
157
|
end
|
533
|
-
|
534
|
-
def parameter_names(block)
|
535
|
-
block.parameters.select { |(type, _name)| %i[key keyreq].include? type }.map { |(_type, name)| name }
|
536
|
-
end
|
537
|
-
|
538
|
-
def expression(type, allowed_filters, &block)
|
539
|
-
if block
|
540
|
-
@format, @expression = type, block
|
541
|
-
allowed_filters = parameter_names(block) if allowed_filters.empty?
|
542
|
-
allowed_filters.flatten.each { |ef| expression_filters[ef] = Filters::IdentityExpressionFilter.new(ef) }
|
543
|
-
end
|
544
|
-
format == type ? @expression : nil
|
545
|
-
end
|
546
158
|
end
|
547
159
|
end
|
548
|
-
|
549
|
-
# 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
|