capybara 2.7.0 → 3.35.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.yardopts +1 -0
- data/History.md +1147 -11
- data/License.txt +1 -1
- data/README.md +252 -131
- data/lib/capybara/config.rb +92 -0
- data/lib/capybara/cucumber.rb +3 -3
- data/lib/capybara/driver/base.rb +52 -21
- data/lib/capybara/driver/node.rb +48 -14
- data/lib/capybara/dsl.rb +16 -9
- data/lib/capybara/helpers.rb +72 -81
- data/lib/capybara/minitest/spec.rb +267 -0
- data/lib/capybara/minitest.rb +385 -0
- data/lib/capybara/node/actions.rb +337 -89
- data/lib/capybara/node/base.rb +50 -32
- data/lib/capybara/node/document.rb +19 -3
- data/lib/capybara/node/document_matchers.rb +22 -24
- data/lib/capybara/node/element.rb +388 -125
- data/lib/capybara/node/finders.rb +231 -121
- data/lib/capybara/node/matchers.rb +503 -217
- data/lib/capybara/node/simple.rb +64 -27
- data/lib/capybara/queries/ancestor_query.rb +27 -0
- data/lib/capybara/queries/base_query.rb +87 -11
- data/lib/capybara/queries/current_path_query.rb +24 -24
- data/lib/capybara/queries/match_query.rb +15 -10
- data/lib/capybara/queries/selector_query.rb +675 -81
- data/lib/capybara/queries/sibling_query.rb +26 -0
- data/lib/capybara/queries/style_query.rb +45 -0
- data/lib/capybara/queries/text_query.rb +88 -20
- data/lib/capybara/queries/title_query.rb +9 -11
- data/lib/capybara/rack_test/browser.rb +63 -39
- data/lib/capybara/rack_test/css_handlers.rb +6 -4
- data/lib/capybara/rack_test/driver.rb +26 -16
- data/lib/capybara/rack_test/errors.rb +6 -0
- data/lib/capybara/rack_test/form.rb +73 -58
- data/lib/capybara/rack_test/node.rb +187 -67
- data/lib/capybara/rails.rb +4 -8
- data/lib/capybara/registration_container.rb +44 -0
- data/lib/capybara/registrations/drivers.rb +42 -0
- data/lib/capybara/registrations/patches/puma_ssl.rb +29 -0
- data/lib/capybara/registrations/servers.rb +45 -0
- data/lib/capybara/result.rb +142 -14
- data/lib/capybara/rspec/features.rb +17 -42
- data/lib/capybara/rspec/matcher_proxies.rb +82 -0
- data/lib/capybara/rspec/matchers/base.rb +111 -0
- data/lib/capybara/rspec/matchers/become_closed.rb +33 -0
- data/lib/capybara/rspec/matchers/compound.rb +88 -0
- data/lib/capybara/rspec/matchers/count_sugar.rb +37 -0
- data/lib/capybara/rspec/matchers/have_ancestor.rb +28 -0
- data/lib/capybara/rspec/matchers/have_current_path.rb +29 -0
- data/lib/capybara/rspec/matchers/have_selector.rb +77 -0
- data/lib/capybara/rspec/matchers/have_sibling.rb +27 -0
- data/lib/capybara/rspec/matchers/have_text.rb +33 -0
- data/lib/capybara/rspec/matchers/have_title.rb +29 -0
- data/lib/capybara/rspec/matchers/match_selector.rb +27 -0
- data/lib/capybara/rspec/matchers/match_style.rb +43 -0
- data/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
- data/lib/capybara/rspec/matchers.rb +143 -244
- data/lib/capybara/rspec.rb +10 -12
- data/lib/capybara/selector/builders/css_builder.rb +84 -0
- data/lib/capybara/selector/builders/xpath_builder.rb +71 -0
- data/lib/capybara/selector/css.rb +102 -0
- data/lib/capybara/selector/definition/button.rb +63 -0
- data/lib/capybara/selector/definition/checkbox.rb +26 -0
- data/lib/capybara/selector/definition/css.rb +10 -0
- data/lib/capybara/selector/definition/datalist_input.rb +35 -0
- data/lib/capybara/selector/definition/datalist_option.rb +25 -0
- data/lib/capybara/selector/definition/element.rb +28 -0
- data/lib/capybara/selector/definition/field.rb +40 -0
- data/lib/capybara/selector/definition/fieldset.rb +14 -0
- data/lib/capybara/selector/definition/file_field.rb +13 -0
- data/lib/capybara/selector/definition/fillable_field.rb +33 -0
- data/lib/capybara/selector/definition/frame.rb +17 -0
- data/lib/capybara/selector/definition/id.rb +6 -0
- data/lib/capybara/selector/definition/label.rb +62 -0
- data/lib/capybara/selector/definition/link.rb +54 -0
- data/lib/capybara/selector/definition/link_or_button.rb +16 -0
- data/lib/capybara/selector/definition/option.rb +27 -0
- data/lib/capybara/selector/definition/radio_button.rb +27 -0
- data/lib/capybara/selector/definition/select.rb +81 -0
- data/lib/capybara/selector/definition/table.rb +109 -0
- data/lib/capybara/selector/definition/table_row.rb +21 -0
- data/lib/capybara/selector/definition/xpath.rb +5 -0
- data/lib/capybara/selector/definition.rb +278 -0
- data/lib/capybara/selector/filter.rb +3 -46
- data/lib/capybara/selector/filter_set.rb +124 -0
- data/lib/capybara/selector/filters/base.rb +77 -0
- data/lib/capybara/selector/filters/expression_filter.rb +22 -0
- data/lib/capybara/selector/filters/locator_filter.rb +29 -0
- data/lib/capybara/selector/filters/node_filter.rb +31 -0
- data/lib/capybara/selector/regexp_disassembler.rb +214 -0
- data/lib/capybara/selector/selector.rb +155 -0
- data/lib/capybara/selector/xpath_extensions.rb +17 -0
- data/lib/capybara/selector.rb +232 -369
- data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -0
- data/lib/capybara/selenium/atoms/isDisplayed.min.js +1 -0
- data/lib/capybara/selenium/atoms/src/getAttribute.js +161 -0
- data/lib/capybara/selenium/atoms/src/isDisplayed.js +454 -0
- data/lib/capybara/selenium/driver.rb +380 -142
- data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +117 -0
- data/lib/capybara/selenium/driver_specializations/edge_driver.rb +124 -0
- data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +89 -0
- data/lib/capybara/selenium/driver_specializations/internet_explorer_driver.rb +26 -0
- data/lib/capybara/selenium/driver_specializations/safari_driver.rb +24 -0
- data/lib/capybara/selenium/extensions/file_input_click_emulation.rb +34 -0
- data/lib/capybara/selenium/extensions/find.rb +110 -0
- data/lib/capybara/selenium/extensions/html5_drag.rb +228 -0
- data/lib/capybara/selenium/extensions/modifier_keys_stack.rb +28 -0
- data/lib/capybara/selenium/extensions/scroll.rb +76 -0
- data/lib/capybara/selenium/logger_suppressor.rb +40 -0
- data/lib/capybara/selenium/node.rb +528 -97
- data/lib/capybara/selenium/nodes/chrome_node.rb +137 -0
- data/lib/capybara/selenium/nodes/edge_node.rb +104 -0
- data/lib/capybara/selenium/nodes/firefox_node.rb +136 -0
- data/lib/capybara/selenium/nodes/ie_node.rb +22 -0
- data/lib/capybara/selenium/nodes/safari_node.rb +118 -0
- data/lib/capybara/selenium/patches/action_pauser.rb +26 -0
- data/lib/capybara/selenium/patches/atoms.rb +18 -0
- data/lib/capybara/selenium/patches/is_displayed.rb +16 -0
- data/lib/capybara/selenium/patches/logs.rb +45 -0
- data/lib/capybara/selenium/patches/pause_duration_fix.rb +9 -0
- data/lib/capybara/selenium/patches/persistent_client.rb +20 -0
- data/lib/capybara/server/animation_disabler.rb +63 -0
- data/lib/capybara/server/checker.rb +44 -0
- data/lib/capybara/server/middleware.rb +71 -0
- data/lib/capybara/server.rb +74 -71
- data/lib/capybara/session/config.rb +126 -0
- data/lib/capybara/session/matchers.rb +44 -27
- data/lib/capybara/session.rb +500 -297
- data/lib/capybara/spec/fixtures/no_extension +1 -0
- data/lib/capybara/spec/public/jquery.js +5 -5
- data/lib/capybara/spec/public/offset.js +6 -0
- data/lib/capybara/spec/public/test.js +168 -14
- data/lib/capybara/spec/session/accept_alert_spec.rb +37 -14
- data/lib/capybara/spec/session/accept_confirm_spec.rb +7 -6
- data/lib/capybara/spec/session/accept_prompt_spec.rb +38 -10
- data/lib/capybara/spec/session/all_spec.rb +179 -59
- data/lib/capybara/spec/session/ancestor_spec.rb +88 -0
- data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +140 -0
- data/lib/capybara/spec/session/assert_current_path_spec.rb +75 -0
- data/lib/capybara/spec/session/assert_selector_spec.rb +143 -0
- data/lib/capybara/spec/session/assert_style_spec.rb +26 -0
- data/lib/capybara/spec/session/assert_text_spec.rb +258 -0
- data/lib/capybara/spec/session/assert_title_spec.rb +93 -0
- data/lib/capybara/spec/session/attach_file_spec.rb +154 -48
- data/lib/capybara/spec/session/body_spec.rb +12 -13
- data/lib/capybara/spec/session/check_spec.rb +168 -41
- data/lib/capybara/spec/session/choose_spec.rb +75 -23
- data/lib/capybara/spec/session/click_button_spec.rb +243 -175
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +57 -32
- data/lib/capybara/spec/session/click_link_spec.rb +100 -53
- data/lib/capybara/spec/session/current_scope_spec.rb +11 -10
- data/lib/capybara/spec/session/current_url_spec.rb +61 -35
- data/lib/capybara/spec/session/dismiss_confirm_spec.rb +7 -7
- data/lib/capybara/spec/session/dismiss_prompt_spec.rb +5 -4
- data/lib/capybara/spec/session/element/{assert_match_selector.rb → assert_match_selector_spec.rb} +13 -6
- data/lib/capybara/spec/session/element/match_css_spec.rb +21 -7
- data/lib/capybara/spec/session/element/match_xpath_spec.rb +9 -7
- data/lib/capybara/spec/session/element/matches_selector_spec.rb +91 -34
- data/lib/capybara/spec/session/evaluate_async_script_spec.rb +23 -0
- data/lib/capybara/spec/session/evaluate_script_spec.rb +45 -3
- data/lib/capybara/spec/session/execute_script_spec.rb +24 -4
- data/lib/capybara/spec/session/fill_in_spec.rb +166 -64
- data/lib/capybara/spec/session/find_button_spec.rb +37 -18
- data/lib/capybara/spec/session/find_by_id_spec.rb +10 -9
- data/lib/capybara/spec/session/find_field_spec.rb +57 -34
- data/lib/capybara/spec/session/find_link_spec.rb +47 -10
- data/lib/capybara/spec/session/find_spec.rb +290 -144
- data/lib/capybara/spec/session/first_spec.rb +91 -48
- data/lib/capybara/spec/session/frame/frame_title_spec.rb +23 -0
- data/lib/capybara/spec/session/frame/frame_url_spec.rb +23 -0
- data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +116 -0
- data/lib/capybara/spec/session/frame/within_frame_spec.rb +112 -0
- data/lib/capybara/spec/session/go_back_spec.rb +3 -2
- data/lib/capybara/spec/session/go_forward_spec.rb +3 -2
- data/lib/capybara/spec/session/has_all_selectors_spec.rb +69 -0
- data/lib/capybara/spec/session/has_ancestor_spec.rb +46 -0
- data/lib/capybara/spec/session/has_any_selectors_spec.rb +25 -0
- data/lib/capybara/spec/session/has_button_spec.rb +76 -19
- data/lib/capybara/spec/session/has_css_spec.rb +277 -131
- data/lib/capybara/spec/session/has_current_path_spec.rb +98 -26
- data/lib/capybara/spec/session/has_field_spec.rb +177 -107
- data/lib/capybara/spec/session/has_link_spec.rb +13 -12
- data/lib/capybara/spec/session/has_none_selectors_spec.rb +78 -0
- data/lib/capybara/spec/session/has_select_spec.rb +191 -95
- data/lib/capybara/spec/session/has_selector_spec.rb +128 -64
- data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
- data/lib/capybara/spec/session/has_table_spec.rb +172 -5
- data/lib/capybara/spec/session/has_text_spec.rb +126 -60
- data/lib/capybara/spec/session/has_title_spec.rb +35 -12
- data/lib/capybara/spec/session/has_xpath_spec.rb +74 -53
- data/lib/capybara/spec/session/{headers.rb → headers_spec.rb} +3 -2
- data/lib/capybara/spec/session/html_spec.rb +14 -6
- data/lib/capybara/spec/session/matches_style_spec.rb +35 -0
- data/lib/capybara/spec/session/node_spec.rb +1028 -131
- data/lib/capybara/spec/session/node_wrapper_spec.rb +39 -0
- data/lib/capybara/spec/session/refresh_spec.rb +34 -0
- data/lib/capybara/spec/session/reset_session_spec.rb +75 -34
- data/lib/capybara/spec/session/{response_code.rb → response_code_spec.rb} +2 -1
- data/lib/capybara/spec/session/save_and_open_page_spec.rb +3 -2
- data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +11 -15
- data/lib/capybara/spec/session/save_page_spec.rb +42 -55
- data/lib/capybara/spec/session/save_screenshot_spec.rb +16 -14
- data/lib/capybara/spec/session/screenshot_spec.rb +2 -2
- data/lib/capybara/spec/session/scroll_spec.rb +117 -0
- data/lib/capybara/spec/session/select_spec.rb +112 -85
- data/lib/capybara/spec/session/selectors_spec.rb +71 -8
- data/lib/capybara/spec/session/sibling_spec.rb +52 -0
- data/lib/capybara/spec/session/text_spec.rb +38 -23
- data/lib/capybara/spec/session/title_spec.rb +17 -5
- data/lib/capybara/spec/session/uncheck_spec.rb +71 -12
- data/lib/capybara/spec/session/unselect_spec.rb +44 -43
- data/lib/capybara/spec/session/visit_spec.rb +99 -32
- data/lib/capybara/spec/session/window/become_closed_spec.rb +33 -29
- data/lib/capybara/spec/session/window/current_window_spec.rb +5 -3
- data/lib/capybara/spec/session/window/open_new_window_spec.rb +5 -3
- data/lib/capybara/spec/session/window/switch_to_window_spec.rb +39 -30
- data/lib/capybara/spec/session/window/window_opened_by_spec.rb +17 -10
- data/lib/capybara/spec/session/window/window_spec.rb +121 -73
- data/lib/capybara/spec/session/window/windows_spec.rb +12 -10
- data/lib/capybara/spec/session/window/within_window_spec.rb +52 -82
- data/lib/capybara/spec/session/within_spec.rb +76 -43
- data/lib/capybara/spec/spec_helper.rb +67 -33
- data/lib/capybara/spec/test_app.rb +85 -36
- data/lib/capybara/spec/views/animated.erb +49 -0
- data/lib/capybara/spec/views/buttons.erb +1 -1
- data/lib/capybara/spec/views/fieldsets.erb +1 -1
- data/lib/capybara/spec/views/form.erb +227 -20
- data/lib/capybara/spec/views/frame_child.erb +10 -2
- data/lib/capybara/spec/views/frame_one.erb +2 -1
- data/lib/capybara/spec/views/frame_parent.erb +2 -2
- data/lib/capybara/spec/views/frame_two.erb +1 -1
- data/lib/capybara/spec/views/header_links.erb +1 -1
- data/lib/capybara/spec/views/host_links.erb +1 -1
- data/lib/capybara/spec/views/initial_alert.erb +10 -0
- data/lib/capybara/spec/views/obscured.erb +47 -0
- data/lib/capybara/spec/views/offset.erb +32 -0
- data/lib/capybara/spec/views/path.erb +1 -1
- data/lib/capybara/spec/views/popup_one.erb +1 -1
- data/lib/capybara/spec/views/popup_two.erb +1 -1
- data/lib/capybara/spec/views/postback.erb +1 -1
- data/lib/capybara/spec/views/react.erb +45 -0
- data/lib/capybara/spec/views/scroll.erb +20 -0
- data/lib/capybara/spec/views/spatial.erb +31 -0
- data/lib/capybara/spec/views/tables.erb +69 -2
- data/lib/capybara/spec/views/with_animation.erb +82 -0
- data/lib/capybara/spec/views/with_base_tag.erb +1 -1
- data/lib/capybara/spec/views/with_count.erb +1 -1
- data/lib/capybara/spec/views/with_dragula.erb +24 -0
- data/lib/capybara/spec/views/with_fixed_header_footer.erb +17 -0
- data/lib/capybara/spec/views/with_hover.erb +7 -1
- data/lib/capybara/spec/views/with_hover1.erb +10 -0
- data/lib/capybara/spec/views/with_html.erb +100 -10
- data/lib/capybara/spec/views/with_html5_svg.erb +20 -0
- data/lib/capybara/spec/views/with_html_entities.erb +1 -1
- data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
- data/lib/capybara/spec/views/with_js.erb +49 -3
- data/lib/capybara/spec/views/with_jstree.erb +26 -0
- data/lib/capybara/spec/views/with_namespace.erb +20 -0
- data/lib/capybara/spec/views/with_scope.erb +1 -1
- data/lib/capybara/spec/views/with_scope_other.erb +6 -0
- data/lib/capybara/spec/views/with_simple_html.erb +1 -1
- data/lib/capybara/spec/views/with_sortable_js.erb +21 -0
- data/lib/capybara/spec/views/with_title.erb +1 -1
- data/lib/capybara/spec/views/with_unload_alert.erb +3 -1
- data/lib/capybara/spec/views/with_windows.erb +7 -1
- data/lib/capybara/spec/views/within_frames.erb +6 -3
- data/lib/capybara/version.rb +2 -1
- data/lib/capybara/window.rb +39 -21
- data/lib/capybara.rb +208 -186
- data/spec/basic_node_spec.rb +52 -39
- data/spec/capybara_spec.rb +72 -50
- data/spec/css_builder_spec.rb +101 -0
- data/spec/css_splitter_spec.rb +38 -0
- data/spec/dsl_spec.rb +81 -61
- data/spec/filter_set_spec.rb +46 -0
- data/spec/fixtures/capybara.csv +1 -0
- data/spec/fixtures/certificate.pem +25 -0
- data/spec/fixtures/key.pem +27 -0
- data/spec/fixtures/selenium_driver_rspec_failure.rb +7 -3
- data/spec/fixtures/selenium_driver_rspec_success.rb +7 -3
- data/spec/minitest_spec.rb +164 -0
- data/spec/minitest_spec_spec.rb +162 -0
- data/spec/per_session_config_spec.rb +68 -0
- data/spec/rack_test_spec.rb +189 -96
- data/spec/regexp_dissassembler_spec.rb +250 -0
- data/spec/result_spec.rb +143 -13
- data/spec/rspec/features_spec.rb +38 -32
- data/spec/rspec/scenarios_spec.rb +9 -7
- data/spec/rspec/shared_spec_matchers.rb +959 -0
- data/spec/rspec/views_spec.rb +9 -3
- data/spec/rspec_matchers_spec.rb +62 -0
- data/spec/rspec_spec.rb +127 -30
- data/spec/sauce_spec_chrome.rb +43 -0
- data/spec/selector_spec.rb +458 -37
- data/spec/selenium_spec_chrome.rb +196 -9
- data/spec/selenium_spec_chrome_remote.rb +100 -0
- data/spec/selenium_spec_edge.rb +47 -0
- data/spec/selenium_spec_firefox.rb +210 -0
- data/spec/selenium_spec_firefox_remote.rb +80 -0
- data/spec/selenium_spec_ie.rb +150 -0
- data/spec/selenium_spec_safari.rb +148 -0
- data/spec/server_spec.rb +200 -101
- data/spec/session_spec.rb +91 -0
- data/spec/shared_selenium_node.rb +83 -0
- data/spec/shared_selenium_session.rb +558 -0
- data/spec/spec_helper.rb +94 -2
- data/spec/xpath_builder_spec.rb +93 -0
- metadata +420 -60
- data/lib/capybara/query.rb +0 -7
- data/lib/capybara/spec/session/assert_current_path.rb +0 -60
- data/lib/capybara/spec/session/assert_selector.rb +0 -148
- data/lib/capybara/spec/session/assert_text.rb +0 -196
- data/lib/capybara/spec/session/assert_title.rb +0 -70
- data/lib/capybara/spec/session/source_spec.rb +0 -0
- data/lib/capybara/spec/session/within_frame_spec.rb +0 -53
- data/spec/rspec/matchers_spec.rb +0 -827
- data/spec/selenium_spec.rb +0 -151
@@ -1,108 +1,179 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Capybara
|
3
4
|
module Node
|
4
5
|
module Finders
|
5
|
-
|
6
6
|
##
|
7
7
|
#
|
8
|
-
# Find an {Capybara::Node::Element} based on the given arguments.
|
8
|
+
# Find an {Capybara::Node::Element} based on the given arguments. {#find} will raise an error if the element
|
9
9
|
# is not found.
|
10
10
|
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
# expires. The length of time +find+ will wait is controlled through {Capybara.default_max_wait_time}
|
15
|
-
# and defaults to 2 seconds.
|
16
|
-
# @option options [false, Numeric] wait (Capybara.default_max_wait_time) Maximum time to wait for matching element to appear.
|
11
|
+
# page.find('#foo').find('.bar')
|
12
|
+
# page.find(:xpath, './/div[contains(., "bar")]')
|
13
|
+
# page.find('li', text: 'Quox').click_link('Delete')
|
17
14
|
#
|
18
|
-
#
|
15
|
+
# @param (see #all)
|
19
16
|
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
17
|
+
# @macro waiting_behavior
|
18
|
+
#
|
19
|
+
# @!macro system_filters
|
20
|
+
# @option options [String, Regexp] text Only find elements which contain this text or match this regexp
|
21
|
+
# @option options [String, Boolean] exact_text
|
22
|
+
# When String the elements contained text must match exactly, when Boolean controls whether the `text` option must match exactly.
|
23
|
+
# Defaults to {Capybara.configure exact_text}.
|
24
|
+
# @option options [Boolean] normalize_ws
|
25
|
+
# Whether the `text`/`exact_text` options are compared against elment text with whitespace normalized or as returned by the driver.
|
26
|
+
# Defaults to {Capybara.configure default_normalize_ws}.
|
27
|
+
# @option options [Boolean, Symbol] visible
|
28
|
+
# Only find elements with the specified visibility. Defaults to behavior indicated by {Capybara.configure ignore_hidden_elements}.
|
29
|
+
# * true - only finds visible elements.
|
30
|
+
# * false - finds invisible _and_ visible elements.
|
31
|
+
# * :all - same as false; finds visible and invisible elements.
|
32
|
+
# * :hidden - only finds invisible elements.
|
33
|
+
# * :visible - same as true; only finds visible elements.
|
34
|
+
# @option options [Boolean] obscured Only find elements with the specified obscured state:
|
35
|
+
# * true - only find elements whose centerpoint is not in the viewport or is obscured by another non-descendant element.
|
36
|
+
# * false - only find elements whose centerpoint is in the viewport and is not obscured by other non-descendant elements.
|
37
|
+
# @option options [String, Regexp] id Only find elements with an id that matches the value passed
|
38
|
+
# @option options [String, Array<String>, Regexp] class Only find elements with matching class/classes.
|
39
|
+
# * Absence of a class can be checked by prefixing the class name with `!`
|
40
|
+
# * If you need to check for existence of a class name that starts with `!` then prefix with `!!`
|
41
|
+
#
|
42
|
+
# class:['a', '!b', '!!!c'] # limit to elements with class 'a' and '!c' but not class 'b'
|
43
|
+
#
|
44
|
+
# @option options [String, Regexp, Hash] style Only find elements with matching style. String and Regexp will be checked against text of the elements `style` attribute, while a Hash will be compared against the elements full style
|
45
|
+
# @option options [Boolean] exact Control whether `is` expressions in the given XPath match exactly or partially. Defaults to {Capybara.configure exact}.
|
46
|
+
# @option options [Symbol] match The matching strategy to use. Defaults to {Capybara.configure match}.
|
47
|
+
#
|
48
|
+
# @return [Capybara::Node::Element] The found element
|
49
|
+
# @raise [Capybara::ElementNotFound] If the element can't be found before time expires
|
23
50
|
#
|
24
|
-
|
51
|
+
def find(*args, **options, &optional_filter_block)
|
52
|
+
options[:session_options] = session_options
|
53
|
+
synced_resolve Capybara::Queries::SelectorQuery.new(*args, **options, &optional_filter_block)
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
#
|
58
|
+
# Find an {Capybara::Node::Element} based on the given arguments that is also an ancestor of the element called on.
|
59
|
+
# {#ancestor} will raise an error if the element is not found.
|
60
|
+
#
|
61
|
+
# {#ancestor} takes the same options as {#find}.
|
25
62
|
#
|
26
|
-
#
|
63
|
+
# element.ancestor('#foo').find('.bar')
|
64
|
+
# element.ancestor(:xpath, './/div[contains(., "bar")]')
|
65
|
+
# element.ancestor('ul', text: 'Quox').click_link('Delete')
|
66
|
+
#
|
67
|
+
# @param (see #find)
|
68
|
+
#
|
69
|
+
# @macro waiting_behavior
|
27
70
|
#
|
28
71
|
# @return [Capybara::Node::Element] The found element
|
29
72
|
# @raise [Capybara::ElementNotFound] If the element can't be found before time expires
|
30
73
|
#
|
31
|
-
def
|
32
|
-
|
33
|
-
|
34
|
-
if query.match == :smart or query.match == :prefer_exact
|
35
|
-
result = query.resolve_for(self, true)
|
36
|
-
result = query.resolve_for(self, false) if result.size == 0 && !query.exact?
|
37
|
-
else
|
38
|
-
result = query.resolve_for(self)
|
39
|
-
end
|
40
|
-
if query.match == :one or query.match == :smart and result.size > 1
|
41
|
-
raise Capybara::Ambiguous.new("Ambiguous match, found #{result.size} elements matching #{query.description}")
|
42
|
-
end
|
43
|
-
if result.size == 0
|
44
|
-
raise Capybara::ElementNotFound.new("Unable to find #{query.description}")
|
45
|
-
end
|
46
|
-
result.first
|
47
|
-
end.tap(&:allow_reload!)
|
74
|
+
def ancestor(*args, **options, &optional_filter_block)
|
75
|
+
options[:session_options] = session_options
|
76
|
+
synced_resolve Capybara::Queries::AncestorQuery.new(*args, **options, &optional_filter_block)
|
48
77
|
end
|
49
78
|
|
50
79
|
##
|
51
80
|
#
|
52
|
-
# Find
|
81
|
+
# Find an {Capybara::Node::Element} based on the given arguments that is also a sibling of the element called on.
|
82
|
+
# {#sibling} will raise an error if the element is not found.
|
83
|
+
#
|
84
|
+
# {#sibling} takes the same options as {#find}.
|
85
|
+
#
|
86
|
+
# element.sibling('#foo').find('.bar')
|
87
|
+
# element.sibling(:xpath, './/div[contains(., "bar")]')
|
88
|
+
# element.sibling('ul', text: 'Quox').click_link('Delete')
|
89
|
+
#
|
90
|
+
# @param (see #find)
|
53
91
|
#
|
54
92
|
# @macro waiting_behavior
|
55
93
|
#
|
56
|
-
# @
|
57
|
-
#
|
58
|
-
#
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
#
|
66
|
-
#
|
94
|
+
# @return [Capybara::Node::Element] The found element
|
95
|
+
# @raise [Capybara::ElementNotFound] If the element can't be found before time expires
|
96
|
+
#
|
97
|
+
def sibling(*args, **options, &optional_filter_block)
|
98
|
+
options[:session_options] = session_options
|
99
|
+
synced_resolve Capybara::Queries::SiblingQuery.new(*args, **options, &optional_filter_block)
|
100
|
+
end
|
101
|
+
|
102
|
+
##
|
103
|
+
#
|
104
|
+
# Find a form field on the page. The field can be found by its name, id or label text.
|
105
|
+
#
|
106
|
+
# @overload find_field([locator], **options)
|
107
|
+
# @param [String] locator name, id, {Capybara.configure test_id} attribute, placeholder or text of associated label element
|
108
|
+
#
|
109
|
+
# @macro waiting_behavior
|
110
|
+
#
|
111
|
+
#
|
112
|
+
# @option options [Boolean] checked Match checked field?
|
113
|
+
# @option options [Boolean] unchecked Match unchecked field?
|
114
|
+
# @option options [Boolean, Symbol] disabled (false) Match disabled field?
|
115
|
+
# * true - only finds a disabled field
|
116
|
+
# * false - only finds an enabled field
|
117
|
+
# * :all - finds either an enabled or disabled field
|
118
|
+
# @option options [Boolean] readonly Match readonly field?
|
119
|
+
# @option options [String, Regexp] with Value of field to match on
|
120
|
+
# @option options [String] type Type of field to match on
|
121
|
+
# @option options [Boolean] multiple Match fields that can have multiple values?
|
122
|
+
# @option options [String, Regexp] id Match fields that match the id attribute
|
123
|
+
# @option options [String] name Match fields that match the name attribute
|
124
|
+
# @option options [String] placeholder Match fields that match the placeholder attribute
|
125
|
+
# @option options [String, Array<String>, Regexp] class Match fields that match the class(es) passed
|
67
126
|
# @return [Capybara::Node::Element] The found element
|
68
127
|
#
|
69
|
-
def find_field(locator, options
|
70
|
-
find(:field, locator, options)
|
128
|
+
def find_field(locator = nil, **options, &optional_filter_block)
|
129
|
+
find(:field, locator, **options, &optional_filter_block)
|
71
130
|
end
|
72
|
-
alias_method :field_labeled, :find_field
|
73
131
|
|
74
132
|
##
|
75
133
|
#
|
76
134
|
# Find a link on the page. The link can be found by its id or text.
|
77
135
|
#
|
78
|
-
# @
|
136
|
+
# @overload find_link([locator], **options)
|
137
|
+
# @param [String] locator id, {Capybara.configure test_id} attribute, title, text, or alt of enclosed img element
|
138
|
+
#
|
139
|
+
# @macro waiting_behavior
|
79
140
|
#
|
80
|
-
#
|
81
|
-
#
|
141
|
+
# @option options [String,Regexp,nil] href Value to match against the links href, if `nil` finds link placeholders (`<a>` elements with no href attribute), if `false` ignores the href
|
142
|
+
# @option options [String, Regexp] id Match links with the id provided
|
143
|
+
# @option options [String] title Match links with the title provided
|
144
|
+
# @option options [String] alt Match links with a contained img element whose alt matches
|
145
|
+
# @option options [String, Array<String>, Regexp] class Match links that match the class(es) provided
|
82
146
|
# @return [Capybara::Node::Element] The found element
|
83
147
|
#
|
84
|
-
def find_link(locator, options
|
85
|
-
find(:link, locator, options)
|
148
|
+
def find_link(locator = nil, **options, &optional_filter_block)
|
149
|
+
find(:link, locator, **options, &optional_filter_block)
|
86
150
|
end
|
87
151
|
|
88
152
|
##
|
89
153
|
#
|
90
154
|
# Find a button on the page.
|
91
|
-
# This can be any
|
92
|
-
#
|
93
|
-
# by their text content, and image
|
94
|
-
|
95
|
-
# @
|
96
|
-
#
|
97
|
-
#
|
98
|
-
#
|
99
|
-
#
|
100
|
-
#
|
101
|
-
#
|
155
|
+
# This can be any `<input>` element of type submit, reset, image, button or it can be a
|
156
|
+
# `<button>` element. All buttons can be found by their id, name, {Capybara.configure test_id} attribute, value, or title.
|
157
|
+
# `<button>` elements can also be found by their text content, and image `<input>` elements by their alt attribute.
|
158
|
+
#
|
159
|
+
# @overload find_button([locator], **options)
|
160
|
+
# @param [String] locator id, name, {Capybara.configure test_id} attribute, value, title, text content, alt of image
|
161
|
+
#
|
162
|
+
# @macro waiting_behavior
|
163
|
+
#
|
164
|
+
# @option options [Boolean, Symbol] disabled (false) Match disabled button?
|
165
|
+
# * true - only finds a disabled button
|
166
|
+
# * false - only finds an enabled button
|
167
|
+
# * :all - finds either an enabled or disabled button
|
168
|
+
# @option options [String, Regexp] id Match buttons with the id provided
|
169
|
+
# @option options [String] name Match buttons with the name provided
|
170
|
+
# @option options [String] title Match buttons with the title provided
|
171
|
+
# @option options [String] value Match buttons with the value provided
|
172
|
+
# @option options [String, Array<String>, Regexp] class Match buttons that match the class(es) provided
|
102
173
|
# @return [Capybara::Node::Element] The found element
|
103
174
|
#
|
104
|
-
def find_button(locator, options
|
105
|
-
find(:button, locator, options)
|
175
|
+
def find_button(locator = nil, **options, &optional_filter_block)
|
176
|
+
find(:button, locator, **options, &optional_filter_block)
|
106
177
|
end
|
107
178
|
|
108
179
|
##
|
@@ -111,15 +182,16 @@ module Capybara
|
|
111
182
|
#
|
112
183
|
# @macro waiting_behavior
|
113
184
|
#
|
114
|
-
# @param [String] id
|
185
|
+
# @param [String] id id of element
|
115
186
|
#
|
116
187
|
# @return [Capybara::Node::Element] The found element
|
117
188
|
#
|
118
|
-
def find_by_id(id, options
|
119
|
-
find(:id, id, options)
|
189
|
+
def find_by_id(id, **options, &optional_filter_block)
|
190
|
+
find(:id, id, **options, &optional_filter_block)
|
120
191
|
end
|
121
192
|
|
122
193
|
##
|
194
|
+
# @!method all([kind = Capybara.default_selector], locator = nil, **options)
|
123
195
|
#
|
124
196
|
# Find all elements on the page matching the given selector
|
125
197
|
# and options.
|
@@ -129,60 +201,68 @@ module Capybara
|
|
129
201
|
# following statements are equivalent:
|
130
202
|
#
|
131
203
|
# page.all(:css, 'a#person_123')
|
132
|
-
# page.all(:xpath, '
|
133
|
-
#
|
204
|
+
# page.all(:xpath, './/a[@id="person_123"]')
|
134
205
|
#
|
135
206
|
# If the type of selector is left out, Capybara uses
|
136
|
-
# {Capybara.default_selector}. It's set to
|
207
|
+
# {Capybara.configure default_selector}. It's set to `:css` by default.
|
137
208
|
#
|
138
209
|
# page.all("a#person_123")
|
139
210
|
#
|
140
211
|
# Capybara.default_selector = :xpath
|
141
|
-
# page.all('
|
212
|
+
# page.all('.//a[@id="person_123"]')
|
142
213
|
#
|
143
214
|
# The set of found elements can further be restricted by specifying
|
144
215
|
# options. It's possible to select elements by their text or visibility:
|
145
216
|
#
|
146
|
-
# page.all('a', :
|
147
|
-
# page.all('#menu li', :
|
148
|
-
#
|
149
|
-
# By default if no elements are found, an empty array is returned;
|
150
|
-
# however, expectations can be set on the number of elements to be found which
|
151
|
-
# will trigger Capybara's waiting behavior for the expectations to match.The
|
152
|
-
# expectations can be set using
|
217
|
+
# page.all('a', text: 'Home')
|
218
|
+
# page.all('#menu li', visible: true)
|
153
219
|
#
|
154
|
-
#
|
155
|
-
#
|
156
|
-
#
|
157
|
-
#
|
220
|
+
# By default Capybara's waiting behavior will wait up to {Capybara.configure default_max_wait_time}
|
221
|
+
# seconds for matching elements to be available and then return an empty result if none
|
222
|
+
# are available. It is possible to set expectations on the number of results located and
|
223
|
+
# Capybara will raise an exception if the number of elements located don't satisfy the
|
224
|
+
# specified conditions. The expectations can be set using:
|
158
225
|
#
|
159
|
-
#
|
160
|
-
#
|
226
|
+
# page.assert_selector('p#foo', count: 4)
|
227
|
+
# page.assert_selector('p#foo', maximum: 10)
|
228
|
+
# page.assert_selector('p#foo', minimum: 1)
|
229
|
+
# page.assert_selector('p#foo', between: 1..10)
|
161
230
|
#
|
162
|
-
# @
|
163
|
-
#
|
164
|
-
#
|
165
|
-
#
|
166
|
-
#
|
167
|
-
#
|
168
|
-
#
|
169
|
-
#
|
170
|
-
#
|
171
|
-
#
|
172
|
-
#
|
173
|
-
#
|
174
|
-
#
|
175
|
-
# @
|
176
|
-
# @
|
177
|
-
# @option options [Integer] wait (Capybara.default_max_wait_time) The time to wait for element count expectations to become true
|
231
|
+
# @param [Symbol] kind Optional selector type (:css, :xpath, :field, etc.). Defaults to {Capybara.configure default_selector}.
|
232
|
+
# @param [String] locator The locator for the specified selector
|
233
|
+
# @macro system_filters
|
234
|
+
# @macro waiting_behavior
|
235
|
+
# @option options [Integer] count Exact number of matches that are expected to be found
|
236
|
+
# @option options [Integer] maximum Maximum number of matches that are expected to be found
|
237
|
+
# @option options [Integer] minimum Minimum number of matches that are expected to be found
|
238
|
+
# @option options [Range] between Number of matches found must be within the given range
|
239
|
+
# @option options [Boolean] allow_reload Beta feature - May be removed in any version.
|
240
|
+
# When `true` allows elements to be reloaded if they become stale. This is an advanced behavior and should only be used
|
241
|
+
# if you fully understand the potential ramifications. The results can be confusing on dynamic pages. Defaults to `false`
|
242
|
+
# @overload all([kind = Capybara.default_selector], locator = nil, **options)
|
243
|
+
# @overload all([kind = Capybara.default_selector], locator = nil, **options, &filter_block)
|
244
|
+
# @yieldparam element [Capybara::Node::Element] The element being considered for inclusion in the results
|
245
|
+
# @yieldreturn [Boolean] Should the element be considered in the results?
|
178
246
|
# @return [Capybara::Result] A collection of found elements
|
179
|
-
#
|
180
|
-
def all(*args)
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
247
|
+
# @raise [Capybara::ExpectationNotMet] The number of elements found doesn't match the specified conditions
|
248
|
+
def all(*args, allow_reload: false, **options, &optional_filter_block)
|
249
|
+
minimum_specified = options_include_minimum?(options)
|
250
|
+
options = { minimum: 1 }.merge(options) unless minimum_specified
|
251
|
+
options[:session_options] = session_options
|
252
|
+
query = Capybara::Queries::SelectorQuery.new(*args, **options, &optional_filter_block)
|
253
|
+
result = nil
|
254
|
+
begin
|
255
|
+
synchronize(query.wait) do
|
256
|
+
result = query.resolve_for(self)
|
257
|
+
result.allow_reload! if allow_reload
|
258
|
+
raise Capybara::ExpectationNotMet, result.failure_message unless result.matches_count?
|
259
|
+
|
260
|
+
result
|
261
|
+
end
|
262
|
+
rescue Capybara::ExpectationNotMet
|
263
|
+
raise if minimum_specified || (result.compare_count == 1)
|
264
|
+
|
265
|
+
Result.new([], nil)
|
186
266
|
end
|
187
267
|
end
|
188
268
|
alias_method :find_all, :all
|
@@ -190,26 +270,56 @@ module Capybara
|
|
190
270
|
##
|
191
271
|
#
|
192
272
|
# Find the first element on the page matching the given selector
|
193
|
-
# and options
|
194
|
-
#
|
195
|
-
#
|
196
|
-
# return the first. Waiting behavior can also be triggered by passing in any of the count
|
197
|
-
# expectation options.
|
273
|
+
# and options. By default {#first} will wait up to {Capybara.configure default_max_wait_time}
|
274
|
+
# seconds for matching elements to appear and then raise an error if no matching
|
275
|
+
# element is found, or `nil` if the provided count options allow for empty results.
|
198
276
|
#
|
199
277
|
# @overload first([kind], locator, options)
|
200
|
-
# @param [
|
278
|
+
# @param [Symbol] kind The type of selector
|
201
279
|
# @param [String] locator The selector
|
202
280
|
# @param [Hash] options Additional options; see {#all}
|
203
281
|
# @return [Capybara::Node::Element] The found element or nil
|
282
|
+
# @raise [Capybara::ElementNotFound] If element(s) matching the provided options can't be found before time expires
|
204
283
|
#
|
205
|
-
def first(*args)
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
284
|
+
def first(*args, **options, &optional_filter_block)
|
285
|
+
options = { minimum: 1 }.merge(options) unless options_include_minimum?(options)
|
286
|
+
all(*args, **options, &optional_filter_block).first
|
287
|
+
end
|
288
|
+
|
289
|
+
private
|
290
|
+
|
291
|
+
def synced_resolve(query)
|
292
|
+
synchronize(query.wait) do
|
293
|
+
if prefer_exact?(query)
|
294
|
+
result = query.resolve_for(self, true)
|
295
|
+
result = query.resolve_for(self, false) if result.empty? && query.supports_exact? && !query.exact?
|
296
|
+
else
|
297
|
+
result = query.resolve_for(self)
|
298
|
+
end
|
299
|
+
|
300
|
+
if ambiguous?(query, result)
|
301
|
+
raise Capybara::Ambiguous, "Ambiguous match, found #{result.size} elements matching #{query.applied_description}"
|
302
|
+
end
|
303
|
+
raise Capybara::ElementNotFound, "Unable to find #{query.applied_description}" if result.empty?
|
304
|
+
|
305
|
+
result.first
|
306
|
+
end.tap(&:allow_reload!)
|
307
|
+
end
|
308
|
+
|
309
|
+
def ambiguous?(query, result)
|
310
|
+
%i[one smart].include?(query.match) && (result.size > 1)
|
311
|
+
end
|
312
|
+
|
313
|
+
def prefer_exact?(query)
|
314
|
+
%i[smart prefer_exact].include?(query.match)
|
315
|
+
end
|
316
|
+
|
317
|
+
def options_include_minimum?(opts)
|
318
|
+
%i[count minimum between].any? { |key| opts.key?(key) }
|
319
|
+
end
|
320
|
+
|
321
|
+
def parent
|
322
|
+
first(:xpath, './parent::*', minimum: 0)
|
213
323
|
end
|
214
324
|
end
|
215
325
|
end
|
@@ -1,11 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Capybara
|
3
4
|
module Node
|
4
5
|
module Matchers
|
5
|
-
|
6
6
|
##
|
7
7
|
#
|
8
|
-
# Checks if a given selector is on the page or current node.
|
8
|
+
# Checks if a given selector is on the page or a descendant of the current node.
|
9
9
|
#
|
10
10
|
# page.has_selector?('p#foo')
|
11
11
|
# page.has_selector?(:xpath, './/p[@id="foo"]')
|
@@ -14,81 +14,68 @@ module Capybara
|
|
14
14
|
# By default it will check if the expression occurs at least once,
|
15
15
|
# but a different number can be specified.
|
16
16
|
#
|
17
|
-
# page.has_selector?('p.foo', :
|
17
|
+
# page.has_selector?('p.foo', count: 4)
|
18
18
|
#
|
19
19
|
# This will check if the expression occurs exactly 4 times.
|
20
20
|
#
|
21
21
|
# It also accepts all options that {Capybara::Node::Finders#all} accepts,
|
22
|
-
# such as
|
22
|
+
# such as `:text` and `:visible`.
|
23
23
|
#
|
24
|
-
# page.has_selector?('li', :
|
24
|
+
# page.has_selector?('li', text: 'Horse', visible: true)
|
25
25
|
#
|
26
|
-
# has_selector? can also accept XPath expressions generated by the
|
26
|
+
# {#has_selector?} can also accept XPath expressions generated by the
|
27
27
|
# XPath gem:
|
28
28
|
#
|
29
29
|
# page.has_selector?(:xpath, XPath.descendant(:p))
|
30
30
|
#
|
31
31
|
# @param (see Capybara::Node::Finders#all)
|
32
|
-
# @
|
33
|
-
# @option
|
34
|
-
# @option
|
35
|
-
# @option
|
36
|
-
# @option args [Range] :between (nil) Range of times that should contain number of times text occurs
|
32
|
+
# @option options [Integer] :count (nil) Number of matching elements that should exist
|
33
|
+
# @option options [Integer] :minimum (nil) Minimum number of matching elements that should exist
|
34
|
+
# @option options [Integer] :maximum (nil) Maximum number of matching elements that should exist
|
35
|
+
# @option options [Range] :between (nil) Range of number of matching elements that should exist
|
37
36
|
# @return [Boolean] If the expression exists
|
38
37
|
#
|
39
|
-
def has_selector?(*args)
|
40
|
-
assert_selector(*args)
|
41
|
-
rescue Capybara::ExpectationNotMet
|
42
|
-
return false
|
38
|
+
def has_selector?(*args, **options, &optional_filter_block)
|
39
|
+
make_predicate(options) { assert_selector(*args, options, &optional_filter_block) }
|
43
40
|
end
|
44
41
|
|
45
42
|
##
|
46
43
|
#
|
47
|
-
# Checks if a given selector is not on the page or current node.
|
48
|
-
# Usage is identical to
|
44
|
+
# Checks if a given selector is not on the page or a descendant of the current node.
|
45
|
+
# Usage is identical to {#has_selector?}.
|
49
46
|
#
|
50
|
-
# @param (see
|
47
|
+
# @param (see #has_selector?)
|
51
48
|
# @return [Boolean]
|
52
49
|
#
|
53
|
-
def has_no_selector?(*args)
|
54
|
-
assert_no_selector(*args)
|
55
|
-
rescue Capybara::ExpectationNotMet
|
56
|
-
return false
|
50
|
+
def has_no_selector?(*args, **options, &optional_filter_block)
|
51
|
+
make_predicate(options) { assert_no_selector(*args, options, &optional_filter_block) }
|
57
52
|
end
|
58
53
|
|
59
54
|
##
|
60
55
|
#
|
61
|
-
# Checks if
|
62
|
-
# Usage is identical to Capybara::Node::Matchers#has_selector?
|
56
|
+
# Checks if a an element has the specified CSS styles.
|
63
57
|
#
|
64
|
-
#
|
65
|
-
# @return [Boolean]
|
58
|
+
# element.matches_style?( 'color' => 'rgb(0,0,255)', 'font-size' => /px/ )
|
66
59
|
#
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
60
|
+
# @param styles [Hash]
|
61
|
+
# @return [Boolean] If the styles match
|
62
|
+
#
|
63
|
+
def matches_style?(styles = nil, **options)
|
64
|
+
styles, options = options, {} if styles.nil?
|
65
|
+
make_predicate(options) { assert_matches_style(styles, **options) }
|
71
66
|
end
|
72
67
|
|
73
|
-
|
74
68
|
##
|
69
|
+
# @deprecated Use {#matches_style?} instead.
|
75
70
|
#
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
# @param (see Capybara::Node::Finders#has_selector?)
|
80
|
-
# @return [Boolean]
|
81
|
-
#
|
82
|
-
def not_matches_selector?(*args)
|
83
|
-
assert_not_matches_selector(*args)
|
84
|
-
rescue Capybara::ExpectationNotMet
|
85
|
-
return false
|
71
|
+
def has_style?(styles = nil, **options)
|
72
|
+
Capybara::Helpers.warn "DEPRECATED: has_style? is deprecated, please use matches_style? : #{Capybara::Helpers.filter_backtrace(caller)}"
|
73
|
+
matches_style?(styles, **options)
|
86
74
|
end
|
87
75
|
|
88
|
-
|
89
76
|
##
|
90
77
|
#
|
91
|
-
# Asserts that a given selector is on the page or current node.
|
78
|
+
# Asserts that a given selector is on the page or a descendant of the current node.
|
92
79
|
#
|
93
80
|
# page.assert_selector('p#foo')
|
94
81
|
# page.assert_selector(:xpath, './/p[@id="foo"]')
|
@@ -97,20 +84,20 @@ module Capybara
|
|
97
84
|
# By default it will check if the expression occurs at least once,
|
98
85
|
# but a different number can be specified.
|
99
86
|
#
|
100
|
-
# page.assert_selector('p#foo', :
|
87
|
+
# page.assert_selector('p#foo', count: 4)
|
101
88
|
#
|
102
89
|
# This will check if the expression occurs exactly 4 times. See
|
103
90
|
# {Capybara::Node::Finders#all} for other available result size options.
|
104
91
|
#
|
105
|
-
# If a
|
92
|
+
# If a `:count` of 0 is specified, it will behave like {#assert_no_selector};
|
106
93
|
# however, use of that method is preferred over this one.
|
107
94
|
#
|
108
95
|
# It also accepts all options that {Capybara::Node::Finders#all} accepts,
|
109
|
-
# such as
|
96
|
+
# such as `:text` and `:visible`.
|
110
97
|
#
|
111
|
-
# page.assert_selector('li', :
|
98
|
+
# page.assert_selector('li', text: 'Horse', visible: true)
|
112
99
|
#
|
113
|
-
#
|
100
|
+
# {#assert_selector} can also accept XPath expressions generated by the
|
114
101
|
# XPath gem:
|
115
102
|
#
|
116
103
|
# page.assert_selector(:xpath, XPath.descendant(:p))
|
@@ -119,105 +106,157 @@ module Capybara
|
|
119
106
|
# @option options [Integer] :count (nil) Number of times the expression should occur
|
120
107
|
# @raise [Capybara::ExpectationNotMet] If the selector does not exist
|
121
108
|
#
|
122
|
-
def assert_selector(*args)
|
123
|
-
|
124
|
-
|
125
|
-
result = query.resolve_for(self)
|
126
|
-
matches_count = Capybara::Helpers.matches_count?(result.size, query.options)
|
127
|
-
unless matches_count && ((result.size > 0) || Capybara::Helpers.expects_none?(query.options))
|
109
|
+
def assert_selector(*args, &optional_filter_block)
|
110
|
+
_verify_selector_result(args, optional_filter_block) do |result, query|
|
111
|
+
unless result.matches_count? && (result.any? || query.expects_none?)
|
128
112
|
raise Capybara::ExpectationNotMet, result.failure_message
|
129
113
|
end
|
130
114
|
end
|
131
|
-
return true
|
132
115
|
end
|
133
116
|
|
134
117
|
##
|
135
118
|
#
|
136
|
-
# Asserts that
|
137
|
-
# Usage is identical to Capybara::Node::Matchers#assert_selector
|
138
|
-
#
|
139
|
-
# Query options such as :count, :minimum, :maximum, and :between are
|
140
|
-
# considered to be an integral part of the selector. This will return
|
141
|
-
# true, for example, if a page contains 4 anchors but the query expects 5:
|
119
|
+
# Asserts that an element has the specified CSS styles.
|
142
120
|
#
|
143
|
-
#
|
144
|
-
# page.assert_no_selector('a', :count => 4) # Found, raises Capybara::ExpectationNotMet
|
145
|
-
# page.assert_no_selector('a', :count => 5) # Not Found, returns true
|
121
|
+
# element.assert_matches_style( 'color' => 'rgb(0,0,255)', 'font-size' => /px/ )
|
146
122
|
#
|
147
|
-
# @param
|
148
|
-
# @raise [Capybara::ExpectationNotMet]
|
123
|
+
# @param styles [Hash]
|
124
|
+
# @raise [Capybara::ExpectationNotMet] If the element doesn't have the specified styles
|
149
125
|
#
|
150
|
-
def
|
151
|
-
|
126
|
+
def assert_matches_style(styles = nil, **options)
|
127
|
+
styles, options = options, {} if styles.nil?
|
128
|
+
query_args, query_opts = _set_query_session_options(styles, options)
|
129
|
+
query = Capybara::Queries::StyleQuery.new(*query_args, **query_opts)
|
152
130
|
synchronize(query.wait) do
|
153
|
-
|
154
|
-
matches_count = Capybara::Helpers.matches_count?(result.size, query.options)
|
155
|
-
if matches_count && ((result.size > 0) || Capybara::Helpers.expects_none?(query.options))
|
156
|
-
raise Capybara::ExpectationNotMet, result.negative_failure_message
|
157
|
-
end
|
131
|
+
raise Capybara::ExpectationNotMet, query.failure_message unless query.resolves_for?(self)
|
158
132
|
end
|
159
|
-
|
133
|
+
true
|
160
134
|
end
|
161
|
-
alias_method :refute_selector, :assert_no_selector
|
162
135
|
|
163
136
|
##
|
137
|
+
# @deprecated Use {#assert_matches_style} instead.
|
164
138
|
#
|
165
|
-
|
139
|
+
def assert_style(styles = nil, **options)
|
140
|
+
warn 'assert_style is deprecated, please use assert_matches_style instead'
|
141
|
+
assert_matches_style(styles, **options)
|
142
|
+
end
|
143
|
+
|
144
|
+
# Asserts that all of the provided selectors are present on the given page
|
145
|
+
# or descendants of the current node. If options are provided, the assertion
|
146
|
+
# will check that each locator is present with those options as well (other than `:wait`).
|
166
147
|
#
|
167
|
-
#
|
168
|
-
#
|
169
|
-
# node.assert_matches_selector(:foo)
|
148
|
+
# page.assert_all_of_selectors(:custom, 'Tom', 'Joe', visible: all)
|
149
|
+
# page.assert_all_of_selectors(:css, '#my_div', 'a.not_clicked')
|
170
150
|
#
|
171
|
-
# It
|
172
|
-
# such as
|
151
|
+
# It accepts all options that {Capybara::Node::Finders#all} accepts,
|
152
|
+
# such as `:text` and `:visible`.
|
173
153
|
#
|
174
|
-
#
|
154
|
+
# The `:wait` option applies to all of the selectors as a group, so all of the locators must be present
|
155
|
+
# within `:wait` (defaults to {Capybara.configure default_max_wait_time}) seconds.
|
175
156
|
#
|
176
|
-
# @
|
177
|
-
# @raise [Capybara::ExpectationNotMet] If the selector does not match
|
157
|
+
# @overload assert_all_of_selectors([kind = Capybara.default_selector], *locators, **options)
|
178
158
|
#
|
179
|
-
def
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
159
|
+
def assert_all_of_selectors(*args, **options, &optional_filter_block)
|
160
|
+
_verify_multiple(*args, **options) do |selector, locator, opts|
|
161
|
+
assert_selector(selector, locator, opts, &optional_filter_block)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
# Asserts that none of the provided selectors are present on the given page
|
166
|
+
# or descendants of the current node. If options are provided, the assertion
|
167
|
+
# will check that each locator is not present with those options as well (other than `:wait`).
|
168
|
+
#
|
169
|
+
# page.assert_none_of_selectors(:custom, 'Tom', 'Joe', visible: all)
|
170
|
+
# page.assert_none_of_selectors(:css, '#my_div', 'a.not_clicked')
|
171
|
+
#
|
172
|
+
# It accepts all options that {Capybara::Node::Finders#all} accepts,
|
173
|
+
# such as `:text` and `:visible`.
|
174
|
+
#
|
175
|
+
# The `:wait` option applies to all of the selectors as a group, so none of the locators must be present
|
176
|
+
# within `:wait` (defaults to {Capybara.configure default_max_wait_time}) seconds.
|
177
|
+
#
|
178
|
+
# @overload assert_none_of_selectors([kind = Capybara.default_selector], *locators, **options)
|
179
|
+
#
|
180
|
+
def assert_none_of_selectors(*args, **options, &optional_filter_block)
|
181
|
+
_verify_multiple(*args, **options) do |selector, locator, opts|
|
182
|
+
assert_no_selector(selector, locator, opts, &optional_filter_block)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
# Asserts that any of the provided selectors are present on the given page
|
187
|
+
# or descendants of the current node. If options are provided, the assertion
|
188
|
+
# will check that each locator is present with those options as well (other than `:wait`).
|
189
|
+
#
|
190
|
+
# page.assert_any_of_selectors(:custom, 'Tom', 'Joe', visible: all)
|
191
|
+
# page.assert_any_of_selectors(:css, '#my_div', 'a.not_clicked')
|
192
|
+
#
|
193
|
+
# It accepts all options that {Capybara::Node::Finders#all} accepts,
|
194
|
+
# such as `:text` and `:visible`.
|
195
|
+
#
|
196
|
+
# The `:wait` option applies to all of the selectors as a group, so any of the locators must be present
|
197
|
+
# within `:wait` (defaults to {Capybara.configure default_max_wait_time}) seconds.
|
198
|
+
#
|
199
|
+
# @overload assert_any_of_selectors([kind = Capybara.default_selector], *locators, **options)
|
200
|
+
#
|
201
|
+
def assert_any_of_selectors(*args, wait: nil, **options, &optional_filter_block)
|
202
|
+
wait = session_options.default_max_wait_time if wait.nil?
|
203
|
+
selector = extract_selector(args)
|
204
|
+
synchronize(wait) do
|
205
|
+
res = args.map do |locator|
|
206
|
+
assert_selector(selector, locator, options, &optional_filter_block)
|
207
|
+
break nil
|
208
|
+
rescue Capybara::ExpectationNotMet => e
|
209
|
+
e.message
|
185
210
|
end
|
211
|
+
raise Capybara::ExpectationNotMet, res.join(' or ') if res
|
212
|
+
|
213
|
+
true
|
186
214
|
end
|
187
|
-
return true
|
188
215
|
end
|
189
216
|
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
217
|
+
##
|
218
|
+
#
|
219
|
+
# Asserts that a given selector is not on the page or a descendant of the current node.
|
220
|
+
# Usage is identical to {#assert_selector}.
|
221
|
+
#
|
222
|
+
# Query options such as `:count`, `:minimum`, `:maximum`, and `:between` are
|
223
|
+
# considered to be an integral part of the selector. This will return
|
224
|
+
# `true`, for example, if a page contains 4 anchors but the query expects 5:
|
225
|
+
#
|
226
|
+
# page.assert_no_selector('a', minimum: 1) # Found, raises Capybara::ExpectationNotMet
|
227
|
+
# page.assert_no_selector('a', count: 4) # Found, raises Capybara::ExpectationNotMet
|
228
|
+
# page.assert_no_selector('a', count: 5) # Not Found, returns true
|
229
|
+
#
|
230
|
+
# @param (see #assert_selector)
|
231
|
+
# @raise [Capybara::ExpectationNotMet] If the selector exists
|
232
|
+
#
|
233
|
+
def assert_no_selector(*args, &optional_filter_block)
|
234
|
+
_verify_selector_result(args, optional_filter_block) do |result, query|
|
235
|
+
if result.matches_count? && (!result.empty? || query.expects_none?)
|
236
|
+
raise Capybara::ExpectationNotMet, result.negative_failure_message
|
196
237
|
end
|
197
238
|
end
|
198
|
-
return true
|
199
239
|
end
|
200
|
-
alias_method :refute_matches_selector, :assert_not_matches_selector
|
201
240
|
|
202
241
|
##
|
203
242
|
#
|
204
|
-
# Checks if a given XPath expression is on the page or current node.
|
243
|
+
# Checks if a given XPath expression is on the page or a descendant of the current node.
|
205
244
|
#
|
206
245
|
# page.has_xpath?('.//p[@id="foo"]')
|
207
246
|
#
|
208
247
|
# By default it will check if the expression occurs at least once,
|
209
248
|
# but a different number can be specified.
|
210
249
|
#
|
211
|
-
# page.has_xpath?('.//p[@id="foo"]', :
|
250
|
+
# page.has_xpath?('.//p[@id="foo"]', count: 4)
|
212
251
|
#
|
213
252
|
# This will check if the expression occurs exactly 4 times.
|
214
253
|
#
|
215
254
|
# It also accepts all options that {Capybara::Node::Finders#all} accepts,
|
216
|
-
# such as
|
255
|
+
# such as `:text` and `:visible`.
|
217
256
|
#
|
218
|
-
# page.has_xpath?('.//li', :
|
257
|
+
# page.has_xpath?('.//li', text: 'Horse', visible: true)
|
219
258
|
#
|
220
|
-
# has_xpath? can also accept XPath expressions
|
259
|
+
# {#has_xpath?} can also accept XPath expressions generated by the
|
221
260
|
# XPath gem:
|
222
261
|
#
|
223
262
|
# xpath = XPath.generate { |x| x.descendant(:p) }
|
@@ -228,59 +267,59 @@ module Capybara
|
|
228
267
|
# @option options [Integer] :count (nil) Number of times the expression should occur
|
229
268
|
# @return [Boolean] If the expression exists
|
230
269
|
#
|
231
|
-
def has_xpath?(path, options
|
232
|
-
has_selector?(:xpath, path, options)
|
270
|
+
def has_xpath?(path, **options, &optional_filter_block)
|
271
|
+
has_selector?(:xpath, path, **options, &optional_filter_block)
|
233
272
|
end
|
234
273
|
|
235
274
|
##
|
236
275
|
#
|
237
|
-
# Checks if a given XPath expression is not on the page or current node.
|
238
|
-
# Usage is identical to
|
276
|
+
# Checks if a given XPath expression is not on the page or a descendant of the current node.
|
277
|
+
# Usage is identical to {#has_xpath?}.
|
239
278
|
#
|
240
|
-
# @param (see
|
279
|
+
# @param (see #has_xpath?)
|
241
280
|
# @return [Boolean]
|
242
281
|
#
|
243
|
-
def has_no_xpath?(path, options
|
244
|
-
has_no_selector?(:xpath, path, options)
|
282
|
+
def has_no_xpath?(path, **options, &optional_filter_block)
|
283
|
+
has_no_selector?(:xpath, path, **options, &optional_filter_block)
|
245
284
|
end
|
246
285
|
|
247
286
|
##
|
248
287
|
#
|
249
|
-
# Checks if a given CSS selector is on the page or current node.
|
288
|
+
# Checks if a given CSS selector is on the page or a descendant of the current node.
|
250
289
|
#
|
251
290
|
# page.has_css?('p#foo')
|
252
291
|
#
|
253
292
|
# By default it will check if the selector occurs at least once,
|
254
293
|
# but a different number can be specified.
|
255
294
|
#
|
256
|
-
# page.has_css?('p#foo', :
|
295
|
+
# page.has_css?('p#foo', count: 4)
|
257
296
|
#
|
258
297
|
# This will check if the selector occurs exactly 4 times.
|
259
298
|
#
|
260
299
|
# It also accepts all options that {Capybara::Node::Finders#all} accepts,
|
261
|
-
# such as
|
300
|
+
# such as `:text` and `:visible`.
|
262
301
|
#
|
263
|
-
# page.has_css?('li', :
|
302
|
+
# page.has_css?('li', text: 'Horse', visible: true)
|
264
303
|
#
|
265
304
|
# @param [String] path A CSS selector
|
266
305
|
# @param options (see Capybara::Node::Finders#all)
|
267
306
|
# @option options [Integer] :count (nil) Number of times the selector should occur
|
268
307
|
# @return [Boolean] If the selector exists
|
269
308
|
#
|
270
|
-
def has_css?(path, options
|
271
|
-
has_selector?(:css, path, options)
|
309
|
+
def has_css?(path, **options, &optional_filter_block)
|
310
|
+
has_selector?(:css, path, **options, &optional_filter_block)
|
272
311
|
end
|
273
312
|
|
274
313
|
##
|
275
314
|
#
|
276
|
-
# Checks if a given CSS selector is not on the page or current node.
|
277
|
-
# Usage is identical to
|
315
|
+
# Checks if a given CSS selector is not on the page or a descendant of the current node.
|
316
|
+
# Usage is identical to {#has_css?}.
|
278
317
|
#
|
279
|
-
# @param (see
|
318
|
+
# @param (see #has_css?)
|
280
319
|
# @return [Boolean]
|
281
320
|
#
|
282
|
-
def has_no_css?(path, options
|
283
|
-
has_no_selector?(:css, path, options)
|
321
|
+
def has_no_css?(path, **options, &optional_filter_block)
|
322
|
+
has_no_selector?(:css, path, **options, &optional_filter_block)
|
284
323
|
end
|
285
324
|
|
286
325
|
##
|
@@ -289,12 +328,11 @@ module Capybara
|
|
289
328
|
# text or id.
|
290
329
|
#
|
291
330
|
# @param [String] locator The text or id of a link to check for
|
292
|
-
# @param options
|
293
331
|
# @option options [String, Regexp] :href The value the href attribute must be
|
294
332
|
# @return [Boolean] Whether it exists
|
295
333
|
#
|
296
|
-
def has_link?(locator, options
|
297
|
-
has_selector?(:link, locator, options)
|
334
|
+
def has_link?(locator = nil, **options, &optional_filter_block)
|
335
|
+
has_selector?(:link, locator, **options, &optional_filter_block)
|
298
336
|
end
|
299
337
|
|
300
338
|
##
|
@@ -302,11 +340,11 @@ module Capybara
|
|
302
340
|
# Checks if the page or current node has no link with the given
|
303
341
|
# text or id.
|
304
342
|
#
|
305
|
-
# @param (see
|
343
|
+
# @param (see #has_link?)
|
306
344
|
# @return [Boolean] Whether it doesn't exist
|
307
345
|
#
|
308
|
-
def has_no_link?(locator, options
|
309
|
-
has_no_selector?(:link, locator, options)
|
346
|
+
def has_no_link?(locator = nil, **options, &optional_filter_block)
|
347
|
+
has_no_selector?(:link, locator, **options, &optional_filter_block)
|
310
348
|
end
|
311
349
|
|
312
350
|
##
|
@@ -317,8 +355,8 @@ module Capybara
|
|
317
355
|
# @param [String] locator The text, value or id of a button to check for
|
318
356
|
# @return [Boolean] Whether it exists
|
319
357
|
#
|
320
|
-
def has_button?(locator, options
|
321
|
-
has_selector?(:button, locator, options)
|
358
|
+
def has_button?(locator = nil, **options, &optional_filter_block)
|
359
|
+
has_selector?(:button, locator, **options, &optional_filter_block)
|
322
360
|
end
|
323
361
|
|
324
362
|
##
|
@@ -329,8 +367,8 @@ module Capybara
|
|
329
367
|
# @param [String] locator The text, value or id of a button to check for
|
330
368
|
# @return [Boolean] Whether it doesn't exist
|
331
369
|
#
|
332
|
-
def has_no_button?(locator, options
|
333
|
-
has_no_selector?(:button, locator, options)
|
370
|
+
def has_no_button?(locator = nil, **options, &optional_filter_block)
|
371
|
+
has_no_selector?(:button, locator, **options, &optional_filter_block)
|
334
372
|
end
|
335
373
|
|
336
374
|
##
|
@@ -339,90 +377,90 @@ module Capybara
|
|
339
377
|
# label, name or id.
|
340
378
|
#
|
341
379
|
# For text fields and other textual fields, such as textareas and
|
342
|
-
# HTML5 email/url/etc. fields, it's possible to specify a
|
380
|
+
# HTML5 email/url/etc. fields, it's possible to specify a `:with`
|
343
381
|
# option to specify the text the field should contain:
|
344
382
|
#
|
345
|
-
# page.has_field?('Name', :
|
383
|
+
# page.has_field?('Name', with: 'Jonas')
|
346
384
|
#
|
347
385
|
# It is also possible to filter by the field type attribute:
|
348
386
|
#
|
349
|
-
# page.has_field?('Email', :
|
387
|
+
# page.has_field?('Email', type: 'email')
|
350
388
|
#
|
351
|
-
#
|
389
|
+
# NOTE: 'textarea' and 'select' are valid type values, matching the associated tag names.
|
352
390
|
#
|
353
|
-
# @param [String] locator
|
354
|
-
# @option options [String] :with
|
355
|
-
# @option options [String] :type
|
356
|
-
# @return [Boolean]
|
391
|
+
# @param [String] locator The label, name or id of a field to check for
|
392
|
+
# @option options [String, Regexp] :with The text content of the field or a Regexp to match
|
393
|
+
# @option options [String] :type The type attribute of the field
|
394
|
+
# @return [Boolean] Whether it exists
|
357
395
|
#
|
358
|
-
def has_field?(locator, options
|
359
|
-
has_selector?(:field, locator, options)
|
396
|
+
def has_field?(locator = nil, **options, &optional_filter_block)
|
397
|
+
has_selector?(:field, locator, **options, &optional_filter_block)
|
360
398
|
end
|
361
399
|
|
362
400
|
##
|
363
401
|
#
|
364
402
|
# Checks if the page or current node has no form field with the given
|
365
|
-
# label, name or id. See {
|
403
|
+
# label, name or id. See {#has_field?}.
|
366
404
|
#
|
367
|
-
# @param [String] locator
|
368
|
-
# @option options [String] :with
|
369
|
-
# @option options [String] :type
|
370
|
-
# @return [Boolean]
|
405
|
+
# @param [String] locator The label, name or id of a field to check for
|
406
|
+
# @option options [String, Regexp] :with The text content of the field or a Regexp to match
|
407
|
+
# @option options [String] :type The type attribute of the field
|
408
|
+
# @return [Boolean] Whether it doesn't exist
|
371
409
|
#
|
372
|
-
def has_no_field?(locator, options
|
373
|
-
has_no_selector?(:field, locator, options)
|
410
|
+
def has_no_field?(locator = nil, **options, &optional_filter_block)
|
411
|
+
has_no_selector?(:field, locator, **options, &optional_filter_block)
|
374
412
|
end
|
375
413
|
|
376
414
|
##
|
377
415
|
#
|
378
416
|
# Checks if the page or current node has a radio button or
|
379
|
-
# checkbox with the given label, value
|
417
|
+
# checkbox with the given label, value, id, or {Capybara.configure test_id} attribute that is currently
|
380
418
|
# checked.
|
381
419
|
#
|
382
420
|
# @param [String] locator The label, name or id of a checked field
|
383
421
|
# @return [Boolean] Whether it exists
|
384
422
|
#
|
385
|
-
def has_checked_field?(locator, options
|
386
|
-
has_selector?(:field, locator, options.merge(:
|
423
|
+
def has_checked_field?(locator = nil, **options, &optional_filter_block)
|
424
|
+
has_selector?(:field, locator, **options.merge(checked: true), &optional_filter_block)
|
387
425
|
end
|
388
426
|
|
389
427
|
##
|
390
428
|
#
|
391
429
|
# Checks if the page or current node has no radio button or
|
392
|
-
# checkbox with the given label, value or id, that is currently
|
430
|
+
# checkbox with the given label, value or id, or {Capybara.configure test_id} attribute that is currently
|
393
431
|
# checked.
|
394
432
|
#
|
395
433
|
# @param [String] locator The label, name or id of a checked field
|
396
434
|
# @return [Boolean] Whether it doesn't exist
|
397
435
|
#
|
398
|
-
def has_no_checked_field?(locator, options
|
399
|
-
has_no_selector?(:field, locator, options.merge(:
|
436
|
+
def has_no_checked_field?(locator = nil, **options, &optional_filter_block)
|
437
|
+
has_no_selector?(:field, locator, **options.merge(checked: true), &optional_filter_block)
|
400
438
|
end
|
401
439
|
|
402
440
|
##
|
403
441
|
#
|
404
442
|
# Checks if the page or current node has a radio button or
|
405
|
-
# checkbox with the given label, value or id, that is currently
|
443
|
+
# checkbox with the given label, value or id, or {Capybara.configure test_id} attribute that is currently
|
406
444
|
# unchecked.
|
407
445
|
#
|
408
446
|
# @param [String] locator The label, name or id of an unchecked field
|
409
447
|
# @return [Boolean] Whether it exists
|
410
448
|
#
|
411
|
-
def has_unchecked_field?(locator, options
|
412
|
-
has_selector?(:field, locator, options.merge(:
|
449
|
+
def has_unchecked_field?(locator = nil, **options, &optional_filter_block)
|
450
|
+
has_selector?(:field, locator, **options.merge(unchecked: true), &optional_filter_block)
|
413
451
|
end
|
414
452
|
|
415
453
|
##
|
416
454
|
#
|
417
455
|
# Checks if the page or current node has no radio button or
|
418
|
-
# checkbox with the given label, value or id, that is currently
|
456
|
+
# checkbox with the given label, value or id, or {Capybara.configure test_id} attribute that is currently
|
419
457
|
# unchecked.
|
420
458
|
#
|
421
459
|
# @param [String] locator The label, name or id of an unchecked field
|
422
460
|
# @return [Boolean] Whether it doesn't exist
|
423
461
|
#
|
424
|
-
def has_no_unchecked_field?(locator, options
|
425
|
-
has_no_selector?(:field, locator, options.merge(:
|
462
|
+
def has_no_unchecked_field?(locator = nil, **options, &optional_filter_block)
|
463
|
+
has_no_selector?(:field, locator, **options.merge(unchecked: true), &optional_filter_block)
|
426
464
|
end
|
427
465
|
|
428
466
|
##
|
@@ -432,41 +470,42 @@ module Capybara
|
|
432
470
|
#
|
433
471
|
# It can be specified which option should currently be selected:
|
434
472
|
#
|
435
|
-
# page.has_select?('Language', :
|
473
|
+
# page.has_select?('Language', selected: 'German')
|
436
474
|
#
|
437
475
|
# For multiple select boxes, several options may be specified:
|
438
476
|
#
|
439
|
-
# page.has_select?('Language', :
|
477
|
+
# page.has_select?('Language', selected: ['English', 'German'])
|
440
478
|
#
|
441
479
|
# It's also possible to check if the exact set of options exists for
|
442
480
|
# this select box:
|
443
481
|
#
|
444
|
-
# page.has_select?('Language', :
|
482
|
+
# page.has_select?('Language', options: ['English', 'German', 'Spanish'])
|
445
483
|
#
|
446
484
|
# You can also check for a partial set of options:
|
447
485
|
#
|
448
|
-
# page.has_select?('Language', :
|
486
|
+
# page.has_select?('Language', with_options: ['English', 'German'])
|
449
487
|
#
|
450
|
-
# @param [String] locator
|
451
|
-
# @option options [Array] :options
|
452
|
-
# @option options [Array] :with_options
|
453
|
-
# @option options [String, Array] :selected
|
454
|
-
# @
|
488
|
+
# @param [String] locator The label, name or id of a select box
|
489
|
+
# @option options [Array] :options Options which should be contained in this select box
|
490
|
+
# @option options [Array] :with_options Partial set of options which should be contained in this select box
|
491
|
+
# @option options [String, Array] :selected Options which should be selected
|
492
|
+
# @option options [String, Array] :with_selected Partial set of options which should minimally be selected
|
493
|
+
# @return [Boolean] Whether it exists
|
455
494
|
#
|
456
|
-
def has_select?(locator, options
|
457
|
-
has_selector?(:select, locator, options)
|
495
|
+
def has_select?(locator = nil, **options, &optional_filter_block)
|
496
|
+
has_selector?(:select, locator, **options, &optional_filter_block)
|
458
497
|
end
|
459
498
|
|
460
499
|
##
|
461
500
|
#
|
462
501
|
# Checks if the page or current node has no select field with the
|
463
|
-
# given label, name or id. See {
|
502
|
+
# given label, name or id. See {#has_select?}.
|
464
503
|
#
|
465
|
-
# @param (see
|
504
|
+
# @param (see #has_select?)
|
466
505
|
# @return [Boolean] Whether it doesn't exist
|
467
506
|
#
|
468
|
-
def has_no_select?(locator, options
|
469
|
-
has_no_selector?(:select, locator, options)
|
507
|
+
def has_no_select?(locator = nil, **options, &optional_filter_block)
|
508
|
+
has_no_selector?(:select, locator, **options, &optional_filter_block)
|
470
509
|
end
|
471
510
|
|
472
511
|
##
|
@@ -476,23 +515,134 @@ module Capybara
|
|
476
515
|
#
|
477
516
|
# page.has_table?('People')
|
478
517
|
#
|
479
|
-
# @param [String] locator
|
480
|
-
# @
|
481
|
-
#
|
482
|
-
|
483
|
-
|
518
|
+
# @param [String] locator The id or caption of a table
|
519
|
+
# @option options [Array<Array<String>>] :rows
|
520
|
+
# Text which should be contained in the tables `<td>` elements organized by row (`<td>` visibility is not considered)
|
521
|
+
# @option options [Array<Array<String>>, Array<Hash<String,String>>] :with_rows
|
522
|
+
# Partial set of text which should be contained in the tables `<td>` elements organized by row (`<td>` visibility is not considered)
|
523
|
+
# @option options [Array<Array<String>>] :cols
|
524
|
+
# Text which should be contained in the tables `<td>` elements organized by column (`<td>` visibility is not considered)
|
525
|
+
# @option options [Array<Array<String>>, Array<Hash<String,String>>] :with_cols
|
526
|
+
# Partial set of text which should be contained in the tables `<td>` elements organized by column (`<td>` visibility is not considered)
|
527
|
+
# @return [Boolean] Whether it exists
|
528
|
+
#
|
529
|
+
def has_table?(locator = nil, **options, &optional_filter_block)
|
530
|
+
has_selector?(:table, locator, **options, &optional_filter_block)
|
484
531
|
end
|
485
532
|
|
486
533
|
##
|
487
534
|
#
|
488
535
|
# Checks if the page or current node has no table with the given id
|
489
|
-
# or caption. See {
|
536
|
+
# or caption. See {#has_table?}.
|
490
537
|
#
|
491
|
-
# @param (see
|
538
|
+
# @param (see #has_table?)
|
492
539
|
# @return [Boolean] Whether it doesn't exist
|
493
540
|
#
|
494
|
-
def has_no_table?(locator, options
|
495
|
-
has_no_selector?(:table, locator, options)
|
541
|
+
def has_no_table?(locator = nil, **options, &optional_filter_block)
|
542
|
+
has_no_selector?(:table, locator, **options, &optional_filter_block)
|
543
|
+
end
|
544
|
+
|
545
|
+
##
|
546
|
+
#
|
547
|
+
# Asserts that the current node matches a given selector.
|
548
|
+
#
|
549
|
+
# node.assert_matches_selector('p#foo')
|
550
|
+
# node.assert_matches_selector(:xpath, '//p[@id="foo"]')
|
551
|
+
# node.assert_matches_selector(:foo)
|
552
|
+
#
|
553
|
+
# It also accepts all options that {Capybara::Node::Finders#all} accepts,
|
554
|
+
# such as `:text` and `:visible`.
|
555
|
+
#
|
556
|
+
# node.assert_matches_selector('li', text: 'Horse', visible: true)
|
557
|
+
#
|
558
|
+
# @param (see Capybara::Node::Finders#all)
|
559
|
+
# @raise [Capybara::ExpectationNotMet] If the selector does not match
|
560
|
+
#
|
561
|
+
def assert_matches_selector(*args, &optional_filter_block)
|
562
|
+
_verify_match_result(args, optional_filter_block) do |result|
|
563
|
+
raise Capybara::ExpectationNotMet, 'Item does not match the provided selector' unless result.include? self
|
564
|
+
end
|
565
|
+
end
|
566
|
+
|
567
|
+
##
|
568
|
+
#
|
569
|
+
# Asserts that the current node does not match a given selector.
|
570
|
+
# Usage is identical to {#assert_matches_selector}.
|
571
|
+
#
|
572
|
+
# @param (see #assert_matches_selector)
|
573
|
+
# @raise [Capybara::ExpectationNotMet] If the selector matches
|
574
|
+
#
|
575
|
+
def assert_not_matches_selector(*args, &optional_filter_block)
|
576
|
+
_verify_match_result(args, optional_filter_block) do |result|
|
577
|
+
raise Capybara::ExpectationNotMet, 'Item matched the provided selector' if result.include? self
|
578
|
+
end
|
579
|
+
end
|
580
|
+
|
581
|
+
##
|
582
|
+
#
|
583
|
+
# Checks if the current node matches given selector.
|
584
|
+
#
|
585
|
+
# @param (see #has_selector?)
|
586
|
+
# @return [Boolean]
|
587
|
+
#
|
588
|
+
def matches_selector?(*args, **options, &optional_filter_block)
|
589
|
+
make_predicate(options) { assert_matches_selector(*args, options, &optional_filter_block) }
|
590
|
+
end
|
591
|
+
|
592
|
+
##
|
593
|
+
#
|
594
|
+
# Checks if the current node matches given XPath expression.
|
595
|
+
#
|
596
|
+
# @param [String, XPath::Expression] xpath The XPath expression to match against the current code
|
597
|
+
# @return [Boolean]
|
598
|
+
#
|
599
|
+
def matches_xpath?(xpath, **options, &optional_filter_block)
|
600
|
+
matches_selector?(:xpath, xpath, **options, &optional_filter_block)
|
601
|
+
end
|
602
|
+
|
603
|
+
##
|
604
|
+
#
|
605
|
+
# Checks if the current node matches given CSS selector.
|
606
|
+
#
|
607
|
+
# @param [String] css The CSS selector to match against the current code
|
608
|
+
# @return [Boolean]
|
609
|
+
#
|
610
|
+
def matches_css?(css, **options, &optional_filter_block)
|
611
|
+
matches_selector?(:css, css, **options, &optional_filter_block)
|
612
|
+
end
|
613
|
+
|
614
|
+
##
|
615
|
+
#
|
616
|
+
# Checks if the current node does not match given selector.
|
617
|
+
# Usage is identical to {#has_selector?}.
|
618
|
+
#
|
619
|
+
# @param (see #has_selector?)
|
620
|
+
# @return [Boolean]
|
621
|
+
#
|
622
|
+
def not_matches_selector?(*args, **options, &optional_filter_block)
|
623
|
+
make_predicate(options) { assert_not_matches_selector(*args, options, &optional_filter_block) }
|
624
|
+
end
|
625
|
+
|
626
|
+
##
|
627
|
+
#
|
628
|
+
# Checks if the current node does not match given XPath expression.
|
629
|
+
#
|
630
|
+
# @param [String, XPath::Expression] xpath The XPath expression to match against the current code
|
631
|
+
# @return [Boolean]
|
632
|
+
#
|
633
|
+
def not_matches_xpath?(xpath, **options, &optional_filter_block)
|
634
|
+
not_matches_selector?(:xpath, xpath, **options, &optional_filter_block)
|
635
|
+
end
|
636
|
+
|
637
|
+
##
|
638
|
+
#
|
639
|
+
# Checks if the current node does not match given CSS selector.
|
640
|
+
#
|
641
|
+
# @param [String] css The CSS selector to match against the current code
|
642
|
+
# @return [Boolean]
|
643
|
+
#
|
644
|
+
def not_matches_css?(css, **options, &optional_filter_block)
|
645
|
+
not_matches_selector?(:css, css, **options, &optional_filter_block)
|
496
646
|
end
|
497
647
|
|
498
648
|
##
|
@@ -500,34 +650,34 @@ module Capybara
|
|
500
650
|
# ignoring any HTML tags.
|
501
651
|
#
|
502
652
|
# @!macro text_query_params
|
503
|
-
# @overload $0(type, text, options
|
504
|
-
# @param [:all, :visible] type Whether to check for only visible or all text
|
653
|
+
# @overload $0(type, text, **options)
|
654
|
+
# @param [:all, :visible] type Whether to check for only visible or all text. If this parameter is missing or nil then we use the value of {Capybara.configure ignore_hidden_elements}, which defaults to `true`, corresponding to `:visible`.
|
505
655
|
# @param [String, Regexp] text The string/regexp to check for. If it's a string, text is expected to include it. If it's a regexp, text is expected to match it.
|
506
656
|
# @option options [Integer] :count (nil) Number of times the text is expected to occur
|
507
657
|
# @option options [Integer] :minimum (nil) Minimum number of times the text is expected to occur
|
508
658
|
# @option options [Integer] :maximum (nil) Maximum number of times the text is expected to occur
|
509
659
|
# @option options [Range] :between (nil) Range of times that is expected to contain number of times text occurs
|
510
|
-
# @option options [Numeric] :wait
|
511
|
-
#
|
660
|
+
# @option options [Numeric] :wait Maximum time that Capybara will wait for text to eq/match given string/regexp argument. Defaults to {Capybara.configure default_max_wait_time}.
|
661
|
+
# @option options [Boolean] :exact Whether text must be an exact match or just substring. Defaults to {Capybara.configure exact_text}.
|
662
|
+
# @option options [Boolean] :normalize_ws (false) When `true` replace all whitespace with standard spaces and collapse consecutive whitespace to a single space
|
663
|
+
# @overload $0(text, **options)
|
512
664
|
# @param [String, Regexp] text The string/regexp to check for. If it's a string, text is expected to include it. If it's a regexp, text is expected to match it.
|
513
665
|
# @option options [Integer] :count (nil) Number of times the text is expected to occur
|
514
666
|
# @option options [Integer] :minimum (nil) Minimum number of times the text is expected to occur
|
515
667
|
# @option options [Integer] :maximum (nil) Maximum number of times the text is expected to occur
|
516
668
|
# @option options [Range] :between (nil) Range of times that is expected to contain number of times text occurs
|
517
|
-
# @option options [Numeric] :wait
|
669
|
+
# @option options [Numeric] :wait Maximum time that Capybara will wait for text to eq/match given string/regexp argument. Defaults to {Capybara.configure default_max_wait_time}.
|
670
|
+
# @option options [Boolean] :exact Whether text must be an exact match or just substring. Defaults to {Capybara.configure exact_text}.
|
671
|
+
# @option options [Boolean] :normalize_ws (false) When `true` replace all whitespace with standard spaces and collapse consecutive whitespace to a single space
|
518
672
|
# @raise [Capybara::ExpectationNotMet] if the assertion hasn't succeeded during wait time
|
519
673
|
# @return [true]
|
520
674
|
#
|
521
|
-
def assert_text(*args)
|
522
|
-
|
523
|
-
|
524
|
-
count = query.resolve_for(self)
|
525
|
-
matches_count = Capybara::Helpers.matches_count?(count, query.options)
|
526
|
-
unless matches_count && ((count > 0) || Capybara::Helpers.expects_none?(query.options))
|
675
|
+
def assert_text(type_or_text, *args, **opts)
|
676
|
+
_verify_text(type_or_text, *args, **opts) do |count, query|
|
677
|
+
unless query.matches_count?(count) && (count.positive? || query.expects_none?)
|
527
678
|
raise Capybara::ExpectationNotMet, query.failure_message
|
528
679
|
end
|
529
680
|
end
|
530
|
-
return true
|
531
681
|
end
|
532
682
|
|
533
683
|
##
|
@@ -538,26 +688,18 @@ module Capybara
|
|
538
688
|
# @raise [Capybara::ExpectationNotMet] if the assertion hasn't succeeded during wait time
|
539
689
|
# @return [true]
|
540
690
|
#
|
541
|
-
def assert_no_text(*args)
|
542
|
-
|
543
|
-
|
544
|
-
count = query.resolve_for(self)
|
545
|
-
matches_count = Capybara::Helpers.matches_count?(count, query.options)
|
546
|
-
if matches_count && ((count > 0) || Capybara::Helpers.expects_none?(query.options))
|
691
|
+
def assert_no_text(type_or_text, *args, **opts)
|
692
|
+
_verify_text(type_or_text, *args, **opts) do |count, query|
|
693
|
+
if query.matches_count?(count) && (count.positive? || query.expects_none?)
|
547
694
|
raise Capybara::ExpectationNotMet, query.negative_failure_message
|
548
695
|
end
|
549
696
|
end
|
550
|
-
return true
|
551
697
|
end
|
552
698
|
|
553
699
|
##
|
554
700
|
# Checks if the page or current node has the given text content,
|
555
701
|
# ignoring any HTML tags.
|
556
702
|
#
|
557
|
-
# Whitespaces are normalized in both node's text and passed text parameter.
|
558
|
-
# Note that whitespace isn't normalized in passed regexp as normalizing whitespace
|
559
|
-
# in regexp isn't easy and doesn't seem to be worth it.
|
560
|
-
#
|
561
703
|
# By default it will check if the text occurs at least once,
|
562
704
|
# but a different number can be specified.
|
563
705
|
#
|
@@ -568,10 +710,8 @@ module Capybara
|
|
568
710
|
# @macro text_query_params
|
569
711
|
# @return [Boolean] Whether it exists
|
570
712
|
#
|
571
|
-
def has_text?(*args)
|
572
|
-
assert_text(*args)
|
573
|
-
rescue Capybara::ExpectationNotMet
|
574
|
-
return false
|
713
|
+
def has_text?(*args, **options)
|
714
|
+
make_predicate(options) { assert_text(*args, **options) }
|
575
715
|
end
|
576
716
|
alias_method :has_content?, :has_text?
|
577
717
|
|
@@ -582,15 +722,161 @@ module Capybara
|
|
582
722
|
# @macro text_query_params
|
583
723
|
# @return [Boolean] Whether it doesn't exist
|
584
724
|
#
|
585
|
-
def has_no_text?(*args)
|
586
|
-
assert_no_text(*args)
|
587
|
-
rescue Capybara::ExpectationNotMet
|
588
|
-
return false
|
725
|
+
def has_no_text?(*args, **options)
|
726
|
+
make_predicate(options) { assert_no_text(*args, **options) }
|
589
727
|
end
|
590
728
|
alias_method :has_no_content?, :has_no_text?
|
591
729
|
|
730
|
+
##
|
731
|
+
#
|
732
|
+
# Asserts that a given selector matches an ancestor of the current node.
|
733
|
+
#
|
734
|
+
# element.assert_ancestor('p#foo')
|
735
|
+
#
|
736
|
+
# Accepts the same options as {#assert_selector}
|
737
|
+
#
|
738
|
+
# @param (see Capybara::Node::Finders#find)
|
739
|
+
# @raise [Capybara::ExpectationNotMet] If the selector does not exist
|
740
|
+
#
|
741
|
+
def assert_ancestor(*args, &optional_filter_block)
|
742
|
+
_verify_selector_result(args, optional_filter_block, Capybara::Queries::AncestorQuery) do |result, query|
|
743
|
+
unless result.matches_count? && (result.any? || query.expects_none?)
|
744
|
+
raise Capybara::ExpectationNotMet, result.failure_message
|
745
|
+
end
|
746
|
+
end
|
747
|
+
end
|
748
|
+
|
749
|
+
def assert_no_ancestor(*args, &optional_filter_block)
|
750
|
+
_verify_selector_result(args, optional_filter_block, Capybara::Queries::AncestorQuery) do |result, query|
|
751
|
+
if result.matches_count? && (!result.empty? || query.expects_none?)
|
752
|
+
raise Capybara::ExpectationNotMet, result.negative_failure_message
|
753
|
+
end
|
754
|
+
end
|
755
|
+
end
|
756
|
+
|
757
|
+
##
|
758
|
+
#
|
759
|
+
# Predicate version of {#assert_ancestor}
|
760
|
+
#
|
761
|
+
def has_ancestor?(*args, **options, &optional_filter_block)
|
762
|
+
make_predicate(options) { assert_ancestor(*args, options, &optional_filter_block) }
|
763
|
+
end
|
764
|
+
|
765
|
+
##
|
766
|
+
#
|
767
|
+
# Predicate version of {#assert_no_ancestor}
|
768
|
+
#
|
769
|
+
def has_no_ancestor?(*args, **options, &optional_filter_block)
|
770
|
+
make_predicate(options) { assert_no_ancestor(*args, options, &optional_filter_block) }
|
771
|
+
end
|
772
|
+
|
773
|
+
##
|
774
|
+
#
|
775
|
+
# Asserts that a given selector matches a sibling of the current node.
|
776
|
+
#
|
777
|
+
# element.assert_sibling('p#foo')
|
778
|
+
#
|
779
|
+
# Accepts the same options as {#assert_selector}
|
780
|
+
#
|
781
|
+
# @param (see Capybara::Node::Finders#find)
|
782
|
+
# @raise [Capybara::ExpectationNotMet] If the selector does not exist
|
783
|
+
#
|
784
|
+
def assert_sibling(*args, &optional_filter_block)
|
785
|
+
_verify_selector_result(args, optional_filter_block, Capybara::Queries::SiblingQuery) do |result, query|
|
786
|
+
unless result.matches_count? && (result.any? || query.expects_none?)
|
787
|
+
raise Capybara::ExpectationNotMet, result.failure_message
|
788
|
+
end
|
789
|
+
end
|
790
|
+
end
|
791
|
+
|
792
|
+
def assert_no_sibling(*args, &optional_filter_block)
|
793
|
+
_verify_selector_result(args, optional_filter_block, Capybara::Queries::SiblingQuery) do |result, query|
|
794
|
+
if result.matches_count? && (!result.empty? || query.expects_none?)
|
795
|
+
raise Capybara::ExpectationNotMet, result.negative_failure_message
|
796
|
+
end
|
797
|
+
end
|
798
|
+
end
|
799
|
+
|
800
|
+
##
|
801
|
+
#
|
802
|
+
# Predicate version of {#assert_sibling}
|
803
|
+
#
|
804
|
+
def has_sibling?(*args, **options, &optional_filter_block)
|
805
|
+
make_predicate(options) { assert_sibling(*args, options, &optional_filter_block) }
|
806
|
+
end
|
807
|
+
|
808
|
+
##
|
809
|
+
#
|
810
|
+
# Predicate version of {#assert_no_sibling}
|
811
|
+
#
|
812
|
+
def has_no_sibling?(*args, **options, &optional_filter_block)
|
813
|
+
make_predicate(options) { assert_no_sibling(*args, options, &optional_filter_block) }
|
814
|
+
end
|
815
|
+
|
592
816
|
def ==(other)
|
593
|
-
|
817
|
+
eql?(other) || (other.respond_to?(:base) && base == other.base)
|
818
|
+
end
|
819
|
+
|
820
|
+
private
|
821
|
+
|
822
|
+
def extract_selector(args)
|
823
|
+
args.first.is_a?(Symbol) ? args.shift : session_options.default_selector
|
824
|
+
end
|
825
|
+
|
826
|
+
def _verify_multiple(*args, wait: nil, **options)
|
827
|
+
wait = session_options.default_max_wait_time if wait.nil?
|
828
|
+
selector = extract_selector(args)
|
829
|
+
synchronize(wait) do
|
830
|
+
args.each { |locator| yield(selector, locator, options) }
|
831
|
+
end
|
832
|
+
end
|
833
|
+
|
834
|
+
def _verify_selector_result(query_args, optional_filter_block, query_type = Capybara::Queries::SelectorQuery)
|
835
|
+
# query_args, query_opts = if query_args[0].is_a? Symbol
|
836
|
+
# a,o = _set_query_session_options(*query_args.slice(2..))
|
837
|
+
# [query_args.slice(0..1).concat(a), o]
|
838
|
+
# else
|
839
|
+
# _set_query_session_options(*query_args)
|
840
|
+
# end
|
841
|
+
query_args, query_opts = _set_query_session_options(*query_args)
|
842
|
+
query = query_type.new(*query_args, **query_opts, &optional_filter_block)
|
843
|
+
synchronize(query.wait) do
|
844
|
+
yield query.resolve_for(self), query
|
845
|
+
end
|
846
|
+
true
|
847
|
+
end
|
848
|
+
|
849
|
+
def _verify_match_result(query_args, optional_filter_block)
|
850
|
+
query_args, query_opts = _set_query_session_options(*query_args)
|
851
|
+
query = Capybara::Queries::MatchQuery.new(*query_args, **query_opts, &optional_filter_block)
|
852
|
+
synchronize(query.wait) do
|
853
|
+
yield query.resolve_for(parent || session&.document || query_scope)
|
854
|
+
end
|
855
|
+
true
|
856
|
+
end
|
857
|
+
|
858
|
+
def _verify_text(type = nil, expected_text, **query_options) # rubocop:disable Style/OptionalArguments
|
859
|
+
query_options[:session_options] = session_options
|
860
|
+
query = Capybara::Queries::TextQuery.new(type, expected_text, **query_options)
|
861
|
+
synchronize(query.wait) do
|
862
|
+
yield query.resolve_for(self), query
|
863
|
+
end
|
864
|
+
true
|
865
|
+
end
|
866
|
+
|
867
|
+
def _set_query_session_options(*query_args)
|
868
|
+
query_args, query_options = query_args.dup, {}
|
869
|
+
# query_options = query_args.pop if query_options.empty? && query_args.last.is_a?(Hash)
|
870
|
+
query_options = query_args.pop if query_args.last.is_a?(Hash)
|
871
|
+
query_options[:session_options] = session_options
|
872
|
+
[query_args, query_options]
|
873
|
+
end
|
874
|
+
|
875
|
+
def make_predicate(options)
|
876
|
+
options[:wait] = 0 unless options.key?(:wait) || session_options.predicates_wait
|
877
|
+
yield
|
878
|
+
rescue Capybara::ExpectationNotMet
|
879
|
+
false
|
594
880
|
end
|
595
881
|
end
|
596
882
|
end
|