capybara 2.7.0 → 3.35.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.yardopts +1 -0
- data/History.md +1147 -11
- data/License.txt +1 -1
- data/README.md +252 -131
- data/lib/capybara/config.rb +92 -0
- data/lib/capybara/cucumber.rb +3 -3
- data/lib/capybara/driver/base.rb +52 -21
- data/lib/capybara/driver/node.rb +48 -14
- data/lib/capybara/dsl.rb +16 -9
- data/lib/capybara/helpers.rb +72 -81
- data/lib/capybara/minitest/spec.rb +267 -0
- data/lib/capybara/minitest.rb +385 -0
- data/lib/capybara/node/actions.rb +337 -89
- data/lib/capybara/node/base.rb +50 -32
- data/lib/capybara/node/document.rb +19 -3
- data/lib/capybara/node/document_matchers.rb +22 -24
- data/lib/capybara/node/element.rb +388 -125
- data/lib/capybara/node/finders.rb +231 -121
- data/lib/capybara/node/matchers.rb +503 -217
- data/lib/capybara/node/simple.rb +64 -27
- data/lib/capybara/queries/ancestor_query.rb +27 -0
- data/lib/capybara/queries/base_query.rb +87 -11
- data/lib/capybara/queries/current_path_query.rb +24 -24
- data/lib/capybara/queries/match_query.rb +15 -10
- data/lib/capybara/queries/selector_query.rb +675 -81
- data/lib/capybara/queries/sibling_query.rb +26 -0
- data/lib/capybara/queries/style_query.rb +45 -0
- data/lib/capybara/queries/text_query.rb +88 -20
- data/lib/capybara/queries/title_query.rb +9 -11
- data/lib/capybara/rack_test/browser.rb +63 -39
- data/lib/capybara/rack_test/css_handlers.rb +6 -4
- data/lib/capybara/rack_test/driver.rb +26 -16
- data/lib/capybara/rack_test/errors.rb +6 -0
- data/lib/capybara/rack_test/form.rb +73 -58
- data/lib/capybara/rack_test/node.rb +187 -67
- data/lib/capybara/rails.rb +4 -8
- data/lib/capybara/registration_container.rb +44 -0
- data/lib/capybara/registrations/drivers.rb +42 -0
- data/lib/capybara/registrations/patches/puma_ssl.rb +29 -0
- data/lib/capybara/registrations/servers.rb +45 -0
- data/lib/capybara/result.rb +142 -14
- data/lib/capybara/rspec/features.rb +17 -42
- data/lib/capybara/rspec/matcher_proxies.rb +82 -0
- data/lib/capybara/rspec/matchers/base.rb +111 -0
- data/lib/capybara/rspec/matchers/become_closed.rb +33 -0
- data/lib/capybara/rspec/matchers/compound.rb +88 -0
- data/lib/capybara/rspec/matchers/count_sugar.rb +37 -0
- data/lib/capybara/rspec/matchers/have_ancestor.rb +28 -0
- data/lib/capybara/rspec/matchers/have_current_path.rb +29 -0
- data/lib/capybara/rspec/matchers/have_selector.rb +77 -0
- data/lib/capybara/rspec/matchers/have_sibling.rb +27 -0
- data/lib/capybara/rspec/matchers/have_text.rb +33 -0
- data/lib/capybara/rspec/matchers/have_title.rb +29 -0
- data/lib/capybara/rspec/matchers/match_selector.rb +27 -0
- data/lib/capybara/rspec/matchers/match_style.rb +43 -0
- data/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
- data/lib/capybara/rspec/matchers.rb +143 -244
- data/lib/capybara/rspec.rb +10 -12
- data/lib/capybara/selector/builders/css_builder.rb +84 -0
- data/lib/capybara/selector/builders/xpath_builder.rb +71 -0
- data/lib/capybara/selector/css.rb +102 -0
- data/lib/capybara/selector/definition/button.rb +63 -0
- data/lib/capybara/selector/definition/checkbox.rb +26 -0
- data/lib/capybara/selector/definition/css.rb +10 -0
- data/lib/capybara/selector/definition/datalist_input.rb +35 -0
- data/lib/capybara/selector/definition/datalist_option.rb +25 -0
- data/lib/capybara/selector/definition/element.rb +28 -0
- data/lib/capybara/selector/definition/field.rb +40 -0
- data/lib/capybara/selector/definition/fieldset.rb +14 -0
- data/lib/capybara/selector/definition/file_field.rb +13 -0
- data/lib/capybara/selector/definition/fillable_field.rb +33 -0
- data/lib/capybara/selector/definition/frame.rb +17 -0
- data/lib/capybara/selector/definition/id.rb +6 -0
- data/lib/capybara/selector/definition/label.rb +62 -0
- data/lib/capybara/selector/definition/link.rb +54 -0
- data/lib/capybara/selector/definition/link_or_button.rb +16 -0
- data/lib/capybara/selector/definition/option.rb +27 -0
- data/lib/capybara/selector/definition/radio_button.rb +27 -0
- data/lib/capybara/selector/definition/select.rb +81 -0
- data/lib/capybara/selector/definition/table.rb +109 -0
- data/lib/capybara/selector/definition/table_row.rb +21 -0
- data/lib/capybara/selector/definition/xpath.rb +5 -0
- data/lib/capybara/selector/definition.rb +278 -0
- data/lib/capybara/selector/filter.rb +3 -46
- data/lib/capybara/selector/filter_set.rb +124 -0
- data/lib/capybara/selector/filters/base.rb +77 -0
- data/lib/capybara/selector/filters/expression_filter.rb +22 -0
- data/lib/capybara/selector/filters/locator_filter.rb +29 -0
- data/lib/capybara/selector/filters/node_filter.rb +31 -0
- data/lib/capybara/selector/regexp_disassembler.rb +214 -0
- data/lib/capybara/selector/selector.rb +155 -0
- data/lib/capybara/selector/xpath_extensions.rb +17 -0
- data/lib/capybara/selector.rb +232 -369
- data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -0
- data/lib/capybara/selenium/atoms/isDisplayed.min.js +1 -0
- data/lib/capybara/selenium/atoms/src/getAttribute.js +161 -0
- data/lib/capybara/selenium/atoms/src/isDisplayed.js +454 -0
- data/lib/capybara/selenium/driver.rb +380 -142
- data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +117 -0
- data/lib/capybara/selenium/driver_specializations/edge_driver.rb +124 -0
- data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +89 -0
- data/lib/capybara/selenium/driver_specializations/internet_explorer_driver.rb +26 -0
- data/lib/capybara/selenium/driver_specializations/safari_driver.rb +24 -0
- data/lib/capybara/selenium/extensions/file_input_click_emulation.rb +34 -0
- data/lib/capybara/selenium/extensions/find.rb +110 -0
- data/lib/capybara/selenium/extensions/html5_drag.rb +228 -0
- data/lib/capybara/selenium/extensions/modifier_keys_stack.rb +28 -0
- data/lib/capybara/selenium/extensions/scroll.rb +76 -0
- data/lib/capybara/selenium/logger_suppressor.rb +40 -0
- data/lib/capybara/selenium/node.rb +528 -97
- data/lib/capybara/selenium/nodes/chrome_node.rb +137 -0
- data/lib/capybara/selenium/nodes/edge_node.rb +104 -0
- data/lib/capybara/selenium/nodes/firefox_node.rb +136 -0
- data/lib/capybara/selenium/nodes/ie_node.rb +22 -0
- data/lib/capybara/selenium/nodes/safari_node.rb +118 -0
- data/lib/capybara/selenium/patches/action_pauser.rb +26 -0
- data/lib/capybara/selenium/patches/atoms.rb +18 -0
- data/lib/capybara/selenium/patches/is_displayed.rb +16 -0
- data/lib/capybara/selenium/patches/logs.rb +45 -0
- data/lib/capybara/selenium/patches/pause_duration_fix.rb +9 -0
- data/lib/capybara/selenium/patches/persistent_client.rb +20 -0
- data/lib/capybara/server/animation_disabler.rb +63 -0
- data/lib/capybara/server/checker.rb +44 -0
- data/lib/capybara/server/middleware.rb +71 -0
- data/lib/capybara/server.rb +74 -71
- data/lib/capybara/session/config.rb +126 -0
- data/lib/capybara/session/matchers.rb +44 -27
- data/lib/capybara/session.rb +500 -297
- data/lib/capybara/spec/fixtures/no_extension +1 -0
- data/lib/capybara/spec/public/jquery.js +5 -5
- data/lib/capybara/spec/public/offset.js +6 -0
- data/lib/capybara/spec/public/test.js +168 -14
- data/lib/capybara/spec/session/accept_alert_spec.rb +37 -14
- data/lib/capybara/spec/session/accept_confirm_spec.rb +7 -6
- data/lib/capybara/spec/session/accept_prompt_spec.rb +38 -10
- data/lib/capybara/spec/session/all_spec.rb +179 -59
- data/lib/capybara/spec/session/ancestor_spec.rb +88 -0
- data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +140 -0
- data/lib/capybara/spec/session/assert_current_path_spec.rb +75 -0
- data/lib/capybara/spec/session/assert_selector_spec.rb +143 -0
- data/lib/capybara/spec/session/assert_style_spec.rb +26 -0
- data/lib/capybara/spec/session/assert_text_spec.rb +258 -0
- data/lib/capybara/spec/session/assert_title_spec.rb +93 -0
- data/lib/capybara/spec/session/attach_file_spec.rb +154 -48
- data/lib/capybara/spec/session/body_spec.rb +12 -13
- data/lib/capybara/spec/session/check_spec.rb +168 -41
- data/lib/capybara/spec/session/choose_spec.rb +75 -23
- data/lib/capybara/spec/session/click_button_spec.rb +243 -175
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +57 -32
- data/lib/capybara/spec/session/click_link_spec.rb +100 -53
- data/lib/capybara/spec/session/current_scope_spec.rb +11 -10
- data/lib/capybara/spec/session/current_url_spec.rb +61 -35
- data/lib/capybara/spec/session/dismiss_confirm_spec.rb +7 -7
- data/lib/capybara/spec/session/dismiss_prompt_spec.rb +5 -4
- data/lib/capybara/spec/session/element/{assert_match_selector.rb → assert_match_selector_spec.rb} +13 -6
- data/lib/capybara/spec/session/element/match_css_spec.rb +21 -7
- data/lib/capybara/spec/session/element/match_xpath_spec.rb +9 -7
- data/lib/capybara/spec/session/element/matches_selector_spec.rb +91 -34
- data/lib/capybara/spec/session/evaluate_async_script_spec.rb +23 -0
- data/lib/capybara/spec/session/evaluate_script_spec.rb +45 -3
- data/lib/capybara/spec/session/execute_script_spec.rb +24 -4
- data/lib/capybara/spec/session/fill_in_spec.rb +166 -64
- data/lib/capybara/spec/session/find_button_spec.rb +37 -18
- data/lib/capybara/spec/session/find_by_id_spec.rb +10 -9
- data/lib/capybara/spec/session/find_field_spec.rb +57 -34
- data/lib/capybara/spec/session/find_link_spec.rb +47 -10
- data/lib/capybara/spec/session/find_spec.rb +290 -144
- data/lib/capybara/spec/session/first_spec.rb +91 -48
- data/lib/capybara/spec/session/frame/frame_title_spec.rb +23 -0
- data/lib/capybara/spec/session/frame/frame_url_spec.rb +23 -0
- data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +116 -0
- data/lib/capybara/spec/session/frame/within_frame_spec.rb +112 -0
- data/lib/capybara/spec/session/go_back_spec.rb +3 -2
- data/lib/capybara/spec/session/go_forward_spec.rb +3 -2
- data/lib/capybara/spec/session/has_all_selectors_spec.rb +69 -0
- data/lib/capybara/spec/session/has_ancestor_spec.rb +46 -0
- data/lib/capybara/spec/session/has_any_selectors_spec.rb +25 -0
- data/lib/capybara/spec/session/has_button_spec.rb +76 -19
- data/lib/capybara/spec/session/has_css_spec.rb +277 -131
- data/lib/capybara/spec/session/has_current_path_spec.rb +98 -26
- data/lib/capybara/spec/session/has_field_spec.rb +177 -107
- data/lib/capybara/spec/session/has_link_spec.rb +13 -12
- data/lib/capybara/spec/session/has_none_selectors_spec.rb +78 -0
- data/lib/capybara/spec/session/has_select_spec.rb +191 -95
- data/lib/capybara/spec/session/has_selector_spec.rb +128 -64
- data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
- data/lib/capybara/spec/session/has_table_spec.rb +172 -5
- data/lib/capybara/spec/session/has_text_spec.rb +126 -60
- data/lib/capybara/spec/session/has_title_spec.rb +35 -12
- data/lib/capybara/spec/session/has_xpath_spec.rb +74 -53
- data/lib/capybara/spec/session/{headers.rb → headers_spec.rb} +3 -2
- data/lib/capybara/spec/session/html_spec.rb +14 -6
- data/lib/capybara/spec/session/matches_style_spec.rb +35 -0
- data/lib/capybara/spec/session/node_spec.rb +1028 -131
- data/lib/capybara/spec/session/node_wrapper_spec.rb +39 -0
- data/lib/capybara/spec/session/refresh_spec.rb +34 -0
- data/lib/capybara/spec/session/reset_session_spec.rb +75 -34
- data/lib/capybara/spec/session/{response_code.rb → response_code_spec.rb} +2 -1
- data/lib/capybara/spec/session/save_and_open_page_spec.rb +3 -2
- data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +11 -15
- data/lib/capybara/spec/session/save_page_spec.rb +42 -55
- data/lib/capybara/spec/session/save_screenshot_spec.rb +16 -14
- data/lib/capybara/spec/session/screenshot_spec.rb +2 -2
- data/lib/capybara/spec/session/scroll_spec.rb +117 -0
- data/lib/capybara/spec/session/select_spec.rb +112 -85
- data/lib/capybara/spec/session/selectors_spec.rb +71 -8
- data/lib/capybara/spec/session/sibling_spec.rb +52 -0
- data/lib/capybara/spec/session/text_spec.rb +38 -23
- data/lib/capybara/spec/session/title_spec.rb +17 -5
- data/lib/capybara/spec/session/uncheck_spec.rb +71 -12
- data/lib/capybara/spec/session/unselect_spec.rb +44 -43
- data/lib/capybara/spec/session/visit_spec.rb +99 -32
- data/lib/capybara/spec/session/window/become_closed_spec.rb +33 -29
- data/lib/capybara/spec/session/window/current_window_spec.rb +5 -3
- data/lib/capybara/spec/session/window/open_new_window_spec.rb +5 -3
- data/lib/capybara/spec/session/window/switch_to_window_spec.rb +39 -30
- data/lib/capybara/spec/session/window/window_opened_by_spec.rb +17 -10
- data/lib/capybara/spec/session/window/window_spec.rb +121 -73
- data/lib/capybara/spec/session/window/windows_spec.rb +12 -10
- data/lib/capybara/spec/session/window/within_window_spec.rb +52 -82
- data/lib/capybara/spec/session/within_spec.rb +76 -43
- data/lib/capybara/spec/spec_helper.rb +67 -33
- data/lib/capybara/spec/test_app.rb +85 -36
- data/lib/capybara/spec/views/animated.erb +49 -0
- data/lib/capybara/spec/views/buttons.erb +1 -1
- data/lib/capybara/spec/views/fieldsets.erb +1 -1
- data/lib/capybara/spec/views/form.erb +227 -20
- data/lib/capybara/spec/views/frame_child.erb +10 -2
- data/lib/capybara/spec/views/frame_one.erb +2 -1
- data/lib/capybara/spec/views/frame_parent.erb +2 -2
- data/lib/capybara/spec/views/frame_two.erb +1 -1
- data/lib/capybara/spec/views/header_links.erb +1 -1
- data/lib/capybara/spec/views/host_links.erb +1 -1
- data/lib/capybara/spec/views/initial_alert.erb +10 -0
- data/lib/capybara/spec/views/obscured.erb +47 -0
- data/lib/capybara/spec/views/offset.erb +32 -0
- data/lib/capybara/spec/views/path.erb +1 -1
- data/lib/capybara/spec/views/popup_one.erb +1 -1
- data/lib/capybara/spec/views/popup_two.erb +1 -1
- data/lib/capybara/spec/views/postback.erb +1 -1
- data/lib/capybara/spec/views/react.erb +45 -0
- data/lib/capybara/spec/views/scroll.erb +20 -0
- data/lib/capybara/spec/views/spatial.erb +31 -0
- data/lib/capybara/spec/views/tables.erb +69 -2
- data/lib/capybara/spec/views/with_animation.erb +82 -0
- data/lib/capybara/spec/views/with_base_tag.erb +1 -1
- data/lib/capybara/spec/views/with_count.erb +1 -1
- data/lib/capybara/spec/views/with_dragula.erb +24 -0
- data/lib/capybara/spec/views/with_fixed_header_footer.erb +17 -0
- data/lib/capybara/spec/views/with_hover.erb +7 -1
- data/lib/capybara/spec/views/with_hover1.erb +10 -0
- data/lib/capybara/spec/views/with_html.erb +100 -10
- data/lib/capybara/spec/views/with_html5_svg.erb +20 -0
- data/lib/capybara/spec/views/with_html_entities.erb +1 -1
- data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
- data/lib/capybara/spec/views/with_js.erb +49 -3
- data/lib/capybara/spec/views/with_jstree.erb +26 -0
- data/lib/capybara/spec/views/with_namespace.erb +20 -0
- data/lib/capybara/spec/views/with_scope.erb +1 -1
- data/lib/capybara/spec/views/with_scope_other.erb +6 -0
- data/lib/capybara/spec/views/with_simple_html.erb +1 -1
- data/lib/capybara/spec/views/with_sortable_js.erb +21 -0
- data/lib/capybara/spec/views/with_title.erb +1 -1
- data/lib/capybara/spec/views/with_unload_alert.erb +3 -1
- data/lib/capybara/spec/views/with_windows.erb +7 -1
- data/lib/capybara/spec/views/within_frames.erb +6 -3
- data/lib/capybara/version.rb +2 -1
- data/lib/capybara/window.rb +39 -21
- data/lib/capybara.rb +208 -186
- data/spec/basic_node_spec.rb +52 -39
- data/spec/capybara_spec.rb +72 -50
- data/spec/css_builder_spec.rb +101 -0
- data/spec/css_splitter_spec.rb +38 -0
- data/spec/dsl_spec.rb +81 -61
- data/spec/filter_set_spec.rb +46 -0
- data/spec/fixtures/capybara.csv +1 -0
- data/spec/fixtures/certificate.pem +25 -0
- data/spec/fixtures/key.pem +27 -0
- data/spec/fixtures/selenium_driver_rspec_failure.rb +7 -3
- data/spec/fixtures/selenium_driver_rspec_success.rb +7 -3
- data/spec/minitest_spec.rb +164 -0
- data/spec/minitest_spec_spec.rb +162 -0
- data/spec/per_session_config_spec.rb +68 -0
- data/spec/rack_test_spec.rb +189 -96
- data/spec/regexp_dissassembler_spec.rb +250 -0
- data/spec/result_spec.rb +143 -13
- data/spec/rspec/features_spec.rb +38 -32
- data/spec/rspec/scenarios_spec.rb +9 -7
- data/spec/rspec/shared_spec_matchers.rb +959 -0
- data/spec/rspec/views_spec.rb +9 -3
- data/spec/rspec_matchers_spec.rb +62 -0
- data/spec/rspec_spec.rb +127 -30
- data/spec/sauce_spec_chrome.rb +43 -0
- data/spec/selector_spec.rb +458 -37
- data/spec/selenium_spec_chrome.rb +196 -9
- data/spec/selenium_spec_chrome_remote.rb +100 -0
- data/spec/selenium_spec_edge.rb +47 -0
- data/spec/selenium_spec_firefox.rb +210 -0
- data/spec/selenium_spec_firefox_remote.rb +80 -0
- data/spec/selenium_spec_ie.rb +150 -0
- data/spec/selenium_spec_safari.rb +148 -0
- data/spec/server_spec.rb +200 -101
- data/spec/session_spec.rb +91 -0
- data/spec/shared_selenium_node.rb +83 -0
- data/spec/shared_selenium_session.rb +558 -0
- data/spec/spec_helper.rb +94 -2
- data/spec/xpath_builder_spec.rb +93 -0
- metadata +420 -60
- data/lib/capybara/query.rb +0 -7
- data/lib/capybara/spec/session/assert_current_path.rb +0 -60
- data/lib/capybara/spec/session/assert_selector.rb +0 -148
- data/lib/capybara/spec/session/assert_text.rb +0 -196
- data/lib/capybara/spec/session/assert_title.rb +0 -70
- data/lib/capybara/spec/session/source_spec.rb +0 -0
- data/lib/capybara/spec/session/within_frame_spec.rb +0 -53
- data/spec/rspec/matchers_spec.rb +0 -827
- data/spec/selenium_spec.rb +0 -151
@@ -1,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
|