capybara 3.13.2 → 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 -0
- data/History.md +587 -16
- data/README.md +240 -90
- data/lib/capybara/config.rb +24 -11
- data/lib/capybara/cucumber.rb +1 -1
- data/lib/capybara/driver/base.rb +8 -0
- data/lib/capybara/driver/node.rb +20 -4
- data/lib/capybara/dsl.rb +5 -3
- data/lib/capybara/helpers.rb +25 -4
- data/lib/capybara/minitest/spec.rb +174 -90
- data/lib/capybara/minitest.rb +256 -142
- data/lib/capybara/node/actions.rb +123 -77
- data/lib/capybara/node/base.rb +20 -12
- data/lib/capybara/node/document.rb +2 -2
- data/lib/capybara/node/document_matchers.rb +3 -3
- data/lib/capybara/node/element.rb +223 -117
- data/lib/capybara/node/finders.rb +81 -71
- data/lib/capybara/node/matchers.rb +271 -134
- data/lib/capybara/node/simple.rb +18 -5
- 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 +8 -9
- data/lib/capybara/queries/base_query.rb +3 -2
- data/lib/capybara/queries/current_path_query.rb +15 -5
- data/lib/capybara/queries/selector_query.rb +364 -54
- data/lib/capybara/queries/sibling_query.rb +8 -6
- data/lib/capybara/queries/style_query.rb +2 -2
- data/lib/capybara/queries/text_query.rb +13 -1
- data/lib/capybara/queries/title_query.rb +1 -1
- data/lib/capybara/rack_test/browser.rb +76 -11
- data/lib/capybara/rack_test/driver.rb +10 -5
- data/lib/capybara/rack_test/errors.rb +6 -0
- data/lib/capybara/rack_test/form.rb +31 -9
- data/lib/capybara/rack_test/node.rb +74 -23
- 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 +44 -20
- data/lib/capybara/rspec/matcher_proxies.rb +13 -11
- data/lib/capybara/rspec/matchers/base.rb +31 -16
- data/lib/capybara/rspec/matchers/compound.rb +1 -1
- 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 +2 -2
- data/lib/capybara/rspec/matchers/have_selector.rb +21 -21
- data/lib/capybara/rspec/matchers/have_sibling.rb +27 -0
- data/lib/capybara/rspec/matchers/have_text.rb +4 -4
- data/lib/capybara/rspec/matchers/have_title.rb +2 -2
- data/lib/capybara/rspec/matchers/match_selector.rb +3 -3
- data/lib/capybara/rspec/matchers/match_style.rb +7 -2
- data/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
- data/lib/capybara/rspec/matchers.rb +111 -68
- data/lib/capybara/rspec.rb +2 -0
- data/lib/capybara/selector/builders/css_builder.rb +11 -7
- data/lib/capybara/selector/builders/xpath_builder.rb +5 -3
- data/lib/capybara/selector/css.rb +11 -9
- 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_set.rb +19 -18
- data/lib/capybara/selector/filters/base.rb +11 -2
- data/lib/capybara/selector/filters/locator_filter.rb +13 -3
- data/lib/capybara/selector/regexp_disassembler.rb +11 -7
- data/lib/capybara/selector/selector.rb +50 -440
- data/lib/capybara/selector/xpath_extensions.rb +17 -0
- data/lib/capybara/selector.rb +473 -482
- 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 +174 -62
- data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +74 -18
- data/lib/capybara/selenium/driver_specializations/edge_driver.rb +128 -0
- data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +37 -3
- data/lib/capybara/selenium/driver_specializations/internet_explorer_driver.rb +14 -1
- 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 +68 -45
- data/lib/capybara/selenium/extensions/html5_drag.rb +192 -22
- data/lib/capybara/selenium/extensions/modifier_keys_stack.rb +28 -0
- data/lib/capybara/selenium/extensions/scroll.rb +8 -10
- data/lib/capybara/selenium/node.rb +268 -72
- data/lib/capybara/selenium/nodes/chrome_node.rb +105 -9
- data/lib/capybara/selenium/nodes/edge_node.rb +110 -0
- data/lib/capybara/selenium/nodes/firefox_node.rb +51 -61
- 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 +1 -1
- data/lib/capybara/selenium/patches/persistent_client.rb +20 -0
- data/lib/capybara/server/animation_disabler.rb +43 -21
- data/lib/capybara/server/checker.rb +6 -2
- data/lib/capybara/server/middleware.rb +25 -13
- data/lib/capybara/server.rb +20 -4
- data/lib/capybara/session/config.rb +15 -11
- data/lib/capybara/session/matchers.rb +11 -11
- data/lib/capybara/session.rb +162 -131
- data/lib/capybara/spec/public/offset.js +6 -0
- data/lib/capybara/spec/public/test.js +105 -6
- data/lib/capybara/spec/session/accept_alert_spec.rb +1 -1
- data/lib/capybara/spec/session/active_element_spec.rb +31 -0
- data/lib/capybara/spec/session/all_spec.rb +89 -15
- data/lib/capybara/spec/session/ancestor_spec.rb +5 -0
- data/lib/capybara/spec/session/assert_current_path_spec.rb +5 -2
- data/lib/capybara/spec/session/assert_text_spec.rb +26 -22
- data/lib/capybara/spec/session/attach_file_spec.rb +64 -31
- data/lib/capybara/spec/session/check_spec.rb +26 -4
- data/lib/capybara/spec/session/choose_spec.rb +14 -2
- data/lib/capybara/spec/session/click_button_spec.rb +109 -61
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +9 -0
- data/lib/capybara/spec/session/click_link_spec.rb +23 -1
- data/lib/capybara/spec/session/current_scope_spec.rb +1 -1
- data/lib/capybara/spec/session/current_url_spec.rb +11 -1
- data/lib/capybara/spec/session/element/matches_selector_spec.rb +40 -39
- data/lib/capybara/spec/session/evaluate_script_spec.rb +12 -0
- data/lib/capybara/spec/session/fill_in_spec.rb +46 -5
- data/lib/capybara/spec/session/find_link_spec.rb +10 -0
- data/lib/capybara/spec/session/find_spec.rb +80 -7
- data/lib/capybara/spec/session/first_spec.rb +2 -2
- data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +14 -1
- data/lib/capybara/spec/session/frame/within_frame_spec.rb +14 -1
- data/lib/capybara/spec/session/has_all_selectors_spec.rb +5 -5
- data/lib/capybara/spec/session/has_ancestor_spec.rb +46 -0
- data/lib/capybara/spec/session/has_any_selectors_spec.rb +6 -2
- data/lib/capybara/spec/session/has_button_spec.rb +81 -0
- data/lib/capybara/spec/session/has_css_spec.rb +45 -8
- data/lib/capybara/spec/session/has_current_path_spec.rb +22 -7
- data/lib/capybara/spec/session/has_element_spec.rb +47 -0
- data/lib/capybara/spec/session/has_field_spec.rb +59 -1
- data/lib/capybara/spec/session/has_link_spec.rb +40 -0
- data/lib/capybara/spec/session/has_none_selectors_spec.rb +7 -7
- data/lib/capybara/spec/session/has_select_spec.rb +42 -8
- data/lib/capybara/spec/session/has_selector_spec.rb +19 -4
- data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
- data/lib/capybara/spec/session/has_table_spec.rb +177 -0
- data/lib/capybara/spec/session/has_text_spec.rb +31 -3
- data/lib/capybara/spec/session/html_spec.rb +1 -1
- data/lib/capybara/spec/session/matches_style_spec.rb +6 -4
- data/lib/capybara/spec/session/node_spec.rb +697 -23
- data/lib/capybara/spec/session/node_wrapper_spec.rb +1 -1
- data/lib/capybara/spec/session/refresh_spec.rb +2 -1
- data/lib/capybara/spec/session/reset_session_spec.rb +21 -7
- data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +2 -2
- data/lib/capybara/spec/session/save_page_spec.rb +4 -4
- data/lib/capybara/spec/session/save_screenshot_spec.rb +4 -4
- data/lib/capybara/spec/session/scroll_spec.rb +9 -7
- data/lib/capybara/spec/session/select_spec.rb +5 -10
- data/lib/capybara/spec/session/selectors_spec.rb +24 -3
- data/lib/capybara/spec/session/uncheck_spec.rb +3 -3
- data/lib/capybara/spec/session/unselect_spec.rb +1 -1
- data/lib/capybara/spec/session/visit_spec.rb +20 -0
- data/lib/capybara/spec/session/window/become_closed_spec.rb +20 -17
- data/lib/capybara/spec/session/window/switch_to_window_spec.rb +1 -1
- data/lib/capybara/spec/session/window/window_opened_by_spec.rb +1 -1
- data/lib/capybara/spec/session/window/window_spec.rb +54 -57
- data/lib/capybara/spec/session/window/windows_spec.rb +2 -2
- data/lib/capybara/spec/session/within_spec.rb +36 -0
- data/lib/capybara/spec/spec_helper.rb +30 -19
- data/lib/capybara/spec/test_app.rb +122 -34
- data/lib/capybara/spec/views/animated.erb +49 -0
- data/lib/capybara/spec/views/form.erb +86 -8
- data/lib/capybara/spec/views/frame_child.erb +3 -2
- 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 +10 -10
- 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 +2 -1
- data/lib/capybara/spec/views/spatial.erb +31 -0
- data/lib/capybara/spec/views/tables.erb +67 -0
- data/lib/capybara/spec/views/with_animation.erb +39 -4
- 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 +34 -6
- data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
- data/lib/capybara/spec/views/with_js.erb +7 -4
- data/lib/capybara/spec/views/with_jstree.erb +26 -0
- data/lib/capybara/spec/views/with_namespace.erb +1 -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 +14 -18
- data/lib/capybara.rb +91 -126
- data/spec/basic_node_spec.rb +30 -16
- data/spec/capybara_spec.rb +40 -28
- data/spec/counter_spec.rb +35 -0
- data/spec/css_builder_spec.rb +3 -1
- data/spec/css_splitter_spec.rb +1 -1
- data/spec/dsl_spec.rb +33 -22
- data/spec/filter_set_spec.rb +5 -5
- data/spec/fixtures/selenium_driver_rspec_failure.rb +3 -3
- data/spec/fixtures/selenium_driver_rspec_success.rb +3 -3
- data/spec/minitest_spec.rb +24 -2
- data/spec/minitest_spec_spec.rb +60 -45
- data/spec/per_session_config_spec.rb +1 -1
- data/spec/rack_test_spec.rb +131 -98
- data/spec/regexp_dissassembler_spec.rb +53 -39
- data/spec/result_spec.rb +68 -66
- data/spec/rspec/features_spec.rb +9 -4
- data/spec/rspec/scenarios_spec.rb +6 -2
- data/spec/rspec/shared_spec_matchers.rb +137 -98
- data/spec/rspec_matchers_spec.rb +25 -0
- data/spec/rspec_spec.rb +23 -21
- data/spec/sauce_spec_chrome.rb +43 -0
- data/spec/selector_spec.rb +77 -21
- data/spec/selenium_spec_chrome.rb +141 -39
- data/spec/selenium_spec_chrome_remote.rb +32 -17
- data/spec/selenium_spec_edge.rb +36 -8
- data/spec/selenium_spec_firefox.rb +110 -68
- data/spec/selenium_spec_firefox_remote.rb +22 -15
- data/spec/selenium_spec_ie.rb +29 -22
- data/spec/selenium_spec_safari.rb +162 -0
- data/spec/server_spec.rb +153 -81
- data/spec/session_spec.rb +11 -4
- data/spec/shared_selenium_node.rb +79 -0
- data/spec/shared_selenium_session.rb +179 -74
- data/spec/spec_helper.rb +80 -5
- data/spec/whitespace_normalizer_spec.rb +54 -0
- data/spec/xpath_builder_spec.rb +3 -1
- metadata +218 -30
- data/lib/capybara/spec/session/source_spec.rb +0 -0
- data/lib/capybara/spec/views/with_title.erb +0 -5
data/lib/capybara/session.rb
CHANGED
@@ -6,7 +6,7 @@ require 'addressable/uri'
|
|
6
6
|
module Capybara
|
7
7
|
##
|
8
8
|
#
|
9
|
-
# The Session class represents a single user's interaction with the system. The Session can use
|
9
|
+
# The {Session} class represents a single user's interaction with the system. The {Session} can use
|
10
10
|
# any of the underlying drivers. A session can be initialized manually like this:
|
11
11
|
#
|
12
12
|
# session = Capybara::Session.new(:culerity, MyRackApp)
|
@@ -17,33 +17,35 @@ module Capybara
|
|
17
17
|
# session = Capybara::Session.new(:culerity)
|
18
18
|
# session.visit('http://www.google.com')
|
19
19
|
#
|
20
|
-
# When Capybara.threadsafe
|
20
|
+
# When {Capybara.configure threadsafe} is `true` the sessions options will be initially set to the
|
21
21
|
# current values of the global options and a configuration block can be passed to the session initializer.
|
22
|
-
# For available options see {Capybara::SessionConfig::OPTIONS}
|
22
|
+
# For available options see {Capybara::SessionConfig::OPTIONS}:
|
23
23
|
#
|
24
24
|
# session = Capybara::Session.new(:driver, MyRackApp) do |config|
|
25
25
|
# config.app_host = "http://my_host.dev"
|
26
26
|
# end
|
27
27
|
#
|
28
|
-
# Session provides a number of methods for controlling the navigation of the page, such as
|
29
|
-
#
|
28
|
+
# The {Session} provides a number of methods for controlling the navigation of the page, such as {#visit},
|
29
|
+
# {#current_path}, and so on. It also delegates a number of methods to a {Capybara::Document}, representing
|
30
30
|
# the current HTML document. This allows interaction:
|
31
31
|
#
|
32
32
|
# session.fill_in('q', with: 'Capybara')
|
33
33
|
# session.click_button('Search')
|
34
34
|
# expect(session).to have_content('Capybara')
|
35
35
|
#
|
36
|
-
# When using capybara/dsl
|
36
|
+
# When using `capybara/dsl`, the {Session} is initialized automatically for you.
|
37
37
|
#
|
38
38
|
class Session
|
39
39
|
include Capybara::SessionMatchers
|
40
40
|
|
41
41
|
NODE_METHODS = %i[
|
42
42
|
all first attach_file text check choose scroll_to scroll_by
|
43
|
+
click double_click right_click
|
43
44
|
click_link_or_button click_button click_link
|
44
45
|
fill_in find find_all find_button find_by_id find_field find_link
|
45
46
|
has_content? has_text? has_css? has_no_content? has_no_text?
|
46
47
|
has_no_css? has_no_xpath? has_xpath? select uncheck
|
48
|
+
has_element? has_no_element?
|
47
49
|
has_link? has_no_link? has_button? has_no_button? has_field?
|
48
50
|
has_no_field? has_checked_field? has_unchecked_field?
|
49
51
|
has_no_table? has_table? unselect has_select? has_no_select?
|
@@ -58,7 +60,7 @@ module Capybara
|
|
58
60
|
].freeze
|
59
61
|
SESSION_METHODS = %i[
|
60
62
|
body html source current_url current_host current_path
|
61
|
-
execute_script evaluate_script visit refresh go_back go_forward
|
63
|
+
execute_script evaluate_script evaluate_async_script visit refresh go_back go_forward send_keys
|
62
64
|
within within_element within_fieldset within_table within_frame switch_to_frame
|
63
65
|
current_window windows open_new_window switch_to_window within_window window_opened_by
|
64
66
|
save_page save_and_open_page save_screenshot
|
@@ -75,9 +77,11 @@ module Capybara
|
|
75
77
|
attr_accessor :synchronized
|
76
78
|
|
77
79
|
def initialize(mode, app = nil)
|
78
|
-
|
80
|
+
if app && !app.respond_to?(:call)
|
81
|
+
raise TypeError, 'The second parameter to Session::new should be a rack app if passed.'
|
82
|
+
end
|
79
83
|
|
80
|
-
@@instance_created = true
|
84
|
+
@@instance_created = true # rubocop:disable Style/ClassVars
|
81
85
|
@mode = mode
|
82
86
|
@app = app
|
83
87
|
if block_given?
|
@@ -88,15 +92,15 @@ module Capybara
|
|
88
92
|
@server = if config.run_server && @app && driver.needs_server?
|
89
93
|
server_options = { port: config.server_port, host: config.server_host, reportable_errors: config.server_errors }
|
90
94
|
server_options[:extra_middleware] = [Capybara::Server::AnimationDisabler] if config.disable_animation
|
91
|
-
Capybara::Server.new(@app, server_options).boot
|
95
|
+
Capybara::Server.new(@app, **server_options).boot
|
92
96
|
end
|
93
97
|
@touched = false
|
94
98
|
end
|
95
99
|
|
96
100
|
def driver
|
97
101
|
@driver ||= begin
|
98
|
-
unless Capybara.drivers
|
99
|
-
other_drivers = Capybara.drivers.
|
102
|
+
unless Capybara.drivers[mode]
|
103
|
+
other_drivers = Capybara.drivers.names.map(&:inspect)
|
100
104
|
raise Capybara::DriverNotFoundError, "no driver called #{mode.inspect} was found, available drivers: #{other_drivers.join(', ')}"
|
101
105
|
end
|
102
106
|
driver = Capybara.drivers[mode].call(app)
|
@@ -107,26 +111,28 @@ module Capybara
|
|
107
111
|
|
108
112
|
##
|
109
113
|
#
|
110
|
-
# Reset the session (i.e. remove cookies and navigate to blank page)
|
114
|
+
# Reset the session (i.e. remove cookies and navigate to blank page).
|
111
115
|
#
|
112
116
|
# This method does not:
|
113
117
|
#
|
114
|
-
#
|
115
|
-
#
|
116
|
-
#
|
118
|
+
# * accept modal dialogs if they are present (Selenium driver now does, others may not)
|
119
|
+
# * clear browser cache/HTML 5 local storage/IndexedDB/Web SQL database/etc.
|
120
|
+
# * modify state of the driver/underlying browser in any other way
|
117
121
|
#
|
118
122
|
# as doing so will result in performance downsides and it's not needed to do everything from the list above for most apps.
|
119
123
|
#
|
120
124
|
# If you want to do anything from the list above on a general basis you can:
|
121
125
|
#
|
122
|
-
#
|
123
|
-
#
|
124
|
-
#
|
126
|
+
# * write RSpec/Cucumber/etc. after hook
|
127
|
+
# * monkeypatch this method
|
128
|
+
# * use Ruby's `prepend` method
|
125
129
|
#
|
126
130
|
def reset!
|
127
131
|
if @touched
|
128
132
|
driver.reset!
|
129
133
|
@touched = false
|
134
|
+
switch_to_frame(:top) rescue nil # rubocop:disable Style/RescueModifier
|
135
|
+
@scopes = [nil]
|
130
136
|
end
|
131
137
|
@server&.wait_for_pending_requests
|
132
138
|
raise_server_error!
|
@@ -136,19 +142,18 @@ module Capybara
|
|
136
142
|
|
137
143
|
##
|
138
144
|
#
|
139
|
-
# Disconnect from the current driver.
|
140
|
-
#
|
145
|
+
# Disconnect from the current driver. A new driver will be instantiated on the next interaction.
|
141
146
|
#
|
142
147
|
def quit
|
143
148
|
@driver.quit if @driver.respond_to? :quit
|
144
|
-
@driver = nil
|
149
|
+
@document = @driver = nil
|
145
150
|
@touched = false
|
146
151
|
@server&.reset_error!
|
147
152
|
end
|
148
153
|
|
149
154
|
##
|
150
155
|
#
|
151
|
-
# Raise errors encountered in the server
|
156
|
+
# Raise errors encountered in the server.
|
152
157
|
#
|
153
158
|
def raise_server_error!
|
154
159
|
return unless @server&.error
|
@@ -158,9 +163,8 @@ module Capybara
|
|
158
163
|
if config.raise_server_errors
|
159
164
|
raise CapybaraError, 'Your application server raised an error - It has been raised in your test code because Capybara.raise_server_errors == true'
|
160
165
|
end
|
161
|
-
rescue CapybaraError
|
162
|
-
|
163
|
-
raise @server.error, @server.error.message, @server.error.backtrace
|
166
|
+
rescue CapybaraError => capy_error # rubocop:disable Naming/RescuedExceptionsVariableName
|
167
|
+
raise @server.error, cause: capy_error
|
164
168
|
ensure
|
165
169
|
@server.reset_error!
|
166
170
|
end
|
@@ -168,9 +172,9 @@ module Capybara
|
|
168
172
|
|
169
173
|
##
|
170
174
|
#
|
171
|
-
# Returns a hash of response headers. Not supported by all drivers (e.g. Selenium)
|
175
|
+
# Returns a hash of response headers. Not supported by all drivers (e.g. Selenium).
|
172
176
|
#
|
173
|
-
# @return [Hash
|
177
|
+
# @return [Hash<String, String>] A hash of response headers.
|
174
178
|
#
|
175
179
|
def response_headers
|
176
180
|
driver.response_headers
|
@@ -178,7 +182,7 @@ module Capybara
|
|
178
182
|
|
179
183
|
##
|
180
184
|
#
|
181
|
-
# Returns the current HTTP status code as an
|
185
|
+
# Returns the current HTTP status code as an integer. Not supported by all drivers (e.g. Selenium).
|
182
186
|
#
|
183
187
|
# @return [Integer] Current HTTP status code
|
184
188
|
#
|
@@ -191,7 +195,7 @@ module Capybara
|
|
191
195
|
# @return [String] A snapshot of the DOM of the current document, as it looks right now (potentially modified by JavaScript).
|
192
196
|
#
|
193
197
|
def html
|
194
|
-
driver.html
|
198
|
+
driver.html || ''
|
195
199
|
end
|
196
200
|
alias_method :body, :html
|
197
201
|
alias_method :source, :html
|
@@ -238,13 +242,13 @@ module Capybara
|
|
238
242
|
#
|
239
243
|
# For drivers which can run against an external application, such as the selenium driver
|
240
244
|
# giving an absolute URL will navigate to that page. This allows testing applications
|
241
|
-
# running on remote servers. For these drivers, setting {Capybara.app_host} will make the
|
245
|
+
# running on remote servers. For these drivers, setting {Capybara.configure app_host} will make the
|
242
246
|
# remote server the default. For example:
|
243
247
|
#
|
244
248
|
# Capybara.app_host = 'http://google.com'
|
245
249
|
# session.visit('/') # visits the google homepage
|
246
250
|
#
|
247
|
-
# If {Capybara.always_include_port} is set to true and this session is running against
|
251
|
+
# If {Capybara.configure always_include_port} is set to `true` and this session is running against
|
248
252
|
# a rack application, then the port that the rack application is running on will automatically
|
249
253
|
# be inserted into the URL. Supposing the app is running on port `4567`, doing something like:
|
250
254
|
#
|
@@ -263,7 +267,7 @@ module Capybara
|
|
263
267
|
|
264
268
|
if base_uri && [nil, 'http', 'https'].include?(visit_uri.scheme)
|
265
269
|
if visit_uri.relative?
|
266
|
-
visit_uri_parts = visit_uri.to_hash.
|
270
|
+
visit_uri_parts = visit_uri.to_hash.compact
|
267
271
|
|
268
272
|
# Useful to people deploying to a subdirectory
|
269
273
|
# and/or single page apps where only the url fragment changes
|
@@ -279,7 +283,7 @@ module Capybara
|
|
279
283
|
|
280
284
|
##
|
281
285
|
#
|
282
|
-
# Refresh the page
|
286
|
+
# Refresh the page.
|
283
287
|
#
|
284
288
|
def refresh
|
285
289
|
raise_server_error!
|
@@ -302,10 +306,28 @@ module Capybara
|
|
302
306
|
driver.go_forward
|
303
307
|
end
|
304
308
|
|
309
|
+
##
|
310
|
+
# @!method send_keys
|
311
|
+
# @see Capybara::Node::Element#send_keys
|
312
|
+
#
|
313
|
+
def send_keys(...)
|
314
|
+
driver.send_keys(...)
|
315
|
+
end
|
316
|
+
|
317
|
+
##
|
318
|
+
#
|
319
|
+
# Returns the element with focus.
|
320
|
+
#
|
321
|
+
# Not supported by Rack Test
|
322
|
+
#
|
323
|
+
def active_element
|
324
|
+
Capybara::Queries::ActiveElementQuery.new.resolve_for(self)[0].tap(&:allow_reload!)
|
325
|
+
end
|
326
|
+
|
305
327
|
##
|
306
328
|
#
|
307
|
-
# Executes the given block within the context of a node.
|
308
|
-
# same options as
|
329
|
+
# Executes the given block within the context of a node. {#within} takes the
|
330
|
+
# same options as {Capybara::Node::Finders#find #find}, as well as a block. For the duration of the
|
309
331
|
# block, any command to Capybara will be handled as though it were scoped
|
310
332
|
# to the given element.
|
311
333
|
#
|
@@ -313,18 +335,18 @@ module Capybara
|
|
313
335
|
# fill_in('Street', with: '12 Main Street')
|
314
336
|
# end
|
315
337
|
#
|
316
|
-
# Just as with
|
317
|
-
#
|
338
|
+
# Just as with `#find`, if multiple elements match the selector given to
|
339
|
+
# {#within}, an error will be raised, and just as with `#find`, this
|
318
340
|
# behaviour can be controlled through the `:match` and `:exact` options.
|
319
341
|
#
|
320
342
|
# It is possible to omit the first parameter, in that case, the selector is
|
321
|
-
# assumed to be of the type set in Capybara.default_selector.
|
343
|
+
# assumed to be of the type set in {Capybara.configure default_selector}.
|
322
344
|
#
|
323
345
|
# within('div#delivery-address') do
|
324
346
|
# fill_in('Street', with: '12 Main Street')
|
325
347
|
# end
|
326
348
|
#
|
327
|
-
# Note that a lot of uses of
|
349
|
+
# Note that a lot of uses of {#within} can be replaced more succinctly with
|
328
350
|
# chaining:
|
329
351
|
#
|
330
352
|
# find('div#delivery-address').fill_in('Street', with: '12 Main Street')
|
@@ -337,11 +359,11 @@ module Capybara
|
|
337
359
|
#
|
338
360
|
# @raise [Capybara::ElementNotFound] If the scope can't be found before time expires
|
339
361
|
#
|
340
|
-
def within(*args)
|
341
|
-
new_scope = args.first.respond_to?(:to_capybara_node) ? args.first.to_capybara_node : find(*args)
|
362
|
+
def within(*args, **kw_args)
|
363
|
+
new_scope = args.first.respond_to?(:to_capybara_node) ? args.first.to_capybara_node : find(*args, **kw_args)
|
342
364
|
begin
|
343
365
|
scopes.push(new_scope)
|
344
|
-
yield if block_given?
|
366
|
+
yield new_scope if block_given?
|
345
367
|
ensure
|
346
368
|
scopes.pop
|
347
369
|
end
|
@@ -354,8 +376,8 @@ module Capybara
|
|
354
376
|
#
|
355
377
|
# @param [String] locator Id or legend of the fieldset
|
356
378
|
#
|
357
|
-
def within_fieldset(locator)
|
358
|
-
within(:fieldset, locator)
|
379
|
+
def within_fieldset(locator, &block)
|
380
|
+
within(:fieldset, locator, &block)
|
359
381
|
end
|
360
382
|
|
361
383
|
##
|
@@ -364,24 +386,24 @@ module Capybara
|
|
364
386
|
#
|
365
387
|
# @param [String] locator Id or caption of the table
|
366
388
|
#
|
367
|
-
def within_table(locator)
|
368
|
-
within(:table, locator)
|
389
|
+
def within_table(locator, &block)
|
390
|
+
within(:table, locator, &block)
|
369
391
|
end
|
370
392
|
|
371
393
|
##
|
372
394
|
#
|
373
|
-
# Switch to the given frame
|
395
|
+
# Switch to the given frame.
|
374
396
|
#
|
375
397
|
# If you use this method you are responsible for making sure you switch back to the parent frame when done in the frame changed to.
|
376
|
-
#
|
398
|
+
# {#within_frame} is preferred over this method and should be used when possible.
|
377
399
|
# May not be supported by all drivers.
|
378
400
|
#
|
379
401
|
# @overload switch_to_frame(element)
|
380
|
-
# @param [Capybara::Node::Element]
|
381
|
-
# @overload switch_to_frame(
|
382
|
-
#
|
383
|
-
#
|
384
|
-
#
|
402
|
+
# @param [Capybara::Node::Element] element iframe/frame element to switch to
|
403
|
+
# @overload switch_to_frame(location)
|
404
|
+
# @param [Symbol] location relative location of the frame to switch to
|
405
|
+
# * :parent - the parent frame
|
406
|
+
# * :top - the top level document
|
385
407
|
#
|
386
408
|
def switch_to_frame(frame)
|
387
409
|
case frame
|
@@ -390,19 +412,20 @@ module Capybara
|
|
390
412
|
scopes.push(:frame)
|
391
413
|
when :parent
|
392
414
|
if scopes.last != :frame
|
393
|
-
raise Capybara::ScopeError, "`switch_to_frame(:parent)` cannot be called from inside a descendant frame's "\
|
415
|
+
raise Capybara::ScopeError, "`switch_to_frame(:parent)` cannot be called from inside a descendant frame's " \
|
394
416
|
'`within` block.'
|
395
417
|
end
|
396
418
|
scopes.pop
|
397
419
|
driver.switch_to_frame(:parent)
|
398
420
|
when :top
|
399
421
|
idx = scopes.index(:frame)
|
422
|
+
top_level_scopes = [:frame, nil]
|
400
423
|
if idx
|
401
|
-
if scopes.slice(idx
|
402
|
-
raise Capybara::ScopeError, "`switch_to_frame(:top)` cannot be called from inside a descendant frame's "\
|
424
|
+
if scopes.slice(idx..).any? { |scope| !top_level_scopes.include?(scope) }
|
425
|
+
raise Capybara::ScopeError, "`switch_to_frame(:top)` cannot be called from inside a descendant frame's " \
|
403
426
|
'`within` block.'
|
404
427
|
end
|
405
|
-
scopes.slice!(idx
|
428
|
+
scopes.slice!(idx..)
|
406
429
|
driver.switch_to_frame(:top)
|
407
430
|
end
|
408
431
|
else
|
@@ -422,8 +445,8 @@ module Capybara
|
|
422
445
|
# @param [String] locator The locator for the given selector kind. For :frame this is the name/id of a frame/iframe element
|
423
446
|
# @overload within_frame(index)
|
424
447
|
# @param [Integer] index index of a frame (0 based)
|
425
|
-
def within_frame(*args)
|
426
|
-
switch_to_frame(_find_frame(*args))
|
448
|
+
def within_frame(*args, **kw_args)
|
449
|
+
switch_to_frame(_find_frame(*args, **kw_args))
|
427
450
|
begin
|
428
451
|
yield if block_given?
|
429
452
|
ensure
|
@@ -452,22 +475,28 @@ module Capybara
|
|
452
475
|
end
|
453
476
|
|
454
477
|
##
|
455
|
-
# Open new window.
|
456
|
-
#
|
478
|
+
# Open a new window.
|
479
|
+
# The current window doesn't change as the result of this call.
|
457
480
|
# It should be switched to explicitly.
|
458
481
|
#
|
459
482
|
# @return [Capybara::Window] window that has been opened
|
460
483
|
#
|
461
|
-
def open_new_window
|
484
|
+
def open_new_window(kind = :tab)
|
462
485
|
window_opened_by do
|
463
|
-
driver.open_new_window
|
486
|
+
if driver.method(:open_new_window).arity.zero?
|
487
|
+
driver.open_new_window
|
488
|
+
else
|
489
|
+
driver.open_new_window(kind)
|
490
|
+
end
|
464
491
|
end
|
465
492
|
end
|
466
493
|
|
467
494
|
##
|
495
|
+
# Switch to the given window.
|
496
|
+
#
|
468
497
|
# @overload switch_to_window(&block)
|
469
498
|
# Switches to the first window for which given block returns a value other than false or nil.
|
470
|
-
# If window that matches block can't be found, the window will be switched back and
|
499
|
+
# If window that matches block can't be found, the window will be switched back and {Capybara::WindowError} will be raised.
|
471
500
|
# @example
|
472
501
|
# window = switch_to_window { title == 'Page title' }
|
473
502
|
# @raise [Capybara::WindowError] if no window matches given block
|
@@ -476,20 +505,20 @@ module Capybara
|
|
476
505
|
# @raise [Capybara::Driver::Base#no_such_window_error] if nonexistent (e.g. closed) window was passed
|
477
506
|
#
|
478
507
|
# @return [Capybara::Window] window that has been switched to
|
479
|
-
# @raise [Capybara::ScopeError] if this method is invoked inside
|
480
|
-
#
|
508
|
+
# @raise [Capybara::ScopeError] if this method is invoked inside {#within} or
|
509
|
+
# {#within_frame} methods
|
481
510
|
# @raise [ArgumentError] if both or neither arguments were provided
|
482
511
|
#
|
483
512
|
def switch_to_window(window = nil, **options, &window_locator)
|
484
|
-
raise ArgumentError, '`switch_to_window` can take either a block or a window, not both' if window &&
|
485
|
-
raise ArgumentError, '`switch_to_window`: either window or block should be provided' if !window && !
|
513
|
+
raise ArgumentError, '`switch_to_window` can take either a block or a window, not both' if window && window_locator
|
514
|
+
raise ArgumentError, '`switch_to_window`: either window or block should be provided' if !window && !window_locator
|
486
515
|
|
487
516
|
unless scopes.last.nil?
|
488
|
-
raise Capybara::ScopeError, '`switch_to_window` is not supposed to be invoked from '\
|
517
|
+
raise Capybara::ScopeError, '`switch_to_window` is not supposed to be invoked from ' \
|
489
518
|
'`within` or `within_frame` blocks.'
|
490
519
|
end
|
491
520
|
|
492
|
-
_switch_to_window(window, options, &window_locator)
|
521
|
+
_switch_to_window(window, **options, &window_locator)
|
493
522
|
end
|
494
523
|
|
495
524
|
##
|
@@ -497,20 +526,20 @@ module Capybara
|
|
497
526
|
#
|
498
527
|
# 1. Switches to the given window (it can be located by window instance/lambda/string).
|
499
528
|
# 2. Executes the given block (within window located at previous step).
|
500
|
-
# 3. Switches back (this step will be invoked even if exception
|
529
|
+
# 3. Switches back (this step will be invoked even if an exception occurs at the second step).
|
501
530
|
#
|
502
531
|
# @overload within_window(window) { do_something }
|
503
|
-
# @param window [Capybara::Window] instance of
|
532
|
+
# @param window [Capybara::Window] instance of {Capybara::Window} class
|
504
533
|
# that will be switched to
|
505
534
|
# @raise [driver#no_such_window_error] if nonexistent (e.g. closed) window was passed
|
506
535
|
# @overload within_window(proc_or_lambda) { do_something }
|
507
|
-
# @param lambda [Proc]
|
536
|
+
# @param lambda [Proc] First window for which lambda
|
508
537
|
# returns a value other than false or nil will be switched to.
|
509
538
|
# @example
|
510
539
|
# within_window(->{ page.title == 'Page title' }) { click_button 'Submit' }
|
511
540
|
# @raise [Capybara::WindowError] if no window matching lambda was found
|
512
541
|
#
|
513
|
-
# @raise [Capybara::ScopeError] if this method is invoked inside
|
542
|
+
# @raise [Capybara::ScopeError] if this method is invoked inside {#within_frame} method
|
514
543
|
# @return value returned by the block
|
515
544
|
#
|
516
545
|
def within_window(window_or_proc)
|
@@ -523,7 +552,7 @@ module Capybara
|
|
523
552
|
when Proc
|
524
553
|
_switch_to_window { window_or_proc.call }
|
525
554
|
else
|
526
|
-
raise ArgumentError
|
555
|
+
raise ArgumentError, '`#within_window` requires a `Capybara::Window` instance or a lambda'
|
527
556
|
end
|
528
557
|
|
529
558
|
begin
|
@@ -540,11 +569,11 @@ module Capybara
|
|
540
569
|
# Get the window that has been opened by the passed block.
|
541
570
|
# It will wait for it to be opened (in the same way as other Capybara methods wait).
|
542
571
|
# It's better to use this method than `windows.last`
|
543
|
-
# {https://dvcs.w3.org/hg/webdriver/raw-file/default/webdriver-spec.html#h_note_10 as order of windows isn't defined in some drivers}
|
572
|
+
# {https://dvcs.w3.org/hg/webdriver/raw-file/default/webdriver-spec.html#h_note_10 as order of windows isn't defined in some drivers}.
|
544
573
|
#
|
545
574
|
# @overload window_opened_by(**options, &block)
|
546
575
|
# @param options [Hash]
|
547
|
-
# @option options [Numeric] :wait
|
576
|
+
# @option options [Numeric] :wait maximum wait time. Defaults to {Capybara.configure default_max_wait_time}
|
548
577
|
# @return [Capybara::Window] the window that has been opened within a block
|
549
578
|
# @raise [Capybara::WindowError] if block passed to window hasn't opened window
|
550
579
|
# or opened more than one window
|
@@ -556,7 +585,7 @@ module Capybara
|
|
556
585
|
synchronize_windows(options) do
|
557
586
|
opened_handles = (driver.window_handles - old_handles)
|
558
587
|
if opened_handles.size != 1
|
559
|
-
raise Capybara::WindowError, 'block passed to #window_opened_by '\
|
588
|
+
raise Capybara::WindowError, 'block passed to #window_opened_by ' \
|
560
589
|
"opened #{opened_handles.size} windows instead of 1"
|
561
590
|
end
|
562
591
|
Window.new(self, opened_handles.first)
|
@@ -566,11 +595,11 @@ module Capybara
|
|
566
595
|
##
|
567
596
|
#
|
568
597
|
# Execute the given script, not returning a result. This is useful for scripts that return
|
569
|
-
# complex objects, such as jQuery statements.
|
570
|
-
#
|
598
|
+
# complex objects, such as jQuery statements. {#execute_script} should be used over
|
599
|
+
# {#evaluate_script} whenever possible.
|
571
600
|
#
|
572
601
|
# @param [String] script A string of JavaScript to execute
|
573
|
-
# @param args Optional arguments that will be passed to the script.
|
602
|
+
# @param args Optional arguments that will be passed to the script. Driver support for this is optional and types of objects supported may differ between drivers
|
574
603
|
#
|
575
604
|
def execute_script(script, *args)
|
576
605
|
@touched = true
|
@@ -580,10 +609,11 @@ module Capybara
|
|
580
609
|
##
|
581
610
|
#
|
582
611
|
# Evaluate the given JavaScript and return the result. Be careful when using this with
|
583
|
-
# scripts that return complex objects, such as jQuery statements.
|
612
|
+
# scripts that return complex objects, such as jQuery statements. {#execute_script} might
|
584
613
|
# be a better alternative.
|
585
614
|
#
|
586
615
|
# @param [String] script A string of JavaScript to evaluate
|
616
|
+
# @param args Optional arguments that will be passed to the script
|
587
617
|
# @return [Object] The result of the evaluated JavaScript (may be driver specific)
|
588
618
|
#
|
589
619
|
def evaluate_script(script, *args)
|
@@ -597,6 +627,7 @@ module Capybara
|
|
597
627
|
# Evaluate the given JavaScript and obtain the result from a callback function which will be passed as the last argument to the script.
|
598
628
|
#
|
599
629
|
# @param [String] script A string of JavaScript to evaluate
|
630
|
+
# @param args Optional arguments that will be passed to the script
|
600
631
|
# @return [Object] The result of the evaluated JavaScript (may be driver specific)
|
601
632
|
#
|
602
633
|
def evaluate_async_script(script, *args)
|
@@ -610,17 +641,17 @@ module Capybara
|
|
610
641
|
# Execute the block, accepting a alert.
|
611
642
|
#
|
612
643
|
# @!macro modal_params
|
613
|
-
# Expects a block whose actions will trigger the display modal to appear
|
644
|
+
# Expects a block whose actions will trigger the display modal to appear.
|
614
645
|
# @example
|
615
646
|
# $0 do
|
616
647
|
# click_link('link that triggers appearance of system modal')
|
617
648
|
# end
|
618
649
|
# @overload $0(text, **options, &blk)
|
619
|
-
# @param text [String, Regexp] Text or regex to match against the text in the modal.
|
620
|
-
# @option options [Numeric] :wait
|
650
|
+
# @param text [String, Regexp] Text or regex to match against the text in the modal. If not provided any modal is matched.
|
651
|
+
# @option options [Numeric] :wait Maximum time to wait for the modal to appear after executing the block. Defaults to {Capybara.configure default_max_wait_time}.
|
621
652
|
# @yield Block whose actions will trigger the system modal
|
622
653
|
# @overload $0(**options, &blk)
|
623
|
-
# @option options [Numeric] :wait
|
654
|
+
# @option options [Numeric] :wait Maximum time to wait for the modal to appear after executing the block. Defaults to {Capybara.configure default_max_wait_time}.
|
624
655
|
# @yield Block whose actions will trigger the system modal
|
625
656
|
# @return [String] the message shown in the modal
|
626
657
|
# @raise [Capybara::ModalNotFound] if modal dialog hasn't been found
|
@@ -672,12 +703,12 @@ module Capybara
|
|
672
703
|
|
673
704
|
##
|
674
705
|
#
|
675
|
-
# Save a snapshot of the page. If
|
676
|
-
#
|
706
|
+
# Save a snapshot of the page. If {Capybara.configure asset_host} is set it will inject `base` tag
|
707
|
+
# pointing to {Capybara.configure asset_host}.
|
677
708
|
#
|
678
|
-
# If invoked without arguments it will save file to
|
679
|
-
#
|
680
|
-
#
|
709
|
+
# If invoked without arguments it will save file to {Capybara.configure save_path}
|
710
|
+
# and file will be given randomly generated filename. If invoked with a relative path
|
711
|
+
# the path will be relative to {Capybara.configure save_path}.
|
681
712
|
#
|
682
713
|
# @param [String] path the path to where it should be saved
|
683
714
|
# @return [String] the path to which the file was saved
|
@@ -692,9 +723,9 @@ module Capybara
|
|
692
723
|
#
|
693
724
|
# Save a snapshot of the page and open it in a browser for inspection.
|
694
725
|
#
|
695
|
-
# If invoked without arguments it will save file to
|
696
|
-
#
|
697
|
-
#
|
726
|
+
# If invoked without arguments it will save file to {Capybara.configure save_path}
|
727
|
+
# and file will be given randomly generated filename. If invoked with a relative path
|
728
|
+
# the path will be relative to {Capybara.configure save_path}.
|
698
729
|
#
|
699
730
|
# @param [String] path the path to where it should be saved
|
700
731
|
#
|
@@ -706,32 +737,30 @@ module Capybara
|
|
706
737
|
#
|
707
738
|
# Save a screenshot of page.
|
708
739
|
#
|
709
|
-
# If invoked without arguments it will save file to
|
710
|
-
#
|
711
|
-
#
|
740
|
+
# If invoked without arguments it will save file to {Capybara.configure save_path}
|
741
|
+
# and file will be given randomly generated filename. If invoked with a relative path
|
742
|
+
# the path will be relative to {Capybara.configure save_path}.
|
712
743
|
#
|
713
744
|
# @param [String] path the path to where it should be saved
|
714
745
|
# @param [Hash] options a customizable set of options
|
715
746
|
# @return [String] the path to which the file was saved
|
716
747
|
def save_screenshot(path = nil, **options)
|
717
|
-
prepare_path(path, 'png').tap { |p_path| driver.save_screenshot(p_path, options) }
|
748
|
+
prepare_path(path, 'png').tap { |p_path| driver.save_screenshot(p_path, **options) }
|
718
749
|
end
|
719
750
|
|
720
751
|
##
|
721
752
|
#
|
722
753
|
# Save a screenshot of the page and open it for inspection.
|
723
754
|
#
|
724
|
-
# If invoked without arguments it will save file to
|
725
|
-
#
|
726
|
-
#
|
755
|
+
# If invoked without arguments it will save file to {Capybara.configure save_path}
|
756
|
+
# and file will be given randomly generated filename. If invoked with a relative path
|
757
|
+
# the path will be relative to {Capybara.configure save_path}.
|
727
758
|
#
|
728
759
|
# @param [String] path the path to where it should be saved
|
729
760
|
# @param [Hash] options a customizable set of options
|
730
761
|
#
|
731
762
|
def save_and_open_screenshot(path = nil, **options)
|
732
|
-
|
733
|
-
save_screenshot(path, options).tap { |s_path| open_file(s_path) }
|
734
|
-
# rubocop:enable Lint/Debugger
|
763
|
+
save_screenshot(path, **options).tap { |s_path| open_file(s_path) }
|
735
764
|
end
|
736
765
|
|
737
766
|
def document
|
@@ -739,16 +768,20 @@ module Capybara
|
|
739
768
|
end
|
740
769
|
|
741
770
|
NODE_METHODS.each do |method|
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
771
|
+
class_eval <<~METHOD, __FILE__, __LINE__ + 1
|
772
|
+
def #{method}(...)
|
773
|
+
@touched = true
|
774
|
+
current_scope.#{method}(...)
|
775
|
+
end
|
776
|
+
METHOD
|
746
777
|
end
|
747
778
|
|
748
779
|
DOCUMENT_METHODS.each do |method|
|
749
|
-
|
750
|
-
|
751
|
-
|
780
|
+
class_eval <<~METHOD, __FILE__, __LINE__ + 1
|
781
|
+
def #{method}(...)
|
782
|
+
document.#{method}(...)
|
783
|
+
end
|
784
|
+
METHOD
|
752
785
|
end
|
753
786
|
|
754
787
|
def inspect
|
@@ -762,9 +795,9 @@ module Capybara
|
|
762
795
|
|
763
796
|
##
|
764
797
|
#
|
765
|
-
# Yield a block using a specific wait time
|
798
|
+
# Yield a block using a specific maximum wait time.
|
766
799
|
#
|
767
|
-
def using_wait_time(seconds)
|
800
|
+
def using_wait_time(seconds, &block)
|
768
801
|
if Capybara.threadsafe
|
769
802
|
begin
|
770
803
|
previous_wait_time = config.default_max_wait_time
|
@@ -774,14 +807,14 @@ module Capybara
|
|
774
807
|
config.default_max_wait_time = previous_wait_time
|
775
808
|
end
|
776
809
|
else
|
777
|
-
Capybara.using_wait_time(seconds)
|
810
|
+
Capybara.using_wait_time(seconds, &block)
|
778
811
|
end
|
779
812
|
end
|
780
813
|
|
781
814
|
##
|
782
815
|
#
|
783
|
-
#
|
784
|
-
#
|
816
|
+
# Accepts a block to set the configuration options if {Capybara.configure threadsafe} is `true`. Note that some options only have an effect
|
817
|
+
# if set at initialization time, so look at the configuration block that can be passed to the initializer too.
|
785
818
|
#
|
786
819
|
def configure
|
787
820
|
raise 'Session configuration is only supported when Capybara.threadsafe == true' unless Capybara.threadsafe
|
@@ -801,20 +834,24 @@ module Capybara
|
|
801
834
|
end
|
802
835
|
end
|
803
836
|
|
837
|
+
def server_url
|
838
|
+
@server&.base_url
|
839
|
+
end
|
840
|
+
|
804
841
|
private
|
805
842
|
|
806
|
-
@@instance_created = false
|
843
|
+
@@instance_created = false # rubocop:disable Style/ClassVars
|
807
844
|
|
808
845
|
def driver_args(args)
|
809
846
|
args.map { |arg| arg.is_a?(Capybara::Node::Element) ? arg.base : arg }
|
810
847
|
end
|
811
848
|
|
812
849
|
def accept_modal(type, text_or_options, options, &blk)
|
813
|
-
driver.accept_modal(type, modal_options(text_or_options, options), &blk)
|
850
|
+
driver.accept_modal(type, **modal_options(text_or_options, **options), &blk)
|
814
851
|
end
|
815
852
|
|
816
853
|
def dismiss_modal(type, text_or_options, options, &blk)
|
817
|
-
driver.dismiss_modal(type, modal_options(text_or_options, options), &blk)
|
854
|
+
driver.dismiss_modal(type, **modal_options(text_or_options, **options), &blk)
|
818
855
|
end
|
819
856
|
|
820
857
|
def modal_options(text = nil, **options)
|
@@ -850,7 +887,7 @@ module Capybara
|
|
850
887
|
when Array
|
851
888
|
arg.map { |subarg| element_script_result(subarg) }
|
852
889
|
when Hash
|
853
|
-
arg.
|
890
|
+
arg.transform_values! { |value| element_script_result(value) }
|
854
891
|
when Capybara::Driver::Node
|
855
892
|
Capybara::Node::Element.new(self, arg, nil, nil)
|
856
893
|
else
|
@@ -858,24 +895,18 @@ module Capybara
|
|
858
895
|
end
|
859
896
|
end
|
860
897
|
|
861
|
-
def server_url
|
862
|
-
"http#{'s' if @server.using_ssl?}://#{@server.host}:#{@server.port}" if @server
|
863
|
-
end
|
864
|
-
|
865
898
|
def adjust_server_port(uri)
|
866
899
|
uri.port ||= @server.port if @server && config.always_include_port
|
867
900
|
end
|
868
901
|
|
869
|
-
def _find_frame(*args)
|
870
|
-
return find(:frame) if args.length.zero?
|
871
|
-
|
902
|
+
def _find_frame(*args, **kw_args)
|
872
903
|
case args[0]
|
873
904
|
when Capybara::Node::Element
|
874
905
|
args[0]
|
875
|
-
when String,
|
876
|
-
find(:frame, *args)
|
906
|
+
when String, nil
|
907
|
+
find(:frame, *args, **kw_args)
|
877
908
|
when Symbol
|
878
|
-
find(*args)
|
909
|
+
find(*args, **kw_args)
|
879
910
|
when Integer
|
880
911
|
idx = args[0]
|
881
912
|
all(:frame, minimum: idx + 1)[idx]
|