capybara 3.32.2
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 +7 -0
- data/.yardopts +1 -0
- data/History.md +1813 -0
- data/License.txt +22 -0
- data/README.md +1099 -0
- data/lib/capybara.rb +511 -0
- data/lib/capybara/config.rb +94 -0
- data/lib/capybara/cucumber.rb +27 -0
- data/lib/capybara/driver/base.rb +170 -0
- data/lib/capybara/driver/node.rb +139 -0
- data/lib/capybara/dsl.rb +65 -0
- data/lib/capybara/helpers.rb +108 -0
- data/lib/capybara/minitest.rb +386 -0
- data/lib/capybara/minitest/spec.rb +264 -0
- data/lib/capybara/node/actions.rb +420 -0
- data/lib/capybara/node/base.rb +143 -0
- data/lib/capybara/node/document.rb +48 -0
- data/lib/capybara/node/document_matchers.rb +67 -0
- data/lib/capybara/node/element.rb +606 -0
- data/lib/capybara/node/finders.rb +325 -0
- data/lib/capybara/node/matchers.rb +883 -0
- data/lib/capybara/node/simple.rb +208 -0
- data/lib/capybara/queries/ancestor_query.rb +27 -0
- data/lib/capybara/queries/base_query.rb +106 -0
- data/lib/capybara/queries/current_path_query.rb +51 -0
- data/lib/capybara/queries/match_query.rb +26 -0
- data/lib/capybara/queries/selector_query.rb +710 -0
- data/lib/capybara/queries/sibling_query.rb +26 -0
- data/lib/capybara/queries/style_query.rb +45 -0
- data/lib/capybara/queries/text_query.rb +110 -0
- data/lib/capybara/queries/title_query.rb +39 -0
- data/lib/capybara/rack_test/browser.rb +140 -0
- data/lib/capybara/rack_test/css_handlers.rb +13 -0
- data/lib/capybara/rack_test/driver.rb +109 -0
- data/lib/capybara/rack_test/errors.rb +6 -0
- data/lib/capybara/rack_test/form.rb +127 -0
- data/lib/capybara/rack_test/node.rb +325 -0
- data/lib/capybara/rails.rb +16 -0
- data/lib/capybara/registrations/drivers.rb +36 -0
- data/lib/capybara/registrations/patches/puma_ssl.rb +27 -0
- data/lib/capybara/registrations/servers.rb +44 -0
- data/lib/capybara/result.rb +190 -0
- data/lib/capybara/rspec.rb +29 -0
- data/lib/capybara/rspec/features.rb +23 -0
- data/lib/capybara/rspec/matcher_proxies.rb +82 -0
- data/lib/capybara/rspec/matchers.rb +201 -0
- data/lib/capybara/rspec/matchers/base.rb +111 -0
- data/lib/capybara/rspec/matchers/become_closed.rb +33 -0
- data/lib/capybara/rspec/matchers/compound.rb +88 -0
- data/lib/capybara/rspec/matchers/count_sugar.rb +37 -0
- data/lib/capybara/rspec/matchers/have_ancestor.rb +28 -0
- data/lib/capybara/rspec/matchers/have_current_path.rb +29 -0
- data/lib/capybara/rspec/matchers/have_selector.rb +77 -0
- data/lib/capybara/rspec/matchers/have_sibling.rb +27 -0
- data/lib/capybara/rspec/matchers/have_text.rb +33 -0
- data/lib/capybara/rspec/matchers/have_title.rb +29 -0
- data/lib/capybara/rspec/matchers/match_selector.rb +27 -0
- data/lib/capybara/rspec/matchers/match_style.rb +38 -0
- data/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
- data/lib/capybara/selector.rb +233 -0
- data/lib/capybara/selector/builders/css_builder.rb +84 -0
- data/lib/capybara/selector/builders/xpath_builder.rb +69 -0
- data/lib/capybara/selector/css.rb +102 -0
- data/lib/capybara/selector/definition.rb +276 -0
- data/lib/capybara/selector/definition/button.rb +51 -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 +27 -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 +46 -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/filter.rb +5 -0
- data/lib/capybara/selector/filter_set.rb +124 -0
- data/lib/capybara/selector/filters/base.rb +77 -0
- data/lib/capybara/selector/filters/expression_filter.rb +22 -0
- data/lib/capybara/selector/filters/locator_filter.rb +29 -0
- data/lib/capybara/selector/filters/node_filter.rb +31 -0
- data/lib/capybara/selector/regexp_disassembler.rb +214 -0
- data/lib/capybara/selector/selector.rb +147 -0
- data/lib/capybara/selector/xpath_extensions.rb +17 -0
- 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 +496 -0
- data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +119 -0
- data/lib/capybara/selenium/driver_specializations/edge_driver.rb +126 -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 +78 -0
- data/lib/capybara/selenium/logger_suppressor.rb +34 -0
- data/lib/capybara/selenium/node.rb +610 -0
- data/lib/capybara/selenium/nodes/chrome_node.rb +119 -0
- data/lib/capybara/selenium/nodes/edge_node.rb +104 -0
- data/lib/capybara/selenium/nodes/firefox_node.rb +131 -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 +47 -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.rb +126 -0
- data/lib/capybara/server/animation_disabler.rb +58 -0
- data/lib/capybara/server/checker.rb +44 -0
- data/lib/capybara/server/middleware.rb +69 -0
- data/lib/capybara/session.rb +942 -0
- data/lib/capybara/session/config.rb +124 -0
- data/lib/capybara/session/matchers.rb +87 -0
- data/lib/capybara/spec/fixtures/another_test_file.txt +1 -0
- data/lib/capybara/spec/fixtures/capybara.jpg +3 -0
- data/lib/capybara/spec/fixtures/no_extension +1 -0
- data/lib/capybara/spec/fixtures/test_file.txt +1 -0
- data/lib/capybara/spec/public/jquery-ui.js +13 -0
- data/lib/capybara/spec/public/jquery.js +5 -0
- data/lib/capybara/spec/public/offset.js +6 -0
- data/lib/capybara/spec/public/test.js +268 -0
- data/lib/capybara/spec/session/accept_alert_spec.rb +81 -0
- data/lib/capybara/spec/session/accept_confirm_spec.rb +32 -0
- data/lib/capybara/spec/session/accept_prompt_spec.rb +78 -0
- data/lib/capybara/spec/session/all_spec.rb +278 -0
- data/lib/capybara/spec/session/ancestor_spec.rb +88 -0
- data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +140 -0
- data/lib/capybara/spec/session/assert_current_path_spec.rb +75 -0
- data/lib/capybara/spec/session/assert_selector_spec.rb +143 -0
- data/lib/capybara/spec/session/assert_style_spec.rb +26 -0
- data/lib/capybara/spec/session/assert_text_spec.rb +258 -0
- data/lib/capybara/spec/session/assert_title_spec.rb +93 -0
- data/lib/capybara/spec/session/attach_file_spec.rb +216 -0
- data/lib/capybara/spec/session/body_spec.rb +23 -0
- data/lib/capybara/spec/session/check_spec.rb +235 -0
- data/lib/capybara/spec/session/choose_spec.rb +121 -0
- data/lib/capybara/spec/session/click_button_spec.rb +506 -0
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +129 -0
- data/lib/capybara/spec/session/click_link_spec.rb +229 -0
- data/lib/capybara/spec/session/current_scope_spec.rb +31 -0
- data/lib/capybara/spec/session/current_url_spec.rb +115 -0
- data/lib/capybara/spec/session/dismiss_confirm_spec.rb +36 -0
- data/lib/capybara/spec/session/dismiss_prompt_spec.rb +21 -0
- data/lib/capybara/spec/session/element/assert_match_selector_spec.rb +38 -0
- data/lib/capybara/spec/session/element/match_css_spec.rb +31 -0
- data/lib/capybara/spec/session/element/match_xpath_spec.rb +25 -0
- data/lib/capybara/spec/session/element/matches_selector_spec.rb +120 -0
- data/lib/capybara/spec/session/evaluate_async_script_spec.rb +23 -0
- data/lib/capybara/spec/session/evaluate_script_spec.rb +49 -0
- data/lib/capybara/spec/session/execute_script_spec.rb +28 -0
- data/lib/capybara/spec/session/fill_in_spec.rb +286 -0
- data/lib/capybara/spec/session/find_button_spec.rb +74 -0
- data/lib/capybara/spec/session/find_by_id_spec.rb +33 -0
- data/lib/capybara/spec/session/find_field_spec.rb +113 -0
- data/lib/capybara/spec/session/find_link_spec.rb +70 -0
- data/lib/capybara/spec/session/find_spec.rb +531 -0
- data/lib/capybara/spec/session/first_spec.rb +156 -0
- data/lib/capybara/spec/session/frame/frame_title_spec.rb +23 -0
- data/lib/capybara/spec/session/frame/frame_url_spec.rb +23 -0
- data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +116 -0
- data/lib/capybara/spec/session/frame/within_frame_spec.rb +112 -0
- data/lib/capybara/spec/session/go_back_spec.rb +12 -0
- data/lib/capybara/spec/session/go_forward_spec.rb +14 -0
- data/lib/capybara/spec/session/has_all_selectors_spec.rb +69 -0
- data/lib/capybara/spec/session/has_ancestor_spec.rb +46 -0
- data/lib/capybara/spec/session/has_any_selectors_spec.rb +25 -0
- data/lib/capybara/spec/session/has_button_spec.rb +69 -0
- data/lib/capybara/spec/session/has_css_spec.rb +374 -0
- data/lib/capybara/spec/session/has_current_path_spec.rb +138 -0
- data/lib/capybara/spec/session/has_field_spec.rb +349 -0
- data/lib/capybara/spec/session/has_link_spec.rb +39 -0
- data/lib/capybara/spec/session/has_none_selectors_spec.rb +78 -0
- data/lib/capybara/spec/session/has_select_spec.rb +310 -0
- data/lib/capybara/spec/session/has_selector_spec.rb +202 -0
- data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
- data/lib/capybara/spec/session/has_table_spec.rb +198 -0
- data/lib/capybara/spec/session/has_text_spec.rb +394 -0
- data/lib/capybara/spec/session/has_title_spec.rb +71 -0
- data/lib/capybara/spec/session/has_xpath_spec.rb +149 -0
- data/lib/capybara/spec/session/headers_spec.rb +8 -0
- data/lib/capybara/spec/session/html_spec.rb +47 -0
- data/lib/capybara/spec/session/matches_style_spec.rb +35 -0
- data/lib/capybara/spec/session/node_spec.rb +1292 -0
- data/lib/capybara/spec/session/node_wrapper_spec.rb +39 -0
- data/lib/capybara/spec/session/refresh_spec.rb +33 -0
- data/lib/capybara/spec/session/reset_session_spec.rb +148 -0
- data/lib/capybara/spec/session/response_code_spec.rb +8 -0
- data/lib/capybara/spec/session/save_and_open_page_spec.rb +21 -0
- data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +43 -0
- data/lib/capybara/spec/session/save_page_spec.rb +110 -0
- data/lib/capybara/spec/session/save_screenshot_spec.rb +55 -0
- data/lib/capybara/spec/session/screenshot_spec.rb +18 -0
- data/lib/capybara/spec/session/scroll_spec.rb +117 -0
- data/lib/capybara/spec/session/select_spec.rb +229 -0
- data/lib/capybara/spec/session/selectors_spec.rb +98 -0
- data/lib/capybara/spec/session/sibling_spec.rb +52 -0
- data/lib/capybara/spec/session/source_spec.rb +0 -0
- data/lib/capybara/spec/session/text_spec.rb +74 -0
- data/lib/capybara/spec/session/title_spec.rb +29 -0
- data/lib/capybara/spec/session/uncheck_spec.rb +100 -0
- data/lib/capybara/spec/session/unselect_spec.rb +116 -0
- data/lib/capybara/spec/session/visit_spec.rb +204 -0
- data/lib/capybara/spec/session/window/become_closed_spec.rb +89 -0
- data/lib/capybara/spec/session/window/current_window_spec.rb +28 -0
- data/lib/capybara/spec/session/window/open_new_window_spec.rb +31 -0
- data/lib/capybara/spec/session/window/switch_to_window_spec.rb +132 -0
- data/lib/capybara/spec/session/window/window_opened_by_spec.rb +99 -0
- data/lib/capybara/spec/session/window/window_spec.rb +203 -0
- data/lib/capybara/spec/session/window/windows_spec.rb +34 -0
- data/lib/capybara/spec/session/window/within_window_spec.rb +157 -0
- data/lib/capybara/spec/session/within_spec.rb +199 -0
- data/lib/capybara/spec/spec_helper.rb +134 -0
- data/lib/capybara/spec/test_app.rb +226 -0
- data/lib/capybara/spec/views/animated.erb +49 -0
- data/lib/capybara/spec/views/buttons.erb +5 -0
- data/lib/capybara/spec/views/fieldsets.erb +30 -0
- data/lib/capybara/spec/views/form.erb +685 -0
- data/lib/capybara/spec/views/frame_child.erb +18 -0
- data/lib/capybara/spec/views/frame_one.erb +10 -0
- data/lib/capybara/spec/views/frame_parent.erb +9 -0
- data/lib/capybara/spec/views/frame_two.erb +9 -0
- data/lib/capybara/spec/views/header_links.erb +8 -0
- data/lib/capybara/spec/views/host_links.erb +13 -0
- data/lib/capybara/spec/views/initial_alert.erb +10 -0
- data/lib/capybara/spec/views/obscured.erb +47 -0
- data/lib/capybara/spec/views/offset.erb +32 -0
- data/lib/capybara/spec/views/path.erb +13 -0
- data/lib/capybara/spec/views/popup_one.erb +9 -0
- data/lib/capybara/spec/views/popup_two.erb +9 -0
- data/lib/capybara/spec/views/postback.erb +14 -0
- data/lib/capybara/spec/views/react.erb +45 -0
- data/lib/capybara/spec/views/scroll.erb +20 -0
- data/lib/capybara/spec/views/spatial.erb +31 -0
- data/lib/capybara/spec/views/tables.erb +130 -0
- data/lib/capybara/spec/views/with_animation.erb +74 -0
- data/lib/capybara/spec/views/with_base_tag.erb +11 -0
- data/lib/capybara/spec/views/with_count.erb +8 -0
- data/lib/capybara/spec/views/with_dragula.erb +22 -0
- data/lib/capybara/spec/views/with_fixed_header_footer.erb +17 -0
- data/lib/capybara/spec/views/with_hover.erb +24 -0
- data/lib/capybara/spec/views/with_hover1.erb +10 -0
- data/lib/capybara/spec/views/with_html.erb +208 -0
- data/lib/capybara/spec/views/with_html5_svg.erb +20 -0
- data/lib/capybara/spec/views/with_html_entities.erb +2 -0
- data/lib/capybara/spec/views/with_js.erb +160 -0
- data/lib/capybara/spec/views/with_jstree.erb +26 -0
- data/lib/capybara/spec/views/with_namespace.erb +20 -0
- data/lib/capybara/spec/views/with_scope.erb +42 -0
- data/lib/capybara/spec/views/with_scope_other.erb +6 -0
- data/lib/capybara/spec/views/with_simple_html.erb +2 -0
- data/lib/capybara/spec/views/with_slow_unload.erb +17 -0
- data/lib/capybara/spec/views/with_sortable_js.erb +21 -0
- data/lib/capybara/spec/views/with_title.erb +5 -0
- data/lib/capybara/spec/views/with_unload_alert.erb +14 -0
- data/lib/capybara/spec/views/with_windows.erb +54 -0
- data/lib/capybara/spec/views/within_frames.erb +15 -0
- data/lib/capybara/version.rb +5 -0
- data/lib/capybara/window.rb +146 -0
- data/spec/basic_node_spec.rb +154 -0
- data/spec/capybara_spec.rb +112 -0
- data/spec/css_builder_spec.rb +101 -0
- data/spec/css_splitter_spec.rb +38 -0
- data/spec/dsl_spec.rb +276 -0
- data/spec/filter_set_spec.rb +46 -0
- data/spec/fixtures/capybara.csv +1 -0
- data/spec/fixtures/certificate.pem +25 -0
- data/spec/fixtures/key.pem +27 -0
- data/spec/fixtures/selenium_driver_rspec_failure.rb +13 -0
- data/spec/fixtures/selenium_driver_rspec_success.rb +13 -0
- data/spec/minitest_spec.rb +163 -0
- data/spec/minitest_spec_spec.rb +162 -0
- data/spec/per_session_config_spec.rb +68 -0
- data/spec/rack_test_spec.rb +268 -0
- data/spec/regexp_dissassembler_spec.rb +250 -0
- data/spec/result_spec.rb +196 -0
- data/spec/rspec/features_spec.rb +99 -0
- data/spec/rspec/scenarios_spec.rb +19 -0
- data/spec/rspec/shared_spec_matchers.rb +947 -0
- data/spec/rspec/views_spec.rb +14 -0
- data/spec/rspec_matchers_spec.rb +62 -0
- data/spec/rspec_spec.rb +145 -0
- data/spec/sauce_spec_chrome.rb +43 -0
- data/spec/selector_spec.rb +513 -0
- data/spec/selenium_spec_chrome.rb +188 -0
- data/spec/selenium_spec_chrome_remote.rb +96 -0
- data/spec/selenium_spec_edge.rb +47 -0
- data/spec/selenium_spec_firefox.rb +208 -0
- data/spec/selenium_spec_firefox_remote.rb +80 -0
- data/spec/selenium_spec_ie.rb +150 -0
- data/spec/selenium_spec_safari.rb +148 -0
- data/spec/server_spec.rb +292 -0
- data/spec/session_spec.rb +91 -0
- data/spec/shared_selenium_node.rb +83 -0
- data/spec/shared_selenium_session.rb +476 -0
- data/spec/spec_helper.rb +100 -0
- data/spec/xpath_builder_spec.rb +93 -0
- metadata +753 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
require 'selenium-webdriver'
|
|
5
|
+
require 'shared_selenium_session'
|
|
6
|
+
require 'shared_selenium_node'
|
|
7
|
+
require 'rspec/shared_spec_matchers'
|
|
8
|
+
|
|
9
|
+
def selenium_host
|
|
10
|
+
ENV.fetch('SELENIUM_HOST', '0.0.0.0')
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def selenium_port
|
|
14
|
+
ENV.fetch('SELENIUM_PORT', 4445)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def ensure_selenium_running!
|
|
18
|
+
timer = Capybara::Helpers.timer(expire_in: 20)
|
|
19
|
+
begin
|
|
20
|
+
TCPSocket.open(selenium_host, selenium_port)
|
|
21
|
+
rescue StandardError
|
|
22
|
+
if timer.expired?
|
|
23
|
+
raise 'Selenium is not running. ' \
|
|
24
|
+
"You can run a selenium server easily with: \n" \
|
|
25
|
+
' $ docker-compose up -d selenium_firefox'
|
|
26
|
+
else
|
|
27
|
+
puts 'Waiting for Selenium docker instance...'
|
|
28
|
+
sleep 1
|
|
29
|
+
retry
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
Capybara.register_driver :selenium_firefox_remote do |app|
|
|
35
|
+
ensure_selenium_running!
|
|
36
|
+
|
|
37
|
+
url = "http://#{selenium_host}:#{selenium_port}/wd/hub"
|
|
38
|
+
browser_options = ::Selenium::WebDriver::Firefox::Options.new
|
|
39
|
+
|
|
40
|
+
Capybara::Selenium::Driver.new app,
|
|
41
|
+
browser: :remote,
|
|
42
|
+
desired_capabilities: :firefox,
|
|
43
|
+
options: browser_options,
|
|
44
|
+
url: url
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
FIREFOX_REMOTE_DRIVER = :selenium_firefox_remote
|
|
48
|
+
|
|
49
|
+
module TestSessions
|
|
50
|
+
RemoteFirefox = Capybara::Session.new(FIREFOX_REMOTE_DRIVER, TestApp)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
skipped_tests = %i[response_headers status_code trigger download]
|
|
54
|
+
|
|
55
|
+
Capybara::SpecHelper.run_specs TestSessions::RemoteFirefox, FIREFOX_REMOTE_DRIVER.to_s, capybara_skip: skipped_tests do |example|
|
|
56
|
+
case example.metadata[:full_description]
|
|
57
|
+
when 'Capybara::Session selenium_firefox_remote node #click should allow multiple modifiers'
|
|
58
|
+
skip "Firefox doesn't generate an event for shift+control+click" if firefox_gte?(62, @session)
|
|
59
|
+
when 'Capybara::Session selenium_firefox_remote #accept_prompt should accept the prompt with a blank response when there is a default'
|
|
60
|
+
pending "Geckodriver doesn't set a blank response in FF < 63 - https://bugzilla.mozilla.org/show_bug.cgi?id=1486485" if firefox_lt?(63, @session)
|
|
61
|
+
when 'Capybara::Session selenium_firefox_remote #attach_file with multipart form should fire change once when uploading multiple files from empty'
|
|
62
|
+
pending "FF < 62 doesn't support setting all files at once" if firefox_lt?(62, @session)
|
|
63
|
+
when 'Capybara::Session selenium_firefox_remote #reset_session! removes ALL cookies'
|
|
64
|
+
pending "Geckodriver doesn't provide a way to remove cookies outside the current domain"
|
|
65
|
+
when /#accept_confirm should work with nested modals$/
|
|
66
|
+
# skip because this is timing based and hence flaky when set to pending
|
|
67
|
+
skip 'Broken in FF 63 - https://bugzilla.mozilla.org/show_bug.cgi?id=1487358' if firefox_gte?(63, @session)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
RSpec.describe 'Capybara::Session with remote firefox' do
|
|
72
|
+
include Capybara::SpecHelper
|
|
73
|
+
['Capybara::Session', 'Capybara::Node', Capybara::RSpecMatchers].each do |examples|
|
|
74
|
+
include_examples examples, TestSessions::RemoteFirefox, FIREFOX_REMOTE_DRIVER
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it 'is considered to be firefox' do
|
|
78
|
+
expect(session.driver.browser.browser).to eq :firefox
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
require 'selenium-webdriver'
|
|
5
|
+
require 'shared_selenium_session'
|
|
6
|
+
require 'shared_selenium_node'
|
|
7
|
+
require 'rspec/shared_spec_matchers'
|
|
8
|
+
|
|
9
|
+
# if ENV['CI']
|
|
10
|
+
# if ::Selenium::WebDriver::Service.respond_to? :driver_path=
|
|
11
|
+
# ::Selenium::WebDriver::IE::Service
|
|
12
|
+
# else
|
|
13
|
+
# ::Selenium::WebDriver::IE
|
|
14
|
+
# end.driver_path = 'C:\Tools\WebDriver\IEDriverServer.exe'
|
|
15
|
+
# end
|
|
16
|
+
|
|
17
|
+
def selenium_host
|
|
18
|
+
ENV.fetch('SELENIUM_HOST', '192.168.56.102')
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def selenium_port
|
|
22
|
+
ENV.fetch('SELENIUM_PORT', 4444)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def server_host
|
|
26
|
+
ENV.fetch('SERVER_HOST', '10.24.4.135')
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
Capybara.register_driver :selenium_ie do |app|
|
|
30
|
+
# ::Selenium::WebDriver.logger.level = "debug"
|
|
31
|
+
options = ::Selenium::WebDriver::IE::Options.new
|
|
32
|
+
# options.require_window_focus = true
|
|
33
|
+
# options.add_option("log", {"level": "trace"})
|
|
34
|
+
|
|
35
|
+
if ENV['REMOTE']
|
|
36
|
+
Capybara.server_host = server_host
|
|
37
|
+
|
|
38
|
+
url = "http://#{selenium_host}:#{selenium_port}/wd/hub"
|
|
39
|
+
Capybara::Selenium::Driver.new(app,
|
|
40
|
+
browser: :remote,
|
|
41
|
+
options: options,
|
|
42
|
+
url: url)
|
|
43
|
+
else
|
|
44
|
+
Capybara::Selenium::Driver.new(
|
|
45
|
+
app,
|
|
46
|
+
browser: :ie,
|
|
47
|
+
options: options
|
|
48
|
+
)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
module TestSessions
|
|
53
|
+
SeleniumIE = Capybara::Session.new(:selenium_ie, TestApp)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
TestSessions::SeleniumIE.current_window.resize_to(800, 500)
|
|
57
|
+
|
|
58
|
+
skipped_tests = %i[response_headers status_code trigger modals hover form_attribute windows]
|
|
59
|
+
|
|
60
|
+
Capybara::SpecHelper.log_selenium_driver_version(Selenium::WebDriver::IE) if ENV['CI']
|
|
61
|
+
|
|
62
|
+
TestSessions::SeleniumIE.current_window.resize_to(1600, 1200)
|
|
63
|
+
|
|
64
|
+
Capybara::SpecHelper.run_specs TestSessions::SeleniumIE, 'selenium', capybara_skip: skipped_tests do |example|
|
|
65
|
+
case example.metadata[:full_description]
|
|
66
|
+
when /#refresh it reposts$/
|
|
67
|
+
skip 'IE insists on prompting without providing a way to suppress'
|
|
68
|
+
when /#click_link can download a file$/
|
|
69
|
+
skip 'Not sure how to configure IE for automatic downloading'
|
|
70
|
+
when /#fill_in with Date /
|
|
71
|
+
pending "IE 11 doesn't support date input types"
|
|
72
|
+
when /#click_link_or_button with :disabled option happily clicks on links which incorrectly have the disabled attribute$/
|
|
73
|
+
skip 'IE 11 obeys non-standard disabled attribute on anchor tag'
|
|
74
|
+
when /#right_click should allow modifiers$/
|
|
75
|
+
skip "Windows can't :meta click because :meta triggers start menu"
|
|
76
|
+
when /#click should allow modifiers$/
|
|
77
|
+
pending "Doesn't work with IE for some unknown reason$"
|
|
78
|
+
when /#double_click should allow modifiers$/
|
|
79
|
+
pending "Doesn't work with IE for some unknown reason$"
|
|
80
|
+
when /#click should allow multiple modifiers$/
|
|
81
|
+
skip "Windows can't :meta click because :meta triggers start menu"
|
|
82
|
+
when /#double_click should allow multiple modifiers$/
|
|
83
|
+
skip "Windows can't :alt double click due to being properties shortcut"
|
|
84
|
+
when /#has_css\? should support case insensitive :class and :id options$/
|
|
85
|
+
pending "IE doesn't support case insensitive CSS selectors"
|
|
86
|
+
when /#reset_session! removes ALL cookies$/
|
|
87
|
+
pending "IE driver doesn't provide a way to remove ALL cookies"
|
|
88
|
+
when /#click_button should send button in document order$/
|
|
89
|
+
pending "IE 11 doesn't support the 'form' attribute"
|
|
90
|
+
when /#click_button should follow permanent redirects that maintain method$/
|
|
91
|
+
pending "Window 7 and 8.1 don't support 308 http status code"
|
|
92
|
+
when /#scroll_to can scroll an element to the center of the viewport$/,
|
|
93
|
+
/#scroll_to can scroll an element to the center of the scrolling element$/
|
|
94
|
+
pending " IE doesn't support ScrollToOptions"
|
|
95
|
+
when /#attach_file with multipart form should fire change once for each set of files uploaded$/,
|
|
96
|
+
/#attach_file with multipart form should fire change once when uploading multiple files from empty$/,
|
|
97
|
+
/#attach_file with multipart form should not break when using HTML5 multiple file input uploading multiple files$/
|
|
98
|
+
pending "IE requires all files be uploaded from same directory. Selenium doesn't provide that." if ENV['REMOTE']
|
|
99
|
+
when %r{#attach_file with multipart form should send content type image/jpeg when uploading an image$}
|
|
100
|
+
pending 'IE gets text/plain type for some reason'
|
|
101
|
+
# when /#click should not retry clicking when wait is disabled$/
|
|
102
|
+
# Fixed in IEDriverServer 3.141.0.5
|
|
103
|
+
# pending "IE driver doesn't error when clicking on covered elements, it just clicks the wrong element"
|
|
104
|
+
when /#click should go to the same page if href is blank$/
|
|
105
|
+
pending 'IE treats blank href as a parent request (against HTML spec)'
|
|
106
|
+
when /#attach_file with a block/
|
|
107
|
+
skip 'Hangs IE testing for unknown reason'
|
|
108
|
+
when /drag_to.*HTML5/
|
|
109
|
+
pending "IE doesn't support a DataTransfer constuctor"
|
|
110
|
+
when /template elements should not be visible/
|
|
111
|
+
skip "IE doesn't support template elements"
|
|
112
|
+
when /Element#drop/
|
|
113
|
+
pending "IE doesn't support DataTransfer constructor"
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
RSpec.describe 'Capybara::Session with Internet Explorer', capybara_skip: skipped_tests do # rubocop:disable RSpec/MultipleDescribes
|
|
118
|
+
include Capybara::SpecHelper
|
|
119
|
+
['Capybara::Session', 'Capybara::Node', Capybara::RSpecMatchers].each do |examples|
|
|
120
|
+
include_examples examples, TestSessions::SeleniumIE, :selenium_ie
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
RSpec.describe Capybara::Selenium::Node do
|
|
125
|
+
it '#right_click should allow modifiers' do
|
|
126
|
+
# pending "Actions API doesn't appear to work for this"
|
|
127
|
+
session = TestSessions::SeleniumIE
|
|
128
|
+
session.visit('/with_js')
|
|
129
|
+
el = session.find(:css, '#click-test')
|
|
130
|
+
el.right_click(:control)
|
|
131
|
+
expect(session).to have_link('Has been control right clicked')
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
it '#click should allow multiple modifiers' do
|
|
135
|
+
# pending "Actions API doesn't appear to work for this"
|
|
136
|
+
session = TestSessions::SeleniumIE
|
|
137
|
+
session.visit('with_js')
|
|
138
|
+
# IE triggers system behavior with :meta so can't use those here
|
|
139
|
+
session.find(:css, '#click-test').click(:ctrl, :shift, :alt)
|
|
140
|
+
expect(session).to have_link('Has been alt control shift clicked')
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
it '#double_click should allow modifiers' do
|
|
144
|
+
# pending "Actions API doesn't appear to work for this"
|
|
145
|
+
session = TestSessions::SeleniumIE
|
|
146
|
+
session.visit('/with_js')
|
|
147
|
+
session.find(:css, '#click-test').double_click(:shift)
|
|
148
|
+
expect(session).to have_link('Has been shift double clicked')
|
|
149
|
+
end
|
|
150
|
+
end
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
require 'selenium-webdriver'
|
|
5
|
+
require 'shared_selenium_session'
|
|
6
|
+
require 'shared_selenium_node'
|
|
7
|
+
require 'rspec/shared_spec_matchers'
|
|
8
|
+
|
|
9
|
+
SAFARI_DRIVER = :selenium_safari
|
|
10
|
+
|
|
11
|
+
if ::Selenium::WebDriver::Service.respond_to? :driver_path=
|
|
12
|
+
::Selenium::WebDriver::Safari::Service
|
|
13
|
+
else
|
|
14
|
+
::Selenium::WebDriver::Safari
|
|
15
|
+
end.driver_path = '/Applications/Safari Technology Preview.app/Contents/MacOS/safaridriver'
|
|
16
|
+
|
|
17
|
+
browser_options = ::Selenium::WebDriver::Safari::Options.new
|
|
18
|
+
# browser_options.headless! if ENV['HEADLESS']
|
|
19
|
+
# browser_options.add_option(:w3c, !!ENV['W3C'])
|
|
20
|
+
|
|
21
|
+
Capybara.register_driver :selenium_safari do |app|
|
|
22
|
+
Capybara::Selenium::Driver.new(app, browser: :safari, options: browser_options, timeout: 30).tap do |driver|
|
|
23
|
+
# driver.browser.download_path = Capybara.save_path
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
Capybara.register_driver :selenium_safari_not_clear_storage do |app|
|
|
28
|
+
safari_options = {
|
|
29
|
+
browser: :safari,
|
|
30
|
+
options: browser_options
|
|
31
|
+
}
|
|
32
|
+
Capybara::Selenium::Driver.new(app, safari_options.merge(clear_local_storage: false, clear_session_storage: false))
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
module TestSessions
|
|
36
|
+
Safari = Capybara::Session.new(SAFARI_DRIVER, TestApp)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
skipped_tests = %i[response_headers status_code trigger windows drag]
|
|
40
|
+
|
|
41
|
+
Capybara::SpecHelper.log_selenium_driver_version(Selenium::WebDriver::Safari) if ENV['CI']
|
|
42
|
+
|
|
43
|
+
Capybara::SpecHelper.run_specs TestSessions::Safari, SAFARI_DRIVER.to_s, capybara_skip: skipped_tests do |example|
|
|
44
|
+
case example.metadata[:full_description]
|
|
45
|
+
when /click_link can download a file/
|
|
46
|
+
skip "safaridriver doesn't provide a way to set the download directory"
|
|
47
|
+
when /Capybara::Session selenium_safari Capybara::Window#maximize/
|
|
48
|
+
pending "Safari headless doesn't support maximize" if ENV['HEADLESS']
|
|
49
|
+
when /Capybara::Session selenium_safari #visit without a server/,
|
|
50
|
+
/Capybara::Session selenium_safari #visit with Capybara.app_host set should override server/,
|
|
51
|
+
/Capybara::Session selenium_safari #reset_session! When reuse_server == false raises any standard errors caught inside the server during a second session/
|
|
52
|
+
skip "Safari webdriver doesn't support multiple sessions"
|
|
53
|
+
when /Capybara::Session selenium_safari #click_link with alternative text given to a contained image/,
|
|
54
|
+
'Capybara::Session selenium_safari #click_link_or_button with enable_aria_label should click on link'
|
|
55
|
+
pending 'safaridriver thinks these links are non-interactable for some unknown reason'
|
|
56
|
+
when /Capybara::Session selenium_safari #attach_file with a block can upload by clicking the file input/
|
|
57
|
+
skip "safaridriver doesn't allow clicking on file inputs"
|
|
58
|
+
when /Capybara::Session selenium_safari #within_frame works if the frame is closed/,
|
|
59
|
+
/Capybara::Session selenium_safari #switch_to_frame works if the frame is closed/
|
|
60
|
+
skip 'Safari has a race condition when clicking an element that causes the frame to close. It will sometimes raise a NoSuchFrameError'
|
|
61
|
+
when /Capybara::Session selenium_safari #reset_session! removes ALL cookies/
|
|
62
|
+
skip 'Safari webdriver can only remove cookies for the current domain'
|
|
63
|
+
when /Capybara::Session selenium_safari #refresh it reposts/
|
|
64
|
+
skip "Safari opens an alert that can't be closed"
|
|
65
|
+
when 'Capybara::Session selenium_safari node #double_click should allow to adjust the offset',
|
|
66
|
+
'Capybara::Session selenium_safari node #double_click should double click an element'
|
|
67
|
+
pending "safardriver doesn't generate a double click event"
|
|
68
|
+
when 'Capybara::Session selenium_safari node #click should allow multiple modifiers',
|
|
69
|
+
/Capybara::Session selenium_safari node #(click|right_click|double_click) should allow modifiers/
|
|
70
|
+
pending "safaridriver doesn't take key state into account when clicking"
|
|
71
|
+
when 'Capybara::Session selenium_safari #fill_in on a pre-populated textfield with a reformatting onchange should trigger change when clearing field'
|
|
72
|
+
pending "safardriver clear doesn't generate change event"
|
|
73
|
+
when 'Capybara::Session selenium_safari #go_back should fetch a response from the driver from the previous page',
|
|
74
|
+
'Capybara::Session selenium_safari #go_forward should fetch a response from the driver from the previous page'
|
|
75
|
+
skip 'safaridriver loses the ability to find elements in the document after `go_back`'
|
|
76
|
+
when /drag_to.*HTML5/
|
|
77
|
+
pending "Safari doesn't support"
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
RSpec.describe 'Capybara::Session with safari' do
|
|
82
|
+
include Capybara::SpecHelper
|
|
83
|
+
['Capybara::Session', 'Capybara::Node', Capybara::RSpecMatchers].each do |examples|
|
|
84
|
+
include_examples examples, TestSessions::Safari, SAFARI_DRIVER
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
context 'storage' do
|
|
88
|
+
describe '#reset!' do
|
|
89
|
+
it 'clears storage by default' do
|
|
90
|
+
session = TestSessions::Safari
|
|
91
|
+
session.visit('/with_js')
|
|
92
|
+
session.find(:css, '#set-storage').click
|
|
93
|
+
session.reset!
|
|
94
|
+
session.visit('/with_js')
|
|
95
|
+
expect(session.evaluate_script('Object.keys(localStorage)')).to be_empty
|
|
96
|
+
expect(session.evaluate_script('Object.keys(sessionStorage)')).to be_empty
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it 'does not clear storage when false' do
|
|
100
|
+
skip "Safari webdriver doesn't support multiple sessions"
|
|
101
|
+
session = Capybara::Session.new(:selenium_safari_not_clear_storage, TestApp)
|
|
102
|
+
session.visit('/with_js')
|
|
103
|
+
session.find(:css, '#set-storage').click
|
|
104
|
+
session.reset!
|
|
105
|
+
session.visit('/with_js')
|
|
106
|
+
expect(session.evaluate_script('Object.keys(localStorage)')).not_to be_empty
|
|
107
|
+
expect(session.evaluate_script('Object.keys(sessionStorage)')).not_to be_empty
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
context 'timeout' do
|
|
113
|
+
it 'sets the http client read timeout' do
|
|
114
|
+
expect(TestSessions::Safari.driver.browser.send(:bridge).http.read_timeout).to eq 30
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
describe 'filling in Safari-specific date and time fields with keystrokes' do
|
|
119
|
+
let(:datetime) { Time.new(1983, 6, 19, 6, 30) }
|
|
120
|
+
let(:session) { TestSessions::Safari }
|
|
121
|
+
|
|
122
|
+
before do
|
|
123
|
+
session.visit('/form')
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
it 'should fill in a date input with a String' do
|
|
127
|
+
pending "Safari doesn't support date inputs"
|
|
128
|
+
session.fill_in('form_date', with: '06/19/1983')
|
|
129
|
+
session.click_button('awesome')
|
|
130
|
+
expect(Date.parse(extract_results(session)['date'])).to eq datetime.to_date
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
it 'should fill in a time input with a String' do
|
|
134
|
+
# Safari doesn't support time inputs - so this is just a text input
|
|
135
|
+
session.fill_in('form_time', with: '06:30A')
|
|
136
|
+
session.click_button('awesome')
|
|
137
|
+
results = extract_results(session)['time']
|
|
138
|
+
expect(Time.parse(results).strftime('%r')).to eq datetime.strftime('%r')
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
it 'should fill in a datetime input with a String' do
|
|
142
|
+
pending "Safari doesn't support datetime inputs"
|
|
143
|
+
session.fill_in('form_datetime', with: "06/19/1983\t06:30A")
|
|
144
|
+
session.click_button('awesome')
|
|
145
|
+
expect(Time.parse(extract_results(session)['datetime'])).to eq datetime
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
data/spec/server_spec.rb
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
RSpec.describe Capybara::Server do
|
|
6
|
+
it 'should spool up a rack server' do
|
|
7
|
+
app = proc { |_env| [200, {}, ['Hello Server!']] }
|
|
8
|
+
server = described_class.new(app).boot
|
|
9
|
+
|
|
10
|
+
res = Net::HTTP.start(server.host, server.port) { |http| http.get('/') }
|
|
11
|
+
|
|
12
|
+
expect(res.body).to include('Hello Server')
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it 'should do nothing when no server given' do
|
|
16
|
+
expect do
|
|
17
|
+
described_class.new(nil).boot
|
|
18
|
+
end.not_to raise_error
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'should bind to the specified host' do
|
|
22
|
+
# TODO: travis with jruby in container mode has an issue with this test
|
|
23
|
+
skip 'This platform has an issue with this test' if (ENV['TRAVIS'] && (RUBY_ENGINE == 'jruby')) || Gem.win_platform?
|
|
24
|
+
|
|
25
|
+
begin
|
|
26
|
+
app = proc { |_env| [200, {}, ['Hello Server!']] }
|
|
27
|
+
|
|
28
|
+
Capybara.server_host = '127.0.0.1'
|
|
29
|
+
server = described_class.new(app).boot
|
|
30
|
+
res = Net::HTTP.get(URI("http://127.0.0.1:#{server.port}"))
|
|
31
|
+
expect(res).to eq('Hello Server!')
|
|
32
|
+
|
|
33
|
+
Capybara.server_host = '0.0.0.0'
|
|
34
|
+
server = described_class.new(app).boot
|
|
35
|
+
res = Net::HTTP.get(URI("http://127.0.0.1:#{server.port}"))
|
|
36
|
+
expect(res).to eq('Hello Server!')
|
|
37
|
+
ensure
|
|
38
|
+
Capybara.server_host = nil
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'should use specified port' do
|
|
43
|
+
Capybara.server_port = 22789
|
|
44
|
+
|
|
45
|
+
app = proc { |_env| [200, {}, ['Hello Server!']] }
|
|
46
|
+
server = described_class.new(app).boot
|
|
47
|
+
|
|
48
|
+
res = Net::HTTP.start(server.host, 22789) { |http| http.get('/') }
|
|
49
|
+
expect(res.body).to include('Hello Server')
|
|
50
|
+
|
|
51
|
+
Capybara.server_port = nil
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it 'should use given port' do
|
|
55
|
+
app = proc { |_env| [200, {}, ['Hello Server!']] }
|
|
56
|
+
server = described_class.new(app, port: 22790).boot
|
|
57
|
+
|
|
58
|
+
res = Net::HTTP.start(server.host, 22790) { |http| http.get('/') }
|
|
59
|
+
expect(res.body).to include('Hello Server')
|
|
60
|
+
|
|
61
|
+
Capybara.server_port = nil
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it 'should find an available port' do
|
|
65
|
+
responses = ['Hello Server!', 'Hello Second Server!']
|
|
66
|
+
apps = responses.map do |response|
|
|
67
|
+
proc { |_env| [200, {}, [response]] }
|
|
68
|
+
end
|
|
69
|
+
servers = apps.map { |app| described_class.new(app).boot }
|
|
70
|
+
|
|
71
|
+
servers.each_with_index do |server, idx|
|
|
72
|
+
result = Net::HTTP.start(server.host, server.port) { |http| http.get('/') }
|
|
73
|
+
expect(result.body).to include(responses[idx])
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it 'should handle that getting available ports fails randomly' do
|
|
78
|
+
begin
|
|
79
|
+
# Use a port to force a EADDRINUSE error to be generated
|
|
80
|
+
server = TCPServer.new('0.0.0.0', 0)
|
|
81
|
+
server_port = server.addr[1]
|
|
82
|
+
d_server = instance_double('TCPServer', addr: [nil, server_port, nil, nil], close: nil)
|
|
83
|
+
call_count = 0
|
|
84
|
+
allow(TCPServer).to receive(:new).and_wrap_original do |m, *args|
|
|
85
|
+
begin
|
|
86
|
+
call_count.zero? ? d_server : m.call(*args)
|
|
87
|
+
ensure
|
|
88
|
+
call_count += 1
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
port = described_class.new(Object.new, host: '0.0.0.0').port
|
|
93
|
+
expect(port).not_to eq(server_port)
|
|
94
|
+
ensure
|
|
95
|
+
server&.close
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it 'should return its #base_url' do
|
|
100
|
+
app = proc { |_env| [200, {}, ['Hello Server!']] }
|
|
101
|
+
server = described_class.new(app).boot
|
|
102
|
+
uri = ::Addressable::URI.parse(server.base_url)
|
|
103
|
+
expect(uri.to_hash).to include(scheme: 'http', host: server.host, port: server.port)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
it 'should support SSL' do
|
|
107
|
+
begin
|
|
108
|
+
key = File.join(Dir.pwd, 'spec', 'fixtures', 'key.pem')
|
|
109
|
+
cert = File.join(Dir.pwd, 'spec', 'fixtures', 'certificate.pem')
|
|
110
|
+
Capybara.server = :puma, { Host: "ssl://#{Capybara.server_host}?key=#{key}&cert=#{cert}" }
|
|
111
|
+
app = proc { |_env| [200, {}, ['Hello SSL Server!']] }
|
|
112
|
+
server = described_class.new(app).boot
|
|
113
|
+
|
|
114
|
+
expect do
|
|
115
|
+
Net::HTTP.start(server.host, server.port, max_retries: 0) { |http| http.get('/__identify__') }
|
|
116
|
+
end.to(raise_error do |e|
|
|
117
|
+
expect(e.is_a?(EOFError) || e.is_a?(Net::ReadTimeout)).to be true
|
|
118
|
+
end)
|
|
119
|
+
|
|
120
|
+
res = Net::HTTP.start(server.host, server.port, use_ssl: true, verify_mode: OpenSSL::SSL::VERIFY_NONE) do |https|
|
|
121
|
+
https.get('/')
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
expect(res.body).to include('Hello SSL Server!')
|
|
125
|
+
uri = ::Addressable::URI.parse(server.base_url)
|
|
126
|
+
expect(uri.to_hash).to include(scheme: 'https', host: server.host, port: server.port)
|
|
127
|
+
ensure
|
|
128
|
+
Capybara.server = :default
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
context 'When Capybara.reuse_server is true' do
|
|
133
|
+
let!(:old_reuse_server) { Capybara.reuse_server }
|
|
134
|
+
|
|
135
|
+
before do
|
|
136
|
+
Capybara.reuse_server = true
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
after do
|
|
140
|
+
Capybara.reuse_server = old_reuse_server
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
it 'should use the existing server if it already running' do
|
|
144
|
+
app = proc { |_env| [200, {}, ['Hello Server!']] }
|
|
145
|
+
|
|
146
|
+
servers = Array.new(2) { described_class.new(app).boot }
|
|
147
|
+
|
|
148
|
+
servers.each do |server|
|
|
149
|
+
res = Net::HTTP.start(server.host, server.port) { |http| http.get('/') }
|
|
150
|
+
expect(res.body).to include('Hello Server')
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
expect(servers[0].port).to eq(servers[1].port)
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
it 'detects and waits for all reused server sessions pending requests' do
|
|
157
|
+
done = 0
|
|
158
|
+
|
|
159
|
+
app = proc do |env|
|
|
160
|
+
request = Rack::Request.new(env)
|
|
161
|
+
sleep request.params['wait_time'].to_f
|
|
162
|
+
done += 1
|
|
163
|
+
[200, {}, ['Hello Server!']]
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
server1 = described_class.new(app).boot
|
|
167
|
+
server2 = described_class.new(app).boot
|
|
168
|
+
|
|
169
|
+
expect do
|
|
170
|
+
start_request(server1, 1.0)
|
|
171
|
+
start_request(server2, 3.0)
|
|
172
|
+
server1.wait_for_pending_requests
|
|
173
|
+
end.to change { done }.from(0).to(2)
|
|
174
|
+
expect(server2.send(:pending_requests?)).to eq(false)
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
context 'When Capybara.reuse_server is false' do
|
|
179
|
+
before do
|
|
180
|
+
@old_reuse_server = Capybara.reuse_server
|
|
181
|
+
Capybara.reuse_server = false
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
after do
|
|
185
|
+
Capybara.reuse_server = @old_reuse_server # rubocop:disable RSpec/InstanceVariable
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
it 'should not reuse an already running server' do
|
|
189
|
+
app = proc { |_env| [200, {}, ['Hello Server!']] }
|
|
190
|
+
|
|
191
|
+
servers = Array.new(2) { described_class.new(app).boot }
|
|
192
|
+
|
|
193
|
+
servers.each do |server|
|
|
194
|
+
res = Net::HTTP.start(server.host, server.port) { |http| http.get('/') }
|
|
195
|
+
expect(res.body).to include('Hello Server')
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
expect(servers[0].port).not_to eq(servers[1].port)
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
it 'detects and waits for only one sessions pending requests' do
|
|
202
|
+
done = 0
|
|
203
|
+
|
|
204
|
+
app = proc do |env|
|
|
205
|
+
request = Rack::Request.new(env)
|
|
206
|
+
sleep request.params['wait_time'].to_f
|
|
207
|
+
done += 1
|
|
208
|
+
[200, {}, ['Hello Server!']]
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
server1 = described_class.new(app).boot
|
|
212
|
+
server2 = described_class.new(app).boot
|
|
213
|
+
|
|
214
|
+
expect do
|
|
215
|
+
start_request(server1, 1.0)
|
|
216
|
+
start_request(server2, 3.0)
|
|
217
|
+
server1.wait_for_pending_requests
|
|
218
|
+
end.to change { done }.from(0).to(1)
|
|
219
|
+
expect(server2.send(:pending_requests?)).to eq(true)
|
|
220
|
+
expect do
|
|
221
|
+
server2.wait_for_pending_requests
|
|
222
|
+
end.to change { done }.from(1).to(2)
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
it 'should raise server errors when the server errors before the timeout' do
|
|
227
|
+
begin
|
|
228
|
+
Capybara.register_server :kaboom do
|
|
229
|
+
sleep 0.1
|
|
230
|
+
raise 'kaboom'
|
|
231
|
+
end
|
|
232
|
+
Capybara.server = :kaboom
|
|
233
|
+
|
|
234
|
+
expect do
|
|
235
|
+
described_class.new(proc { |e| }).boot
|
|
236
|
+
end.to raise_error(RuntimeError, 'kaboom')
|
|
237
|
+
ensure
|
|
238
|
+
Capybara.server = :default
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
it 'should raise an error when there are pending requests' do
|
|
243
|
+
app = proc do |env|
|
|
244
|
+
request = Rack::Request.new(env)
|
|
245
|
+
sleep request.params['wait_time'].to_f
|
|
246
|
+
[200, {}, ['Hello Server!']]
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
server = described_class.new(app).boot
|
|
250
|
+
|
|
251
|
+
expect do
|
|
252
|
+
start_request(server, 59.0)
|
|
253
|
+
server.wait_for_pending_requests
|
|
254
|
+
end.not_to raise_error
|
|
255
|
+
|
|
256
|
+
expect do
|
|
257
|
+
start_request(server, 61.0)
|
|
258
|
+
server.wait_for_pending_requests
|
|
259
|
+
end.to raise_error('Requests did not finish in 60 seconds: ["/?wait_time=61.0"]')
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
it 'is not #responsive? when Net::HTTP raises a SystemCallError' do
|
|
263
|
+
app = -> { [200, {}, ['Hello, world']] }
|
|
264
|
+
server = described_class.new(app)
|
|
265
|
+
allow(Net::HTTP).to receive(:start).and_raise(SystemCallError.allocate)
|
|
266
|
+
expect(server.responsive?).to eq false
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
[EOFError, Net::ReadTimeout].each do |err|
|
|
270
|
+
it "should attempt an HTTPS connection if HTTP connection returns #{err}" do
|
|
271
|
+
app = -> { [200, {}, ['Hello, world']] }
|
|
272
|
+
ordered_errors = [Errno::ECONNREFUSED, err]
|
|
273
|
+
allow(Net::HTTP).to receive(:start).with(anything, anything, hash_excluding(:use_ssl)) do
|
|
274
|
+
raise ordered_errors.shift
|
|
275
|
+
end
|
|
276
|
+
response = Net::HTTPSuccess.allocate
|
|
277
|
+
allow(response).to receive(:body).and_return app.object_id.to_s
|
|
278
|
+
allow(Net::HTTP).to receive(:start).with(anything, anything, hash_including(use_ssl: true)).and_return(response).once
|
|
279
|
+
described_class.new(app).boot
|
|
280
|
+
expect(Net::HTTP).to have_received(:start).exactly(3).times
|
|
281
|
+
end
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
def start_request(server, wait_time)
|
|
285
|
+
# Start request, but don't wait for it to finish
|
|
286
|
+
socket = TCPSocket.new(server.host, server.port)
|
|
287
|
+
socket.write "GET /?wait_time=#{wait_time} HTTP/1.0\r\n\r\n"
|
|
288
|
+
sleep 0.1
|
|
289
|
+
socket.close
|
|
290
|
+
sleep 0.1
|
|
291
|
+
end
|
|
292
|
+
end
|