capybara 3.0.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 +891 -12
- data/License.txt +1 -1
- data/README.md +257 -84
- data/lib/capybara/config.rb +29 -10
- data/lib/capybara/cucumber.rb +1 -1
- data/lib/capybara/driver/base.rb +22 -4
- data/lib/capybara/driver/node.rb +38 -9
- data/lib/capybara/dsl.rb +9 -7
- data/lib/capybara/helpers.rb +57 -8
- data/lib/capybara/minitest/spec.rb +185 -84
- data/lib/capybara/minitest.rb +264 -145
- data/lib/capybara/node/actions.rb +248 -124
- data/lib/capybara/node/base.rb +35 -20
- data/lib/capybara/node/document.rb +14 -2
- data/lib/capybara/node/document_matchers.rb +13 -15
- data/lib/capybara/node/element.rb +350 -113
- data/lib/capybara/node/finders.rb +104 -82
- data/lib/capybara/node/matchers.rb +363 -157
- data/lib/capybara/node/simple.rb +54 -15
- 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 +9 -10
- data/lib/capybara/queries/base_query.rb +25 -18
- data/lib/capybara/queries/current_path_query.rb +16 -6
- data/lib/capybara/queries/match_query.rb +11 -0
- data/lib/capybara/queries/selector_query.rb +617 -104
- data/lib/capybara/queries/sibling_query.rb +9 -7
- data/lib/capybara/queries/style_query.rb +45 -0
- data/lib/capybara/queries/text_query.rb +40 -22
- data/lib/capybara/queries/title_query.rb +2 -2
- data/lib/capybara/rack_test/browser.rb +106 -31
- data/lib/capybara/rack_test/driver.rb +16 -7
- data/lib/capybara/rack_test/errors.rb +6 -0
- data/lib/capybara/rack_test/form.rb +74 -49
- data/lib/capybara/rack_test/node.rb +120 -47
- data/lib/capybara/rails.rb +1 -1
- 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 +87 -53
- data/lib/capybara/rspec/features.rb +8 -10
- data/lib/capybara/rspec/matcher_proxies.rb +39 -18
- 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 +142 -315
- data/lib/capybara/rspec.rb +3 -2
- data/lib/capybara/selector/builders/css_builder.rb +84 -0
- data/lib/capybara/selector/builders/xpath_builder.rb +71 -0
- data/lib/capybara/selector/css.rb +85 -8
- 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 +1 -0
- data/lib/capybara/selector/filter_set.rb +72 -28
- data/lib/capybara/selector/filters/base.rb +45 -2
- data/lib/capybara/selector/filters/expression_filter.rb +5 -6
- data/lib/capybara/selector/filters/locator_filter.rb +29 -0
- data/lib/capybara/selector/filters/node_filter.rb +18 -4
- data/lib/capybara/selector/regexp_disassembler.rb +211 -0
- data/lib/capybara/selector/selector.rb +89 -200
- data/lib/capybara/selector/xpath_extensions.rb +17 -0
- data/lib/capybara/selector.rb +474 -534
- 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 +270 -245
- 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 +460 -170
- 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 +58 -67
- data/lib/capybara/session/config.rb +40 -6
- data/lib/capybara/session/matchers.rb +26 -19
- data/lib/capybara/session.rb +252 -194
- 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 +126 -8
- data/lib/capybara/spec/session/accept_alert_spec.rb +11 -11
- data/lib/capybara/spec/session/accept_confirm_spec.rb +3 -3
- data/lib/capybara/spec/session/accept_prompt_spec.rb +9 -10
- data/lib/capybara/spec/session/active_element_spec.rb +31 -0
- data/lib/capybara/spec/session/all_spec.rb +135 -44
- data/lib/capybara/spec/session/ancestor_spec.rb +24 -19
- data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +67 -38
- data/lib/capybara/spec/session/{assert_current_path.rb → assert_current_path_spec.rb} +20 -18
- data/lib/capybara/spec/session/assert_selector_spec.rb +143 -0
- data/lib/capybara/spec/session/assert_style_spec.rb +26 -0
- data/lib/capybara/spec/session/{assert_text.rb → assert_text_spec.rb} +76 -52
- data/lib/capybara/spec/session/{assert_title.rb → assert_title_spec.rb} +12 -12
- data/lib/capybara/spec/session/attach_file_spec.rb +126 -72
- data/lib/capybara/spec/session/body_spec.rb +11 -13
- data/lib/capybara/spec/session/check_spec.rb +112 -51
- data/lib/capybara/spec/session/choose_spec.rb +62 -30
- data/lib/capybara/spec/session/click_button_spec.rb +227 -161
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +49 -30
- data/lib/capybara/spec/session/click_link_spec.rb +89 -55
- data/lib/capybara/spec/session/current_scope_spec.rb +8 -8
- data/lib/capybara/spec/session/current_url_spec.rb +44 -37
- data/lib/capybara/spec/session/dismiss_confirm_spec.rb +3 -3
- data/lib/capybara/spec/session/dismiss_prompt_spec.rb +2 -2
- data/lib/capybara/spec/session/element/{assert_match_selector.rb → assert_match_selector_spec.rb} +11 -9
- data/lib/capybara/spec/session/element/match_css_spec.rb +18 -10
- data/lib/capybara/spec/session/element/match_xpath_spec.rb +8 -6
- data/lib/capybara/spec/session/element/matches_selector_spec.rb +70 -56
- data/lib/capybara/spec/session/evaluate_async_script_spec.rb +7 -7
- data/lib/capybara/spec/session/evaluate_script_spec.rb +28 -8
- data/lib/capybara/spec/session/execute_script_spec.rb +8 -7
- data/lib/capybara/spec/session/fill_in_spec.rb +110 -44
- data/lib/capybara/spec/session/find_button_spec.rb +23 -23
- data/lib/capybara/spec/session/find_by_id_spec.rb +8 -8
- data/lib/capybara/spec/session/find_field_spec.rb +33 -31
- data/lib/capybara/spec/session/find_link_spec.rb +42 -14
- data/lib/capybara/spec/session/find_spec.rb +251 -142
- data/lib/capybara/spec/session/first_spec.rb +45 -44
- data/lib/capybara/spec/session/frame/frame_title_spec.rb +6 -6
- data/lib/capybara/spec/session/frame/frame_url_spec.rb +6 -6
- data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +32 -20
- data/lib/capybara/spec/session/frame/within_frame_spec.rb +46 -19
- data/lib/capybara/spec/session/go_back_spec.rb +1 -1
- data/lib/capybara/spec/session/go_forward_spec.rb +1 -1
- data/lib/capybara/spec/session/has_all_selectors_spec.rb +23 -23
- 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 +98 -12
- data/lib/capybara/spec/session/has_css_spec.rb +271 -137
- data/lib/capybara/spec/session/has_current_path_spec.rb +50 -35
- data/lib/capybara/spec/session/has_element_spec.rb +47 -0
- data/lib/capybara/spec/session/has_field_spec.rb +137 -58
- data/lib/capybara/spec/session/has_link_spec.rb +46 -6
- data/lib/capybara/spec/session/has_none_selectors_spec.rb +33 -31
- data/lib/capybara/spec/session/has_select_spec.rb +84 -50
- data/lib/capybara/spec/session/has_selector_spec.rb +117 -69
- data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
- data/lib/capybara/spec/session/has_table_spec.rb +181 -4
- data/lib/capybara/spec/session/has_text_spec.rb +101 -53
- data/lib/capybara/spec/session/has_title_spec.rb +19 -14
- data/lib/capybara/spec/session/has_xpath_spec.rb +56 -38
- data/lib/capybara/spec/session/{headers.rb → headers_spec.rb} +1 -1
- data/lib/capybara/spec/session/html_spec.rb +13 -6
- data/lib/capybara/spec/session/matches_style_spec.rb +37 -0
- data/lib/capybara/spec/session/node_spec.rb +958 -122
- data/lib/capybara/spec/session/node_wrapper_spec.rb +15 -12
- data/lib/capybara/spec/session/refresh_spec.rb +9 -7
- data/lib/capybara/spec/session/reset_session_spec.rb +65 -37
- data/lib/capybara/spec/session/{response_code.rb → response_code_spec.rb} +1 -1
- data/lib/capybara/spec/session/save_and_open_page_spec.rb +2 -2
- data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +5 -4
- data/lib/capybara/spec/session/save_page_spec.rb +41 -38
- data/lib/capybara/spec/session/save_screenshot_spec.rb +13 -11
- data/lib/capybara/spec/session/screenshot_spec.rb +2 -2
- data/lib/capybara/spec/session/scroll_spec.rb +119 -0
- data/lib/capybara/spec/session/select_spec.rb +102 -76
- data/lib/capybara/spec/session/selectors_spec.rb +51 -18
- data/lib/capybara/spec/session/sibling_spec.rb +9 -9
- data/lib/capybara/spec/session/text_spec.rb +26 -24
- data/lib/capybara/spec/session/title_spec.rb +8 -6
- data/lib/capybara/spec/session/uncheck_spec.rb +41 -22
- data/lib/capybara/spec/session/unselect_spec.rb +37 -37
- data/lib/capybara/spec/session/visit_spec.rb +79 -53
- data/lib/capybara/spec/session/window/become_closed_spec.rb +22 -19
- data/lib/capybara/spec/session/window/current_window_spec.rb +4 -3
- data/lib/capybara/spec/session/window/open_new_window_spec.rb +4 -3
- data/lib/capybara/spec/session/window/switch_to_window_spec.rb +25 -21
- data/lib/capybara/spec/session/window/window_opened_by_spec.rb +10 -5
- data/lib/capybara/spec/session/window/window_spec.rb +88 -54
- data/lib/capybara/spec/session/window/windows_spec.rb +11 -8
- data/lib/capybara/spec/session/window/within_window_spec.rb +17 -16
- data/lib/capybara/spec/session/within_spec.rb +82 -44
- data/lib/capybara/spec/spec_helper.rb +46 -52
- data/lib/capybara/spec/test_app.rb +148 -41
- data/lib/capybara/spec/views/animated.erb +49 -0
- data/lib/capybara/spec/views/form.erb +156 -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 +46 -11
- 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 +1 -1
- data/lib/capybara/version.rb +1 -1
- data/lib/capybara/window.rb +32 -26
- data/lib/capybara.rb +128 -104
- data/spec/basic_node_spec.rb +59 -34
- data/spec/capybara_spec.rb +65 -51
- 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 +84 -55
- data/spec/filter_set_spec.rb +24 -7
- data/spec/fixtures/certificate.pem +25 -0
- data/spec/fixtures/key.pem +27 -0
- data/spec/fixtures/selenium_driver_rspec_failure.rb +5 -5
- data/spec/fixtures/selenium_driver_rspec_success.rb +5 -5
- data/spec/minitest_spec.rb +49 -5
- data/spec/minitest_spec_spec.rb +92 -62
- data/spec/per_session_config_spec.rb +6 -6
- data/spec/rack_test_spec.rb +183 -115
- data/spec/regexp_dissassembler_spec.rb +250 -0
- data/spec/result_spec.rb +99 -39
- data/spec/rspec/features_spec.rb +28 -25
- data/spec/rspec/scenarios_spec.rb +10 -6
- data/spec/rspec/shared_spec_matchers.rb +418 -364
- data/spec/rspec/views_spec.rb +4 -3
- data/spec/rspec_matchers_spec.rb +35 -10
- data/spec/rspec_spec.rb +109 -85
- data/spec/sauce_spec_chrome.rb +43 -0
- data/spec/selector_spec.rb +392 -62
- data/spec/selenium_spec_chrome.rb +183 -41
- data/spec/selenium_spec_chrome_remote.rb +96 -0
- data/spec/selenium_spec_edge.rb +41 -8
- data/spec/selenium_spec_firefox.rb +228 -0
- data/spec/selenium_spec_firefox_remote.rb +94 -0
- data/spec/selenium_spec_ie.rb +129 -11
- data/spec/selenium_spec_safari.rb +162 -0
- data/spec/server_spec.rb +192 -81
- data/spec/session_spec.rb +52 -16
- data/spec/shared_selenium_node.rb +79 -0
- data/spec/shared_selenium_session.rb +460 -123
- data/spec/spec_helper.rb +124 -2
- data/spec/whitespace_normalizer_spec.rb +54 -0
- data/spec/xpath_builder_spec.rb +93 -0
- metadata +344 -45
- data/.yard/templates_custom/default/class/html/selectors.erb +0 -38
- data/.yard/templates_custom/default/class/html/setup.rb +0 -17
- data/.yard/yard_extensions.rb +0 -78
- data/lib/capybara/rspec/compound.rb +0 -90
- data/lib/capybara/spec/session/assert_selector.rb +0 -149
- data/lib/capybara/spec/session/source_spec.rb +0 -0
- data/lib/capybara/spec/views/with_title.erb +0 -5
- data/spec/selenium_spec_marionette.rb +0 -143
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Capybara
|
4
|
+
class Server
|
5
|
+
class AnimationDisabler
|
6
|
+
def self.selector_for(css_or_bool)
|
7
|
+
case css_or_bool
|
8
|
+
when String
|
9
|
+
css_or_bool
|
10
|
+
when true
|
11
|
+
'*'
|
12
|
+
else
|
13
|
+
raise CapybaraError, 'Capybara.disable_animation supports either a String (the css selector to disable) or a boolean'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(app)
|
18
|
+
@app = app
|
19
|
+
@disable_css_markup = format(DISABLE_CSS_MARKUP_TEMPLATE,
|
20
|
+
selector: self.class.selector_for(Capybara.disable_animation))
|
21
|
+
@disable_js_markup = +DISABLE_JS_MARKUP_TEMPLATE
|
22
|
+
end
|
23
|
+
|
24
|
+
def call(env)
|
25
|
+
status, headers, body = @app.call(env)
|
26
|
+
return [status, headers, body] unless html_content?(headers)
|
27
|
+
|
28
|
+
nonces = directive_nonces(headers).transform_values { |nonce| "nonce=\"#{nonce}\"" if nonce && !nonce.empty? }
|
29
|
+
response = Rack::Response.new([], status, headers)
|
30
|
+
|
31
|
+
body.each { |html| response.write insert_disable(html, nonces) }
|
32
|
+
body.close if body.respond_to?(:close)
|
33
|
+
|
34
|
+
response.finish
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
attr_reader :disable_css_markup, :disable_js_markup
|
40
|
+
|
41
|
+
def html_content?(headers)
|
42
|
+
/html/.match?(headers['Content-Type']) # rubocop:todo Performance/StringInclude
|
43
|
+
end
|
44
|
+
|
45
|
+
def insert_disable(html, nonces)
|
46
|
+
html.sub(%r{(</head>)}, "<style #{nonces['style-src']}>#{disable_css_markup}</style>\\1")
|
47
|
+
.sub(%r{(</body>)}, "<script #{nonces['script-src']}>#{disable_js_markup}</script>\\1")
|
48
|
+
end
|
49
|
+
|
50
|
+
def directive_nonces(headers)
|
51
|
+
headers.fetch('Content-Security-Policy', '')
|
52
|
+
.split(';')
|
53
|
+
.map(&:split) # rubocop:disable Style/MapToHash
|
54
|
+
.to_h do |s|
|
55
|
+
[
|
56
|
+
s[0], s[1..].filter_map do |value|
|
57
|
+
/^'nonce-(?<nonce>.+)'/ =~ value
|
58
|
+
nonce
|
59
|
+
end[0]
|
60
|
+
]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
DISABLE_CSS_MARKUP_TEMPLATE = <<~CSS
|
65
|
+
%<selector>s, %<selector>s::before, %<selector>s::after {
|
66
|
+
transition: none !important;
|
67
|
+
animation-duration: 0s !important;
|
68
|
+
animation-delay: 0s !important;
|
69
|
+
scroll-behavior: auto !important;
|
70
|
+
}
|
71
|
+
CSS
|
72
|
+
|
73
|
+
DISABLE_JS_MARKUP_TEMPLATE = <<~SCRIPT
|
74
|
+
//<![CDATA[
|
75
|
+
(typeof jQuery !== 'undefined') && (jQuery.fx.off = true);
|
76
|
+
//]]>
|
77
|
+
SCRIPT
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Capybara
|
4
|
+
class Server
|
5
|
+
class Checker
|
6
|
+
TRY_HTTPS_ERRORS = [EOFError, Net::ReadTimeout, Errno::ECONNRESET].freeze
|
7
|
+
|
8
|
+
def initialize(host, port)
|
9
|
+
@host, @port = host, port
|
10
|
+
@ssl = false
|
11
|
+
end
|
12
|
+
|
13
|
+
def request(&block)
|
14
|
+
ssl? ? https_request(&block) : http_request(&block)
|
15
|
+
rescue *TRY_HTTPS_ERRORS
|
16
|
+
res = https_request(&block)
|
17
|
+
@ssl = true
|
18
|
+
res
|
19
|
+
end
|
20
|
+
|
21
|
+
def ssl?
|
22
|
+
@ssl
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def http_request(&block)
|
28
|
+
make_request(read_timeout: 2, &block)
|
29
|
+
end
|
30
|
+
|
31
|
+
def https_request(&block)
|
32
|
+
make_request(**ssl_options, &block)
|
33
|
+
end
|
34
|
+
|
35
|
+
def make_request(**options, &block)
|
36
|
+
Net::HTTP.start(@host, @port, options.merge(max_retries: 0), &block)
|
37
|
+
end
|
38
|
+
|
39
|
+
def ssl_options
|
40
|
+
{ use_ssl: true, verify_mode: OpenSSL::SSL::VERIFY_NONE }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Capybara
|
4
|
+
class Server
|
5
|
+
class Middleware
|
6
|
+
class Counter
|
7
|
+
def initialize
|
8
|
+
@value = []
|
9
|
+
@mutex = Mutex.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def increment(uri)
|
13
|
+
@mutex.synchronize { @value.push(uri) }
|
14
|
+
end
|
15
|
+
|
16
|
+
def decrement(uri)
|
17
|
+
@mutex.synchronize { @value.delete_at(@value.index(uri) || - 1) }
|
18
|
+
end
|
19
|
+
|
20
|
+
def positive?
|
21
|
+
@mutex.synchronize { @value.length.positive? }
|
22
|
+
end
|
23
|
+
|
24
|
+
def value
|
25
|
+
@mutex.synchronize { @value.dup }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
attr_reader :error
|
30
|
+
|
31
|
+
def initialize(app, server_errors, extra_middleware = [])
|
32
|
+
@app = app
|
33
|
+
@extended_app = extra_middleware.inject(@app) do |ex_app, klass|
|
34
|
+
klass.new(ex_app)
|
35
|
+
end
|
36
|
+
@counter = Counter.new
|
37
|
+
@server_errors = server_errors
|
38
|
+
end
|
39
|
+
|
40
|
+
def pending_requests
|
41
|
+
@counter.value
|
42
|
+
end
|
43
|
+
|
44
|
+
def pending_requests?
|
45
|
+
@counter.positive?
|
46
|
+
end
|
47
|
+
|
48
|
+
def clear_error
|
49
|
+
@error = nil
|
50
|
+
end
|
51
|
+
|
52
|
+
def call(env)
|
53
|
+
if env['PATH_INFO'] == '/__identify__'
|
54
|
+
[200, {}, [@app.object_id.to_s]]
|
55
|
+
else
|
56
|
+
request_uri = env['REQUEST_URI']
|
57
|
+
@counter.increment(request_uri)
|
58
|
+
|
59
|
+
begin
|
60
|
+
@extended_app.call(env)
|
61
|
+
rescue *@server_errors => e
|
62
|
+
@error ||= e
|
63
|
+
raise e
|
64
|
+
ensure
|
65
|
+
@counter.decrement(request_uri)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/lib/capybara/server.rb
CHANGED
@@ -3,56 +3,13 @@
|
|
3
3
|
require 'uri'
|
4
4
|
require 'net/http'
|
5
5
|
require 'rack'
|
6
|
+
require 'capybara/server/middleware'
|
7
|
+
require 'capybara/server/animation_disabler'
|
8
|
+
require 'capybara/server/checker'
|
6
9
|
|
7
10
|
module Capybara
|
11
|
+
# @api private
|
8
12
|
class Server
|
9
|
-
class Middleware
|
10
|
-
class Counter
|
11
|
-
attr_reader :value
|
12
|
-
|
13
|
-
def initialize
|
14
|
-
@value = 0
|
15
|
-
@mutex = Mutex.new
|
16
|
-
end
|
17
|
-
|
18
|
-
def increment
|
19
|
-
@mutex.synchronize { @value += 1 }
|
20
|
-
end
|
21
|
-
|
22
|
-
def decrement
|
23
|
-
@mutex.synchronize { @value -= 1 }
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
attr_accessor :error
|
28
|
-
|
29
|
-
def initialize(app, server_errors)
|
30
|
-
@app = app
|
31
|
-
@counter = Counter.new
|
32
|
-
@server_errors = server_errors
|
33
|
-
end
|
34
|
-
|
35
|
-
def pending_requests?
|
36
|
-
@counter.value > 0
|
37
|
-
end
|
38
|
-
|
39
|
-
def call(env)
|
40
|
-
if env["PATH_INFO"] == "/__identify__"
|
41
|
-
[200, {}, [@app.object_id.to_s]]
|
42
|
-
else
|
43
|
-
@counter.increment
|
44
|
-
begin
|
45
|
-
@app.call(env)
|
46
|
-
rescue *@server_errors => e
|
47
|
-
@error ||= e
|
48
|
-
raise e
|
49
|
-
ensure
|
50
|
-
@counter.decrement
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
13
|
class << self
|
57
14
|
def ports
|
58
15
|
@ports ||= {}
|
@@ -61,38 +18,55 @@ module Capybara
|
|
61
18
|
|
62
19
|
attr_reader :app, :port, :host
|
63
20
|
|
64
|
-
def initialize(app,
|
21
|
+
def initialize(app,
|
22
|
+
*deprecated_options,
|
23
|
+
port: Capybara.server_port,
|
24
|
+
host: Capybara.server_host,
|
25
|
+
reportable_errors: Capybara.server_errors,
|
26
|
+
extra_middleware: [])
|
27
|
+
unless deprecated_options.empty?
|
28
|
+
warn 'Positional arguments, other than the application, to Server#new are deprecated, please use keyword arguments'
|
29
|
+
end
|
65
30
|
@app = app
|
31
|
+
@extra_middleware = extra_middleware
|
66
32
|
@server_thread = nil # suppress warnings
|
67
|
-
@host
|
33
|
+
@host = deprecated_options[1] || host
|
34
|
+
@reportable_errors = deprecated_options[2] || reportable_errors
|
35
|
+
@port = deprecated_options[0] || port
|
68
36
|
@port ||= Capybara::Server.ports[port_key]
|
69
37
|
@port ||= find_available_port(host)
|
38
|
+
@checker = Checker.new(@host, @port)
|
70
39
|
end
|
71
40
|
|
72
41
|
def reset_error!
|
73
|
-
middleware.
|
42
|
+
middleware.clear_error
|
74
43
|
end
|
75
44
|
|
76
45
|
def error
|
77
46
|
middleware.error
|
78
47
|
end
|
79
48
|
|
49
|
+
def using_ssl?
|
50
|
+
@checker.ssl?
|
51
|
+
end
|
52
|
+
|
80
53
|
def responsive?
|
81
|
-
return false if @server_thread
|
54
|
+
return false if @server_thread&.join(0)
|
82
55
|
|
83
|
-
res =
|
56
|
+
res = @checker.request { |http| http.get('/__identify__') }
|
84
57
|
|
85
|
-
if res.is_a?(Net::HTTPSuccess)
|
86
|
-
|
87
|
-
|
88
|
-
rescue SystemCallError
|
89
|
-
return false
|
58
|
+
res.body == app.object_id.to_s if res.is_a?(Net::HTTPSuccess) || res.is_a?(Net::HTTPRedirection)
|
59
|
+
rescue SystemCallError, Net::ReadTimeout, OpenSSL::SSL::SSLError
|
60
|
+
false
|
90
61
|
end
|
91
62
|
|
92
63
|
def wait_for_pending_requests
|
93
|
-
|
94
|
-
|
95
|
-
|
64
|
+
timer = Capybara::Helpers.timer(expire_in: 60)
|
65
|
+
while pending_requests?
|
66
|
+
raise "Requests did not finish in 60 seconds: #{middleware.pending_requests}" if timer.expired?
|
67
|
+
|
68
|
+
sleep 0.01
|
69
|
+
end
|
96
70
|
end
|
97
71
|
|
98
72
|
def boot
|
@@ -103,18 +77,25 @@ module Capybara
|
|
103
77
|
Capybara.server.call(middleware, port, host)
|
104
78
|
end
|
105
79
|
|
106
|
-
|
80
|
+
timer = Capybara::Helpers.timer(expire_in: 60)
|
81
|
+
until responsive?
|
82
|
+
raise 'Rack application timed out during boot' if timer.expired?
|
83
|
+
|
84
|
+
@server_thread.join(0.1)
|
85
|
+
end
|
107
86
|
end
|
108
|
-
|
109
|
-
raise "Rack application timed out during boot"
|
110
|
-
else
|
87
|
+
|
111
88
|
self
|
112
89
|
end
|
113
90
|
|
91
|
+
def base_url
|
92
|
+
"http#{'s' if using_ssl?}://#{host}:#{port}"
|
93
|
+
end
|
94
|
+
|
114
95
|
private
|
115
96
|
|
116
97
|
def middleware
|
117
|
-
@middleware ||= Middleware.new(app, @
|
98
|
+
@middleware ||= Middleware.new(app, @reportable_errors, @extra_middleware)
|
118
99
|
end
|
119
100
|
|
120
101
|
def port_key
|
@@ -127,9 +108,19 @@ module Capybara
|
|
127
108
|
|
128
109
|
def find_available_port(host)
|
129
110
|
server = TCPServer.new(host, 0)
|
130
|
-
server.addr[1]
|
111
|
+
port = server.addr[1]
|
112
|
+
server.close
|
113
|
+
|
114
|
+
# Workaround issue where some platforms (mac, ???) when passed a host
|
115
|
+
# of '0.0.0.0' will return a port that is only available on one of the
|
116
|
+
# ip addresses that resolves to, but the next binding to that port requires
|
117
|
+
# that port to be available on all ips
|
118
|
+
server = TCPServer.new(host, port)
|
119
|
+
port
|
120
|
+
rescue Errno::EADDRINUSE
|
121
|
+
retry
|
131
122
|
ensure
|
132
|
-
server
|
123
|
+
server&.close
|
133
124
|
end
|
134
125
|
end
|
135
126
|
end
|
@@ -7,7 +7,8 @@ module Capybara
|
|
7
7
|
OPTIONS = %i[always_include_port run_server default_selector default_max_wait_time ignore_hidden_elements
|
8
8
|
automatic_reload match exact exact_text raise_server_errors visible_text_only
|
9
9
|
automatic_label_click enable_aria_label save_path asset_host default_host app_host
|
10
|
-
server_host server_port server_errors
|
10
|
+
server_host server_port server_errors default_set_options disable_animation test_id
|
11
|
+
predicates_wait default_normalize_ws w3c_click_offset enable_aria_role default_retry_interval].freeze
|
11
12
|
|
12
13
|
attr_accessor(*OPTIONS)
|
13
14
|
|
@@ -20,6 +21,8 @@ module Capybara
|
|
20
21
|
# See {Capybara.configure}
|
21
22
|
# @!method default_max_wait_time
|
22
23
|
# See {Capybara.configure}
|
24
|
+
# @!method default_retry_interval
|
25
|
+
# See {Capybara.configure}
|
23
26
|
# @!method ignore_hidden_elements
|
24
27
|
# See {Capybara.configure}
|
25
28
|
# @!method automatic_reload
|
@@ -36,6 +39,8 @@ module Capybara
|
|
36
39
|
# See {Capybara.configure}
|
37
40
|
# @!method enable_aria_label
|
38
41
|
# See {Capybara.configure}
|
42
|
+
# @!method enable_aria_role
|
43
|
+
# See {Capybara.configure}
|
39
44
|
# @!method save_path
|
40
45
|
# See {Capybara.configure}
|
41
46
|
# @!method asset_host
|
@@ -50,6 +55,16 @@ module Capybara
|
|
50
55
|
# See {Capybara.configure}
|
51
56
|
# @!method server_errors
|
52
57
|
# See {Capybara.configure}
|
58
|
+
# @!method default_set_options
|
59
|
+
# See {Capybara.configure}
|
60
|
+
# @!method disable_animation
|
61
|
+
# See {Capybara.configure}
|
62
|
+
# @!method test_id
|
63
|
+
# See {Capybara.configure}
|
64
|
+
# @!method default_normalize_ws
|
65
|
+
# See {Capybara.configure}
|
66
|
+
# @!method w3c_click_offset
|
67
|
+
# See {Capybara.configure}
|
53
68
|
|
54
69
|
remove_method :server_host
|
55
70
|
|
@@ -68,16 +83,35 @@ module Capybara
|
|
68
83
|
|
69
84
|
remove_method :app_host=
|
70
85
|
def app_host=(url)
|
71
|
-
|
86
|
+
unless url.nil? || url.match?(URI::DEFAULT_PARSER.make_regexp)
|
87
|
+
raise ArgumentError, "Capybara.app_host should be set to a url (http://www.example.com). Attempted to set #{url.inspect}."
|
88
|
+
end
|
89
|
+
|
72
90
|
@app_host = url
|
73
91
|
end
|
74
92
|
|
75
93
|
remove_method :default_host=
|
76
94
|
def default_host=(url)
|
77
|
-
|
95
|
+
unless url.nil? || url.match?(URI::DEFAULT_PARSER.make_regexp)
|
96
|
+
raise ArgumentError, "Capybara.default_host should be set to a url (http://www.example.com). Attempted to set #{url.inspect}."
|
97
|
+
end
|
98
|
+
|
78
99
|
@default_host = url
|
79
100
|
end
|
80
101
|
|
102
|
+
remove_method :test_id=
|
103
|
+
##
|
104
|
+
#
|
105
|
+
# Set an attribute to be optionally matched against the locator for builtin selector types.
|
106
|
+
# This attribute will be checked by builtin selector types whenever id would normally be checked.
|
107
|
+
# If `nil` then it will be ignored.
|
108
|
+
#
|
109
|
+
# @param [String, Symbol, nil] id Name of the attribute to use as the test id
|
110
|
+
#
|
111
|
+
def test_id=(id)
|
112
|
+
@test_id = id&.to_sym
|
113
|
+
end
|
114
|
+
|
81
115
|
def initialize_copy(other)
|
82
116
|
super
|
83
117
|
@server_errors = @server_errors.dup
|
@@ -85,9 +119,9 @@ module Capybara
|
|
85
119
|
end
|
86
120
|
|
87
121
|
class ReadOnlySessionConfig < SimpleDelegator
|
88
|
-
SessionConfig::OPTIONS.each do |
|
89
|
-
define_method "#{
|
90
|
-
raise
|
122
|
+
SessionConfig::OPTIONS.each do |option|
|
123
|
+
define_method "#{option}=" do |_|
|
124
|
+
raise 'Per session settings are only supported when Capybara.threadsafe == true'
|
91
125
|
end
|
92
126
|
end
|
93
127
|
end
|
@@ -6,21 +6,23 @@ module Capybara
|
|
6
6
|
# Asserts that the page has the given path.
|
7
7
|
# By default, if passed a full url this will compare against the full url,
|
8
8
|
# if passed a path only the path+query portion will be compared, if passed a regexp
|
9
|
-
# the comparison will depend on the :url option
|
9
|
+
# the comparison will depend on the :url option (path+query by default)
|
10
10
|
#
|
11
11
|
# @!macro current_path_query_params
|
12
|
-
# @overload $0(string, options
|
12
|
+
# @overload $0(string, **options)
|
13
13
|
# @param string [String] The string that the current 'path' should equal
|
14
|
-
# @overload $0(regexp, options
|
14
|
+
# @overload $0(regexp, **options)
|
15
15
|
# @param regexp [Regexp] The regexp that the current 'path' should match to
|
16
|
-
# @option options [Boolean] :url (true if `string`
|
16
|
+
# @option options [Boolean] :url (true if `string` is a full url, otherwise false) Whether the comparison should be done against the full current url or just the path
|
17
17
|
# @option options [Boolean] :ignore_query (false) Whether the query portion of the current url/path should be ignored
|
18
18
|
# @option options [Numeric] :wait (Capybara.default_max_wait_time) Maximum time that Capybara will wait for the current url/path to eq/match given string/regexp argument
|
19
19
|
# @raise [Capybara::ExpectationNotMet] if the assertion hasn't succeeded during wait time
|
20
20
|
# @return [true]
|
21
21
|
#
|
22
|
-
def assert_current_path(path, **options)
|
23
|
-
_verify_current_path(path, options)
|
22
|
+
def assert_current_path(path, **options, &optional_filter_block)
|
23
|
+
_verify_current_path(path, optional_filter_block, **options) do |query|
|
24
|
+
raise Capybara::ExpectationNotMet, query.failure_message unless query.resolves_for?(self)
|
25
|
+
end
|
24
26
|
end
|
25
27
|
|
26
28
|
##
|
@@ -33,8 +35,10 @@ module Capybara
|
|
33
35
|
# @raise [Capybara::ExpectationNotMet] if the assertion hasn't succeeded during wait time
|
34
36
|
# @return [true]
|
35
37
|
#
|
36
|
-
def assert_no_current_path(path, **options)
|
37
|
-
_verify_current_path(path, options)
|
38
|
+
def assert_no_current_path(path, **options, &optional_filter_block)
|
39
|
+
_verify_current_path(path, optional_filter_block, **options) do |query|
|
40
|
+
raise Capybara::ExpectationNotMet, query.negative_failure_message if query.resolves_for?(self)
|
41
|
+
end
|
38
42
|
end
|
39
43
|
|
40
44
|
##
|
@@ -46,10 +50,8 @@ module Capybara
|
|
46
50
|
# @macro current_path_query_params
|
47
51
|
# @return [Boolean]
|
48
52
|
#
|
49
|
-
def has_current_path?(path, **options)
|
50
|
-
assert_current_path(path, options)
|
51
|
-
rescue Capybara::ExpectationNotMet
|
52
|
-
return false
|
53
|
+
def has_current_path?(path, **options, &optional_filter_block)
|
54
|
+
make_predicate(options) { assert_current_path(path, **options, &optional_filter_block) }
|
53
55
|
end
|
54
56
|
|
55
57
|
##
|
@@ -61,20 +63,25 @@ module Capybara
|
|
61
63
|
# @macro current_path_query_params
|
62
64
|
# @return [Boolean]
|
63
65
|
#
|
64
|
-
def has_no_current_path?(path, **options)
|
65
|
-
assert_no_current_path(path, options)
|
66
|
-
rescue Capybara::ExpectationNotMet
|
67
|
-
return false
|
66
|
+
def has_no_current_path?(path, **options, &optional_filter_block)
|
67
|
+
make_predicate(options) { assert_no_current_path(path, **options, &optional_filter_block) }
|
68
68
|
end
|
69
69
|
|
70
70
|
private
|
71
71
|
|
72
|
-
def _verify_current_path(path, options)
|
73
|
-
query = Capybara::Queries::CurrentPathQuery.new(path, options)
|
72
|
+
def _verify_current_path(path, filter_block, **options)
|
73
|
+
query = Capybara::Queries::CurrentPathQuery.new(path, **options, &filter_block)
|
74
74
|
document.synchronize(query.wait) do
|
75
75
|
yield(query)
|
76
76
|
end
|
77
|
-
|
77
|
+
true
|
78
|
+
end
|
79
|
+
|
80
|
+
def make_predicate(options)
|
81
|
+
options[:wait] = 0 unless options.key?(:wait) || config.predicates_wait
|
82
|
+
yield
|
83
|
+
rescue Capybara::ExpectationNotMet
|
84
|
+
false
|
78
85
|
end
|
79
86
|
end
|
80
87
|
end
|