capybara 2.18.0 → 3.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.yardopts +1 -1
- data/History.md +945 -12
- data/License.txt +1 -1
- data/README.md +264 -90
- data/lib/capybara/config.rb +29 -57
- data/lib/capybara/cucumber.rb +2 -3
- data/lib/capybara/driver/base.rb +35 -18
- data/lib/capybara/driver/node.rb +40 -10
- data/lib/capybara/dsl.rb +10 -7
- data/lib/capybara/helpers.rb +70 -31
- data/lib/capybara/minitest/spec.rb +185 -83
- data/lib/capybara/minitest.rb +232 -112
- data/lib/capybara/node/actions.rb +274 -171
- data/lib/capybara/node/base.rb +42 -34
- data/lib/capybara/node/document.rb +15 -3
- data/lib/capybara/node/document_matchers.rb +19 -21
- data/lib/capybara/node/element.rb +362 -135
- data/lib/capybara/node/finders.rb +151 -137
- data/lib/capybara/node/matchers.rb +394 -209
- data/lib/capybara/node/simple.rb +59 -26
- data/lib/capybara/node/whitespace_normalizer.rb +81 -0
- data/lib/capybara/queries/active_element_query.rb +18 -0
- data/lib/capybara/queries/ancestor_query.rb +12 -9
- data/lib/capybara/queries/base_query.rb +39 -28
- data/lib/capybara/queries/current_path_query.rb +21 -27
- data/lib/capybara/queries/match_query.rb +14 -7
- data/lib/capybara/queries/selector_query.rb +659 -149
- data/lib/capybara/queries/sibling_query.rb +11 -9
- data/lib/capybara/queries/style_query.rb +45 -0
- data/lib/capybara/queries/text_query.rb +56 -38
- data/lib/capybara/queries/title_query.rb +8 -11
- data/lib/capybara/rack_test/browser.rb +114 -42
- data/lib/capybara/rack_test/css_handlers.rb +6 -4
- data/lib/capybara/rack_test/driver.rb +22 -17
- data/lib/capybara/rack_test/errors.rb +6 -0
- data/lib/capybara/rack_test/form.rb +93 -58
- data/lib/capybara/rack_test/node.rb +184 -81
- data/lib/capybara/rails.rb +3 -7
- data/lib/capybara/registration_container.rb +41 -0
- data/lib/capybara/registrations/drivers.rb +42 -0
- data/lib/capybara/registrations/patches/puma_ssl.rb +29 -0
- data/lib/capybara/registrations/servers.rb +66 -0
- data/lib/capybara/result.rb +97 -63
- data/lib/capybara/rspec/features.rb +17 -50
- data/lib/capybara/rspec/matcher_proxies.rb +52 -15
- data/lib/capybara/rspec/matchers/base.rb +113 -0
- data/lib/capybara/rspec/matchers/become_closed.rb +33 -0
- data/lib/capybara/rspec/matchers/compound.rb +88 -0
- data/lib/capybara/rspec/matchers/count_sugar.rb +37 -0
- data/lib/capybara/rspec/matchers/have_ancestor.rb +28 -0
- data/lib/capybara/rspec/matchers/have_current_path.rb +29 -0
- data/lib/capybara/rspec/matchers/have_selector.rb +69 -0
- data/lib/capybara/rspec/matchers/have_sibling.rb +27 -0
- data/lib/capybara/rspec/matchers/have_text.rb +33 -0
- data/lib/capybara/rspec/matchers/have_title.rb +29 -0
- data/lib/capybara/rspec/matchers/match_selector.rb +27 -0
- data/lib/capybara/rspec/matchers/match_style.rb +43 -0
- data/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
- data/lib/capybara/rspec/matchers.rb +146 -310
- data/lib/capybara/rspec.rb +7 -11
- data/lib/capybara/selector/builders/css_builder.rb +84 -0
- data/lib/capybara/selector/builders/xpath_builder.rb +71 -0
- data/lib/capybara/selector/css.rb +85 -13
- data/lib/capybara/selector/definition/button.rb +68 -0
- data/lib/capybara/selector/definition/checkbox.rb +26 -0
- data/lib/capybara/selector/definition/css.rb +10 -0
- data/lib/capybara/selector/definition/datalist_input.rb +35 -0
- data/lib/capybara/selector/definition/datalist_option.rb +25 -0
- data/lib/capybara/selector/definition/element.rb +28 -0
- data/lib/capybara/selector/definition/field.rb +40 -0
- data/lib/capybara/selector/definition/fieldset.rb +14 -0
- data/lib/capybara/selector/definition/file_field.rb +13 -0
- data/lib/capybara/selector/definition/fillable_field.rb +33 -0
- data/lib/capybara/selector/definition/frame.rb +17 -0
- data/lib/capybara/selector/definition/id.rb +6 -0
- data/lib/capybara/selector/definition/label.rb +62 -0
- data/lib/capybara/selector/definition/link.rb +55 -0
- data/lib/capybara/selector/definition/link_or_button.rb +16 -0
- data/lib/capybara/selector/definition/option.rb +27 -0
- data/lib/capybara/selector/definition/radio_button.rb +27 -0
- data/lib/capybara/selector/definition/select.rb +81 -0
- data/lib/capybara/selector/definition/table.rb +109 -0
- data/lib/capybara/selector/definition/table_row.rb +21 -0
- data/lib/capybara/selector/definition/xpath.rb +5 -0
- data/lib/capybara/selector/definition.rb +280 -0
- data/lib/capybara/selector/filter.rb +2 -17
- data/lib/capybara/selector/filter_set.rb +80 -33
- data/lib/capybara/selector/filters/base.rb +50 -6
- data/lib/capybara/selector/filters/expression_filter.rb +8 -26
- data/lib/capybara/selector/filters/locator_filter.rb +29 -0
- data/lib/capybara/selector/filters/node_filter.rb +16 -12
- data/lib/capybara/selector/regexp_disassembler.rb +211 -0
- data/lib/capybara/selector/selector.rb +93 -210
- data/lib/capybara/selector/xpath_extensions.rb +17 -0
- data/lib/capybara/selector.rb +475 -523
- data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -0
- data/lib/capybara/selenium/atoms/isDisplayed.min.js +1 -0
- data/lib/capybara/selenium/atoms/src/getAttribute.js +161 -0
- data/lib/capybara/selenium/atoms/src/isDisplayed.js +454 -0
- data/lib/capybara/selenium/driver.rb +298 -267
- data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +117 -0
- data/lib/capybara/selenium/driver_specializations/edge_driver.rb +128 -0
- data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +84 -0
- data/lib/capybara/selenium/driver_specializations/internet_explorer_driver.rb +26 -0
- data/lib/capybara/selenium/driver_specializations/safari_driver.rb +24 -0
- data/lib/capybara/selenium/extensions/file_input_click_emulation.rb +34 -0
- data/lib/capybara/selenium/extensions/find.rb +110 -0
- data/lib/capybara/selenium/extensions/html5_drag.rb +229 -0
- data/lib/capybara/selenium/extensions/modifier_keys_stack.rb +28 -0
- data/lib/capybara/selenium/extensions/scroll.rb +76 -0
- data/lib/capybara/selenium/node.rb +517 -145
- data/lib/capybara/selenium/nodes/chrome_node.rb +125 -0
- data/lib/capybara/selenium/nodes/edge_node.rb +110 -0
- data/lib/capybara/selenium/nodes/firefox_node.rb +136 -0
- data/lib/capybara/selenium/nodes/ie_node.rb +22 -0
- data/lib/capybara/selenium/nodes/safari_node.rb +118 -0
- data/lib/capybara/selenium/patches/atoms.rb +18 -0
- data/lib/capybara/selenium/patches/is_displayed.rb +16 -0
- data/lib/capybara/selenium/patches/logs.rb +45 -0
- data/lib/capybara/selenium/patches/pause_duration_fix.rb +9 -0
- data/lib/capybara/selenium/patches/persistent_client.rb +20 -0
- data/lib/capybara/server/animation_disabler.rb +80 -0
- data/lib/capybara/server/checker.rb +44 -0
- data/lib/capybara/server/middleware.rb +71 -0
- data/lib/capybara/server.rb +59 -67
- data/lib/capybara/session/config.rb +81 -67
- data/lib/capybara/session/matchers.rb +28 -20
- data/lib/capybara/session.rb +337 -365
- data/lib/capybara/spec/public/jquery.js +5 -5
- data/lib/capybara/spec/public/offset.js +6 -0
- data/lib/capybara/spec/public/test.js +151 -12
- data/lib/capybara/spec/session/accept_alert_spec.rb +12 -11
- data/lib/capybara/spec/session/accept_confirm_spec.rb +6 -5
- data/lib/capybara/spec/session/accept_prompt_spec.rb +10 -10
- data/lib/capybara/spec/session/active_element_spec.rb +31 -0
- data/lib/capybara/spec/session/all_spec.rb +161 -57
- data/lib/capybara/spec/session/ancestor_spec.rb +27 -24
- data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +68 -38
- data/lib/capybara/spec/session/assert_current_path_spec.rb +75 -0
- data/lib/capybara/spec/session/assert_selector_spec.rb +143 -0
- data/lib/capybara/spec/session/assert_style_spec.rb +26 -0
- data/lib/capybara/spec/session/assert_text_spec.rb +258 -0
- data/lib/capybara/spec/session/{assert_title.rb → assert_title_spec.rb} +22 -12
- data/lib/capybara/spec/session/attach_file_spec.rb +144 -69
- data/lib/capybara/spec/session/body_spec.rb +12 -13
- data/lib/capybara/spec/session/check_spec.rb +117 -55
- data/lib/capybara/spec/session/choose_spec.rb +64 -31
- data/lib/capybara/spec/session/click_button_spec.rb +231 -173
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +55 -35
- data/lib/capybara/spec/session/click_link_spec.rb +93 -58
- data/lib/capybara/spec/session/current_scope_spec.rb +12 -11
- data/lib/capybara/spec/session/current_url_spec.rb +57 -39
- data/lib/capybara/spec/session/dismiss_confirm_spec.rb +4 -4
- data/lib/capybara/spec/session/dismiss_prompt_spec.rb +3 -2
- data/lib/capybara/spec/session/element/{assert_match_selector.rb → assert_match_selector_spec.rb} +11 -9
- data/lib/capybara/spec/session/element/match_css_spec.rb +18 -10
- data/lib/capybara/spec/session/element/match_xpath_spec.rb +9 -7
- data/lib/capybara/spec/session/element/matches_selector_spec.rb +71 -57
- data/lib/capybara/spec/session/evaluate_async_script_spec.rb +8 -7
- data/lib/capybara/spec/session/evaluate_script_spec.rb +29 -8
- data/lib/capybara/spec/session/execute_script_spec.rb +10 -8
- data/lib/capybara/spec/session/fill_in_spec.rb +134 -43
- data/lib/capybara/spec/session/find_button_spec.rb +25 -24
- data/lib/capybara/spec/session/find_by_id_spec.rb +10 -9
- data/lib/capybara/spec/session/find_field_spec.rb +37 -41
- data/lib/capybara/spec/session/find_link_spec.rb +46 -17
- data/lib/capybara/spec/session/find_spec.rb +260 -145
- data/lib/capybara/spec/session/first_spec.rb +80 -52
- data/lib/capybara/spec/session/frame/frame_title_spec.rb +23 -0
- data/lib/capybara/spec/session/frame/frame_url_spec.rb +23 -0
- data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +33 -20
- data/lib/capybara/spec/session/frame/within_frame_spec.rb +52 -32
- data/lib/capybara/spec/session/go_back_spec.rb +2 -1
- data/lib/capybara/spec/session/go_forward_spec.rb +2 -1
- data/lib/capybara/spec/session/has_all_selectors_spec.rb +31 -31
- data/lib/capybara/spec/session/has_ancestor_spec.rb +46 -0
- data/lib/capybara/spec/session/has_any_selectors_spec.rb +29 -0
- data/lib/capybara/spec/session/has_button_spec.rb +100 -13
- data/lib/capybara/spec/session/has_css_spec.rb +272 -137
- data/lib/capybara/spec/session/has_current_path_spec.rb +60 -61
- data/lib/capybara/spec/session/has_element_spec.rb +47 -0
- data/lib/capybara/spec/session/has_field_spec.rb +139 -59
- data/lib/capybara/spec/session/has_link_spec.rb +47 -6
- data/lib/capybara/spec/session/has_none_selectors_spec.rb +42 -40
- data/lib/capybara/spec/session/has_select_spec.rb +107 -72
- data/lib/capybara/spec/session/has_selector_spec.rb +120 -71
- data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
- data/lib/capybara/spec/session/has_table_spec.rb +183 -5
- data/lib/capybara/spec/session/has_text_spec.rb +106 -62
- data/lib/capybara/spec/session/has_title_spec.rb +20 -14
- data/lib/capybara/spec/session/has_xpath_spec.rb +57 -38
- data/lib/capybara/spec/session/{headers.rb → headers_spec.rb} +3 -2
- data/lib/capybara/spec/session/html_spec.rb +14 -6
- data/lib/capybara/spec/session/matches_style_spec.rb +37 -0
- data/lib/capybara/spec/session/node_spec.rb +1024 -153
- data/lib/capybara/spec/session/node_wrapper_spec.rb +39 -0
- data/lib/capybara/spec/session/refresh_spec.rb +12 -6
- data/lib/capybara/spec/session/reset_session_spec.rb +82 -35
- data/lib/capybara/spec/session/{response_code.rb → response_code_spec.rb} +2 -1
- data/lib/capybara/spec/session/save_and_open_page_spec.rb +3 -2
- data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +8 -12
- data/lib/capybara/spec/session/save_page_spec.rb +42 -55
- data/lib/capybara/spec/session/save_screenshot_spec.rb +16 -14
- data/lib/capybara/spec/session/screenshot_spec.rb +2 -2
- data/lib/capybara/spec/session/scroll_spec.rb +119 -0
- data/lib/capybara/spec/session/select_spec.rb +107 -81
- data/lib/capybara/spec/session/selectors_spec.rb +52 -19
- data/lib/capybara/spec/session/sibling_spec.rb +10 -10
- data/lib/capybara/spec/session/text_spec.rb +37 -21
- data/lib/capybara/spec/session/title_spec.rb +17 -5
- data/lib/capybara/spec/session/uncheck_spec.rb +43 -23
- data/lib/capybara/spec/session/unselect_spec.rb +39 -38
- data/lib/capybara/spec/session/visit_spec.rb +85 -53
- data/lib/capybara/spec/session/window/become_closed_spec.rb +24 -20
- data/lib/capybara/spec/session/window/current_window_spec.rb +5 -3
- data/lib/capybara/spec/session/window/open_new_window_spec.rb +5 -3
- data/lib/capybara/spec/session/window/switch_to_window_spec.rb +27 -22
- data/lib/capybara/spec/session/window/window_opened_by_spec.rb +12 -6
- data/lib/capybara/spec/session/window/window_spec.rb +97 -63
- data/lib/capybara/spec/session/window/windows_spec.rb +12 -10
- data/lib/capybara/spec/session/window/within_window_spec.rb +31 -86
- data/lib/capybara/spec/session/within_spec.rb +83 -44
- data/lib/capybara/spec/spec_helper.rb +54 -44
- data/lib/capybara/spec/test_app.rb +158 -43
- data/lib/capybara/spec/views/animated.erb +49 -0
- data/lib/capybara/spec/views/form.erb +163 -42
- data/lib/capybara/spec/views/frame_child.erb +4 -3
- data/lib/capybara/spec/views/frame_one.erb +2 -1
- data/lib/capybara/spec/views/frame_parent.erb +1 -1
- data/lib/capybara/spec/views/frame_two.erb +1 -1
- data/lib/capybara/spec/views/initial_alert.erb +2 -1
- data/lib/capybara/spec/views/layout.erb +10 -0
- data/lib/capybara/spec/views/obscured.erb +47 -0
- data/lib/capybara/spec/views/offset.erb +33 -0
- data/lib/capybara/spec/views/path.erb +2 -2
- data/lib/capybara/spec/views/popup_one.erb +1 -1
- data/lib/capybara/spec/views/popup_two.erb +1 -1
- data/lib/capybara/spec/views/react.erb +45 -0
- data/lib/capybara/spec/views/scroll.erb +21 -0
- data/lib/capybara/spec/views/spatial.erb +31 -0
- data/lib/capybara/spec/views/tables.erb +68 -1
- data/lib/capybara/spec/views/with_animation.erb +81 -0
- data/lib/capybara/spec/views/with_base_tag.erb +2 -2
- data/lib/capybara/spec/views/with_dragula.erb +24 -0
- data/lib/capybara/spec/views/with_fixed_header_footer.erb +2 -1
- data/lib/capybara/spec/views/with_hover.erb +3 -2
- data/lib/capybara/spec/views/with_hover1.erb +10 -0
- data/lib/capybara/spec/views/with_html.erb +69 -12
- data/lib/capybara/spec/views/with_html5_svg.erb +20 -0
- data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
- data/lib/capybara/spec/views/with_js.erb +30 -5
- data/lib/capybara/spec/views/with_jstree.erb +26 -0
- data/lib/capybara/spec/views/with_namespace.erb +21 -0
- data/lib/capybara/spec/views/with_scope.erb +2 -2
- data/lib/capybara/spec/views/with_scope_other.erb +6 -0
- data/lib/capybara/spec/views/with_shadow.erb +31 -0
- data/lib/capybara/spec/views/with_slow_unload.erb +2 -1
- data/lib/capybara/spec/views/with_sortable_js.erb +21 -0
- data/lib/capybara/spec/views/with_unload_alert.erb +1 -0
- data/lib/capybara/spec/views/with_windows.erb +1 -1
- data/lib/capybara/spec/views/within_frames.erb +5 -2
- data/lib/capybara/version.rb +2 -1
- data/lib/capybara/window.rb +36 -34
- data/lib/capybara.rb +134 -107
- data/spec/basic_node_spec.rb +60 -34
- data/spec/capybara_spec.rb +63 -88
- data/spec/counter_spec.rb +35 -0
- data/spec/css_builder_spec.rb +101 -0
- data/spec/css_splitter_spec.rb +38 -0
- data/spec/dsl_spec.rb +85 -64
- data/spec/filter_set_spec.rb +27 -9
- data/spec/fixtures/certificate.pem +25 -0
- data/spec/fixtures/key.pem +27 -0
- data/spec/fixtures/selenium_driver_rspec_failure.rb +6 -5
- data/spec/fixtures/selenium_driver_rspec_success.rb +6 -5
- data/spec/minitest_spec.rb +52 -7
- data/spec/minitest_spec_spec.rb +94 -63
- data/spec/per_session_config_spec.rb +14 -13
- data/spec/rack_test_spec.rb +194 -125
- data/spec/regexp_dissassembler_spec.rb +250 -0
- data/spec/result_spec.rb +111 -50
- data/spec/rspec/features_spec.rb +37 -31
- data/spec/rspec/scenarios_spec.rb +10 -8
- data/spec/rspec/shared_spec_matchers.rb +473 -422
- data/spec/rspec/views_spec.rb +5 -3
- data/spec/rspec_matchers_spec.rb +52 -11
- data/spec/rspec_spec.rb +109 -89
- data/spec/sauce_spec_chrome.rb +43 -0
- data/spec/selector_spec.rb +397 -68
- data/spec/selenium_spec_chrome.rb +187 -40
- data/spec/selenium_spec_chrome_remote.rb +96 -0
- data/spec/selenium_spec_edge.rb +60 -0
- data/spec/selenium_spec_firefox.rb +201 -41
- data/spec/selenium_spec_firefox_remote.rb +94 -0
- data/spec/selenium_spec_ie.rb +149 -0
- data/spec/selenium_spec_safari.rb +162 -0
- data/spec/server_spec.rb +213 -102
- data/spec/session_spec.rb +53 -16
- data/spec/shared_selenium_node.rb +79 -0
- data/spec/shared_selenium_session.rb +473 -122
- data/spec/spec_helper.rb +126 -7
- data/spec/whitespace_normalizer_spec.rb +54 -0
- data/spec/xpath_builder_spec.rb +93 -0
- metadata +355 -73
- data/.yard/templates_custom/default/class/html/selectors.erb +0 -38
- data/.yard/templates_custom/default/class/html/setup.rb +0 -17
- data/.yard/yard_extensions.rb +0 -78
- data/lib/capybara/query.rb +0 -7
- data/lib/capybara/rspec/compound.rb +0 -95
- data/lib/capybara/spec/session/assert_current_path.rb +0 -72
- data/lib/capybara/spec/session/assert_selector.rb +0 -148
- data/lib/capybara/spec/session/assert_text.rb +0 -234
- data/lib/capybara/spec/session/source_spec.rb +0 -0
- data/lib/capybara/spec/views/with_title.erb +0 -5
- data/spec/selenium_spec_marionette.rb +0 -127
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
# NOTE: This file uses `sleep` to sync up parts of the tests. This is only implemented like this
|
|
4
|
+
# because of the methods being tested. In tests using Capybara this type of behavior should be implemented
|
|
5
|
+
# using Capybara provided assertions with builtin waiting behavior.
|
|
6
|
+
|
|
7
|
+
Capybara::SpecHelper.spec 'node' do
|
|
4
8
|
before do
|
|
5
9
|
@session.visit('/with_html')
|
|
6
10
|
end
|
|
7
11
|
|
|
8
|
-
it
|
|
12
|
+
it 'should act like a session object' do
|
|
9
13
|
@session.visit('/form')
|
|
10
14
|
@form = @session.find(:css, '#get-form')
|
|
11
15
|
expect(@form).to have_field('Middle Name')
|
|
@@ -15,67 +19,70 @@ Capybara::SpecHelper.spec "node" do
|
|
|
15
19
|
expect(extract_results(@session)['middle_name']).to eq('Monkey')
|
|
16
20
|
end
|
|
17
21
|
|
|
18
|
-
it
|
|
22
|
+
it 'should scope CSS selectors' do
|
|
19
23
|
expect(@session.find(:css, '#second')).to have_no_css('h1')
|
|
20
24
|
end
|
|
21
25
|
|
|
22
|
-
describe
|
|
23
|
-
it
|
|
24
|
-
|
|
25
|
-
expect(
|
|
26
|
-
expect(
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
describe "#parent" do
|
|
31
|
-
it "should be deprecated" do
|
|
32
|
-
@node = @session.find(:css, '#first')
|
|
33
|
-
expect(@node).to receive(:warn).with(/^DEPRECATED:/)
|
|
34
|
-
expect(@node.parent).to eq(@node.query_scope)
|
|
26
|
+
describe '#query_scope' do
|
|
27
|
+
it 'should have a reference to the element the query was evaluated on if there is one' do
|
|
28
|
+
node = @session.find(:css, '#first')
|
|
29
|
+
expect(node.query_scope).to eq(node.session.document)
|
|
30
|
+
expect(node.find(:css, '#foo').query_scope).to eq(node)
|
|
35
31
|
end
|
|
36
32
|
end
|
|
37
33
|
|
|
38
|
-
describe
|
|
39
|
-
it
|
|
34
|
+
describe '#text' do
|
|
35
|
+
it 'should extract node texts' do
|
|
40
36
|
expect(@session.all('//a')[0].text).to eq('labore')
|
|
41
37
|
expect(@session.all('//a')[1].text).to eq('ullamco')
|
|
42
38
|
end
|
|
43
39
|
|
|
44
|
-
it
|
|
40
|
+
it 'should return document text on /html selector' do
|
|
45
41
|
@session.visit('/with_simple_html')
|
|
46
42
|
expect(@session.all('/html')[0].text).to eq('Bar')
|
|
47
43
|
end
|
|
48
44
|
end
|
|
49
45
|
|
|
50
|
-
describe
|
|
51
|
-
it
|
|
46
|
+
describe '#[]' do
|
|
47
|
+
it 'should extract node attributes' do
|
|
52
48
|
expect(@session.all('//a')[0][:class]).to eq('simple')
|
|
53
49
|
expect(@session.all('//a')[1][:id]).to eq('foo')
|
|
54
50
|
expect(@session.all('//input')[0][:type]).to eq('text')
|
|
55
51
|
end
|
|
56
52
|
|
|
57
|
-
it
|
|
53
|
+
it 'should extract boolean node attributes' do
|
|
58
54
|
expect(@session.find('//input[@id="checked_field"]')[:checked]).to be_truthy
|
|
59
55
|
end
|
|
60
56
|
end
|
|
61
57
|
|
|
62
|
-
describe
|
|
63
|
-
it
|
|
58
|
+
describe '#style', requires: [:css] do
|
|
59
|
+
it 'should return the computed style value' do
|
|
60
|
+
expect(@session.find(:css, '#first').style('display')).to eq('display' => 'block')
|
|
61
|
+
expect(@session.find(:css, '#second').style(:display)).to eq('display' => 'inline')
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it 'should return multiple style values' do
|
|
65
|
+
expect(@session.find(:css, '#first').style('display', :'line-height')).to eq('display' => 'block', 'line-height' => '25px')
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
describe '#value' do
|
|
70
|
+
it 'should allow retrieval of the value' do
|
|
64
71
|
expect(@session.find('//textarea[@id="normal"]').value).to eq('banana')
|
|
65
72
|
end
|
|
66
73
|
|
|
67
|
-
it
|
|
74
|
+
it 'should not swallow extra newlines in textarea' do
|
|
68
75
|
expect(@session.find('//textarea[@id="additional_newline"]').value).to eq("\nbanana")
|
|
69
76
|
end
|
|
70
77
|
|
|
71
|
-
it
|
|
78
|
+
it 'should not swallow leading newlines for set content in textarea' do
|
|
72
79
|
@session.find('//textarea[@id="normal"]').set("\nbanana")
|
|
73
80
|
expect(@session.find('//textarea[@id="normal"]').value).to eq("\nbanana")
|
|
74
81
|
end
|
|
75
82
|
|
|
76
|
-
it
|
|
77
|
-
@session.find('//textarea[1]').set(
|
|
78
|
-
expect(@session.find('//textarea[1]').value).to eq(
|
|
83
|
+
it 'return any HTML content in textarea' do
|
|
84
|
+
@session.find('//textarea[1]').set('some <em>html</em> here')
|
|
85
|
+
expect(@session.find('//textarea[1]').value).to eq('some <em>html</em> here')
|
|
79
86
|
end
|
|
80
87
|
|
|
81
88
|
it "defaults to 'on' for checkbox" do
|
|
@@ -89,125 +96,158 @@ Capybara::SpecHelper.spec "node" do
|
|
|
89
96
|
end
|
|
90
97
|
end
|
|
91
98
|
|
|
92
|
-
describe
|
|
93
|
-
it
|
|
99
|
+
describe '#set' do
|
|
100
|
+
it 'should allow assignment of field value' do
|
|
94
101
|
expect(@session.first('//input').value).to eq('monkey')
|
|
95
102
|
@session.first('//input').set('gorilla')
|
|
96
103
|
expect(@session.first('//input').value).to eq('gorilla')
|
|
97
104
|
end
|
|
98
105
|
|
|
99
|
-
it
|
|
106
|
+
it 'should fill the field even if the caret was not at the end', requires: [:js] do
|
|
100
107
|
@session.execute_script("var el = document.getElementById('test_field'); el.focus(); el.setSelectionRange(0, 0);")
|
|
101
108
|
@session.first('//input').set('')
|
|
102
109
|
expect(@session.first('//input').value).to eq('')
|
|
103
110
|
end
|
|
104
111
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
end
|
|
112
|
+
if ENV['CAPYBARA_THOROUGH']
|
|
113
|
+
it 'should raise if the text field is readonly' do
|
|
114
|
+
expect { @session.first('//input[@readonly]').set('changed') }.to raise_error(Capybara::ReadOnlyElementError)
|
|
115
|
+
end
|
|
110
116
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
117
|
+
it 'should raise if the textarea is readonly' do
|
|
118
|
+
expect { @session.first('//textarea[@readonly]').set('changed') }.to raise_error(Capybara::ReadOnlyElementError)
|
|
119
|
+
end
|
|
120
|
+
else
|
|
121
|
+
it 'should not change if the text field is readonly' do
|
|
122
|
+
@session.first('//input[@readonly]').set('changed')
|
|
123
|
+
expect(@session.first('//input[@readonly]').value).to eq 'should not change'
|
|
124
|
+
end
|
|
114
125
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
126
|
+
it 'should not change if the textarea is readonly' do
|
|
127
|
+
@session.first('//textarea[@readonly]').set('changed')
|
|
128
|
+
expect(@session.first('//textarea[@readonly]').value).to eq 'textarea should not change'
|
|
129
|
+
end
|
|
119
130
|
end
|
|
120
131
|
|
|
121
|
-
it
|
|
122
|
-
|
|
123
|
-
|
|
132
|
+
it 'should use global default options' do
|
|
133
|
+
Capybara.default_set_options = { clear: :backspace }
|
|
134
|
+
element = @session.first(:fillable_field, type: 'text')
|
|
135
|
+
allow(element.base).to receive(:set)
|
|
136
|
+
element.set('gorilla')
|
|
137
|
+
expect(element.base).to have_received(:set).with('gorilla', clear: :backspace)
|
|
138
|
+
end
|
|
124
139
|
|
|
125
|
-
context
|
|
140
|
+
context 'with a contenteditable element', requires: [:js] do
|
|
126
141
|
it 'should allow me to change the contents' do
|
|
127
142
|
@session.visit('/with_js')
|
|
128
|
-
@session.find(:css,'#existing_content_editable').set('WYSIWYG')
|
|
129
|
-
expect(@session.find(:css,'#existing_content_editable').text).to eq('WYSIWYG')
|
|
143
|
+
@session.find(:css, '#existing_content_editable').set('WYSIWYG')
|
|
144
|
+
expect(@session.find(:css, '#existing_content_editable').text).to eq('WYSIWYG')
|
|
130
145
|
end
|
|
131
146
|
|
|
132
147
|
it 'should allow me to set the contents' do
|
|
133
148
|
@session.visit('/with_js')
|
|
134
|
-
@session.find(:css,'#blank_content_editable').set('WYSIWYG')
|
|
135
|
-
expect(@session.find(:css,'#blank_content_editable').text).to eq('WYSIWYG')
|
|
149
|
+
@session.find(:css, '#blank_content_editable').set('WYSIWYG')
|
|
150
|
+
expect(@session.find(:css, '#blank_content_editable').text).to eq('WYSIWYG')
|
|
136
151
|
end
|
|
137
152
|
|
|
138
153
|
it 'should allow me to change the contents of a child element' do
|
|
139
154
|
@session.visit('/with_js')
|
|
140
|
-
@session.find(:css,'#existing_content_editable_child').set('WYSIWYG')
|
|
141
|
-
expect(@session.find(:css,'#existing_content_editable_child').text).to eq('WYSIWYG')
|
|
142
|
-
expect(@session.find(:css,'#existing_content_editable_child_parent').text).to eq(
|
|
155
|
+
@session.find(:css, '#existing_content_editable_child').set('WYSIWYG')
|
|
156
|
+
expect(@session.find(:css, '#existing_content_editable_child').text).to eq('WYSIWYG')
|
|
157
|
+
expect(@session.find(:css, '#existing_content_editable_child_parent').text).to eq("Some content\nWYSIWYG")
|
|
143
158
|
end
|
|
144
159
|
end
|
|
160
|
+
|
|
161
|
+
it 'should submit single text input forms if ended with \n' do
|
|
162
|
+
@session.visit('/form')
|
|
163
|
+
@session.find(:css, '#single_input').set("my entry\n")
|
|
164
|
+
expect(extract_results(@session)['single_input']).to eq('my entry')
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
it 'should not submit single text input forms if ended with \n and has multiple values' do
|
|
168
|
+
@session.visit('/form')
|
|
169
|
+
@session.find(:css, '#two_input_1').set("my entry\n")
|
|
170
|
+
expect(@session.find(:css, '#two_input_1').value).to eq("my entry\n").or(eq 'my entry')
|
|
171
|
+
end
|
|
145
172
|
end
|
|
146
173
|
|
|
147
|
-
describe
|
|
148
|
-
it
|
|
174
|
+
describe '#tag_name' do
|
|
175
|
+
it 'should extract node tag name' do
|
|
149
176
|
expect(@session.all('//a')[0].tag_name).to eq('a')
|
|
150
177
|
expect(@session.all('//a')[1].tag_name).to eq('a')
|
|
151
178
|
expect(@session.all('//p')[1].tag_name).to eq('p')
|
|
152
179
|
end
|
|
153
180
|
end
|
|
154
181
|
|
|
155
|
-
describe
|
|
156
|
-
it
|
|
182
|
+
describe '#disabled?' do
|
|
183
|
+
it 'should extract disabled node' do
|
|
157
184
|
@session.visit('/form')
|
|
158
185
|
expect(@session.find('//input[@id="customer_name"]')).to be_disabled
|
|
159
186
|
expect(@session.find('//input[@id="customer_email"]')).not_to be_disabled
|
|
160
187
|
end
|
|
161
188
|
|
|
162
|
-
it
|
|
189
|
+
it 'should see disabled options as disabled' do
|
|
163
190
|
@session.visit('/form')
|
|
164
191
|
expect(@session.find('//select[@id="form_title"]/option[1]')).not_to be_disabled
|
|
165
192
|
expect(@session.find('//select[@id="form_title"]/option[@disabled]')).to be_disabled
|
|
166
193
|
end
|
|
167
194
|
|
|
168
|
-
it
|
|
195
|
+
it 'should see enabled options in disabled select as disabled' do
|
|
169
196
|
@session.visit('/form')
|
|
170
197
|
expect(@session.find('//select[@id="form_disabled_select"]/option')).to be_disabled
|
|
171
198
|
expect(@session.find('//select[@id="form_disabled_select"]/optgroup/option')).to be_disabled
|
|
172
199
|
expect(@session.find('//select[@id="form_title"]/option[1]')).not_to be_disabled
|
|
173
200
|
end
|
|
174
201
|
|
|
175
|
-
it
|
|
202
|
+
it 'should see enabled options in disabled optgroup as disabled' do
|
|
176
203
|
@session.visit('/form')
|
|
177
|
-
expect(@session.find('//option', text:
|
|
178
|
-
expect(@session.find('//option', text:
|
|
204
|
+
expect(@session.find('//option', text: 'A.B.1')).to be_disabled
|
|
205
|
+
expect(@session.find('//option', text: 'A.2')).not_to be_disabled
|
|
179
206
|
end
|
|
180
207
|
|
|
181
|
-
|
|
208
|
+
it 'should see a disabled fieldset as disabled' do
|
|
209
|
+
@session.visit('/form')
|
|
210
|
+
expect(@session.find(:xpath, './/fieldset[@id="form_disabled_fieldset"]')).to be_disabled
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
context 'in a disabled fieldset' do
|
|
182
214
|
# https://html.spec.whatwg.org/#the-fieldset-element
|
|
183
|
-
it
|
|
215
|
+
it 'should see elements not in first legend as disabled' do
|
|
184
216
|
@session.visit('/form')
|
|
185
217
|
expect(@session.find('//input[@id="form_disabled_fieldset_child"]')).to be_disabled
|
|
186
218
|
expect(@session.find('//input[@id="form_disabled_fieldset_second_legend_child"]')).to be_disabled
|
|
187
219
|
expect(@session.find('//input[@id="form_enabled_fieldset_child"]')).not_to be_disabled
|
|
188
220
|
end
|
|
189
221
|
|
|
190
|
-
it
|
|
222
|
+
it 'should see elements in first legend as enabled' do
|
|
191
223
|
@session.visit('/form')
|
|
192
224
|
expect(@session.find('//input[@id="form_disabled_fieldset_legend_child"]')).not_to be_disabled
|
|
193
225
|
end
|
|
194
226
|
|
|
195
|
-
it
|
|
227
|
+
it 'should sees options not in first legend as disabled' do
|
|
196
228
|
@session.visit('/form')
|
|
197
229
|
expect(@session.find('//option', text: 'Disabled Child Option')).to be_disabled
|
|
198
230
|
end
|
|
199
231
|
end
|
|
200
|
-
|
|
232
|
+
|
|
233
|
+
it 'should be boolean' do
|
|
201
234
|
@session.visit('/form')
|
|
202
235
|
expect(@session.find('//select[@id="form_disabled_select"]/option').disabled?).to be true
|
|
203
236
|
expect(@session.find('//select[@id="form_disabled_select2"]/option').disabled?).to be true
|
|
204
237
|
expect(@session.find('//select[@id="form_title"]/option[1]').disabled?).to be false
|
|
205
238
|
end
|
|
239
|
+
|
|
240
|
+
it 'should be disabled for all elements that are CSS :disabled' do
|
|
241
|
+
@session.visit('/form')
|
|
242
|
+
# sanity check
|
|
243
|
+
expect(@session.all(:css, ':disabled')).to all(be_disabled)
|
|
244
|
+
end
|
|
206
245
|
end
|
|
207
246
|
|
|
208
|
-
describe
|
|
209
|
-
|
|
210
|
-
|
|
247
|
+
describe '#visible?' do
|
|
248
|
+
before { Capybara.ignore_hidden_elements = false }
|
|
249
|
+
|
|
250
|
+
it 'should extract node visibility' do
|
|
211
251
|
expect(@session.first('//a')).to be_visible
|
|
212
252
|
|
|
213
253
|
expect(@session.find('//div[@id="hidden"]')).not_to be_visible
|
|
@@ -217,22 +257,124 @@ Capybara::SpecHelper.spec "node" do
|
|
|
217
257
|
expect(@session.find('//input[@id="hidden_input"]')).not_to be_visible
|
|
218
258
|
end
|
|
219
259
|
|
|
220
|
-
it
|
|
221
|
-
|
|
260
|
+
it 'template elements should not be visible' do
|
|
261
|
+
expect(@session.find('//template')).not_to be_visible
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
it 'should be boolean' do
|
|
222
265
|
expect(@session.first('//a').visible?).to be true
|
|
223
266
|
expect(@session.find('//div[@id="hidden"]').visible?).to be false
|
|
224
267
|
end
|
|
268
|
+
|
|
269
|
+
it 'closed details > summary elements and descendants should be visible' do
|
|
270
|
+
expect(@session.find(:css, '#closed_details summary')).to be_visible
|
|
271
|
+
expect(@session.find(:css, '#closed_details summary h6')).to be_visible
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
it 'details non-summary descendants should be non-visible when closed' do
|
|
275
|
+
descendants = @session.all(:css, '#closed_details > *:not(summary), #closed_details > *:not(summary) *', minimum: 2)
|
|
276
|
+
expect(descendants).not_to include(be_visible)
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
it 'deatils descendants should be visible when open' do
|
|
280
|
+
descendants = @session.all(:css, '#open_details *')
|
|
281
|
+
expect(descendants).to all(be_visible)
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
it 'works when details is toggled open and closed' do
|
|
285
|
+
@session.find(:css, '#closed_details > summary').click
|
|
286
|
+
expect(@session).to have_css('#closed_details *', visible: :visible, count: 5)
|
|
287
|
+
.and(have_no_css('#closed_details *', visible: :hidden))
|
|
288
|
+
|
|
289
|
+
@session.find(:css, '#closed_details > summary').click
|
|
290
|
+
descendants_css = '#closed_details > *:not(summary), #closed_details > *:not(summary) *'
|
|
291
|
+
expect(@session).to have_no_css(descendants_css, visible: :visible)
|
|
292
|
+
.and(have_css(descendants_css, visible: :hidden, count: 3))
|
|
293
|
+
end
|
|
225
294
|
end
|
|
226
295
|
|
|
227
|
-
describe
|
|
228
|
-
it
|
|
296
|
+
describe '#obscured?', requires: [:css] do
|
|
297
|
+
it 'should see non visible elements as obscured' do
|
|
298
|
+
Capybara.ignore_hidden_elements = false
|
|
299
|
+
expect(@session.find('//div[@id="hidden"]')).to be_obscured
|
|
300
|
+
expect(@session.find('//div[@id="hidden_via_ancestor"]')).to be_obscured
|
|
301
|
+
expect(@session.find('//div[@id="hidden_attr"]')).to be_obscured
|
|
302
|
+
expect(@session.find('//a[@id="hidden_attr_via_ancestor"]')).to be_obscured
|
|
303
|
+
expect(@session.find('//input[@id="hidden_input"]')).to be_obscured
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
it 'should see non-overlapped elements as not obscured' do
|
|
307
|
+
@session.visit('/obscured')
|
|
308
|
+
expect(@session.find(:css, '#cover')).not_to be_obscured
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
it 'should see elements only overlapped by descendants as not obscured' do
|
|
312
|
+
expect(@session.first(:css, 'p:not(.para)')).not_to be_obscured
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
it 'should see elements outside the viewport as obscured' do
|
|
316
|
+
@session.visit('/obscured')
|
|
317
|
+
off = @session.find(:css, '#offscreen')
|
|
318
|
+
off_wrapper = @session.find(:css, '#offscreen_wrapper')
|
|
319
|
+
expect(off).to be_obscured
|
|
320
|
+
expect(off_wrapper).to be_obscured
|
|
321
|
+
@session.scroll_to(off_wrapper)
|
|
322
|
+
expect(off_wrapper).not_to be_obscured
|
|
323
|
+
expect(off).to be_obscured
|
|
324
|
+
off_wrapper.scroll_to(off)
|
|
325
|
+
expect(off).not_to be_obscured
|
|
326
|
+
expect(off_wrapper).not_to be_obscured
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
it 'should see overlapped elements as obscured' do
|
|
330
|
+
@session.visit('/obscured')
|
|
331
|
+
expect(@session.find(:css, '#obscured')).to be_obscured
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
it 'should be boolean' do
|
|
335
|
+
Capybara.ignore_hidden_elements = false
|
|
336
|
+
expect(@session.first('//a').obscured?).to be false
|
|
337
|
+
expect(@session.find('//div[@id="hidden"]').obscured?).to be true
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
it 'should work in frames' do
|
|
341
|
+
@session.visit('/obscured')
|
|
342
|
+
frame = @session.find(:css, '#frameOne')
|
|
343
|
+
@session.within_frame(frame) do
|
|
344
|
+
div = @session.find(:css, '#divInFrameOne')
|
|
345
|
+
expect(div).to be_obscured
|
|
346
|
+
@session.scroll_to div
|
|
347
|
+
expect(div).not_to be_obscured
|
|
348
|
+
end
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
it 'should work in nested iframes' do
|
|
352
|
+
@session.visit('/obscured')
|
|
353
|
+
frame = @session.find(:css, '#nestedFrames')
|
|
354
|
+
@session.within_frame(frame) do
|
|
355
|
+
@session.within_frame(:css, '#childFrame') do
|
|
356
|
+
gcframe = @session.find(:css, '#grandchildFrame2')
|
|
357
|
+
@session.within_frame(gcframe) do
|
|
358
|
+
expect(@session.find(:css, '#divInFrameTwo')).to be_obscured
|
|
359
|
+
end
|
|
360
|
+
@session.scroll_to(gcframe)
|
|
361
|
+
@session.within_frame(gcframe) do
|
|
362
|
+
expect(@session.find(:css, '#divInFrameTwo')).not_to be_obscured
|
|
363
|
+
end
|
|
364
|
+
end
|
|
365
|
+
end
|
|
366
|
+
end
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
describe '#checked?' do
|
|
370
|
+
it 'should extract node checked state' do
|
|
229
371
|
@session.visit('/form')
|
|
230
372
|
expect(@session.find('//input[@id="gender_female"]')).to be_checked
|
|
231
373
|
expect(@session.find('//input[@id="gender_male"]')).not_to be_checked
|
|
232
374
|
expect(@session.first('//h1')).not_to be_checked
|
|
233
375
|
end
|
|
234
376
|
|
|
235
|
-
it
|
|
377
|
+
it 'should be boolean' do
|
|
236
378
|
@session.visit('/form')
|
|
237
379
|
expect(@session.find('//input[@id="gender_female"]').checked?).to be true
|
|
238
380
|
expect(@session.find('//input[@id="gender_male"]').checked?).to be false
|
|
@@ -240,15 +382,15 @@ Capybara::SpecHelper.spec "node" do
|
|
|
240
382
|
end
|
|
241
383
|
end
|
|
242
384
|
|
|
243
|
-
describe
|
|
244
|
-
it
|
|
385
|
+
describe '#selected?' do
|
|
386
|
+
it 'should extract node selected state' do
|
|
245
387
|
@session.visit('/form')
|
|
246
388
|
expect(@session.find('//option[@value="en"]')).to be_selected
|
|
247
389
|
expect(@session.find('//option[@value="sv"]')).not_to be_selected
|
|
248
390
|
expect(@session.first('//h1')).not_to be_selected
|
|
249
391
|
end
|
|
250
392
|
|
|
251
|
-
it
|
|
393
|
+
it 'should be boolean' do
|
|
252
394
|
@session.visit('/form')
|
|
253
395
|
expect(@session.find('//option[@value="en"]').selected?).to be true
|
|
254
396
|
expect(@session.find('//option[@value="sv"]').selected?).to be false
|
|
@@ -256,86 +398,368 @@ Capybara::SpecHelper.spec "node" do
|
|
|
256
398
|
end
|
|
257
399
|
end
|
|
258
400
|
|
|
259
|
-
describe
|
|
260
|
-
it
|
|
261
|
-
expect(@session.find('//h1') == @session.find('//h1')).to be true
|
|
262
|
-
expect(@session.find('//h1') === @session.find('//h1')).to be true
|
|
263
|
-
expect(@session.find('//h1').eql?
|
|
401
|
+
describe '#==' do
|
|
402
|
+
it 'preserve object identity' do
|
|
403
|
+
expect(@session.find('//h1') == @session.find('//h1')).to be true # rubocop:disable Lint/BinaryOperatorWithIdenticalOperands
|
|
404
|
+
expect(@session.find('//h1') === @session.find('//h1')).to be true # rubocop:disable Style/CaseEquality, Lint/BinaryOperatorWithIdenticalOperands
|
|
405
|
+
expect(@session.find('//h1').eql?(@session.find('//h1'))).to be false
|
|
264
406
|
end
|
|
265
407
|
|
|
266
|
-
it
|
|
267
|
-
expect(@session.find('//h1') ==
|
|
408
|
+
it 'returns false for unrelated object' do
|
|
409
|
+
expect(@session.find('//h1') == 'Not Capybara::Node::Base').to be false
|
|
268
410
|
end
|
|
269
411
|
end
|
|
270
412
|
|
|
271
|
-
describe
|
|
413
|
+
describe '#path' do
|
|
272
414
|
# Testing for specific XPaths here doesn't make sense since there
|
|
273
415
|
# are many that can refer to the same element
|
|
274
|
-
before
|
|
416
|
+
before do
|
|
275
417
|
@session.visit('/path')
|
|
276
418
|
end
|
|
277
419
|
|
|
278
|
-
it
|
|
420
|
+
it 'returns xpath which points to itself' do
|
|
279
421
|
element = @session.find(:link, 'Second Link')
|
|
280
422
|
expect(@session.find(:xpath, element.path)).to eq(element)
|
|
281
423
|
end
|
|
424
|
+
|
|
425
|
+
it 'reports when element in shadow dom', requires: [:shadow_dom] do
|
|
426
|
+
@session.visit('/with_js')
|
|
427
|
+
shadow = @session.find(:css, '#shadow')
|
|
428
|
+
element = @session.evaluate_script(<<~JS, shadow)
|
|
429
|
+
(function(root){
|
|
430
|
+
return root.shadowRoot.querySelector('span');
|
|
431
|
+
})(arguments[0])
|
|
432
|
+
JS
|
|
433
|
+
expect(element.path).to eq '(: Shadow DOM element - no XPath :)'
|
|
434
|
+
end
|
|
282
435
|
end
|
|
283
436
|
|
|
284
|
-
describe
|
|
285
|
-
it
|
|
437
|
+
describe '#trigger', requires: %i[js trigger] do
|
|
438
|
+
it 'should allow triggering of custom JS events' do
|
|
286
439
|
@session.visit('/with_js')
|
|
287
440
|
@session.find(:css, '#with_focus_event').trigger(:focus)
|
|
288
441
|
expect(@session).to have_css('#focus_event_triggered')
|
|
289
442
|
end
|
|
290
443
|
end
|
|
291
444
|
|
|
292
|
-
describe '#drag_to', requires: [
|
|
293
|
-
it
|
|
445
|
+
describe '#drag_to', requires: %i[js drag] do
|
|
446
|
+
it 'should drag and drop an object' do
|
|
294
447
|
@session.visit('/with_js')
|
|
295
448
|
element = @session.find('//div[@id="drag"]')
|
|
296
449
|
target = @session.find('//div[@id="drop"]')
|
|
297
450
|
element.drag_to(target)
|
|
298
|
-
expect(@session.
|
|
451
|
+
expect(@session).to have_xpath('//div[contains(., "Dropped!")]')
|
|
299
452
|
end
|
|
300
453
|
|
|
301
|
-
it
|
|
454
|
+
it 'should drag and drop if scrolling is needed' do
|
|
302
455
|
@session.visit('/with_js')
|
|
303
456
|
element = @session.find('//div[@id="drag_scroll"]')
|
|
304
457
|
target = @session.find('//div[@id="drop_scroll"]')
|
|
305
458
|
element.drag_to(target)
|
|
306
|
-
expect(@session.
|
|
459
|
+
expect(@session).to have_xpath('//div[contains(., "Dropped!")]')
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
it 'should drag a link' do
|
|
463
|
+
@session.visit('/with_js')
|
|
464
|
+
link = @session.find_link('drag_link')
|
|
465
|
+
target = @session.find(:id, 'drop')
|
|
466
|
+
link.drag_to target
|
|
467
|
+
expect(@session).to have_xpath('//div[contains(., "Dropped!")]')
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
it 'should work with Dragula' do
|
|
471
|
+
@session.visit('/with_dragula')
|
|
472
|
+
@session.within(:css, '#sortable.ready') do
|
|
473
|
+
src = @session.find('div', text: 'Item 1')
|
|
474
|
+
target = @session.find('div', text: 'Item 3')
|
|
475
|
+
src.drag_to target
|
|
476
|
+
expect(@session).to have_content(/Item 2.*Item 1/, normalize_ws: true)
|
|
477
|
+
end
|
|
478
|
+
end
|
|
479
|
+
|
|
480
|
+
it 'should work with jsTree' do
|
|
481
|
+
@session.visit('/with_jstree')
|
|
482
|
+
@session.within(:css, '#container') do
|
|
483
|
+
@session.assert_text(/A.*B.*C/m)
|
|
484
|
+
source = @session.find(:css, '#j1_1_anchor')
|
|
485
|
+
target = @session.find(:css, '#j1_2_anchor')
|
|
486
|
+
|
|
487
|
+
source.drag_to(target)
|
|
488
|
+
|
|
489
|
+
@session.assert_no_text(/A.*B.*C/m)
|
|
490
|
+
@session.assert_text(/B.*C/m)
|
|
491
|
+
end
|
|
492
|
+
end
|
|
493
|
+
|
|
494
|
+
it 'should simulate a single held down modifier key' do
|
|
495
|
+
%I[
|
|
496
|
+
alt
|
|
497
|
+
ctrl
|
|
498
|
+
meta
|
|
499
|
+
shift
|
|
500
|
+
].each do |modifier_key|
|
|
501
|
+
@session.visit('/with_js')
|
|
502
|
+
|
|
503
|
+
element = @session.find('//div[@id="drag"]')
|
|
504
|
+
target = @session.find('//div[@id="drop"]')
|
|
505
|
+
|
|
506
|
+
element.drag_to(target, drop_modifiers: modifier_key)
|
|
507
|
+
expect(@session).to have_css('div.drag_start', exact_text: 'Dragged!')
|
|
508
|
+
expect(@session).to have_xpath("//div[contains(., 'Dropped!-#{modifier_key}')]")
|
|
509
|
+
end
|
|
510
|
+
end
|
|
511
|
+
|
|
512
|
+
it 'should simulate multiple held down modifier keys' do
|
|
513
|
+
@session.visit('/with_js')
|
|
514
|
+
|
|
515
|
+
element = @session.find('//div[@id="drag"]')
|
|
516
|
+
target = @session.find('//div[@id="drop"]')
|
|
517
|
+
|
|
518
|
+
modifier_keys = %I[alt ctrl meta shift]
|
|
519
|
+
|
|
520
|
+
element.drag_to(target, drop_modifiers: modifier_keys)
|
|
521
|
+
expect(@session).to have_xpath("//div[contains(., 'Dropped!-#{modifier_keys.join('-')}')]")
|
|
522
|
+
end
|
|
523
|
+
|
|
524
|
+
it 'should support key aliases' do
|
|
525
|
+
{ control: :ctrl,
|
|
526
|
+
command: :meta,
|
|
527
|
+
cmd: :meta }.each do |(key_alias, key)|
|
|
528
|
+
@session.visit('/with_js')
|
|
529
|
+
|
|
530
|
+
element = @session.find('//div[@id="drag"]')
|
|
531
|
+
target = @session.find('//div[@id="drop"]')
|
|
532
|
+
|
|
533
|
+
element.drag_to(target, drop_modifiers: [key_alias])
|
|
534
|
+
expect(target).to have_text("Dropped!-#{key}", exact: true)
|
|
535
|
+
end
|
|
536
|
+
end
|
|
537
|
+
|
|
538
|
+
context 'HTML5', requires: %i[js html5_drag] do
|
|
539
|
+
it 'should HTML5 drag and drop an object' do
|
|
540
|
+
@session.visit('/with_js')
|
|
541
|
+
element = @session.find('//div[@id="drag_html5"]')
|
|
542
|
+
target = @session.find('//div[@id="drop_html5"]')
|
|
543
|
+
element.drag_to(target)
|
|
544
|
+
expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped string: text/plain drag_html5")]')
|
|
545
|
+
end
|
|
546
|
+
|
|
547
|
+
it 'should HTML5 drag and drop an object child' do
|
|
548
|
+
@session.visit('/with_js')
|
|
549
|
+
element = @session.find('//div[@id="drag_html5"]/p')
|
|
550
|
+
target = @session.find('//div[@id="drop_html5"]')
|
|
551
|
+
element.drag_to(target)
|
|
552
|
+
expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped string: text/plain drag_html5")]')
|
|
553
|
+
end
|
|
554
|
+
|
|
555
|
+
it 'should set clientX/Y in dragover events' do
|
|
556
|
+
@session.visit('/with_js')
|
|
557
|
+
element = @session.find('//div[@id="drag_html5"]')
|
|
558
|
+
target = @session.find('//div[@id="drop_html5"]')
|
|
559
|
+
element.drag_to(target)
|
|
560
|
+
expect(@session).to have_css('div.log', text: /DragOver with client position: [1-9]\d*,[1-9]\d*/, count: 2)
|
|
561
|
+
end
|
|
562
|
+
|
|
563
|
+
it 'should preserve clientX/Y from last dragover event' do
|
|
564
|
+
@session.visit('/with_js')
|
|
565
|
+
element = @session.find('//div[@id="drag_html5"]')
|
|
566
|
+
target = @session.find('//div[@id="drop_html5"]')
|
|
567
|
+
element.drag_to(target)
|
|
568
|
+
|
|
569
|
+
conditions = %w[DragLeave Drop DragEnd].map do |text|
|
|
570
|
+
have_css('div.log', text: text)
|
|
571
|
+
end
|
|
572
|
+
expect(@session).to(conditions.reduce { |memo, cond| memo.and(cond) })
|
|
573
|
+
|
|
574
|
+
# The first "DragOver" div is inserted by the last dragover event dispatched
|
|
575
|
+
drag_over_div = @session.first('//div[@class="log" and starts-with(text(), "DragOver")]')
|
|
576
|
+
position = drag_over_div.text.sub('DragOver ', '')
|
|
577
|
+
|
|
578
|
+
expect(@session).to have_css('div.log', text: /DragLeave #{position}/, count: 1)
|
|
579
|
+
expect(@session).to have_css('div.log', text: /Drop #{position}/, count: 1)
|
|
580
|
+
expect(@session).to have_css('div.log', text: /DragEnd #{position}/, count: 1)
|
|
581
|
+
end
|
|
582
|
+
|
|
583
|
+
it 'should not HTML5 drag and drop on a non HTML5 drop element' do
|
|
584
|
+
@session.visit('/with_js')
|
|
585
|
+
element = @session.find('//div[@id="drag_html5"]')
|
|
586
|
+
target = @session.find('//div[@id="drop_html5"]')
|
|
587
|
+
target.execute_script("$(this).removeClass('drop');")
|
|
588
|
+
element.drag_to(target)
|
|
589
|
+
sleep 1
|
|
590
|
+
expect(@session).not_to have_xpath('//div[contains(., "HTML5 Dropped")]')
|
|
591
|
+
end
|
|
592
|
+
|
|
593
|
+
it 'should HTML5 drag and drop when scrolling needed' do
|
|
594
|
+
@session.visit('/with_js')
|
|
595
|
+
element = @session.find('//div[@id="drag_html5_scroll"]')
|
|
596
|
+
target = @session.find('//div[@id="drop_html5_scroll"]')
|
|
597
|
+
element.drag_to(target)
|
|
598
|
+
expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped string: text/plain drag_html5_scroll")]')
|
|
599
|
+
end
|
|
600
|
+
|
|
601
|
+
it 'should drag HTML5 default draggable elements' do
|
|
602
|
+
@session.visit('/with_js')
|
|
603
|
+
link = @session.find_link('drag_link_html5')
|
|
604
|
+
target = @session.find(:id, 'drop_html5')
|
|
605
|
+
link.drag_to target
|
|
606
|
+
expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped")]')
|
|
607
|
+
end
|
|
608
|
+
|
|
609
|
+
it 'should work with SortableJS' do
|
|
610
|
+
@session.visit('/with_sortable_js')
|
|
611
|
+
@session.within(:css, '#sortable') do
|
|
612
|
+
src = @session.find('div', text: 'Item 1')
|
|
613
|
+
target = @session.find('div', text: 'Item 3')
|
|
614
|
+
src.drag_to target
|
|
615
|
+
expect(@session).to have_content(/Item 3.*Item 1/, normalize_ws: true)
|
|
616
|
+
end
|
|
617
|
+
end
|
|
618
|
+
|
|
619
|
+
it 'should drag HTML5 default draggable element child' do
|
|
620
|
+
@session.visit('/with_js')
|
|
621
|
+
source = @session.find_link('drag_link_html5').find(:css, 'p')
|
|
622
|
+
target = @session.find(:id, 'drop_html5')
|
|
623
|
+
source.drag_to target
|
|
624
|
+
expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped")]')
|
|
625
|
+
end
|
|
626
|
+
|
|
627
|
+
it 'should simulate a single held down modifier key' do
|
|
628
|
+
%I[alt ctrl meta shift].each do |modifier_key|
|
|
629
|
+
@session.visit('/with_js')
|
|
630
|
+
|
|
631
|
+
element = @session.find('//div[@id="drag_html5"]')
|
|
632
|
+
target = @session.find('//div[@id="drop_html5"]')
|
|
633
|
+
|
|
634
|
+
element.drag_to(target, drop_modifiers: modifier_key)
|
|
635
|
+
|
|
636
|
+
expect(@session).to have_css('div.drag_start', exact_text: 'HTML5 Dragged!')
|
|
637
|
+
expect(@session).to have_xpath("//div[contains(., 'HTML5 Dropped string: text/plain drag_html5-#{modifier_key}')]")
|
|
638
|
+
end
|
|
639
|
+
end
|
|
640
|
+
|
|
641
|
+
it 'should simulate multiple held down modifier keys' do
|
|
642
|
+
@session.visit('/with_js')
|
|
643
|
+
|
|
644
|
+
element = @session.find('//div[@id="drag_html5"]')
|
|
645
|
+
target = @session.find('//div[@id="drop_html5"]')
|
|
646
|
+
|
|
647
|
+
modifier_keys = %I[alt ctrl meta shift]
|
|
648
|
+
|
|
649
|
+
element.drag_to(target, drop_modifiers: modifier_keys)
|
|
650
|
+
expect(@session).to have_xpath("//div[contains(., 'HTML5 Dropped string: text/plain drag_html5-#{modifier_keys.join('-')}')]")
|
|
651
|
+
end
|
|
652
|
+
|
|
653
|
+
it 'should support key aliases' do
|
|
654
|
+
{ control: :ctrl,
|
|
655
|
+
command: :meta,
|
|
656
|
+
cmd: :meta }.each do |(key_alias, key)|
|
|
657
|
+
@session.visit('/with_js')
|
|
658
|
+
|
|
659
|
+
element = @session.find('//div[@id="drag_html5"]')
|
|
660
|
+
target = @session.find('//div[@id="drop_html5"]')
|
|
661
|
+
|
|
662
|
+
element.drag_to(target, drop_modifiers: [key_alias])
|
|
663
|
+
expect(target).to have_text(%r{^HTML5 Dropped string: text/plain drag_html5-#{key}$}m, exact: true)
|
|
664
|
+
end
|
|
665
|
+
end
|
|
666
|
+
|
|
667
|
+
it 'should trigger a dragenter event, before the first dragover event' do
|
|
668
|
+
@session.visit('/with_js')
|
|
669
|
+
element = @session.find('//div[@id="drag_html5"]')
|
|
670
|
+
target = @session.find('//div[@id="drop_html5"]')
|
|
671
|
+
element.drag_to(target)
|
|
672
|
+
|
|
673
|
+
# Events are listed in reverse chronological order
|
|
674
|
+
expect(@session).to have_text(/DragOver.*DragEnter/m)
|
|
675
|
+
end
|
|
676
|
+
end
|
|
677
|
+
end
|
|
678
|
+
|
|
679
|
+
describe 'Element#drop', requires: %i[js html5_drag] do
|
|
680
|
+
it 'can drop a file' do
|
|
681
|
+
@session.visit('/with_js')
|
|
682
|
+
target = @session.find('//div[@id="drop_html5"]')
|
|
683
|
+
target.drop(
|
|
684
|
+
with_os_path_separators(File.expand_path('../fixtures/capybara.jpg', File.dirname(__FILE__)))
|
|
685
|
+
)
|
|
686
|
+
expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped file: capybara.jpg")]')
|
|
687
|
+
end
|
|
688
|
+
|
|
689
|
+
it 'can drop multiple files' do
|
|
690
|
+
@session.visit('/with_js')
|
|
691
|
+
target = @session.find('//div[@id="drop_html5"]')
|
|
692
|
+
target.drop(
|
|
693
|
+
with_os_path_separators(File.expand_path('../fixtures/capybara.jpg', File.dirname(__FILE__))),
|
|
694
|
+
with_os_path_separators(File.expand_path('../fixtures/test_file.txt', File.dirname(__FILE__)))
|
|
695
|
+
)
|
|
696
|
+
expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped file: capybara.jpg")]')
|
|
697
|
+
expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped file: test_file.txt")]')
|
|
698
|
+
end
|
|
699
|
+
|
|
700
|
+
it 'can drop strings' do
|
|
701
|
+
@session.visit('/with_js')
|
|
702
|
+
target = @session.find('//div[@id="drop_html5"]')
|
|
703
|
+
target.drop('text/plain' => 'Some dropped text')
|
|
704
|
+
expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped string: text/plain Some dropped text")]')
|
|
705
|
+
end
|
|
706
|
+
|
|
707
|
+
it 'can drop a pathname' do
|
|
708
|
+
@session.visit('/with_js')
|
|
709
|
+
target = @session.find('//div[@id="drop_html5"]')
|
|
710
|
+
target.drop(
|
|
711
|
+
Pathname.new(with_os_path_separators(File.expand_path('../fixtures/capybara.jpg', File.dirname(__FILE__))))
|
|
712
|
+
)
|
|
713
|
+
expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped file: capybara.jpg")]')
|
|
714
|
+
end
|
|
715
|
+
|
|
716
|
+
it 'can drop multiple strings' do
|
|
717
|
+
@session.visit('/with_js')
|
|
718
|
+
target = @session.find('//div[@id="drop_html5"]')
|
|
719
|
+
target.drop('text/plain' => 'Some dropped text', 'text/url' => 'http://www.google.com')
|
|
720
|
+
expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped string: text/plain Some dropped text")]')
|
|
721
|
+
expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped string: text/url http://www.google.com")]')
|
|
307
722
|
end
|
|
308
723
|
end
|
|
309
724
|
|
|
310
725
|
describe '#hover', requires: [:hover] do
|
|
311
|
-
it
|
|
726
|
+
it 'should allow hovering on an element' do
|
|
312
727
|
@session.visit('/with_hover')
|
|
313
728
|
expect(@session.find(:css, '.wrapper:not(.scroll_needed) .hidden_until_hover', visible: false)).not_to be_visible
|
|
314
|
-
@session.find(:css,'.wrapper:not(.scroll_needed)').hover
|
|
729
|
+
@session.find(:css, '.wrapper:not(.scroll_needed)').hover
|
|
315
730
|
expect(@session.find(:css, '.wrapper:not(.scroll_needed) .hidden_until_hover', visible: false)).to be_visible
|
|
316
731
|
end
|
|
317
732
|
|
|
318
|
-
it
|
|
733
|
+
it 'should allow hovering on an element that needs to be scrolled into view' do
|
|
319
734
|
@session.visit('/with_hover')
|
|
320
735
|
expect(@session.find(:css, '.wrapper.scroll_needed .hidden_until_hover', visible: false)).not_to be_visible
|
|
321
|
-
@session.find(:css,'.wrapper.scroll_needed').hover
|
|
736
|
+
@session.find(:css, '.wrapper.scroll_needed').hover
|
|
322
737
|
expect(@session.find(:css, '.wrapper.scroll_needed .hidden_until_hover', visible: false)).to be_visible
|
|
323
738
|
end
|
|
739
|
+
|
|
740
|
+
it 'should hover again after following a link and back' do
|
|
741
|
+
@session.visit('/with_hover')
|
|
742
|
+
@session.find(:css, '.wrapper:not(.scroll_needed)').hover
|
|
743
|
+
@session.click_link('Other hover page')
|
|
744
|
+
@session.click_link('Go back')
|
|
745
|
+
@session.find(:css, '.wrapper:not(.scroll_needed)').hover
|
|
746
|
+
expect(@session.find(:css, '.wrapper:not(.scroll_needed) .hidden_until_hover', visible: false)).to be_visible
|
|
747
|
+
end
|
|
324
748
|
end
|
|
325
749
|
|
|
326
750
|
describe '#click' do
|
|
327
|
-
it
|
|
751
|
+
it 'should not follow a link if no href' do
|
|
328
752
|
@session.find(:css, '#link_placeholder').click
|
|
329
753
|
expect(@session.current_url).to match(%r{/with_html$})
|
|
330
754
|
end
|
|
331
755
|
|
|
332
|
-
it
|
|
756
|
+
it 'should go to the same page if href is blank' do
|
|
333
757
|
@session.find(:css, '#link_blank_href').click
|
|
334
758
|
sleep 1
|
|
335
759
|
expect(@session).to have_current_path('/with_html')
|
|
336
760
|
end
|
|
337
761
|
|
|
338
|
-
it
|
|
762
|
+
it 'should be able to check a checkbox' do
|
|
339
763
|
@session.visit('form')
|
|
340
764
|
cbox = @session.find(:checkbox, 'form_terms_of_use')
|
|
341
765
|
expect(cbox).not_to be_checked
|
|
@@ -343,7 +767,7 @@ Capybara::SpecHelper.spec "node" do
|
|
|
343
767
|
expect(cbox).to be_checked
|
|
344
768
|
end
|
|
345
769
|
|
|
346
|
-
it
|
|
770
|
+
it 'should be able to uncheck a checkbox' do
|
|
347
771
|
@session.visit('/form')
|
|
348
772
|
cbox = @session.find(:checkbox, 'form_pets_dog')
|
|
349
773
|
expect(cbox).to be_checked
|
|
@@ -351,65 +775,523 @@ Capybara::SpecHelper.spec "node" do
|
|
|
351
775
|
expect(cbox).not_to be_checked
|
|
352
776
|
end
|
|
353
777
|
|
|
354
|
-
it
|
|
778
|
+
it 'should be able to select a radio button' do
|
|
355
779
|
@session.visit('/form')
|
|
356
780
|
radio = @session.find(:radio_button, 'gender_male')
|
|
357
781
|
expect(radio).not_to be_checked
|
|
358
782
|
radio.click
|
|
359
783
|
expect(radio).to be_checked
|
|
360
784
|
end
|
|
785
|
+
|
|
786
|
+
it 'should allow modifiers', requires: [:js] do
|
|
787
|
+
@session.visit('/with_js')
|
|
788
|
+
@session.find(:css, '#click-test').click(:shift)
|
|
789
|
+
expect(@session).to have_link('Has been shift clicked')
|
|
790
|
+
end
|
|
791
|
+
|
|
792
|
+
it 'should allow multiple modifiers', requires: [:js] do
|
|
793
|
+
@session.visit('with_js')
|
|
794
|
+
@session.find(:css, '#click-test').click(:control, :alt, :meta, :shift)
|
|
795
|
+
# Selenium with Chrome on OSX ctrl-click generates a right click so just verify all keys but not click type
|
|
796
|
+
expect(@session).to have_link('alt control meta shift')
|
|
797
|
+
end
|
|
798
|
+
|
|
799
|
+
it 'should allow to adjust the click offset', requires: [:js] do
|
|
800
|
+
Capybara.w3c_click_offset = false
|
|
801
|
+
@session.visit('with_js')
|
|
802
|
+
@session.find(:css, '#click-test').click(x: 5, y: 5)
|
|
803
|
+
link = @session.find(:link, 'has-been-clicked')
|
|
804
|
+
locations = link.text.match(/^Has been clicked at (?<x>[\d.-]+),(?<y>[\d.-]+)$/)
|
|
805
|
+
# Resulting click location should be very close to 0, 0 relative to top left corner of the element, but may not be exact due to
|
|
806
|
+
# integer/float conversions and rounding.
|
|
807
|
+
expect(locations[:x].to_f).to be_within(1).of(5)
|
|
808
|
+
expect(locations[:y].to_f).to be_within(1).of(5)
|
|
809
|
+
end
|
|
810
|
+
|
|
811
|
+
it 'should raise error if both x and y values are not passed' do
|
|
812
|
+
@session.visit('with_js')
|
|
813
|
+
el = @session.find(:css, '#click-test')
|
|
814
|
+
expect { el.click(x: 5) }.to raise_error ArgumentError
|
|
815
|
+
expect { el.click(x: nil, y: 3) }.to raise_error ArgumentError
|
|
816
|
+
end
|
|
817
|
+
|
|
818
|
+
it 'should be able to click a table row', requires: [:js] do
|
|
819
|
+
@session.visit('/tables')
|
|
820
|
+
tr = @session.find(:css, '#agent_table tr:first-child').click
|
|
821
|
+
expect(tr).to have_css('label', text: 'Clicked')
|
|
822
|
+
end
|
|
823
|
+
|
|
824
|
+
it 'should retry clicking', requires: [:js] do
|
|
825
|
+
@session.visit('/animated')
|
|
826
|
+
obscured = @session.find(:css, '#obscured')
|
|
827
|
+
@session.execute_script <<~JS
|
|
828
|
+
setTimeout(function(){ $('#cover').hide(); }, 700)
|
|
829
|
+
JS
|
|
830
|
+
expect { obscured.click }.not_to raise_error
|
|
831
|
+
end
|
|
832
|
+
|
|
833
|
+
it 'should allow to retry longer', requires: [:js] do
|
|
834
|
+
@session.visit('/animated')
|
|
835
|
+
obscured = @session.find(:css, '#obscured')
|
|
836
|
+
@session.execute_script <<~JS
|
|
837
|
+
setTimeout(function(){ $('#cover').hide(); }, 3000)
|
|
838
|
+
JS
|
|
839
|
+
expect { obscured.click(wait: 4) }.not_to raise_error
|
|
840
|
+
end
|
|
841
|
+
|
|
842
|
+
it 'should not retry clicking when wait is disabled', requires: [:js] do
|
|
843
|
+
@session.visit('/animated')
|
|
844
|
+
obscured = @session.find(:css, '#obscured')
|
|
845
|
+
@session.execute_script <<~JS
|
|
846
|
+
setTimeout(function(){ $('#cover').hide(); }, 2000)
|
|
847
|
+
JS
|
|
848
|
+
expect { obscured.click(wait: 0) }.to(raise_error { |e| expect(e).to be_an_invalid_element_error(@session) })
|
|
849
|
+
end
|
|
850
|
+
|
|
851
|
+
context 'offset', requires: [:js] do
|
|
852
|
+
before do
|
|
853
|
+
@session.visit('/offset')
|
|
854
|
+
end
|
|
855
|
+
|
|
856
|
+
let :clicker do
|
|
857
|
+
@session.find(:id, 'clicker')
|
|
858
|
+
end
|
|
859
|
+
|
|
860
|
+
context 'when w3c_click_offset is false' do
|
|
861
|
+
before do
|
|
862
|
+
Capybara.w3c_click_offset = false
|
|
863
|
+
end
|
|
864
|
+
|
|
865
|
+
it 'should offset from top left of element' do
|
|
866
|
+
clicker.click(x: 10, y: 5)
|
|
867
|
+
expect(@session).to have_text(/clicked at 110,105/)
|
|
868
|
+
end
|
|
869
|
+
|
|
870
|
+
it 'should offset outside the element' do
|
|
871
|
+
clicker.click(x: -15, y: -10)
|
|
872
|
+
expect(@session).to have_text(/clicked at 85,90/)
|
|
873
|
+
end
|
|
874
|
+
|
|
875
|
+
it 'should default to click the middle' do
|
|
876
|
+
clicker.click
|
|
877
|
+
expect(@session).to have_text(/clicked at 150,150/)
|
|
878
|
+
end
|
|
879
|
+
end
|
|
880
|
+
|
|
881
|
+
context 'when w3c_click_offset is true' do
|
|
882
|
+
before do
|
|
883
|
+
Capybara.w3c_click_offset = true
|
|
884
|
+
end
|
|
885
|
+
|
|
886
|
+
it 'should offset from center of element' do
|
|
887
|
+
clicker.click(x: 10, y: 5)
|
|
888
|
+
expect(@session).to have_text(/clicked at 160,155/)
|
|
889
|
+
end
|
|
890
|
+
|
|
891
|
+
it 'should offset outside from center of element' do
|
|
892
|
+
clicker.click(x: -65, y: -60)
|
|
893
|
+
expect(@session).to have_text(/clicked at 85,90/)
|
|
894
|
+
end
|
|
895
|
+
|
|
896
|
+
it 'should default to click the middle' do
|
|
897
|
+
clicker.click
|
|
898
|
+
expect(@session).to have_text(/clicked at 150,150/)
|
|
899
|
+
end
|
|
900
|
+
end
|
|
901
|
+
end
|
|
902
|
+
|
|
903
|
+
context 'delay', requires: [:js] do
|
|
904
|
+
it 'should delay the mouse up' do
|
|
905
|
+
@session.visit('with_js')
|
|
906
|
+
@session.find(:css, '#click-test').click(delay: 2)
|
|
907
|
+
delay = @session.evaluate_script('window.click_delay')
|
|
908
|
+
expect(delay).to be >= 2
|
|
909
|
+
end
|
|
910
|
+
end
|
|
361
911
|
end
|
|
362
912
|
|
|
363
913
|
describe '#double_click', requires: [:js] do
|
|
364
|
-
it
|
|
365
|
-
pending "selenium-webdriver/geckodriver doesn't generate double click event" if marionette?(@session)
|
|
914
|
+
it 'should double click an element' do
|
|
366
915
|
@session.visit('/with_js')
|
|
367
916
|
@session.find(:css, '#click-test').double_click
|
|
368
|
-
expect(@session.find(:css, '#has-been-double-clicked')).to
|
|
917
|
+
expect(@session.find(:css, '#has-been-double-clicked')).to be_truthy
|
|
918
|
+
end
|
|
919
|
+
|
|
920
|
+
it 'should allow modifiers', requires: [:js] do
|
|
921
|
+
@session.visit('/with_js')
|
|
922
|
+
@session.find(:css, '#click-test').double_click(:alt)
|
|
923
|
+
expect(@session).to have_link('Has been alt double clicked')
|
|
924
|
+
end
|
|
925
|
+
|
|
926
|
+
it 'should allow to adjust the offset', requires: [:js] do
|
|
927
|
+
Capybara.w3c_click_offset = false
|
|
928
|
+
@session.visit('with_js')
|
|
929
|
+
@session.find(:css, '#click-test').double_click(x: 10, y: 5)
|
|
930
|
+
link = @session.find(:link, 'has-been-double-clicked')
|
|
931
|
+
locations = link.text.match(/^Has been double clicked at (?<x>[\d.-]+),(?<y>[\d.-]+)$/)
|
|
932
|
+
# Resulting click location should be very close to 10, 5 relative to top left corner of the element, but may not be exact due
|
|
933
|
+
# to integer/float conversions and rounding.
|
|
934
|
+
expect(locations[:x].to_f).to be_within(1).of(10)
|
|
935
|
+
expect(locations[:y].to_f).to be_within(1).of(5)
|
|
936
|
+
end
|
|
937
|
+
|
|
938
|
+
it 'should retry clicking', requires: [:js] do
|
|
939
|
+
@session.visit('/animated')
|
|
940
|
+
obscured = @session.find(:css, '#obscured')
|
|
941
|
+
@session.execute_script <<~JS
|
|
942
|
+
setTimeout(function(){ $('#cover').hide(); }, 700)
|
|
943
|
+
JS
|
|
944
|
+
expect { obscured.double_click }.not_to raise_error
|
|
945
|
+
end
|
|
946
|
+
|
|
947
|
+
context 'offset', requires: [:js] do
|
|
948
|
+
before do
|
|
949
|
+
@session.visit('/offset')
|
|
950
|
+
end
|
|
951
|
+
|
|
952
|
+
let :clicker do
|
|
953
|
+
@session.find(:id, 'clicker')
|
|
954
|
+
end
|
|
955
|
+
|
|
956
|
+
context 'when w3c_click_offset is false' do
|
|
957
|
+
before do
|
|
958
|
+
Capybara.w3c_click_offset = false
|
|
959
|
+
end
|
|
960
|
+
|
|
961
|
+
it 'should offset from top left of element' do
|
|
962
|
+
clicker.double_click(x: 10, y: 5)
|
|
963
|
+
expect(@session).to have_text(/clicked at 110,105/)
|
|
964
|
+
end
|
|
965
|
+
|
|
966
|
+
it 'should offset outside the element' do
|
|
967
|
+
clicker.double_click(x: -15, y: -10)
|
|
968
|
+
expect(@session).to have_text(/clicked at 85,90/)
|
|
969
|
+
end
|
|
970
|
+
|
|
971
|
+
it 'should default to click the middle' do
|
|
972
|
+
clicker.double_click
|
|
973
|
+
expect(@session).to have_text(/clicked at 150,150/)
|
|
974
|
+
end
|
|
975
|
+
end
|
|
976
|
+
|
|
977
|
+
context 'when w3c_click_offset is true' do
|
|
978
|
+
before do
|
|
979
|
+
Capybara.w3c_click_offset = true
|
|
980
|
+
end
|
|
981
|
+
|
|
982
|
+
it 'should offset from center of element' do
|
|
983
|
+
clicker.double_click(x: 10, y: 5)
|
|
984
|
+
expect(@session).to have_text(/clicked at 160,155/)
|
|
985
|
+
end
|
|
986
|
+
|
|
987
|
+
it 'should offset outside from center of element' do
|
|
988
|
+
clicker.double_click(x: -65, y: -60)
|
|
989
|
+
expect(@session).to have_text(/clicked at 85,90/)
|
|
990
|
+
end
|
|
991
|
+
|
|
992
|
+
it 'should default to click the middle' do
|
|
993
|
+
clicker.double_click
|
|
994
|
+
expect(@session).to have_text(/clicked at 150,150/)
|
|
995
|
+
end
|
|
996
|
+
end
|
|
369
997
|
end
|
|
370
998
|
end
|
|
371
999
|
|
|
372
1000
|
describe '#right_click', requires: [:js] do
|
|
373
|
-
it
|
|
1001
|
+
it 'should right click an element' do
|
|
374
1002
|
@session.visit('/with_js')
|
|
375
1003
|
@session.find(:css, '#click-test').right_click
|
|
376
|
-
expect(@session.find(:css, '#has-been-right-clicked')).to
|
|
1004
|
+
expect(@session.find(:css, '#has-been-right-clicked')).to be_truthy
|
|
1005
|
+
end
|
|
1006
|
+
|
|
1007
|
+
it 'should allow modifiers', requires: [:js] do
|
|
1008
|
+
@session.visit('/with_js')
|
|
1009
|
+
@session.find(:css, '#click-test').right_click(:meta)
|
|
1010
|
+
expect(@session).to have_link('Has been meta right clicked')
|
|
1011
|
+
end
|
|
1012
|
+
|
|
1013
|
+
it 'should allow to adjust the offset', requires: [:js] do
|
|
1014
|
+
Capybara.w3c_click_offset = false
|
|
1015
|
+
@session.visit('with_js')
|
|
1016
|
+
@session.find(:css, '#click-test').right_click(x: 10, y: 10)
|
|
1017
|
+
link = @session.find(:link, 'has-been-right-clicked')
|
|
1018
|
+
locations = link.text.match(/^Has been right clicked at (?<x>[\d.-]+),(?<y>[\d.-]+)$/)
|
|
1019
|
+
# Resulting click location should be very close to 10, 10 relative to top left corner of the element, but may not be exact due
|
|
1020
|
+
# to integer/float conversions and rounding
|
|
1021
|
+
expect(locations[:x].to_f).to be_within(1).of(10)
|
|
1022
|
+
expect(locations[:y].to_f).to be_within(1).of(10)
|
|
1023
|
+
end
|
|
1024
|
+
|
|
1025
|
+
it 'should retry clicking', requires: [:js] do
|
|
1026
|
+
@session.visit('/animated')
|
|
1027
|
+
obscured = @session.find(:css, '#obscured')
|
|
1028
|
+
@session.execute_script <<~JS
|
|
1029
|
+
setTimeout(function(){ $('#cover').hide(); }, 700)
|
|
1030
|
+
JS
|
|
1031
|
+
expect { obscured.right_click }.not_to raise_error
|
|
1032
|
+
end
|
|
1033
|
+
|
|
1034
|
+
context 'offset', requires: [:js] do
|
|
1035
|
+
before do
|
|
1036
|
+
@session.visit('/offset')
|
|
1037
|
+
end
|
|
1038
|
+
|
|
1039
|
+
let :clicker do
|
|
1040
|
+
@session.find(:id, 'clicker')
|
|
1041
|
+
end
|
|
1042
|
+
|
|
1043
|
+
context 'when w3c_click_offset is false' do
|
|
1044
|
+
before do
|
|
1045
|
+
Capybara.w3c_click_offset = false
|
|
1046
|
+
end
|
|
1047
|
+
|
|
1048
|
+
it 'should offset from top left of element' do
|
|
1049
|
+
clicker.right_click(x: 10, y: 5)
|
|
1050
|
+
expect(@session).to have_text(/clicked at 110,105/)
|
|
1051
|
+
end
|
|
1052
|
+
|
|
1053
|
+
it 'should offset outside the element' do
|
|
1054
|
+
clicker.right_click(x: -15, y: -10)
|
|
1055
|
+
expect(@session).to have_text(/clicked at 85,90/)
|
|
1056
|
+
end
|
|
1057
|
+
|
|
1058
|
+
it 'should default to click the middle' do
|
|
1059
|
+
clicker.right_click
|
|
1060
|
+
expect(@session).to have_text(/clicked at 150,150/)
|
|
1061
|
+
end
|
|
1062
|
+
end
|
|
1063
|
+
|
|
1064
|
+
context 'when w3c_click_offset is true' do
|
|
1065
|
+
before do
|
|
1066
|
+
Capybara.w3c_click_offset = true
|
|
1067
|
+
end
|
|
1068
|
+
|
|
1069
|
+
it 'should offset from center of element' do
|
|
1070
|
+
clicker.right_click(x: 10, y: 5)
|
|
1071
|
+
expect(@session).to have_text(/clicked at 160,155/)
|
|
1072
|
+
end
|
|
1073
|
+
|
|
1074
|
+
it 'should offset outside from center of element' do
|
|
1075
|
+
clicker.right_click(x: -65, y: -60)
|
|
1076
|
+
expect(@session).to have_text(/clicked at 85,90/)
|
|
1077
|
+
end
|
|
1078
|
+
|
|
1079
|
+
it 'should default to click the middle' do
|
|
1080
|
+
clicker.right_click
|
|
1081
|
+
expect(@session).to have_text(/clicked at 150,150/)
|
|
1082
|
+
end
|
|
1083
|
+
end
|
|
1084
|
+
end
|
|
1085
|
+
|
|
1086
|
+
context 'delay', requires: [:js] do
|
|
1087
|
+
it 'should delay the mouse up' do
|
|
1088
|
+
@session.visit('with_js')
|
|
1089
|
+
@session.find(:css, '#click-test').right_click(delay: 2)
|
|
1090
|
+
delay = @session.evaluate_script('window.right_click_delay')
|
|
1091
|
+
expect(delay).to be >= 2
|
|
1092
|
+
end
|
|
377
1093
|
end
|
|
378
1094
|
end
|
|
379
1095
|
|
|
380
1096
|
describe '#send_keys', requires: [:send_keys] do
|
|
381
|
-
it
|
|
1097
|
+
it 'should send a string of keys to an element' do
|
|
382
1098
|
@session.visit('/form')
|
|
383
1099
|
@session.find(:css, '#address1_city').send_keys('Oceanside')
|
|
384
1100
|
expect(@session.find(:css, '#address1_city').value).to eq 'Oceanside'
|
|
385
1101
|
end
|
|
386
1102
|
|
|
387
|
-
it
|
|
388
|
-
pending "selenium-webdriver/geckodriver doesn't support complex sets of characters" if marionette?(@session)
|
|
1103
|
+
it 'should send special characters' do
|
|
389
1104
|
@session.visit('/form')
|
|
390
1105
|
@session.find(:css, '#address1_city').send_keys('Ocean', :space, 'sie', :left, 'd')
|
|
391
1106
|
expect(@session.find(:css, '#address1_city').value).to eq 'Ocean side'
|
|
392
1107
|
end
|
|
393
1108
|
|
|
394
|
-
it
|
|
395
|
-
pending "selenium-webdriver/geckodriver doesn't support complex sets of characters" if marionette?(@session)
|
|
1109
|
+
it 'should allow for multiple simultaneous keys' do
|
|
396
1110
|
@session.visit('/form')
|
|
397
1111
|
@session.find(:css, '#address1_city').send_keys([:shift, 'o'], 'ceanside')
|
|
398
1112
|
expect(@session.find(:css, '#address1_city').value).to eq 'Oceanside'
|
|
399
1113
|
end
|
|
400
1114
|
|
|
401
|
-
it
|
|
402
|
-
|
|
1115
|
+
it 'should hold modifiers at top level' do
|
|
1116
|
+
@session.visit('/form')
|
|
1117
|
+
@session.find(:css, '#address1_city').send_keys('ocean', :shift, 'side')
|
|
1118
|
+
expect(@session.find(:css, '#address1_city').value).to eq 'oceanSIDE'
|
|
1119
|
+
end
|
|
1120
|
+
|
|
1121
|
+
it 'should generate key events', requires: %i[send_keys js] do
|
|
403
1122
|
@session.visit('/with_js')
|
|
404
|
-
@session.find(:css, '#with-key-events').send_keys([:shift,'t'], [:shift,'w'])
|
|
1123
|
+
@session.find(:css, '#with-key-events').send_keys([:shift, 't'], [:shift, 'w'])
|
|
405
1124
|
expect(@session.find(:css, '#key-events-output')).to have_text('keydown:16 keydown:84 keydown:16 keydown:87')
|
|
406
1125
|
end
|
|
407
1126
|
end
|
|
408
1127
|
|
|
1128
|
+
describe '#execute_script', requires: %i[js es_args] do
|
|
1129
|
+
it 'should execute the given script in the context of the element and return nothing' do
|
|
1130
|
+
@session.visit('/with_js')
|
|
1131
|
+
expect(@session.find(:css, '#change').execute_script("this.textContent = 'Funky Doodle'")).to be_nil
|
|
1132
|
+
expect(@session).to have_css('#change', text: 'Funky Doodle')
|
|
1133
|
+
end
|
|
1134
|
+
|
|
1135
|
+
it 'should pass arguments to the script' do
|
|
1136
|
+
@session.visit('/with_js')
|
|
1137
|
+
@session.find(:css, '#change').execute_script('this.textContent = arguments[0]', 'Doodle Funk')
|
|
1138
|
+
expect(@session).to have_css('#change', text: 'Doodle Funk')
|
|
1139
|
+
end
|
|
1140
|
+
end
|
|
1141
|
+
|
|
1142
|
+
describe '#evaluate_script', requires: %i[js es_args] do
|
|
1143
|
+
it 'should evaluate the given script in the context of the element and return whatever it produces' do
|
|
1144
|
+
@session.visit('/with_js')
|
|
1145
|
+
el = @session.find(:css, '#with_change_event')
|
|
1146
|
+
expect(el.evaluate_script('this.value')).to eq('default value')
|
|
1147
|
+
end
|
|
1148
|
+
|
|
1149
|
+
it 'should ignore leading whitespace' do
|
|
1150
|
+
@session.visit('/with_js')
|
|
1151
|
+
expect(@session.find(:css, '#change').evaluate_script('
|
|
1152
|
+
2 + 3
|
|
1153
|
+
')).to eq 5
|
|
1154
|
+
end
|
|
1155
|
+
|
|
1156
|
+
it 'should pass arguments to the script' do
|
|
1157
|
+
@session.visit('/with_js')
|
|
1158
|
+
@session.find(:css, '#change').evaluate_script('this.textContent = arguments[0]', 'Doodle Funk')
|
|
1159
|
+
expect(@session).to have_css('#change', text: 'Doodle Funk')
|
|
1160
|
+
end
|
|
1161
|
+
|
|
1162
|
+
it 'should pass multiple arguments' do
|
|
1163
|
+
@session.visit('/with_js')
|
|
1164
|
+
change = @session.find(:css, '#change')
|
|
1165
|
+
expect(change.evaluate_script('arguments[0] + arguments[1]', 2, 3)).to eq 5
|
|
1166
|
+
end
|
|
1167
|
+
|
|
1168
|
+
it 'should support returning elements' do
|
|
1169
|
+
@session.visit('/with_js')
|
|
1170
|
+
change = @session.find(:css, '#change') # ensure page has loaded and element is available
|
|
1171
|
+
el = change.evaluate_script('this')
|
|
1172
|
+
expect(el).to be_instance_of(Capybara::Node::Element)
|
|
1173
|
+
expect(el).to eq(change)
|
|
1174
|
+
end
|
|
1175
|
+
|
|
1176
|
+
it 'should support multiple statements via IIFE' do
|
|
1177
|
+
@session.visit('/with_js')
|
|
1178
|
+
change = @session.find(:css, '#change') # ensure page has loaded and element is available
|
|
1179
|
+
res = change.evaluate_script(<<~JS, 3)
|
|
1180
|
+
(function(n){
|
|
1181
|
+
var el = this;
|
|
1182
|
+
return [el, n];
|
|
1183
|
+
}).apply(this, arguments)
|
|
1184
|
+
JS
|
|
1185
|
+
expect(res).to eq [change, 3]
|
|
1186
|
+
end
|
|
1187
|
+
end
|
|
1188
|
+
|
|
1189
|
+
describe '#evaluate_async_script', requires: %i[js es_args] do
|
|
1190
|
+
it 'should evaluate the given script in the context of the element' do
|
|
1191
|
+
@session.visit('/with_js')
|
|
1192
|
+
el = @session.find(:css, '#with_change_event')
|
|
1193
|
+
expect(el.evaluate_async_script('arguments[0](this.value)')).to eq('default value')
|
|
1194
|
+
end
|
|
1195
|
+
|
|
1196
|
+
it 'should support returning elements after asynchronous operation' do
|
|
1197
|
+
@session.visit('/with_js')
|
|
1198
|
+
change = @session.find(:css, '#change') # ensure page has loaded and element is available
|
|
1199
|
+
el = change.evaluate_async_script('var cb = arguments[0]; setTimeout(function(el){ cb(el) }, 100, this)')
|
|
1200
|
+
expect(el).to eq(change)
|
|
1201
|
+
end
|
|
1202
|
+
end
|
|
1203
|
+
|
|
1204
|
+
describe '#shadow_root', requires: %i[js] do
|
|
1205
|
+
it 'should get the shadow root' do
|
|
1206
|
+
@session.visit('/with_shadow')
|
|
1207
|
+
expect do
|
|
1208
|
+
shadow_root = @session.find(:css, '#shadow_host').shadow_root
|
|
1209
|
+
expect(shadow_root).to be_a(Capybara::Node::Element)
|
|
1210
|
+
end.not_to raise_error
|
|
1211
|
+
end
|
|
1212
|
+
|
|
1213
|
+
it 'should find elements inside the shadow dom using CSS' do
|
|
1214
|
+
@session.visit('/with_shadow')
|
|
1215
|
+
shadow_root = @session.find(:css, '#shadow_host').shadow_root
|
|
1216
|
+
expect(shadow_root).to have_css('#shadow_content', text: 'some text')
|
|
1217
|
+
end
|
|
1218
|
+
|
|
1219
|
+
it 'should find nested shadow roots' do
|
|
1220
|
+
@session.visit('/with_shadow')
|
|
1221
|
+
shadow_root = @session.find(:css, '#shadow_host').shadow_root
|
|
1222
|
+
nested_shadow_root = shadow_root.find(:css, '#nested_shadow_host').shadow_root
|
|
1223
|
+
expect(nested_shadow_root).to have_css('#nested_shadow_content', text: 'nested text')
|
|
1224
|
+
end
|
|
1225
|
+
|
|
1226
|
+
it 'should click on elements' do
|
|
1227
|
+
@session.visit('/with_shadow')
|
|
1228
|
+
shadow_root = @session.find(:css, '#shadow_host').shadow_root
|
|
1229
|
+
checkbox = shadow_root.find(:css, 'input[type="checkbox"]')
|
|
1230
|
+
expect(checkbox).not_to be_checked
|
|
1231
|
+
checkbox.click
|
|
1232
|
+
expect(checkbox).to be_checked
|
|
1233
|
+
end
|
|
1234
|
+
|
|
1235
|
+
it 'should use convenience methods once moved to a descendant of the shadow root' do
|
|
1236
|
+
@session.visit('/with_shadow')
|
|
1237
|
+
shadow_root = @session.find(:css, '#shadow_host').shadow_root
|
|
1238
|
+
descendant = shadow_root.find(:css, '#controls_wrapper')
|
|
1239
|
+
expect do
|
|
1240
|
+
descendant.check('shadow_checkbox')
|
|
1241
|
+
end.not_to raise_error
|
|
1242
|
+
expect(descendant).to have_checked_field('shadow_checkbox')
|
|
1243
|
+
end
|
|
1244
|
+
|
|
1245
|
+
it 'should produce error messages when failing' do
|
|
1246
|
+
@session.visit('/with_shadow')
|
|
1247
|
+
shadow_root = @session.find(:css, '#shadow_host').shadow_root
|
|
1248
|
+
expect do
|
|
1249
|
+
expect(shadow_root).to have_css('#shadow_content', text: 'Not in the document')
|
|
1250
|
+
end.to raise_error(/tag="ShadowRoot"/)
|
|
1251
|
+
end
|
|
1252
|
+
|
|
1253
|
+
it 'should get visible text' do
|
|
1254
|
+
@session.visit('/with_shadow')
|
|
1255
|
+
shadow_root = @session.find(:css, '#shadow_host').shadow_root
|
|
1256
|
+
expect(shadow_root).to have_text('some text scroll.html')
|
|
1257
|
+
end
|
|
1258
|
+
|
|
1259
|
+
it 'should get all text' do
|
|
1260
|
+
@session.visit('/with_shadow')
|
|
1261
|
+
shadow_root = @session.find(:css, '#shadow_host').shadow_root
|
|
1262
|
+
expect(shadow_root).to have_text(:all, 'some text scroll.html')
|
|
1263
|
+
end
|
|
1264
|
+
end
|
|
1265
|
+
|
|
409
1266
|
describe '#reload', requires: [:js] do
|
|
410
|
-
|
|
1267
|
+
it 'should reload elements found via ancestor with CSS' do
|
|
1268
|
+
@session.visit('/with_js')
|
|
1269
|
+
node = @session.find(:css, '#reload-me em').ancestor(:css, 'div')
|
|
1270
|
+
node.reload
|
|
1271
|
+
expect(node[:id]).to eq 'reload-me'
|
|
1272
|
+
end
|
|
1273
|
+
|
|
1274
|
+
it 'should reload elements found via ancestor with XPath' do
|
|
1275
|
+
@session.visit('/with_js')
|
|
1276
|
+
node = @session.find(:css, '#reload-me em').ancestor(:xpath, './/div')
|
|
1277
|
+
node.reload
|
|
1278
|
+
expect(node[:id]).to eq 'reload-me'
|
|
1279
|
+
end
|
|
1280
|
+
|
|
1281
|
+
it 'should reload elements found via sibling' do
|
|
1282
|
+
@session.visit('/with_js')
|
|
1283
|
+
node = @session.find(:css, '#the-list li', text: 'Item 1').sibling(:css, 'li')
|
|
1284
|
+
expect(node.text).to eq 'Item 2'
|
|
1285
|
+
node.reload
|
|
1286
|
+
expect(node.text).to eq 'Item 2'
|
|
1287
|
+
end
|
|
1288
|
+
|
|
1289
|
+
context 'without automatic reload' do
|
|
411
1290
|
before { Capybara.automatic_reload = false }
|
|
412
|
-
|
|
1291
|
+
|
|
1292
|
+
after { Capybara.automatic_reload = true }
|
|
1293
|
+
|
|
1294
|
+
it 'should reload the current context of the node' do
|
|
413
1295
|
@session.visit('/with_js')
|
|
414
1296
|
node = @session.find(:css, '#reload-me')
|
|
415
1297
|
@session.click_link('Reload!')
|
|
@@ -418,7 +1300,7 @@ Capybara::SpecHelper.spec "node" do
|
|
|
418
1300
|
expect(node.text).to eq('has been reloaded')
|
|
419
1301
|
end
|
|
420
1302
|
|
|
421
|
-
it
|
|
1303
|
+
it 'should reload a parent node' do
|
|
422
1304
|
@session.visit('/with_js')
|
|
423
1305
|
node = @session.find(:css, '#reload-me').find(:css, 'em')
|
|
424
1306
|
@session.click_link('Reload!')
|
|
@@ -427,26 +1309,25 @@ Capybara::SpecHelper.spec "node" do
|
|
|
427
1309
|
expect(node.text).to eq('has been reloaded')
|
|
428
1310
|
end
|
|
429
1311
|
|
|
430
|
-
it
|
|
1312
|
+
it 'should not automatically reload' do
|
|
431
1313
|
@session.visit('/with_js')
|
|
432
1314
|
node = @session.find(:css, '#reload-me')
|
|
433
1315
|
@session.click_link('Reload!')
|
|
434
1316
|
sleep(0.3)
|
|
435
1317
|
expect do
|
|
436
1318
|
expect(node).to have_text('has been reloaded')
|
|
437
|
-
end.to
|
|
1319
|
+
end.to(raise_error do |error|
|
|
438
1320
|
expect(error).to be_an_invalid_element_error(@session)
|
|
439
|
-
end
|
|
1321
|
+
end)
|
|
440
1322
|
end
|
|
441
|
-
after { Capybara.automatic_reload = true }
|
|
442
1323
|
end
|
|
443
1324
|
|
|
444
|
-
context
|
|
1325
|
+
context 'with automatic reload' do
|
|
445
1326
|
before do
|
|
446
1327
|
Capybara.default_max_wait_time = 4
|
|
447
1328
|
end
|
|
448
1329
|
|
|
449
|
-
it
|
|
1330
|
+
it 'should reload the current context of the node automatically' do
|
|
450
1331
|
@session.visit('/with_js')
|
|
451
1332
|
node = @session.find(:css, '#reload-me')
|
|
452
1333
|
@session.click_link('Reload!')
|
|
@@ -454,7 +1335,7 @@ Capybara::SpecHelper.spec "node" do
|
|
|
454
1335
|
expect(node.text).to eq('has been reloaded')
|
|
455
1336
|
end
|
|
456
1337
|
|
|
457
|
-
it
|
|
1338
|
+
it 'should reload a parent node automatically' do
|
|
458
1339
|
@session.visit('/with_js')
|
|
459
1340
|
node = @session.find(:css, '#reload-me').find(:css, 'em')
|
|
460
1341
|
@session.click_link('Reload!')
|
|
@@ -462,7 +1343,7 @@ Capybara::SpecHelper.spec "node" do
|
|
|
462
1343
|
expect(node.text).to eq('has been reloaded')
|
|
463
1344
|
end
|
|
464
1345
|
|
|
465
|
-
it
|
|
1346
|
+
it 'should reload a node automatically when using find' do
|
|
466
1347
|
@session.visit('/with_js')
|
|
467
1348
|
node = @session.find(:css, '#reload-me')
|
|
468
1349
|
@session.click_link('Reload!')
|
|
@@ -478,19 +1359,15 @@ Capybara::SpecHelper.spec "node" do
|
|
|
478
1359
|
|
|
479
1360
|
expect do
|
|
480
1361
|
expect(node).to have_text('Foo')
|
|
481
|
-
end.to
|
|
482
|
-
expect(error).to be_an_invalid_element_error(@session)
|
|
483
|
-
}
|
|
1362
|
+
end.to(raise_error { |error| expect(error).to be_an_invalid_element_error(@session) })
|
|
484
1363
|
expect do
|
|
485
1364
|
expect(node).to have_text('Bar')
|
|
486
|
-
end.to
|
|
487
|
-
expect(error).to be_an_invalid_element_error(@session)
|
|
488
|
-
}
|
|
1365
|
+
end.to(raise_error { |error| expect(error).to be_an_invalid_element_error(@session) })
|
|
489
1366
|
end
|
|
490
1367
|
|
|
491
|
-
it
|
|
1368
|
+
it 'should reload nodes with options' do
|
|
492
1369
|
@session.visit('/with_js')
|
|
493
|
-
node = @session.find(:css, 'em', text:
|
|
1370
|
+
node = @session.find(:css, 'em', text: 'reloaded')
|
|
494
1371
|
@session.click_link('Reload!')
|
|
495
1372
|
sleep(1)
|
|
496
1373
|
expect(node.text).to eq('has been reloaded')
|
|
@@ -498,31 +1375,25 @@ Capybara::SpecHelper.spec "node" do
|
|
|
498
1375
|
end
|
|
499
1376
|
end
|
|
500
1377
|
|
|
501
|
-
context
|
|
502
|
-
it
|
|
503
|
-
|
|
504
|
-
quietly { @session.visit("/error") }
|
|
1378
|
+
context 'when #synchronize raises server errors' do
|
|
1379
|
+
it 'sets an explanatory exception as the cause of server exceptions', requires: %i[server js] do
|
|
1380
|
+
quietly { @session.visit('/error') }
|
|
505
1381
|
expect do
|
|
506
1382
|
@session.find(:css, 'span')
|
|
507
|
-
end.to
|
|
1383
|
+
end.to(raise_error(TestApp::TestAppError) do |e|
|
|
508
1384
|
expect(e.cause).to be_a Capybara::CapybaraError
|
|
509
1385
|
expect(e.cause.message).to match(/Your application server raised an error/)
|
|
510
|
-
end
|
|
1386
|
+
end)
|
|
511
1387
|
end
|
|
512
1388
|
|
|
513
|
-
it
|
|
514
|
-
|
|
515
|
-
quietly { @session.visit("/other_error") }
|
|
1389
|
+
it 'sets an explanatory exception as the cause of server exceptions with errors with initializers', requires: %i[server js] do
|
|
1390
|
+
quietly { @session.visit('/other_error') }
|
|
516
1391
|
expect do
|
|
517
1392
|
@session.find(:css, 'span')
|
|
518
|
-
end.to
|
|
1393
|
+
end.to(raise_error(TestApp::TestAppOtherError) do |e|
|
|
519
1394
|
expect(e.cause).to be_a Capybara::CapybaraError
|
|
520
1395
|
expect(e.cause.message).to match(/Your application server raised an error/)
|
|
521
|
-
end
|
|
1396
|
+
end)
|
|
522
1397
|
end
|
|
523
1398
|
end
|
|
524
|
-
|
|
525
|
-
def be_an_invalid_element_error(session)
|
|
526
|
-
satisfy { |error| session.driver.invalid_element_errors.any? { |e| error.is_a? e } }
|
|
527
|
-
end
|
|
528
1399
|
end
|