capybara 3.0.0 → 3.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.yardopts +1 -1
- data/History.md +777 -10
- data/License.txt +1 -1
- data/README.md +75 -58
- data/lib/capybara/config.rb +29 -10
- data/lib/capybara/cucumber.rb +1 -1
- data/lib/capybara/driver/base.rb +22 -4
- data/lib/capybara/driver/node.rb +34 -9
- data/lib/capybara/dsl.rb +14 -6
- data/lib/capybara/helpers.rb +52 -7
- data/lib/capybara/minitest/spec.rb +173 -84
- data/lib/capybara/minitest.rb +250 -144
- data/lib/capybara/node/actions.rb +248 -124
- data/lib/capybara/node/base.rb +34 -20
- data/lib/capybara/node/document.rb +14 -2
- data/lib/capybara/node/document_matchers.rb +13 -15
- data/lib/capybara/node/element.rb +339 -113
- data/lib/capybara/node/finders.rb +95 -82
- data/lib/capybara/node/matchers.rb +338 -157
- data/lib/capybara/node/simple.rb +54 -15
- data/lib/capybara/queries/active_element_query.rb +18 -0
- data/lib/capybara/queries/ancestor_query.rb +9 -10
- data/lib/capybara/queries/base_query.rb +25 -18
- data/lib/capybara/queries/current_path_query.rb +16 -6
- data/lib/capybara/queries/match_query.rb +11 -0
- data/lib/capybara/queries/selector_query.rb +600 -103
- data/lib/capybara/queries/sibling_query.rb +9 -7
- data/lib/capybara/queries/style_query.rb +45 -0
- data/lib/capybara/queries/text_query.rb +40 -22
- data/lib/capybara/queries/title_query.rb +2 -2
- data/lib/capybara/rack_test/browser.rb +47 -28
- data/lib/capybara/rack_test/driver.rb +12 -3
- data/lib/capybara/rack_test/errors.rb +6 -0
- data/lib/capybara/rack_test/form.rb +53 -50
- data/lib/capybara/rack_test/node.rb +114 -37
- data/lib/capybara/rails.rb +1 -1
- 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 +86 -52
- data/lib/capybara/rspec/features.rb +8 -10
- data/lib/capybara/rspec/matcher_proxies.rb +39 -18
- 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 +138 -316
- data/lib/capybara/rspec.rb +3 -2
- 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 +89 -12
- data/lib/capybara/selector/definition/button.rb +68 -0
- data/lib/capybara/selector/definition/checkbox.rb +26 -0
- data/lib/capybara/selector/definition/css.rb +10 -0
- data/lib/capybara/selector/definition/datalist_input.rb +35 -0
- data/lib/capybara/selector/definition/datalist_option.rb +25 -0
- data/lib/capybara/selector/definition/element.rb +28 -0
- data/lib/capybara/selector/definition/field.rb +40 -0
- data/lib/capybara/selector/definition/fieldset.rb +14 -0
- data/lib/capybara/selector/definition/file_field.rb +13 -0
- data/lib/capybara/selector/definition/fillable_field.rb +33 -0
- data/lib/capybara/selector/definition/frame.rb +17 -0
- data/lib/capybara/selector/definition/id.rb +6 -0
- data/lib/capybara/selector/definition/label.rb +62 -0
- data/lib/capybara/selector/definition/link.rb +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 +279 -0
- data/lib/capybara/selector/filter.rb +1 -0
- data/lib/capybara/selector/filter_set.rb +72 -27
- data/lib/capybara/selector/filters/base.rb +45 -2
- data/lib/capybara/selector/filters/expression_filter.rb +5 -6
- data/lib/capybara/selector/filters/locator_filter.rb +29 -0
- data/lib/capybara/selector/filters/node_filter.rb +18 -4
- data/lib/capybara/selector/regexp_disassembler.rb +214 -0
- data/lib/capybara/selector/selector.rb +85 -200
- data/lib/capybara/selector/xpath_extensions.rb +17 -0
- data/lib/capybara/selector.rb +226 -537
- 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 +296 -238
- 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 +436 -166
- 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 +69 -0
- data/lib/capybara/server/checker.rb +44 -0
- data/lib/capybara/server/middleware.rb +71 -0
- data/lib/capybara/server.rb +58 -67
- data/lib/capybara/session/config.rb +38 -6
- data/lib/capybara/session/matchers.rb +26 -19
- data/lib/capybara/session.rb +258 -190
- 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 +122 -8
- data/lib/capybara/spec/session/accept_alert_spec.rb +11 -11
- data/lib/capybara/spec/session/accept_confirm_spec.rb +3 -3
- data/lib/capybara/spec/session/accept_prompt_spec.rb +9 -10
- data/lib/capybara/spec/session/active_element_spec.rb +31 -0
- data/lib/capybara/spec/session/all_spec.rb +135 -42
- data/lib/capybara/spec/session/ancestor_spec.rb +24 -19
- data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +67 -38
- data/lib/capybara/spec/session/{assert_current_path.rb → assert_current_path_spec.rb} +20 -18
- 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.rb → assert_text_spec.rb} +62 -38
- data/lib/capybara/spec/session/{assert_title.rb → assert_title_spec.rb} +12 -12
- data/lib/capybara/spec/session/attach_file_spec.rb +120 -72
- data/lib/capybara/spec/session/body_spec.rb +11 -13
- data/lib/capybara/spec/session/check_spec.rb +111 -51
- data/lib/capybara/spec/session/choose_spec.rb +62 -30
- data/lib/capybara/spec/session/click_button_spec.rb +227 -161
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +49 -30
- data/lib/capybara/spec/session/click_link_spec.rb +78 -55
- data/lib/capybara/spec/session/current_scope_spec.rb +7 -7
- data/lib/capybara/spec/session/current_url_spec.rb +44 -37
- data/lib/capybara/spec/session/dismiss_confirm_spec.rb +3 -3
- data/lib/capybara/spec/session/dismiss_prompt_spec.rb +2 -2
- data/lib/capybara/spec/session/element/{assert_match_selector.rb → assert_match_selector_spec.rb} +11 -9
- data/lib/capybara/spec/session/element/match_css_spec.rb +18 -10
- data/lib/capybara/spec/session/element/match_xpath_spec.rb +8 -6
- data/lib/capybara/spec/session/element/matches_selector_spec.rb +70 -56
- data/lib/capybara/spec/session/evaluate_async_script_spec.rb +7 -7
- data/lib/capybara/spec/session/evaluate_script_spec.rb +28 -8
- data/lib/capybara/spec/session/execute_script_spec.rb +8 -7
- data/lib/capybara/spec/session/fill_in_spec.rb +104 -44
- data/lib/capybara/spec/session/find_button_spec.rb +23 -23
- data/lib/capybara/spec/session/find_by_id_spec.rb +8 -8
- data/lib/capybara/spec/session/find_field_spec.rb +33 -31
- data/lib/capybara/spec/session/find_link_spec.rb +32 -14
- data/lib/capybara/spec/session/find_spec.rb +236 -141
- data/lib/capybara/spec/session/first_spec.rb +44 -43
- data/lib/capybara/spec/session/frame/frame_title_spec.rb +6 -6
- data/lib/capybara/spec/session/frame/frame_url_spec.rb +6 -6
- data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +32 -20
- data/lib/capybara/spec/session/frame/within_frame_spec.rb +44 -19
- data/lib/capybara/spec/session/go_back_spec.rb +1 -1
- data/lib/capybara/spec/session/go_forward_spec.rb +1 -1
- data/lib/capybara/spec/session/has_all_selectors_spec.rb +18 -18
- data/lib/capybara/spec/session/has_ancestor_spec.rb +46 -0
- data/lib/capybara/spec/session/has_any_selectors_spec.rb +29 -0
- data/lib/capybara/spec/session/has_button_spec.rb +92 -12
- data/lib/capybara/spec/session/has_css_spec.rb +271 -137
- data/lib/capybara/spec/session/has_current_path_spec.rb +48 -33
- data/lib/capybara/spec/session/has_field_spec.rb +137 -58
- data/lib/capybara/spec/session/has_link_spec.rb +30 -6
- data/lib/capybara/spec/session/has_none_selectors_spec.rb +26 -24
- data/lib/capybara/spec/session/has_select_spec.rb +75 -47
- data/lib/capybara/spec/session/has_selector_spec.rb +102 -69
- data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
- data/lib/capybara/spec/session/has_table_spec.rb +170 -4
- data/lib/capybara/spec/session/has_text_spec.rb +108 -52
- data/lib/capybara/spec/session/has_title_spec.rb +19 -14
- data/lib/capybara/spec/session/has_xpath_spec.rb +56 -38
- data/lib/capybara/spec/session/{headers.rb → headers_spec.rb} +1 -1
- data/lib/capybara/spec/session/html_spec.rb +13 -6
- data/lib/capybara/spec/session/matches_style_spec.rb +35 -0
- data/lib/capybara/spec/session/node_spec.rb +871 -122
- data/lib/capybara/spec/session/node_wrapper_spec.rb +15 -12
- data/lib/capybara/spec/session/refresh_spec.rb +9 -7
- data/lib/capybara/spec/session/reset_session_spec.rb +52 -37
- data/lib/capybara/spec/session/{response_code.rb → response_code_spec.rb} +1 -1
- data/lib/capybara/spec/session/save_and_open_page_spec.rb +2 -2
- data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +5 -4
- data/lib/capybara/spec/session/save_page_spec.rb +41 -38
- data/lib/capybara/spec/session/save_screenshot_spec.rb +13 -11
- 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 +102 -76
- data/lib/capybara/spec/session/selectors_spec.rb +51 -18
- data/lib/capybara/spec/session/sibling_spec.rb +9 -9
- data/lib/capybara/spec/session/text_spec.rb +26 -24
- data/lib/capybara/spec/session/title_spec.rb +8 -6
- data/lib/capybara/spec/session/uncheck_spec.rb +40 -21
- data/lib/capybara/spec/session/unselect_spec.rb +37 -37
- data/lib/capybara/spec/session/visit_spec.rb +59 -53
- data/lib/capybara/spec/session/window/become_closed_spec.rb +22 -19
- data/lib/capybara/spec/session/window/current_window_spec.rb +4 -3
- data/lib/capybara/spec/session/window/open_new_window_spec.rb +4 -3
- data/lib/capybara/spec/session/window/switch_to_window_spec.rb +25 -21
- data/lib/capybara/spec/session/window/window_opened_by_spec.rb +10 -5
- data/lib/capybara/spec/session/window/window_spec.rb +88 -54
- data/lib/capybara/spec/session/window/windows_spec.rb +10 -7
- data/lib/capybara/spec/session/window/within_window_spec.rb +17 -16
- data/lib/capybara/spec/session/within_spec.rb +69 -44
- data/lib/capybara/spec/spec_helper.rb +41 -53
- data/lib/capybara/spec/test_app.rb +79 -40
- data/lib/capybara/spec/views/animated.erb +49 -0
- data/lib/capybara/spec/views/form.erb +134 -42
- data/lib/capybara/spec/views/frame_child.erb +4 -3
- data/lib/capybara/spec/views/frame_one.erb +2 -1
- data/lib/capybara/spec/views/frame_parent.erb +1 -1
- data/lib/capybara/spec/views/frame_two.erb +1 -1
- data/lib/capybara/spec/views/initial_alert.erb +2 -1
- data/lib/capybara/spec/views/layout.erb +10 -0
- data/lib/capybara/spec/views/obscured.erb +47 -0
- data/lib/capybara/spec/views/offset.erb +33 -0
- data/lib/capybara/spec/views/path.erb +2 -2
- data/lib/capybara/spec/views/popup_one.erb +1 -1
- data/lib/capybara/spec/views/popup_two.erb +1 -1
- data/lib/capybara/spec/views/react.erb +45 -0
- data/lib/capybara/spec/views/scroll.erb +21 -0
- data/lib/capybara/spec/views/spatial.erb +31 -0
- data/lib/capybara/spec/views/tables.erb +68 -1
- data/lib/capybara/spec/views/with_animation.erb +81 -0
- data/lib/capybara/spec/views/with_base_tag.erb +2 -2
- data/lib/capybara/spec/views/with_dragula.erb +24 -0
- data/lib/capybara/spec/views/with_fixed_header_footer.erb +2 -1
- data/lib/capybara/spec/views/with_hover.erb +3 -2
- data/lib/capybara/spec/views/with_hover1.erb +10 -0
- data/lib/capybara/spec/views/with_html.erb +43 -10
- data/lib/capybara/spec/views/with_html5_svg.erb +20 -0
- data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
- data/lib/capybara/spec/views/with_js.erb +30 -5
- data/lib/capybara/spec/views/with_jstree.erb +26 -0
- data/lib/capybara/spec/views/with_namespace.erb +21 -0
- data/lib/capybara/spec/views/with_scope_other.erb +6 -0
- data/lib/capybara/spec/views/with_slow_unload.erb +2 -1
- data/lib/capybara/spec/views/with_sortable_js.erb +21 -0
- data/lib/capybara/spec/views/with_unload_alert.erb +1 -0
- data/lib/capybara/spec/views/with_windows.erb +1 -1
- data/lib/capybara/spec/views/within_frames.erb +1 -1
- data/lib/capybara/version.rb +1 -1
- data/lib/capybara/window.rb +31 -25
- data/lib/capybara.rb +120 -100
- data/spec/basic_node_spec.rb +59 -34
- data/spec/capybara_spec.rb +54 -52
- data/spec/css_builder_spec.rb +101 -0
- data/spec/css_splitter_spec.rb +38 -0
- data/spec/dsl_spec.rb +80 -53
- data/spec/filter_set_spec.rb +24 -7
- data/spec/fixtures/certificate.pem +25 -0
- data/spec/fixtures/key.pem +27 -0
- data/spec/fixtures/selenium_driver_rspec_failure.rb +4 -4
- data/spec/fixtures/selenium_driver_rspec_success.rb +4 -4
- data/spec/minitest_spec.rb +38 -5
- data/spec/minitest_spec_spec.rb +88 -62
- data/spec/per_session_config_spec.rb +5 -5
- data/spec/rack_test_spec.rb +169 -115
- data/spec/regexp_dissassembler_spec.rb +250 -0
- data/spec/result_spec.rb +86 -33
- data/spec/rspec/features_spec.rb +26 -23
- data/spec/rspec/scenarios_spec.rb +8 -4
- data/spec/rspec/shared_spec_matchers.rb +393 -363
- data/spec/rspec/views_spec.rb +4 -3
- data/spec/rspec_matchers_spec.rb +10 -10
- data/spec/rspec_spec.rb +109 -85
- data/spec/sauce_spec_chrome.rb +43 -0
- data/spec/selector_spec.rb +391 -61
- data/spec/selenium_spec_chrome.rb +180 -41
- data/spec/selenium_spec_chrome_remote.rb +101 -0
- data/spec/selenium_spec_edge.rb +28 -8
- data/spec/selenium_spec_firefox.rb +211 -0
- data/spec/selenium_spec_firefox_remote.rb +80 -0
- data/spec/selenium_spec_ie.rb +127 -11
- data/spec/selenium_spec_safari.rb +156 -0
- data/spec/server_spec.rb +177 -78
- data/spec/session_spec.rb +52 -16
- data/spec/shared_selenium_node.rb +79 -0
- data/spec/shared_selenium_session.rb +455 -123
- data/spec/spec_helper.rb +91 -2
- data/spec/xpath_builder_spec.rb +93 -0
- metadata +343 -42
- data/.yard/templates_custom/default/class/html/selectors.erb +0 -38
- data/.yard/templates_custom/default/class/html/setup.rb +0 -17
- data/.yard/yard_extensions.rb +0 -78
- data/lib/capybara/rspec/compound.rb +0 -90
- data/lib/capybara/spec/session/assert_selector.rb +0 -149
- data/lib/capybara/spec/session/source_spec.rb +0 -0
- data/lib/capybara/spec/views/with_title.erb +0 -5
- data/spec/selenium_spec_marionette.rb +0 -143
|
@@ -19,41 +19,58 @@ module Capybara
|
|
|
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
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, &optional_filter_block)
|
|
40
|
-
assert_selector(*args, &optional_filter_block)
|
|
41
|
-
rescue Capybara::ExpectationNotMet
|
|
42
|
-
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
44
|
# Checks if a given selector is not on the page or a descendant of the current node.
|
|
48
|
-
# Usage is identical to
|
|
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, &optional_filter_block)
|
|
54
|
-
assert_no_selector(*args, &optional_filter_block)
|
|
55
|
-
|
|
56
|
-
|
|
50
|
+
def has_no_selector?(*args, **options, &optional_filter_block)
|
|
51
|
+
make_predicate(options) { assert_no_selector(*args, options, &optional_filter_block) }
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
##
|
|
55
|
+
#
|
|
56
|
+
# Checks if a an element has the specified CSS styles.
|
|
57
|
+
#
|
|
58
|
+
# element.matches_style?( 'color' => 'rgb(0,0,255)', 'font-size' => /px/ )
|
|
59
|
+
#
|
|
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) }
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
##
|
|
69
|
+
# @deprecated Use {#matches_style?} instead.
|
|
70
|
+
#
|
|
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)
|
|
57
74
|
end
|
|
58
75
|
|
|
59
76
|
##
|
|
@@ -72,15 +89,15 @@ module Capybara
|
|
|
72
89
|
# This will check if the expression occurs exactly 4 times. See
|
|
73
90
|
# {Capybara::Node::Finders#all} for other available result size options.
|
|
74
91
|
#
|
|
75
|
-
# If a
|
|
92
|
+
# If a `:count` of 0 is specified, it will behave like {#assert_no_selector};
|
|
76
93
|
# however, use of that method is preferred over this one.
|
|
77
94
|
#
|
|
78
95
|
# It also accepts all options that {Capybara::Node::Finders#all} accepts,
|
|
79
|
-
# such as
|
|
96
|
+
# such as `:text` and `:visible`.
|
|
80
97
|
#
|
|
81
98
|
# page.assert_selector('li', text: 'Horse', visible: true)
|
|
82
99
|
#
|
|
83
|
-
#
|
|
100
|
+
# {#assert_selector} can also accept XPath expressions generated by the
|
|
84
101
|
# XPath gem:
|
|
85
102
|
#
|
|
86
103
|
# page.assert_selector(:xpath, XPath.descendant(:p))
|
|
@@ -91,76 +108,126 @@ module Capybara
|
|
|
91
108
|
#
|
|
92
109
|
def assert_selector(*args, &optional_filter_block)
|
|
93
110
|
_verify_selector_result(args, optional_filter_block) do |result, query|
|
|
94
|
-
unless result.matches_count? && (
|
|
111
|
+
unless result.matches_count? && (result.any? || query.expects_none?)
|
|
95
112
|
raise Capybara::ExpectationNotMet, result.failure_message
|
|
96
113
|
end
|
|
97
114
|
end
|
|
98
115
|
end
|
|
99
116
|
|
|
117
|
+
##
|
|
118
|
+
#
|
|
119
|
+
# Asserts that an element has the specified CSS styles.
|
|
120
|
+
#
|
|
121
|
+
# element.assert_matches_style( 'color' => 'rgb(0,0,255)', 'font-size' => /px/ )
|
|
122
|
+
#
|
|
123
|
+
# @param styles [Hash]
|
|
124
|
+
# @raise [Capybara::ExpectationNotMet] If the element doesn't have the specified styles
|
|
125
|
+
#
|
|
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)
|
|
130
|
+
synchronize(query.wait) do
|
|
131
|
+
raise Capybara::ExpectationNotMet, query.failure_message unless query.resolves_for?(self)
|
|
132
|
+
end
|
|
133
|
+
true
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
##
|
|
137
|
+
# @deprecated Use {#assert_matches_style} instead.
|
|
138
|
+
#
|
|
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
|
+
|
|
100
144
|
# Asserts that all of the provided selectors are present on the given page
|
|
101
145
|
# or descendants of the current node. If options are provided, the assertion
|
|
102
|
-
# will check that each locator is present with those options as well (other than
|
|
146
|
+
# will check that each locator is present with those options as well (other than `:wait`).
|
|
103
147
|
#
|
|
104
|
-
#
|
|
105
|
-
#
|
|
148
|
+
# page.assert_all_of_selectors(:custom, 'Tom', 'Joe', visible: all)
|
|
149
|
+
# page.assert_all_of_selectors(:css, '#my_div', 'a.not_clicked')
|
|
106
150
|
#
|
|
107
151
|
# It accepts all options that {Capybara::Node::Finders#all} accepts,
|
|
108
|
-
# such as
|
|
152
|
+
# such as `:text` and `:visible`.
|
|
109
153
|
#
|
|
110
|
-
# The
|
|
111
|
-
# within
|
|
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.
|
|
112
156
|
#
|
|
113
|
-
# @overload assert_all_of_selectors([kind = Capybara.default_selector], *locators, options
|
|
157
|
+
# @overload assert_all_of_selectors([kind = Capybara.default_selector], *locators, **options)
|
|
114
158
|
#
|
|
115
|
-
def assert_all_of_selectors(*args,
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
synchronize(wait) do
|
|
119
|
-
args.each do |locator|
|
|
120
|
-
assert_selector(selector, locator, options, &optional_filter_block)
|
|
121
|
-
end
|
|
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)
|
|
122
162
|
end
|
|
123
163
|
end
|
|
124
164
|
|
|
125
165
|
# Asserts that none of the provided selectors are present on the given page
|
|
126
166
|
# or descendants of the current node. If options are provided, the assertion
|
|
127
|
-
# will check that each locator is present with those options as well (other than
|
|
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`).
|
|
128
189
|
#
|
|
129
|
-
#
|
|
130
|
-
#
|
|
190
|
+
# page.assert_any_of_selectors(:custom, 'Tom', 'Joe', visible: all)
|
|
191
|
+
# page.assert_any_of_selectors(:css, '#my_div', 'a.not_clicked')
|
|
131
192
|
#
|
|
132
193
|
# It accepts all options that {Capybara::Node::Finders#all} accepts,
|
|
133
|
-
# such as
|
|
194
|
+
# such as `:text` and `:visible`.
|
|
134
195
|
#
|
|
135
|
-
# The
|
|
136
|
-
# within
|
|
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.
|
|
137
198
|
#
|
|
138
|
-
# @overload
|
|
199
|
+
# @overload assert_any_of_selectors([kind = Capybara.default_selector], *locators, **options)
|
|
139
200
|
#
|
|
140
|
-
def
|
|
201
|
+
def assert_any_of_selectors(*args, wait: nil, **options, &optional_filter_block)
|
|
141
202
|
wait = session_options.default_max_wait_time if wait.nil?
|
|
142
|
-
selector = args
|
|
203
|
+
selector = extract_selector(args)
|
|
143
204
|
synchronize(wait) do
|
|
144
|
-
args.
|
|
145
|
-
|
|
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
|
|
146
210
|
end
|
|
211
|
+
raise Capybara::ExpectationNotMet, res.join(' or ') if res
|
|
212
|
+
|
|
213
|
+
true
|
|
147
214
|
end
|
|
148
215
|
end
|
|
149
216
|
|
|
150
217
|
##
|
|
151
218
|
#
|
|
152
219
|
# Asserts that a given selector is not on the page or a descendant of the current node.
|
|
153
|
-
# Usage is identical to
|
|
220
|
+
# Usage is identical to {#assert_selector}.
|
|
154
221
|
#
|
|
155
|
-
# Query options such as
|
|
222
|
+
# Query options such as `:count`, `:minimum`, `:maximum`, and `:between` are
|
|
156
223
|
# considered to be an integral part of the selector. This will return
|
|
157
|
-
# true
|
|
224
|
+
# `true`, for example, if a page contains 4 anchors but the query expects 5:
|
|
158
225
|
#
|
|
159
226
|
# page.assert_no_selector('a', minimum: 1) # Found, raises Capybara::ExpectationNotMet
|
|
160
227
|
# page.assert_no_selector('a', count: 4) # Found, raises Capybara::ExpectationNotMet
|
|
161
228
|
# page.assert_no_selector('a', count: 5) # Not Found, returns true
|
|
162
229
|
#
|
|
163
|
-
# @param (see
|
|
230
|
+
# @param (see #assert_selector)
|
|
164
231
|
# @raise [Capybara::ExpectationNotMet] If the selector exists
|
|
165
232
|
#
|
|
166
233
|
def assert_no_selector(*args, &optional_filter_block)
|
|
@@ -170,7 +237,6 @@ module Capybara
|
|
|
170
237
|
end
|
|
171
238
|
end
|
|
172
239
|
end
|
|
173
|
-
alias_method :refute_selector, :assert_no_selector
|
|
174
240
|
|
|
175
241
|
##
|
|
176
242
|
#
|
|
@@ -186,11 +252,11 @@ module Capybara
|
|
|
186
252
|
# This will check if the expression occurs exactly 4 times.
|
|
187
253
|
#
|
|
188
254
|
# It also accepts all options that {Capybara::Node::Finders#all} accepts,
|
|
189
|
-
# such as
|
|
255
|
+
# such as `:text` and `:visible`.
|
|
190
256
|
#
|
|
191
257
|
# page.has_xpath?('.//li', text: 'Horse', visible: true)
|
|
192
258
|
#
|
|
193
|
-
# has_xpath? can also accept XPath expressions
|
|
259
|
+
# {#has_xpath?} can also accept XPath expressions generated by the
|
|
194
260
|
# XPath gem:
|
|
195
261
|
#
|
|
196
262
|
# xpath = XPath.generate { |x| x.descendant(:p) }
|
|
@@ -202,19 +268,19 @@ module Capybara
|
|
|
202
268
|
# @return [Boolean] If the expression exists
|
|
203
269
|
#
|
|
204
270
|
def has_xpath?(path, **options, &optional_filter_block)
|
|
205
|
-
has_selector?(:xpath, path, options, &optional_filter_block)
|
|
271
|
+
has_selector?(:xpath, path, **options, &optional_filter_block)
|
|
206
272
|
end
|
|
207
273
|
|
|
208
274
|
##
|
|
209
275
|
#
|
|
210
276
|
# Checks if a given XPath expression is not on the page or a descendant of the current node.
|
|
211
|
-
# Usage is identical to
|
|
277
|
+
# Usage is identical to {#has_xpath?}.
|
|
212
278
|
#
|
|
213
|
-
# @param (see
|
|
279
|
+
# @param (see #has_xpath?)
|
|
214
280
|
# @return [Boolean]
|
|
215
281
|
#
|
|
216
282
|
def has_no_xpath?(path, **options, &optional_filter_block)
|
|
217
|
-
has_no_selector?(:xpath, path, options, &optional_filter_block)
|
|
283
|
+
has_no_selector?(:xpath, path, **options, &optional_filter_block)
|
|
218
284
|
end
|
|
219
285
|
|
|
220
286
|
##
|
|
@@ -231,7 +297,7 @@ module Capybara
|
|
|
231
297
|
# This will check if the selector occurs exactly 4 times.
|
|
232
298
|
#
|
|
233
299
|
# It also accepts all options that {Capybara::Node::Finders#all} accepts,
|
|
234
|
-
# such as
|
|
300
|
+
# such as `:text` and `:visible`.
|
|
235
301
|
#
|
|
236
302
|
# page.has_css?('li', text: 'Horse', visible: true)
|
|
237
303
|
#
|
|
@@ -241,19 +307,19 @@ module Capybara
|
|
|
241
307
|
# @return [Boolean] If the selector exists
|
|
242
308
|
#
|
|
243
309
|
def has_css?(path, **options, &optional_filter_block)
|
|
244
|
-
has_selector?(:css, path, options, &optional_filter_block)
|
|
310
|
+
has_selector?(:css, path, **options, &optional_filter_block)
|
|
245
311
|
end
|
|
246
312
|
|
|
247
313
|
##
|
|
248
314
|
#
|
|
249
315
|
# Checks if a given CSS selector is not on the page or a descendant of the current node.
|
|
250
|
-
# Usage is identical to
|
|
316
|
+
# Usage is identical to {#has_css?}.
|
|
251
317
|
#
|
|
252
|
-
# @param (see
|
|
318
|
+
# @param (see #has_css?)
|
|
253
319
|
# @return [Boolean]
|
|
254
320
|
#
|
|
255
321
|
def has_no_css?(path, **options, &optional_filter_block)
|
|
256
|
-
has_no_selector?(:css, path, options, &optional_filter_block)
|
|
322
|
+
has_no_selector?(:css, path, **options, &optional_filter_block)
|
|
257
323
|
end
|
|
258
324
|
|
|
259
325
|
##
|
|
@@ -262,12 +328,11 @@ module Capybara
|
|
|
262
328
|
# text or id.
|
|
263
329
|
#
|
|
264
330
|
# @param [String] locator The text or id of a link to check for
|
|
265
|
-
# @param options
|
|
266
331
|
# @option options [String, Regexp] :href The value the href attribute must be
|
|
267
332
|
# @return [Boolean] Whether it exists
|
|
268
333
|
#
|
|
269
334
|
def has_link?(locator = nil, **options, &optional_filter_block)
|
|
270
|
-
has_selector?(:link, locator, options, &optional_filter_block)
|
|
335
|
+
has_selector?(:link, locator, **options, &optional_filter_block)
|
|
271
336
|
end
|
|
272
337
|
|
|
273
338
|
##
|
|
@@ -275,11 +340,11 @@ module Capybara
|
|
|
275
340
|
# Checks if the page or current node has no link with the given
|
|
276
341
|
# text or id.
|
|
277
342
|
#
|
|
278
|
-
# @param (see
|
|
343
|
+
# @param (see #has_link?)
|
|
279
344
|
# @return [Boolean] Whether it doesn't exist
|
|
280
345
|
#
|
|
281
346
|
def has_no_link?(locator = nil, **options, &optional_filter_block)
|
|
282
|
-
has_no_selector?(:link, locator, options, &optional_filter_block)
|
|
347
|
+
has_no_selector?(:link, locator, **options, &optional_filter_block)
|
|
283
348
|
end
|
|
284
349
|
|
|
285
350
|
##
|
|
@@ -291,7 +356,7 @@ module Capybara
|
|
|
291
356
|
# @return [Boolean] Whether it exists
|
|
292
357
|
#
|
|
293
358
|
def has_button?(locator = nil, **options, &optional_filter_block)
|
|
294
|
-
has_selector?(:button, locator, options, &optional_filter_block)
|
|
359
|
+
has_selector?(:button, locator, **options, &optional_filter_block)
|
|
295
360
|
end
|
|
296
361
|
|
|
297
362
|
##
|
|
@@ -303,7 +368,7 @@ module Capybara
|
|
|
303
368
|
# @return [Boolean] Whether it doesn't exist
|
|
304
369
|
#
|
|
305
370
|
def has_no_button?(locator = nil, **options, &optional_filter_block)
|
|
306
|
-
has_no_selector?(:button, locator, options, &optional_filter_block)
|
|
371
|
+
has_no_selector?(:button, locator, **options, &optional_filter_block)
|
|
307
372
|
end
|
|
308
373
|
|
|
309
374
|
##
|
|
@@ -312,7 +377,7 @@ module Capybara
|
|
|
312
377
|
# label, name or id.
|
|
313
378
|
#
|
|
314
379
|
# For text fields and other textual fields, such as textareas and
|
|
315
|
-
# HTML5 email/url/etc. fields, it's possible to specify a
|
|
380
|
+
# HTML5 email/url/etc. fields, it's possible to specify a `:with`
|
|
316
381
|
# option to specify the text the field should contain:
|
|
317
382
|
#
|
|
318
383
|
# page.has_field?('Name', with: 'Jonas')
|
|
@@ -321,7 +386,7 @@ module Capybara
|
|
|
321
386
|
#
|
|
322
387
|
# page.has_field?('Email', type: 'email')
|
|
323
388
|
#
|
|
324
|
-
#
|
|
389
|
+
# NOTE: 'textarea' and 'select' are valid type values, matching the associated tag names.
|
|
325
390
|
#
|
|
326
391
|
# @param [String] locator The label, name or id of a field to check for
|
|
327
392
|
# @option options [String, Regexp] :with The text content of the field or a Regexp to match
|
|
@@ -329,13 +394,13 @@ module Capybara
|
|
|
329
394
|
# @return [Boolean] Whether it exists
|
|
330
395
|
#
|
|
331
396
|
def has_field?(locator = nil, **options, &optional_filter_block)
|
|
332
|
-
has_selector?(:field, locator, options, &optional_filter_block)
|
|
397
|
+
has_selector?(:field, locator, **options, &optional_filter_block)
|
|
333
398
|
end
|
|
334
399
|
|
|
335
400
|
##
|
|
336
401
|
#
|
|
337
402
|
# Checks if the page or current node has no form field with the given
|
|
338
|
-
# label, name or id. See {
|
|
403
|
+
# label, name or id. See {#has_field?}.
|
|
339
404
|
#
|
|
340
405
|
# @param [String] locator The label, name or id of a field to check for
|
|
341
406
|
# @option options [String, Regexp] :with The text content of the field or a Regexp to match
|
|
@@ -343,59 +408,59 @@ module Capybara
|
|
|
343
408
|
# @return [Boolean] Whether it doesn't exist
|
|
344
409
|
#
|
|
345
410
|
def has_no_field?(locator = nil, **options, &optional_filter_block)
|
|
346
|
-
has_no_selector?(:field, locator, options, &optional_filter_block)
|
|
411
|
+
has_no_selector?(:field, locator, **options, &optional_filter_block)
|
|
347
412
|
end
|
|
348
413
|
|
|
349
414
|
##
|
|
350
415
|
#
|
|
351
416
|
# Checks if the page or current node has a radio button or
|
|
352
|
-
# checkbox with the given label, value
|
|
417
|
+
# checkbox with the given label, value, id, or {Capybara.configure test_id} attribute that is currently
|
|
353
418
|
# checked.
|
|
354
419
|
#
|
|
355
420
|
# @param [String] locator The label, name or id of a checked field
|
|
356
421
|
# @return [Boolean] Whether it exists
|
|
357
422
|
#
|
|
358
423
|
def has_checked_field?(locator = nil, **options, &optional_filter_block)
|
|
359
|
-
has_selector?(:field, locator, options.merge(checked: true), &optional_filter_block)
|
|
424
|
+
has_selector?(:field, locator, **options.merge(checked: true), &optional_filter_block)
|
|
360
425
|
end
|
|
361
426
|
|
|
362
427
|
##
|
|
363
428
|
#
|
|
364
429
|
# Checks if the page or current node has no radio button or
|
|
365
|
-
# 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
|
|
366
431
|
# checked.
|
|
367
432
|
#
|
|
368
433
|
# @param [String] locator The label, name or id of a checked field
|
|
369
434
|
# @return [Boolean] Whether it doesn't exist
|
|
370
435
|
#
|
|
371
436
|
def has_no_checked_field?(locator = nil, **options, &optional_filter_block)
|
|
372
|
-
has_no_selector?(:field, locator, options.merge(checked: true), &optional_filter_block)
|
|
437
|
+
has_no_selector?(:field, locator, **options.merge(checked: true), &optional_filter_block)
|
|
373
438
|
end
|
|
374
439
|
|
|
375
440
|
##
|
|
376
441
|
#
|
|
377
442
|
# Checks if the page or current node has a radio button or
|
|
378
|
-
# 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
|
|
379
444
|
# unchecked.
|
|
380
445
|
#
|
|
381
446
|
# @param [String] locator The label, name or id of an unchecked field
|
|
382
447
|
# @return [Boolean] Whether it exists
|
|
383
448
|
#
|
|
384
449
|
def has_unchecked_field?(locator = nil, **options, &optional_filter_block)
|
|
385
|
-
has_selector?(:field, locator, options.merge(unchecked: true), &optional_filter_block)
|
|
450
|
+
has_selector?(:field, locator, **options.merge(unchecked: true), &optional_filter_block)
|
|
386
451
|
end
|
|
387
452
|
|
|
388
453
|
##
|
|
389
454
|
#
|
|
390
455
|
# Checks if the page or current node has no radio button or
|
|
391
|
-
# 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
|
|
392
457
|
# unchecked.
|
|
393
458
|
#
|
|
394
459
|
# @param [String] locator The label, name or id of an unchecked field
|
|
395
460
|
# @return [Boolean] Whether it doesn't exist
|
|
396
461
|
#
|
|
397
462
|
def has_no_unchecked_field?(locator = nil, **options, &optional_filter_block)
|
|
398
|
-
has_no_selector?(:field, locator, options.merge(unchecked: true), &optional_filter_block)
|
|
463
|
+
has_no_selector?(:field, locator, **options.merge(unchecked: true), &optional_filter_block)
|
|
399
464
|
end
|
|
400
465
|
|
|
401
466
|
##
|
|
@@ -428,19 +493,19 @@ module Capybara
|
|
|
428
493
|
# @return [Boolean] Whether it exists
|
|
429
494
|
#
|
|
430
495
|
def has_select?(locator = nil, **options, &optional_filter_block)
|
|
431
|
-
has_selector?(:select, locator, options, &optional_filter_block)
|
|
496
|
+
has_selector?(:select, locator, **options, &optional_filter_block)
|
|
432
497
|
end
|
|
433
498
|
|
|
434
499
|
##
|
|
435
500
|
#
|
|
436
501
|
# Checks if the page or current node has no select field with the
|
|
437
|
-
# given label, name or id. See {
|
|
502
|
+
# given label, name or id. See {#has_select?}.
|
|
438
503
|
#
|
|
439
|
-
# @param (see
|
|
504
|
+
# @param (see #has_select?)
|
|
440
505
|
# @return [Boolean] Whether it doesn't exist
|
|
441
506
|
#
|
|
442
507
|
def has_no_select?(locator = nil, **options, &optional_filter_block)
|
|
443
|
-
has_no_selector?(:select, locator, options, &optional_filter_block)
|
|
508
|
+
has_no_selector?(:select, locator, **options, &optional_filter_block)
|
|
444
509
|
end
|
|
445
510
|
|
|
446
511
|
##
|
|
@@ -450,35 +515,43 @@ module Capybara
|
|
|
450
515
|
#
|
|
451
516
|
# page.has_table?('People')
|
|
452
517
|
#
|
|
453
|
-
# @param [String] locator
|
|
454
|
-
# @
|
|
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
|
|
455
528
|
#
|
|
456
529
|
def has_table?(locator = nil, **options, &optional_filter_block)
|
|
457
|
-
has_selector?(:table, locator, options, &optional_filter_block)
|
|
530
|
+
has_selector?(:table, locator, **options, &optional_filter_block)
|
|
458
531
|
end
|
|
459
532
|
|
|
460
533
|
##
|
|
461
534
|
#
|
|
462
535
|
# Checks if the page or current node has no table with the given id
|
|
463
|
-
# or caption. See {
|
|
536
|
+
# or caption. See {#has_table?}.
|
|
464
537
|
#
|
|
465
|
-
# @param (see
|
|
538
|
+
# @param (see #has_table?)
|
|
466
539
|
# @return [Boolean] Whether it doesn't exist
|
|
467
540
|
#
|
|
468
541
|
def has_no_table?(locator = nil, **options, &optional_filter_block)
|
|
469
|
-
has_no_selector?(:table, locator, options, &optional_filter_block)
|
|
542
|
+
has_no_selector?(:table, locator, **options, &optional_filter_block)
|
|
470
543
|
end
|
|
471
544
|
|
|
472
545
|
##
|
|
473
546
|
#
|
|
474
|
-
# Asserts that the
|
|
547
|
+
# Asserts that the current node matches a given selector.
|
|
475
548
|
#
|
|
476
549
|
# node.assert_matches_selector('p#foo')
|
|
477
550
|
# node.assert_matches_selector(:xpath, '//p[@id="foo"]')
|
|
478
551
|
# node.assert_matches_selector(:foo)
|
|
479
552
|
#
|
|
480
553
|
# It also accepts all options that {Capybara::Node::Finders#all} accepts,
|
|
481
|
-
# such as
|
|
554
|
+
# such as `:text` and `:visible`.
|
|
482
555
|
#
|
|
483
556
|
# node.assert_matches_selector('li', text: 'Horse', visible: true)
|
|
484
557
|
#
|
|
@@ -487,86 +560,89 @@ module Capybara
|
|
|
487
560
|
#
|
|
488
561
|
def assert_matches_selector(*args, &optional_filter_block)
|
|
489
562
|
_verify_match_result(args, optional_filter_block) do |result|
|
|
490
|
-
raise Capybara::ExpectationNotMet,
|
|
563
|
+
raise Capybara::ExpectationNotMet, 'Item does not match the provided selector' unless result.include? self
|
|
491
564
|
end
|
|
492
565
|
end
|
|
493
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
|
+
#
|
|
494
575
|
def assert_not_matches_selector(*args, &optional_filter_block)
|
|
495
576
|
_verify_match_result(args, optional_filter_block) do |result|
|
|
496
577
|
raise Capybara::ExpectationNotMet, 'Item matched the provided selector' if result.include? self
|
|
497
578
|
end
|
|
498
579
|
end
|
|
499
|
-
alias_method :refute_matches_selector, :assert_not_matches_selector
|
|
500
580
|
|
|
501
581
|
##
|
|
502
582
|
#
|
|
503
|
-
# Checks if the current node matches given selector
|
|
583
|
+
# Checks if the current node matches given selector.
|
|
504
584
|
#
|
|
505
|
-
# @param (see
|
|
585
|
+
# @param (see #has_selector?)
|
|
506
586
|
# @return [Boolean]
|
|
507
587
|
#
|
|
508
|
-
def matches_selector?(*args, &optional_filter_block)
|
|
509
|
-
assert_matches_selector(*args, &optional_filter_block)
|
|
510
|
-
rescue Capybara::ExpectationNotMet
|
|
511
|
-
return false
|
|
588
|
+
def matches_selector?(*args, **options, &optional_filter_block)
|
|
589
|
+
make_predicate(options) { assert_matches_selector(*args, options, &optional_filter_block) }
|
|
512
590
|
end
|
|
513
591
|
|
|
514
592
|
##
|
|
515
593
|
#
|
|
516
|
-
# Checks if the current node matches given XPath expression
|
|
594
|
+
# Checks if the current node matches given XPath expression.
|
|
517
595
|
#
|
|
518
596
|
# @param [String, XPath::Expression] xpath The XPath expression to match against the current code
|
|
519
597
|
# @return [Boolean]
|
|
520
598
|
#
|
|
521
599
|
def matches_xpath?(xpath, **options, &optional_filter_block)
|
|
522
|
-
matches_selector?(:xpath, xpath, options, &optional_filter_block)
|
|
600
|
+
matches_selector?(:xpath, xpath, **options, &optional_filter_block)
|
|
523
601
|
end
|
|
524
602
|
|
|
525
603
|
##
|
|
526
604
|
#
|
|
527
|
-
# Checks if the current node matches given CSS selector
|
|
605
|
+
# Checks if the current node matches given CSS selector.
|
|
528
606
|
#
|
|
529
607
|
# @param [String] css The CSS selector to match against the current code
|
|
530
608
|
# @return [Boolean]
|
|
531
609
|
#
|
|
532
610
|
def matches_css?(css, **options, &optional_filter_block)
|
|
533
|
-
matches_selector?(:css, css, options, &optional_filter_block)
|
|
611
|
+
matches_selector?(:css, css, **options, &optional_filter_block)
|
|
534
612
|
end
|
|
535
613
|
|
|
536
614
|
##
|
|
537
615
|
#
|
|
538
|
-
# Checks if the current node does not match given selector
|
|
539
|
-
# Usage is identical to
|
|
616
|
+
# Checks if the current node does not match given selector.
|
|
617
|
+
# Usage is identical to {#has_selector?}.
|
|
540
618
|
#
|
|
541
|
-
# @param (see
|
|
619
|
+
# @param (see #has_selector?)
|
|
542
620
|
# @return [Boolean]
|
|
543
621
|
#
|
|
544
|
-
def not_matches_selector?(*args, &optional_filter_block)
|
|
545
|
-
assert_not_matches_selector(*args, &optional_filter_block)
|
|
546
|
-
rescue Capybara::ExpectationNotMet
|
|
547
|
-
return false
|
|
622
|
+
def not_matches_selector?(*args, **options, &optional_filter_block)
|
|
623
|
+
make_predicate(options) { assert_not_matches_selector(*args, options, &optional_filter_block) }
|
|
548
624
|
end
|
|
549
625
|
|
|
550
626
|
##
|
|
551
627
|
#
|
|
552
|
-
# Checks if the current node does not match given XPath expression
|
|
628
|
+
# Checks if the current node does not match given XPath expression.
|
|
553
629
|
#
|
|
554
630
|
# @param [String, XPath::Expression] xpath The XPath expression to match against the current code
|
|
555
631
|
# @return [Boolean]
|
|
556
632
|
#
|
|
557
633
|
def not_matches_xpath?(xpath, **options, &optional_filter_block)
|
|
558
|
-
not_matches_selector?(:xpath, xpath, options, &optional_filter_block)
|
|
634
|
+
not_matches_selector?(:xpath, xpath, **options, &optional_filter_block)
|
|
559
635
|
end
|
|
560
636
|
|
|
561
637
|
##
|
|
562
638
|
#
|
|
563
|
-
# Checks if the current node does not match given CSS selector
|
|
639
|
+
# Checks if the current node does not match given CSS selector.
|
|
564
640
|
#
|
|
565
641
|
# @param [String] css The CSS selector to match against the current code
|
|
566
642
|
# @return [Boolean]
|
|
567
643
|
#
|
|
568
644
|
def not_matches_css?(css, **options, &optional_filter_block)
|
|
569
|
-
not_matches_selector?(:css, css, options, &optional_filter_block)
|
|
645
|
+
not_matches_selector?(:css, css, **options, &optional_filter_block)
|
|
570
646
|
end
|
|
571
647
|
|
|
572
648
|
##
|
|
@@ -574,29 +650,31 @@ module Capybara
|
|
|
574
650
|
# ignoring any HTML tags.
|
|
575
651
|
#
|
|
576
652
|
# @!macro text_query_params
|
|
577
|
-
# @overload $0(type, text, options
|
|
578
|
-
# @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
|
|
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`.
|
|
579
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.
|
|
580
656
|
# @option options [Integer] :count (nil) Number of times the text is expected to occur
|
|
581
657
|
# @option options [Integer] :minimum (nil) Minimum number of times the text is expected to occur
|
|
582
658
|
# @option options [Integer] :maximum (nil) Maximum number of times the text is expected to occur
|
|
583
659
|
# @option options [Range] :between (nil) Range of times that is expected to contain number of times text occurs
|
|
584
|
-
# @option options [Numeric] :wait
|
|
585
|
-
# @option options [Boolean] :exact
|
|
586
|
-
#
|
|
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)
|
|
587
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.
|
|
588
665
|
# @option options [Integer] :count (nil) Number of times the text is expected to occur
|
|
589
666
|
# @option options [Integer] :minimum (nil) Minimum number of times the text is expected to occur
|
|
590
667
|
# @option options [Integer] :maximum (nil) Maximum number of times the text is expected to occur
|
|
591
668
|
# @option options [Range] :between (nil) Range of times that is expected to contain number of times text occurs
|
|
592
|
-
# @option options [Numeric] :wait
|
|
593
|
-
# @option options [Boolean] :exact
|
|
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
|
|
594
672
|
# @raise [Capybara::ExpectationNotMet] if the assertion hasn't succeeded during wait time
|
|
595
673
|
# @return [true]
|
|
596
674
|
#
|
|
597
|
-
def assert_text(*args)
|
|
598
|
-
_verify_text(args) do |count, query|
|
|
599
|
-
unless query.matches_count?(count) && (
|
|
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?)
|
|
600
678
|
raise Capybara::ExpectationNotMet, query.failure_message
|
|
601
679
|
end
|
|
602
680
|
end
|
|
@@ -610,9 +688,9 @@ module Capybara
|
|
|
610
688
|
# @raise [Capybara::ExpectationNotMet] if the assertion hasn't succeeded during wait time
|
|
611
689
|
# @return [true]
|
|
612
690
|
#
|
|
613
|
-
def assert_no_text(*args)
|
|
614
|
-
_verify_text(args) do |count, query|
|
|
615
|
-
if query.matches_count?(count) && (
|
|
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?)
|
|
616
694
|
raise Capybara::ExpectationNotMet, query.negative_failure_message
|
|
617
695
|
end
|
|
618
696
|
end
|
|
@@ -622,10 +700,6 @@ module Capybara
|
|
|
622
700
|
# Checks if the page or current node has the given text content,
|
|
623
701
|
# ignoring any HTML tags.
|
|
624
702
|
#
|
|
625
|
-
# Whitespaces are normalized in both node's text and passed text parameter.
|
|
626
|
-
# Note that whitespace isn't normalized in passed regexp as normalizing whitespace
|
|
627
|
-
# in regexp isn't easy and doesn't seem to be worth it.
|
|
628
|
-
#
|
|
629
703
|
# By default it will check if the text occurs at least once,
|
|
630
704
|
# but a different number can be specified.
|
|
631
705
|
#
|
|
@@ -636,10 +710,8 @@ module Capybara
|
|
|
636
710
|
# @macro text_query_params
|
|
637
711
|
# @return [Boolean] Whether it exists
|
|
638
712
|
#
|
|
639
|
-
def has_text?(*args)
|
|
640
|
-
assert_text(*args)
|
|
641
|
-
rescue Capybara::ExpectationNotMet
|
|
642
|
-
false
|
|
713
|
+
def has_text?(*args, **options)
|
|
714
|
+
make_predicate(options) { assert_text(*args, **options) }
|
|
643
715
|
end
|
|
644
716
|
alias_method :has_content?, :has_text?
|
|
645
717
|
|
|
@@ -650,52 +722,161 @@ module Capybara
|
|
|
650
722
|
# @macro text_query_params
|
|
651
723
|
# @return [Boolean] Whether it doesn't exist
|
|
652
724
|
#
|
|
653
|
-
def has_no_text?(*args)
|
|
654
|
-
assert_no_text(*args)
|
|
655
|
-
rescue Capybara::ExpectationNotMet
|
|
656
|
-
false
|
|
725
|
+
def has_no_text?(*args, **options)
|
|
726
|
+
make_predicate(options) { assert_no_text(*args, **options) }
|
|
657
727
|
end
|
|
658
728
|
alias_method :has_no_content?, :has_no_text?
|
|
659
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
|
+
|
|
660
816
|
def ==(other)
|
|
661
817
|
eql?(other) || (other.respond_to?(:base) && base == other.base)
|
|
662
818
|
end
|
|
663
819
|
|
|
664
820
|
private
|
|
665
821
|
|
|
666
|
-
def
|
|
667
|
-
|
|
668
|
-
|
|
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)
|
|
669
843
|
synchronize(query.wait) do
|
|
670
|
-
|
|
671
|
-
yield result, query
|
|
844
|
+
yield query.resolve_for(self), query
|
|
672
845
|
end
|
|
673
846
|
true
|
|
674
847
|
end
|
|
675
848
|
|
|
676
849
|
def _verify_match_result(query_args, optional_filter_block)
|
|
677
|
-
query_args = _set_query_session_options(*query_args)
|
|
678
|
-
query = Capybara::Queries::MatchQuery.new(*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)
|
|
679
852
|
synchronize(query.wait) do
|
|
680
|
-
|
|
681
|
-
yield result
|
|
853
|
+
yield query.resolve_for(parent || session&.document || query_scope)
|
|
682
854
|
end
|
|
683
855
|
true
|
|
684
856
|
end
|
|
685
857
|
|
|
686
|
-
def _verify_text(
|
|
687
|
-
|
|
688
|
-
query = Capybara::Queries::TextQuery.new(
|
|
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)
|
|
689
861
|
synchronize(query.wait) do
|
|
690
|
-
|
|
691
|
-
yield(count, query)
|
|
862
|
+
yield query.resolve_for(self), query
|
|
692
863
|
end
|
|
693
864
|
true
|
|
694
865
|
end
|
|
695
866
|
|
|
696
|
-
def _set_query_session_options(*query_args
|
|
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)
|
|
697
871
|
query_options[:session_options] = session_options
|
|
698
|
-
query_args
|
|
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
|
|
699
880
|
end
|
|
700
881
|
end
|
|
701
882
|
end
|