capybara 2.5.0 → 2.18.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 +5 -5
- data/.yard/templates_custom/default/class/html/selectors.erb +38 -0
- data/.yard/templates_custom/default/class/html/setup.rb +17 -0
- data/.yard/yard_extensions.rb +78 -0
- data/.yardopts +1 -0
- data/History.md +413 -10
- data/License.txt +1 -1
- data/README.md +237 -130
- data/lib/capybara/config.rb +132 -0
- data/lib/capybara/cucumber.rb +3 -1
- data/lib/capybara/driver/base.rb +27 -6
- data/lib/capybara/driver/node.rb +14 -5
- data/lib/capybara/dsl.rb +2 -3
- data/lib/capybara/helpers.rb +13 -65
- data/lib/capybara/minitest/spec.rb +177 -0
- data/lib/capybara/minitest.rb +278 -0
- data/lib/capybara/node/actions.rb +180 -24
- data/lib/capybara/node/base.rb +17 -5
- data/lib/capybara/node/document.rb +5 -0
- data/lib/capybara/node/document_matchers.rb +15 -14
- data/lib/capybara/node/element.rb +55 -7
- data/lib/capybara/node/finders.rb +179 -67
- data/lib/capybara/node/matchers.rb +301 -105
- data/lib/capybara/node/simple.rb +15 -4
- data/lib/capybara/queries/ancestor_query.rb +25 -0
- data/lib/capybara/queries/base_query.rb +69 -3
- data/lib/capybara/queries/current_path_query.rb +17 -8
- data/lib/capybara/queries/match_query.rb +19 -0
- data/lib/capybara/queries/selector_query.rb +251 -0
- data/lib/capybara/queries/sibling_query.rb +25 -0
- data/lib/capybara/queries/text_query.rb +67 -16
- data/lib/capybara/queries/title_query.rb +4 -2
- data/lib/capybara/query.rb +3 -131
- data/lib/capybara/rack_test/browser.rb +14 -5
- data/lib/capybara/rack_test/css_handlers.rb +1 -0
- data/lib/capybara/rack_test/driver.rb +15 -8
- data/lib/capybara/rack_test/form.rb +34 -12
- data/lib/capybara/rack_test/node.rb +29 -12
- data/lib/capybara/rails.rb +3 -3
- data/lib/capybara/result.rb +104 -9
- data/lib/capybara/rspec/compound.rb +95 -0
- data/lib/capybara/rspec/features.rb +17 -6
- data/lib/capybara/rspec/matcher_proxies.rb +45 -0
- data/lib/capybara/rspec/matchers.rb +199 -80
- data/lib/capybara/rspec.rb +4 -2
- data/lib/capybara/selector/css.rb +30 -0
- data/lib/capybara/selector/filter.rb +20 -0
- data/lib/capybara/selector/filter_set.rb +74 -0
- data/lib/capybara/selector/filters/base.rb +33 -0
- data/lib/capybara/selector/filters/expression_filter.rb +40 -0
- data/lib/capybara/selector/filters/node_filter.rb +27 -0
- data/lib/capybara/selector/selector.rb +276 -0
- data/lib/capybara/selector.rb +452 -157
- data/lib/capybara/selenium/driver.rb +282 -81
- data/lib/capybara/selenium/node.rb +144 -46
- data/lib/capybara/server.rb +59 -16
- data/lib/capybara/session/config.rb +114 -0
- data/lib/capybara/session/matchers.rb +29 -19
- data/lib/capybara/session.rb +378 -143
- data/lib/capybara/spec/fixtures/no_extension +1 -0
- data/lib/capybara/spec/public/jquery-ui.js +13 -791
- data/lib/capybara/spec/public/jquery.js +4 -9045
- data/lib/capybara/spec/public/test.js +45 -11
- data/lib/capybara/spec/session/accept_alert_spec.rb +30 -7
- data/lib/capybara/spec/session/accept_confirm_spec.rb +14 -2
- data/lib/capybara/spec/session/accept_prompt_spec.rb +35 -6
- data/lib/capybara/spec/session/all_spec.rb +45 -32
- data/lib/capybara/spec/session/ancestor_spec.rb +85 -0
- data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +110 -0
- data/lib/capybara/spec/session/assert_current_path.rb +15 -2
- data/lib/capybara/spec/session/assert_selector.rb +29 -28
- data/lib/capybara/spec/session/assert_text.rb +59 -20
- data/lib/capybara/spec/session/assert_title.rb +25 -11
- data/lib/capybara/spec/session/attach_file_spec.rb +42 -4
- data/lib/capybara/spec/session/body_spec.rb +1 -0
- data/lib/capybara/spec/session/check_spec.rb +90 -14
- data/lib/capybara/spec/session/choose_spec.rb +31 -5
- data/lib/capybara/spec/session/click_button_spec.rb +20 -9
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +15 -9
- data/lib/capybara/spec/session/click_link_spec.rb +39 -15
- data/lib/capybara/spec/session/current_scope_spec.rb +2 -1
- data/lib/capybara/spec/session/current_url_spec.rb +12 -3
- data/lib/capybara/spec/session/dismiss_confirm_spec.rb +6 -5
- data/lib/capybara/spec/session/dismiss_prompt_spec.rb +4 -3
- data/lib/capybara/spec/session/element/assert_match_selector.rb +36 -0
- data/lib/capybara/spec/session/element/match_css_spec.rb +23 -0
- data/lib/capybara/spec/session/element/match_xpath_spec.rb +23 -0
- data/lib/capybara/spec/session/element/matches_selector_spec.rb +106 -0
- data/lib/capybara/spec/session/evaluate_async_script_spec.rb +22 -0
- data/lib/capybara/spec/session/evaluate_script_spec.rb +23 -1
- data/lib/capybara/spec/session/execute_script_spec.rb +22 -3
- data/lib/capybara/spec/session/fill_in_spec.rb +50 -32
- data/lib/capybara/spec/session/find_button_spec.rb +43 -2
- data/lib/capybara/spec/session/find_by_id_spec.rb +3 -2
- data/lib/capybara/spec/session/find_field_spec.rb +42 -6
- data/lib/capybara/spec/session/find_link_spec.rb +22 -3
- data/lib/capybara/spec/session/find_spec.rb +103 -57
- data/lib/capybara/spec/session/first_spec.rb +34 -18
- data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +103 -0
- data/lib/capybara/spec/session/{within_frame_spec.rb → frame/within_frame_spec.rb} +44 -2
- data/lib/capybara/spec/session/go_back_spec.rb +2 -1
- data/lib/capybara/spec/session/go_forward_spec.rb +2 -1
- data/lib/capybara/spec/session/has_all_selectors_spec.rb +69 -0
- data/lib/capybara/spec/session/has_button_spec.rb +17 -8
- data/lib/capybara/spec/session/has_css_spec.rb +85 -73
- data/lib/capybara/spec/session/has_current_path_spec.rb +91 -7
- data/lib/capybara/spec/session/has_field_spec.rb +93 -58
- data/lib/capybara/spec/session/has_link_spec.rb +9 -8
- data/lib/capybara/spec/session/has_none_selectors_spec.rb +76 -0
- data/lib/capybara/spec/session/has_select_spec.rb +159 -59
- data/lib/capybara/spec/session/has_selector_spec.rb +64 -28
- data/lib/capybara/spec/session/has_table_spec.rb +1 -0
- data/lib/capybara/spec/session/has_text_spec.rb +27 -12
- data/lib/capybara/spec/session/has_title_spec.rb +22 -4
- data/lib/capybara/spec/session/has_xpath_spec.rb +32 -29
- data/lib/capybara/spec/session/headers.rb +2 -1
- data/lib/capybara/spec/session/html_spec.rb +4 -3
- data/lib/capybara/spec/session/node_spec.rb +198 -38
- data/lib/capybara/spec/session/refresh_spec.rb +28 -0
- data/lib/capybara/spec/session/reset_session_spec.rb +46 -5
- data/lib/capybara/spec/session/response_code.rb +2 -1
- data/lib/capybara/spec/session/save_and_open_page_spec.rb +1 -0
- data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +6 -5
- data/lib/capybara/spec/session/save_page_spec.rb +34 -2
- data/lib/capybara/spec/session/save_screenshot_spec.rb +31 -1
- data/lib/capybara/spec/session/screenshot_spec.rb +4 -2
- data/lib/capybara/spec/session/select_spec.rb +34 -32
- data/lib/capybara/spec/session/selectors_spec.rb +65 -0
- data/lib/capybara/spec/session/sibling_spec.rb +52 -0
- data/lib/capybara/spec/session/text_spec.rb +4 -4
- data/lib/capybara/spec/session/title_spec.rb +2 -1
- data/lib/capybara/spec/session/uncheck_spec.rb +42 -2
- data/lib/capybara/spec/session/unselect_spec.rb +17 -16
- data/lib/capybara/spec/session/visit_spec.rb +77 -2
- data/lib/capybara/spec/session/window/become_closed_spec.rb +12 -11
- data/lib/capybara/spec/session/window/current_window_spec.rb +1 -0
- data/lib/capybara/spec/session/window/open_new_window_spec.rb +1 -0
- data/lib/capybara/spec/session/window/switch_to_window_spec.rb +16 -11
- data/lib/capybara/spec/session/window/window_opened_by_spec.rb +7 -4
- data/lib/capybara/spec/session/window/window_spec.rb +36 -29
- data/lib/capybara/spec/session/window/windows_spec.rb +1 -0
- data/lib/capybara/spec/session/window/within_window_spec.rb +31 -7
- data/lib/capybara/spec/session/within_spec.rb +14 -6
- data/lib/capybara/spec/spec_helper.rb +37 -4
- data/lib/capybara/spec/test_app.rb +15 -3
- data/lib/capybara/spec/views/buttons.erb +1 -0
- data/lib/capybara/spec/views/fieldsets.erb +2 -1
- data/lib/capybara/spec/views/form.erb +169 -9
- data/lib/capybara/spec/views/frame_child.erb +10 -2
- data/lib/capybara/spec/views/frame_one.erb +2 -1
- data/lib/capybara/spec/views/frame_parent.erb +3 -2
- data/lib/capybara/spec/views/frame_two.erb +2 -1
- data/lib/capybara/spec/views/header_links.erb +1 -0
- data/lib/capybara/spec/views/host_links.erb +1 -0
- data/lib/capybara/spec/views/initial_alert.erb +10 -0
- data/lib/capybara/spec/views/path.erb +1 -0
- data/lib/capybara/spec/views/popup_one.erb +1 -0
- data/lib/capybara/spec/views/popup_two.erb +1 -0
- data/lib/capybara/spec/views/postback.erb +2 -1
- data/lib/capybara/spec/views/tables.erb +1 -0
- data/lib/capybara/spec/views/with_base_tag.erb +1 -0
- data/lib/capybara/spec/views/with_count.erb +2 -1
- data/lib/capybara/spec/views/with_fixed_header_footer.erb +17 -0
- data/lib/capybara/spec/views/with_hover.erb +7 -1
- data/lib/capybara/spec/views/with_html.erb +40 -2
- data/lib/capybara/spec/views/with_html_entities.erb +1 -0
- data/lib/capybara/spec/views/with_js.erb +32 -1
- data/lib/capybara/spec/views/with_scope.erb +1 -0
- data/lib/capybara/spec/views/with_simple_html.erb +2 -1
- data/lib/capybara/spec/views/with_slow_unload.erb +17 -0
- data/lib/capybara/spec/views/with_title.erb +2 -1
- data/lib/capybara/spec/views/with_unload_alert.erb +14 -0
- data/lib/capybara/spec/views/with_windows.erb +7 -0
- data/lib/capybara/spec/views/within_frames.erb +3 -2
- data/lib/capybara/version.rb +2 -1
- data/lib/capybara/window.rb +20 -3
- data/lib/capybara.rb +189 -93
- data/spec/basic_node_spec.rb +7 -6
- data/spec/capybara_spec.rb +90 -4
- data/spec/dsl_spec.rb +3 -1
- data/spec/filter_set_spec.rb +28 -0
- data/spec/fixtures/capybara.csv +1 -0
- data/spec/fixtures/selenium_driver_rspec_failure.rb +5 -1
- data/spec/fixtures/selenium_driver_rspec_success.rb +5 -1
- data/spec/minitest_spec.rb +130 -0
- data/spec/minitest_spec_spec.rb +135 -0
- data/spec/per_session_config_spec.rb +67 -0
- data/spec/rack_test_spec.rb +50 -7
- data/spec/result_spec.rb +76 -0
- data/spec/rspec/features_spec.rb +21 -8
- data/spec/rspec/scenarios_spec.rb +21 -0
- data/spec/rspec/{matchers_spec.rb → shared_spec_matchers.rb} +160 -54
- data/spec/rspec/views_spec.rb +5 -0
- data/spec/rspec_matchers_spec.rb +46 -0
- data/spec/rspec_spec.rb +79 -1
- data/spec/selector_spec.rb +199 -0
- data/spec/selenium_spec_chrome.rb +54 -9
- data/spec/selenium_spec_firefox.rb +68 -0
- data/spec/selenium_spec_marionette.rb +127 -0
- data/spec/server_spec.rb +102 -14
- data/spec/session_spec.rb +54 -0
- data/spec/shared_selenium_session.rb +215 -0
- data/spec/spec_helper.rb +7 -0
- metadata +140 -15
- data/spec/selenium_spec.rb +0 -128
data/lib/capybara/session.rb
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
require 'capybara/session/matchers'
|
|
3
|
+
require 'addressable/uri'
|
|
2
4
|
|
|
3
5
|
module Capybara
|
|
4
6
|
|
|
@@ -15,11 +17,19 @@ module Capybara
|
|
|
15
17
|
# session = Capybara::Session.new(:culerity)
|
|
16
18
|
# session.visit('http://www.google.com')
|
|
17
19
|
#
|
|
20
|
+
# When Capybara.threadsafe == true the sessions options will be initially set to the
|
|
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}
|
|
23
|
+
#
|
|
24
|
+
# session = Capybara::Session.new(:driver, MyRackApp) do |config|
|
|
25
|
+
# config.app_host = "http://my_host.dev"
|
|
26
|
+
# end
|
|
27
|
+
#
|
|
18
28
|
# Session provides a number of methods for controlling the navigation of the page, such as +visit+,
|
|
19
29
|
# +current_path, and so on. It also delegate a number of methods to a Capybara::Document, representing
|
|
20
30
|
# the current HTML document. This allows interaction:
|
|
21
31
|
#
|
|
22
|
-
# session.fill_in('q', :
|
|
32
|
+
# session.fill_in('q', with: 'Capybara')
|
|
23
33
|
# session.click_button('Search')
|
|
24
34
|
# expect(session).to have_content('Capybara')
|
|
25
35
|
#
|
|
@@ -39,6 +49,7 @@ module Capybara
|
|
|
39
49
|
:has_no_table?, :has_table?, :unselect, :has_select?, :has_no_select?,
|
|
40
50
|
:has_selector?, :has_no_selector?, :click_on, :has_no_checked_field?,
|
|
41
51
|
:has_no_unchecked_field?, :query, :assert_selector, :assert_no_selector,
|
|
52
|
+
:assert_all_of_selectors, :assert_none_of_selectors,
|
|
42
53
|
:refute_selector, :assert_text, :assert_no_text
|
|
43
54
|
]
|
|
44
55
|
# @api private
|
|
@@ -47,9 +58,9 @@ module Capybara
|
|
|
47
58
|
]
|
|
48
59
|
SESSION_METHODS = [
|
|
49
60
|
:body, :html, :source, :current_url, :current_host, :current_path,
|
|
50
|
-
:execute_script, :evaluate_script, :visit, :go_back, :go_forward,
|
|
51
|
-
:within, :within_fieldset, :within_table, :within_frame, :
|
|
52
|
-
:windows, :open_new_window, :switch_to_window, :within_window, :window_opened_by,
|
|
61
|
+
:execute_script, :evaluate_script, :visit, :refresh, :go_back, :go_forward,
|
|
62
|
+
:within, :within_element, :within_fieldset, :within_table, :within_frame, :switch_to_frame,
|
|
63
|
+
:current_window, :windows, :open_new_window, :switch_to_window, :within_window, :window_opened_by,
|
|
53
64
|
:save_page, :save_and_open_page, :save_screenshot,
|
|
54
65
|
:save_and_open_screenshot, :reset_session!, :response_headers,
|
|
55
66
|
:status_code, :current_scope,
|
|
@@ -65,10 +76,16 @@ module Capybara
|
|
|
65
76
|
attr_accessor :synchronized
|
|
66
77
|
|
|
67
78
|
def initialize(mode, app=nil)
|
|
79
|
+
raise TypeError, "The second parameter to Session::new should be a rack app if passed." if app && !app.respond_to?(:call)
|
|
80
|
+
@@instance_created = true
|
|
68
81
|
@mode = mode
|
|
69
82
|
@app = app
|
|
70
|
-
if
|
|
71
|
-
|
|
83
|
+
if block_given?
|
|
84
|
+
raise "A configuration block is only accepted when Capybara.threadsafe == true" unless Capybara.threadsafe
|
|
85
|
+
yield config if block_given?
|
|
86
|
+
end
|
|
87
|
+
if config.run_server and @app and driver.needs_server?
|
|
88
|
+
@server = Capybara::Server.new(@app, config.server_port, config.server_host, config.server_errors).boot
|
|
72
89
|
else
|
|
73
90
|
@server = nil
|
|
74
91
|
end
|
|
@@ -81,7 +98,9 @@ module Capybara
|
|
|
81
98
|
other_drivers = Capybara.drivers.keys.map { |key| key.inspect }
|
|
82
99
|
raise Capybara::DriverNotFoundError, "no driver called #{mode.inspect} was found, available drivers: #{other_drivers.join(', ')}"
|
|
83
100
|
end
|
|
84
|
-
Capybara.drivers[mode].call(app)
|
|
101
|
+
driver = Capybara.drivers[mode].call(app)
|
|
102
|
+
driver.session = self if driver.respond_to?(:session=)
|
|
103
|
+
driver
|
|
85
104
|
end
|
|
86
105
|
end
|
|
87
106
|
|
|
@@ -106,9 +125,9 @@ module Capybara
|
|
|
106
125
|
def reset!
|
|
107
126
|
if @touched
|
|
108
127
|
driver.reset!
|
|
109
|
-
assert_no_selector :xpath, "/html/body/*" if driver.browser_initialized?
|
|
110
128
|
@touched = false
|
|
111
129
|
end
|
|
130
|
+
@server.wait_for_pending_requests if @server
|
|
112
131
|
raise_server_error!
|
|
113
132
|
end
|
|
114
133
|
alias_method :cleanup!, :reset!
|
|
@@ -119,9 +138,19 @@ module Capybara
|
|
|
119
138
|
# Raise errors encountered in the server
|
|
120
139
|
#
|
|
121
140
|
def raise_server_error!
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
141
|
+
if @server and @server.error
|
|
142
|
+
# Force an explanation for the error being raised as the exception cause
|
|
143
|
+
begin
|
|
144
|
+
if config.raise_server_errors
|
|
145
|
+
raise CapybaraError, "Your application server raised an error - It has been raised in your test code because Capybara.raise_server_errors == true"
|
|
146
|
+
end
|
|
147
|
+
rescue CapybaraError
|
|
148
|
+
#needed to get the cause set correctly in JRuby -- otherwise we could just do raise @server.error
|
|
149
|
+
raise @server.error, @server.error.message, @server.error.backtrace
|
|
150
|
+
ensure
|
|
151
|
+
@server.reset_error!
|
|
152
|
+
end
|
|
153
|
+
end
|
|
125
154
|
end
|
|
126
155
|
|
|
127
156
|
##
|
|
@@ -159,7 +188,15 @@ module Capybara
|
|
|
159
188
|
# @return [String] Path of the current page, without any domain information
|
|
160
189
|
#
|
|
161
190
|
def current_path
|
|
162
|
-
|
|
191
|
+
# Addressable parsing is more lenient than URI
|
|
192
|
+
uri = ::Addressable::URI.parse(current_url)
|
|
193
|
+
|
|
194
|
+
# If current_url ends up being nil, won't be able to call .path on a NilClass.
|
|
195
|
+
return nil if uri.nil?
|
|
196
|
+
|
|
197
|
+
# Addressable doesn't support opaque URIs - we want nil here
|
|
198
|
+
return nil if uri.scheme == "about"
|
|
199
|
+
path = uri.path
|
|
163
200
|
path if path and not path.empty?
|
|
164
201
|
end
|
|
165
202
|
|
|
@@ -204,32 +241,46 @@ module Capybara
|
|
|
204
241
|
#
|
|
205
242
|
# Will actually navigate to `http://google.com:4567/test`.
|
|
206
243
|
#
|
|
207
|
-
# @param [#to_s]
|
|
244
|
+
# @param [#to_s] visit_uri The URL to navigate to. The parameter will be cast to a String.
|
|
208
245
|
#
|
|
209
|
-
def visit(
|
|
246
|
+
def visit(visit_uri)
|
|
210
247
|
raise_server_error!
|
|
211
|
-
|
|
212
|
-
url = url.to_s
|
|
213
248
|
@touched = true
|
|
214
249
|
|
|
215
|
-
|
|
250
|
+
visit_uri = ::Addressable::URI.parse(visit_uri.to_s)
|
|
216
251
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
252
|
+
uri_base = if @server
|
|
253
|
+
::Addressable::URI.parse(config.app_host || "http://#{@server.host}:#{@server.port}")
|
|
254
|
+
else
|
|
255
|
+
config.app_host && ::Addressable::URI.parse(config.app_host)
|
|
220
256
|
end
|
|
221
257
|
|
|
222
|
-
if
|
|
223
|
-
|
|
258
|
+
if uri_base && [nil, 'http', 'https'].include?(visit_uri.scheme)
|
|
259
|
+
if visit_uri.relative?
|
|
260
|
+
uri_base.port ||= @server.port if @server && config.always_include_port
|
|
261
|
+
|
|
262
|
+
visit_uri_parts = visit_uri.to_hash.delete_if { |k,v| v.nil? }
|
|
263
|
+
|
|
264
|
+
# Useful to people deploying to a subdirectory
|
|
265
|
+
# and/or single page apps where only the url fragment changes
|
|
266
|
+
visit_uri_parts[:path] = uri_base.path + visit_uri.path
|
|
224
267
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
url = uri.to_s
|
|
268
|
+
visit_uri = uri_base.merge(visit_uri_parts)
|
|
269
|
+
else
|
|
270
|
+
visit_uri.port ||= @server.port if @server && config.always_include_port
|
|
229
271
|
end
|
|
230
272
|
end
|
|
231
273
|
|
|
232
|
-
driver.visit(
|
|
274
|
+
driver.visit(visit_uri.to_s)
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
##
|
|
278
|
+
#
|
|
279
|
+
# Refresh the page
|
|
280
|
+
#
|
|
281
|
+
def refresh
|
|
282
|
+
raise_server_error!
|
|
283
|
+
driver.refresh
|
|
233
284
|
end
|
|
234
285
|
|
|
235
286
|
##
|
|
@@ -255,8 +306,8 @@ module Capybara
|
|
|
255
306
|
# block, any command to Capybara will be handled as though it were scoped
|
|
256
307
|
# to the given element.
|
|
257
308
|
#
|
|
258
|
-
# within(:xpath, '
|
|
259
|
-
# fill_in('Street', :
|
|
309
|
+
# within(:xpath, './/div[@id="delivery-address"]') do
|
|
310
|
+
# fill_in('Street', with: '12 Main Street')
|
|
260
311
|
# end
|
|
261
312
|
#
|
|
262
313
|
# Just as with `find`, if multiple elements match the selector given to
|
|
@@ -267,13 +318,13 @@ module Capybara
|
|
|
267
318
|
# assumed to be of the type set in Capybara.default_selector.
|
|
268
319
|
#
|
|
269
320
|
# within('div#delivery-address') do
|
|
270
|
-
# fill_in('Street', :
|
|
321
|
+
# fill_in('Street', with: '12 Main Street')
|
|
271
322
|
# end
|
|
272
323
|
#
|
|
273
324
|
# Note that a lot of uses of `within` can be replaced more succinctly with
|
|
274
325
|
# chaining:
|
|
275
326
|
#
|
|
276
|
-
# find('div#delivery-address').fill_in('Street', :
|
|
327
|
+
# find('div#delivery-address').fill_in('Street', with: '12 Main Street')
|
|
277
328
|
#
|
|
278
329
|
# @overload within(*find_args)
|
|
279
330
|
# @param (see Capybara::Node::Finders#all)
|
|
@@ -292,6 +343,7 @@ module Capybara
|
|
|
292
343
|
scopes.pop
|
|
293
344
|
end
|
|
294
345
|
end
|
|
346
|
+
alias_method :within_element, :within
|
|
295
347
|
|
|
296
348
|
##
|
|
297
349
|
#
|
|
@@ -319,21 +371,77 @@ module Capybara
|
|
|
319
371
|
|
|
320
372
|
##
|
|
321
373
|
#
|
|
322
|
-
#
|
|
323
|
-
# May be supported by not all drivers. Drivers that support it, may provide additional options.
|
|
374
|
+
# Switch to the given frame
|
|
324
375
|
#
|
|
325
|
-
#
|
|
326
|
-
#
|
|
327
|
-
#
|
|
328
|
-
# @param [String] name name of a frame
|
|
376
|
+
# 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.
|
|
377
|
+
# Capybara::Session#within_frame is preferred over this method and should be used when possible.
|
|
378
|
+
# May not be supported by all drivers.
|
|
329
379
|
#
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
380
|
+
# @overload switch_to_frame(element)
|
|
381
|
+
# @param [Capybara::Node::Element] iframe/frame element to switch to
|
|
382
|
+
# @overload switch_to_frame(:parent)
|
|
383
|
+
# Switch to the parent element
|
|
384
|
+
# @overload switch_to_frame(:top)
|
|
385
|
+
# Switch to the top level document
|
|
386
|
+
#
|
|
387
|
+
def switch_to_frame(frame)
|
|
388
|
+
case frame
|
|
389
|
+
when Capybara::Node::Element
|
|
390
|
+
driver.switch_to_frame(frame)
|
|
391
|
+
scopes.push(:frame)
|
|
392
|
+
when :parent
|
|
393
|
+
raise Capybara::ScopeError, "`switch_to_frame(:parent)` cannot be called from inside a descendant frame's "\
|
|
394
|
+
"`within` block." if scopes.last() != :frame
|
|
395
|
+
scopes.pop
|
|
396
|
+
driver.switch_to_frame(:parent)
|
|
397
|
+
when :top
|
|
398
|
+
idx = scopes.index(:frame)
|
|
399
|
+
if idx
|
|
400
|
+
raise Capybara::ScopeError, "`switch_to_frame(:top)` cannot be called from inside a descendant frame's "\
|
|
401
|
+
"`within` block." if scopes.slice(idx..-1).any? {|scope| ![:frame, nil].include?(scope)}
|
|
402
|
+
scopes.slice!(idx..-1)
|
|
403
|
+
driver.switch_to_frame(:top)
|
|
404
|
+
end
|
|
405
|
+
end
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
##
|
|
409
|
+
#
|
|
410
|
+
# Execute the given block within the given iframe using given frame, frame name/id or index.
|
|
411
|
+
# May not be supported by all drivers.
|
|
412
|
+
#
|
|
413
|
+
# @overload within_frame(element)
|
|
414
|
+
# @param [Capybara::Node::Element] frame element
|
|
415
|
+
# @overload within_frame([kind = :frame], locator, options = {})
|
|
416
|
+
# @param [Symobl] kind Optional selector type (:css, :xpath, :field, etc.) - Defaults to :frame
|
|
417
|
+
# @param [String] locator The locator for the given selector kind. For :frame this is the name/id of a frame/iframe element
|
|
418
|
+
# @overload within_frame(index)
|
|
419
|
+
# @param [Integer] index index of a frame (0 based)
|
|
420
|
+
def within_frame(*args)
|
|
421
|
+
frame = _find_frame(*args)
|
|
422
|
+
|
|
423
|
+
begin
|
|
424
|
+
switch_to_frame(frame)
|
|
425
|
+
begin
|
|
426
|
+
yield
|
|
427
|
+
ensure
|
|
428
|
+
switch_to_frame(:parent)
|
|
429
|
+
end
|
|
430
|
+
rescue Capybara::NotSupportedByDriverError
|
|
431
|
+
# Support older driver frame API for now
|
|
432
|
+
if driver.respond_to?(:within_frame)
|
|
433
|
+
begin
|
|
434
|
+
scopes.push(:frame)
|
|
435
|
+
driver.within_frame(frame) do
|
|
436
|
+
yield
|
|
437
|
+
end
|
|
438
|
+
ensure
|
|
439
|
+
scopes.pop
|
|
440
|
+
end
|
|
441
|
+
else
|
|
442
|
+
raise
|
|
443
|
+
end
|
|
334
444
|
end
|
|
335
|
-
ensure
|
|
336
|
-
scopes.pop
|
|
337
445
|
end
|
|
338
446
|
|
|
339
447
|
##
|
|
@@ -378,51 +486,27 @@ module Capybara
|
|
|
378
486
|
# @raise [Capybara::WindowError] if no window matches given block
|
|
379
487
|
# @overload switch_to_window(window)
|
|
380
488
|
# @param window [Capybara::Window] window that should be switched to
|
|
381
|
-
# @raise [Capybara::Driver::Base#no_such_window_error] if
|
|
489
|
+
# @raise [Capybara::Driver::Base#no_such_window_error] if nonexistent (e.g. closed) window was passed
|
|
382
490
|
#
|
|
383
491
|
# @return [Capybara::Window] window that has been switched to
|
|
384
|
-
# @raise [Capybara::ScopeError] if this method is invoked inside `within
|
|
385
|
-
# `within_frame`
|
|
492
|
+
# @raise [Capybara::ScopeError] if this method is invoked inside `within` or
|
|
493
|
+
# `within_frame` methods
|
|
386
494
|
# @raise [ArgumentError] if both or neither arguments were provided
|
|
387
495
|
#
|
|
388
|
-
def switch_to_window(window = nil, options= {})
|
|
389
|
-
if window.is_a? Hash
|
|
390
|
-
|
|
391
|
-
window = nil
|
|
392
|
-
end
|
|
496
|
+
def switch_to_window(window = nil, options= {}, &window_locator)
|
|
497
|
+
options, window = window, nil if window.is_a? Hash
|
|
498
|
+
|
|
393
499
|
block_given = block_given?
|
|
394
500
|
if window && block_given
|
|
395
501
|
raise ArgumentError, "`switch_to_window` can take either a block or a window, not both"
|
|
396
502
|
elsif !window && !block_given
|
|
397
503
|
raise ArgumentError, "`switch_to_window`: either window or block should be provided"
|
|
398
|
-
elsif scopes.
|
|
504
|
+
elsif !scopes.last.nil?
|
|
399
505
|
raise Capybara::ScopeError, "`switch_to_window` is not supposed to be invoked from "\
|
|
400
|
-
"`within`
|
|
506
|
+
"`within` or `within_frame` blocks."
|
|
401
507
|
end
|
|
402
508
|
|
|
403
|
-
|
|
404
|
-
driver.switch_to_window(window.handle)
|
|
405
|
-
window
|
|
406
|
-
else
|
|
407
|
-
wait_time = Capybara::Query.new(options).wait
|
|
408
|
-
document.synchronize(wait_time, errors: [Capybara::WindowError]) do
|
|
409
|
-
original_window_handle = driver.current_window_handle
|
|
410
|
-
begin
|
|
411
|
-
driver.window_handles.each do |handle|
|
|
412
|
-
driver.switch_to_window handle
|
|
413
|
-
if yield
|
|
414
|
-
return Window.new(self, handle)
|
|
415
|
-
end
|
|
416
|
-
end
|
|
417
|
-
rescue => e
|
|
418
|
-
driver.switch_to_window(original_window_handle)
|
|
419
|
-
raise e
|
|
420
|
-
else
|
|
421
|
-
driver.switch_to_window(original_window_handle)
|
|
422
|
-
raise Capybara::WindowError, "Could not find a window matching block/lambda"
|
|
423
|
-
end
|
|
424
|
-
end
|
|
425
|
-
end
|
|
509
|
+
_switch_to_window(window, options, &window_locator)
|
|
426
510
|
end
|
|
427
511
|
|
|
428
512
|
##
|
|
@@ -435,7 +519,7 @@ module Capybara
|
|
|
435
519
|
# @overload within_window(window) { do_something }
|
|
436
520
|
# @param window [Capybara::Window] instance of `Capybara::Window` class
|
|
437
521
|
# that will be switched to
|
|
438
|
-
# @raise [driver#no_such_window_error] if
|
|
522
|
+
# @raise [driver#no_such_window_error] if nonexistent (e.g. closed) window was passed
|
|
439
523
|
# @overload within_window(proc_or_lambda) { do_something }
|
|
440
524
|
# @param lambda [Proc] lambda. First window for which lambda
|
|
441
525
|
# returns a value other than false or nil will be switched to.
|
|
@@ -446,30 +530,35 @@ module Capybara
|
|
|
446
530
|
# @deprecated Pass window or lambda instead
|
|
447
531
|
# @param [String] handle, name, url or title of the window
|
|
448
532
|
#
|
|
449
|
-
# @raise [Capybara::ScopeError] if this method is invoked inside `
|
|
450
|
-
# `within_frame` or `within_window` methods
|
|
533
|
+
# @raise [Capybara::ScopeError] if this method is invoked inside `within_frame` method
|
|
451
534
|
# @return value returned by the block
|
|
452
535
|
#
|
|
453
536
|
def within_window(window_or_handle)
|
|
454
537
|
if window_or_handle.instance_of?(Capybara::Window)
|
|
455
538
|
original = current_window
|
|
456
|
-
switch_to_window(window_or_handle) unless original == window_or_handle
|
|
457
539
|
scopes << nil
|
|
458
540
|
begin
|
|
459
|
-
|
|
541
|
+
_switch_to_window(window_or_handle) unless original == window_or_handle
|
|
542
|
+
begin
|
|
543
|
+
yield
|
|
544
|
+
ensure
|
|
545
|
+
_switch_to_window(original) unless original == window_or_handle
|
|
546
|
+
end
|
|
460
547
|
ensure
|
|
461
|
-
|
|
462
|
-
switch_to_window(original) unless original == window_or_handle
|
|
548
|
+
scopes.pop
|
|
463
549
|
end
|
|
464
550
|
elsif window_or_handle.is_a?(Proc)
|
|
465
551
|
original = current_window
|
|
466
|
-
switch_to_window { window_or_handle.call }
|
|
467
552
|
scopes << nil
|
|
468
553
|
begin
|
|
469
|
-
|
|
554
|
+
_switch_to_window { window_or_handle.call }
|
|
555
|
+
begin
|
|
556
|
+
yield
|
|
557
|
+
ensure
|
|
558
|
+
_switch_to_window(original)
|
|
559
|
+
end
|
|
470
560
|
ensure
|
|
471
|
-
|
|
472
|
-
switch_to_window(original)
|
|
561
|
+
scopes.pop
|
|
473
562
|
end
|
|
474
563
|
else
|
|
475
564
|
offending_line = caller.first
|
|
@@ -480,7 +569,7 @@ module Capybara
|
|
|
480
569
|
scopes << nil
|
|
481
570
|
driver.within_window(window_or_handle) { yield }
|
|
482
571
|
ensure
|
|
483
|
-
|
|
572
|
+
scopes.pop
|
|
484
573
|
end
|
|
485
574
|
end
|
|
486
575
|
end
|
|
@@ -501,7 +590,7 @@ module Capybara
|
|
|
501
590
|
old_handles = driver.window_handles
|
|
502
591
|
block.call
|
|
503
592
|
|
|
504
|
-
wait_time = Capybara::
|
|
593
|
+
wait_time = Capybara::Queries::BaseQuery.wait(options, config.default_max_wait_time)
|
|
505
594
|
document.synchronize(wait_time, errors: [Capybara::WindowError]) do
|
|
506
595
|
opened_handles = (driver.window_handles - old_handles)
|
|
507
596
|
if opened_handles.size != 1
|
|
@@ -519,10 +608,16 @@ module Capybara
|
|
|
519
608
|
# +evaluate_script+ whenever possible.
|
|
520
609
|
#
|
|
521
610
|
# @param [String] script A string of JavaScript to execute
|
|
611
|
+
# @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
|
|
522
612
|
#
|
|
523
|
-
def execute_script(script)
|
|
613
|
+
def execute_script(script, *args)
|
|
524
614
|
@touched = true
|
|
525
|
-
|
|
615
|
+
if args.empty?
|
|
616
|
+
driver.execute_script(script)
|
|
617
|
+
else
|
|
618
|
+
raise Capybara::NotSupportedByDriverError, "The current driver does not support execute_script arguments" if driver.method(:execute_script).arity == 1
|
|
619
|
+
driver.execute_script(script, *args.map { |arg| arg.is_a?(Capybara::Node::Element) ? arg.base : arg} )
|
|
620
|
+
end
|
|
526
621
|
end
|
|
527
622
|
|
|
528
623
|
##
|
|
@@ -534,9 +629,33 @@ module Capybara
|
|
|
534
629
|
# @param [String] script A string of JavaScript to evaluate
|
|
535
630
|
# @return [Object] The result of the evaluated JavaScript (may be driver specific)
|
|
536
631
|
#
|
|
537
|
-
def evaluate_script(script)
|
|
632
|
+
def evaluate_script(script, *args)
|
|
538
633
|
@touched = true
|
|
539
|
-
|
|
634
|
+
result = if args.empty?
|
|
635
|
+
driver.evaluate_script(script)
|
|
636
|
+
else
|
|
637
|
+
raise Capybara::NotSupportedByDriverError, "The current driver does not support evaluate_script arguments" if driver.method(:evaluate_script).arity == 1
|
|
638
|
+
driver.evaluate_script(script, *args.map { |arg| arg.is_a?(Capybara::Node::Element) ? arg.base : arg} )
|
|
639
|
+
end
|
|
640
|
+
element_script_result(result)
|
|
641
|
+
end
|
|
642
|
+
|
|
643
|
+
##
|
|
644
|
+
#
|
|
645
|
+
# Evaluate the given JavaScript and obtain the result from a callback function which will be passed as the last argument to the script.
|
|
646
|
+
#
|
|
647
|
+
# @param [String] script A string of JavaScript to evaluate
|
|
648
|
+
# @return [Object] The result of the evaluated JavaScript (may be driver specific)
|
|
649
|
+
#
|
|
650
|
+
def evaluate_async_script(script, *args)
|
|
651
|
+
@touched = true
|
|
652
|
+
result = if args.empty?
|
|
653
|
+
driver.evaluate_async_script(script)
|
|
654
|
+
else
|
|
655
|
+
raise Capybara::NotSupportedByDriverError, "The current driver does not support evaluate_async_script arguments" if driver.method(:evaluate_async_script).arity == 1
|
|
656
|
+
driver.evaluate_async_script(script, *args.map { |arg| arg.is_a?(Capybara::Node::Element) ? arg.base : arg} )
|
|
657
|
+
end
|
|
658
|
+
element_script_result(result)
|
|
540
659
|
end
|
|
541
660
|
|
|
542
661
|
##
|
|
@@ -544,21 +663,24 @@ module Capybara
|
|
|
544
663
|
# Execute the block, accepting a alert.
|
|
545
664
|
#
|
|
546
665
|
# @!macro modal_params
|
|
666
|
+
# Expects a block whose actions will trigger the display modal to appear
|
|
667
|
+
# @example
|
|
668
|
+
# $0 do
|
|
669
|
+
# click_link('link that triggers appearance of system modal')
|
|
670
|
+
# end
|
|
547
671
|
# @overload $0(text, options = {}, &blk)
|
|
548
672
|
# @param text [String, Regexp] Text or regex to match against the text in the modal. If not provided any modal is matched
|
|
673
|
+
# @option options [Numeric] :wait (Capybara.default_max_wait_time) Maximum time to wait for the modal to appear after executing the block.
|
|
674
|
+
# @yield Block whose actions will trigger the system modal
|
|
549
675
|
# @overload $0(options = {}, &blk)
|
|
550
|
-
#
|
|
676
|
+
# @option options [Numeric] :wait (Capybara.default_max_wait_time) Maximum time to wait for the modal to appear after executing the block.
|
|
677
|
+
# @yield Block whose actions will trigger the system modal
|
|
551
678
|
# @return [String] the message shown in the modal
|
|
552
679
|
# @raise [Capybara::ModalNotFound] if modal dialog hasn't been found
|
|
553
680
|
#
|
|
681
|
+
#
|
|
554
682
|
def accept_alert(text_or_options=nil, options={}, &blk)
|
|
555
|
-
|
|
556
|
-
options=text_or_options
|
|
557
|
-
else
|
|
558
|
-
options[:text]=text_or_options
|
|
559
|
-
end
|
|
560
|
-
|
|
561
|
-
driver.accept_modal(:alert, options, &blk)
|
|
683
|
+
accept_modal(:alert, text_or_options, options, &blk)
|
|
562
684
|
end
|
|
563
685
|
|
|
564
686
|
##
|
|
@@ -568,13 +690,7 @@ module Capybara
|
|
|
568
690
|
# @macro modal_params
|
|
569
691
|
#
|
|
570
692
|
def accept_confirm(text_or_options=nil, options={}, &blk)
|
|
571
|
-
|
|
572
|
-
options=text_or_options
|
|
573
|
-
else
|
|
574
|
-
options[:text]=text_or_options
|
|
575
|
-
end
|
|
576
|
-
|
|
577
|
-
driver.accept_modal(:confirm, options, &blk)
|
|
693
|
+
accept_modal(:confirm, text_or_options, options, &blk)
|
|
578
694
|
end
|
|
579
695
|
|
|
580
696
|
##
|
|
@@ -584,13 +700,7 @@ module Capybara
|
|
|
584
700
|
# @macro modal_params
|
|
585
701
|
#
|
|
586
702
|
def dismiss_confirm(text_or_options=nil, options={}, &blk)
|
|
587
|
-
|
|
588
|
-
options=text_or_options
|
|
589
|
-
else
|
|
590
|
-
options[:text]=text_or_options
|
|
591
|
-
end
|
|
592
|
-
|
|
593
|
-
driver.dismiss_modal(:confirm, options, &blk)
|
|
703
|
+
dismiss_modal(:confirm, text_or_options, options, &blk)
|
|
594
704
|
end
|
|
595
705
|
|
|
596
706
|
##
|
|
@@ -601,13 +711,7 @@ module Capybara
|
|
|
601
711
|
# @option options [String] :with Response to provide to the prompt
|
|
602
712
|
#
|
|
603
713
|
def accept_prompt(text_or_options=nil, options={}, &blk)
|
|
604
|
-
|
|
605
|
-
options=text_or_options
|
|
606
|
-
else
|
|
607
|
-
options[:text]=text_or_options
|
|
608
|
-
end
|
|
609
|
-
|
|
610
|
-
driver.accept_modal(:prompt, options, &blk)
|
|
714
|
+
accept_modal(:prompt, text_or_options, options, &blk)
|
|
611
715
|
end
|
|
612
716
|
|
|
613
717
|
##
|
|
@@ -617,13 +721,7 @@ module Capybara
|
|
|
617
721
|
# @macro modal_params
|
|
618
722
|
#
|
|
619
723
|
def dismiss_prompt(text_or_options=nil, options={}, &blk)
|
|
620
|
-
|
|
621
|
-
options=text_or_options
|
|
622
|
-
else
|
|
623
|
-
options[:text]=text_or_options
|
|
624
|
-
end
|
|
625
|
-
|
|
626
|
-
driver.dismiss_modal(:prompt, options, &blk)
|
|
724
|
+
dismiss_modal(:prompt, text_or_options, options, &blk)
|
|
627
725
|
end
|
|
628
726
|
|
|
629
727
|
##
|
|
@@ -631,15 +729,18 @@ module Capybara
|
|
|
631
729
|
# Save a snapshot of the page. If `Capybara.asset_host` is set it will inject `base` tag
|
|
632
730
|
# pointing to `asset_host`.
|
|
633
731
|
#
|
|
634
|
-
# If invoked without arguments it will save file to `Capybara.
|
|
635
|
-
# and file will be given randomly generated filename.
|
|
732
|
+
# If invoked without arguments it will save file to `Capybara.save_path`
|
|
733
|
+
# and file will be given randomly generated filename. If invoked with a relative path
|
|
734
|
+
# the path will be relative to `Capybara.save_path`, which is different from
|
|
735
|
+
# the previous behavior with `Capybara.save_and_open_page_path` where the relative path was
|
|
736
|
+
# relative to Dir.pwd
|
|
636
737
|
#
|
|
637
738
|
# @param [String] path the path to where it should be saved
|
|
638
739
|
# @return [String] the path to which the file was saved
|
|
639
740
|
#
|
|
640
741
|
def save_page(path = nil)
|
|
641
742
|
path = prepare_path(path, 'html')
|
|
642
|
-
File.write(path, Capybara::Helpers.inject_asset_host(body), mode: 'wb')
|
|
743
|
+
File.write(path, Capybara::Helpers.inject_asset_host(body, config.asset_host), mode: 'wb')
|
|
643
744
|
path
|
|
644
745
|
end
|
|
645
746
|
|
|
@@ -647,8 +748,11 @@ module Capybara
|
|
|
647
748
|
#
|
|
648
749
|
# Save a snapshot of the page and open it in a browser for inspection.
|
|
649
750
|
#
|
|
650
|
-
# If invoked without arguments it will save file to `Capybara.
|
|
651
|
-
# and file will be given randomly generated filename.
|
|
751
|
+
# If invoked without arguments it will save file to `Capybara.save_path`
|
|
752
|
+
# and file will be given randomly generated filename. If invoked with a relative path
|
|
753
|
+
# the path will be relative to `Capybara.save_path`, which is different from
|
|
754
|
+
# the previous behavior with `Capybara.save_and_open_page_path` where the relative path was
|
|
755
|
+
# relative to Dir.pwd
|
|
652
756
|
#
|
|
653
757
|
# @param [String] path the path to where it should be saved
|
|
654
758
|
#
|
|
@@ -661,8 +765,11 @@ module Capybara
|
|
|
661
765
|
#
|
|
662
766
|
# Save a screenshot of page.
|
|
663
767
|
#
|
|
664
|
-
# If invoked without
|
|
665
|
-
# and file will be given randomly generated filename.
|
|
768
|
+
# If invoked without arguments it will save file to `Capybara.save_path`
|
|
769
|
+
# and file will be given randomly generated filename. If invoked with a relative path
|
|
770
|
+
# the path will be relative to `Capybara.save_path`, which is different from
|
|
771
|
+
# the previous behavior with `Capybara.save_and_open_page_path` where the relative path was
|
|
772
|
+
# relative to Dir.pwd
|
|
666
773
|
#
|
|
667
774
|
# @param [String] path the path to where it should be saved
|
|
668
775
|
# @param [Hash] options a customizable set of options
|
|
@@ -677,8 +784,11 @@ module Capybara
|
|
|
677
784
|
#
|
|
678
785
|
# Save a screenshot of the page and open it for inspection.
|
|
679
786
|
#
|
|
680
|
-
# If invoked without
|
|
681
|
-
# and file will be given randomly generated filename.
|
|
787
|
+
# If invoked without arguments it will save file to `Capybara.save_path`
|
|
788
|
+
# and file will be given randomly generated filename. If invoked with a relative path
|
|
789
|
+
# the path will be relative to `Capybara.save_path`, which is different from
|
|
790
|
+
# the previous behavior with `Capybara.save_and_open_page_path` where the relative path was
|
|
791
|
+
# relative to Dir.pwd
|
|
682
792
|
#
|
|
683
793
|
# @param [String] path the path to where it should be saved
|
|
684
794
|
# @param [Hash] options a customizable set of options
|
|
@@ -710,11 +820,70 @@ module Capybara
|
|
|
710
820
|
end
|
|
711
821
|
|
|
712
822
|
def current_scope
|
|
713
|
-
scopes.last
|
|
823
|
+
scope = scopes.last
|
|
824
|
+
scope = document if [nil, :frame].include? scope
|
|
825
|
+
scope
|
|
714
826
|
end
|
|
715
827
|
|
|
828
|
+
##
|
|
829
|
+
#
|
|
830
|
+
# Yield a block using a specific wait time
|
|
831
|
+
#
|
|
832
|
+
def using_wait_time(seconds)
|
|
833
|
+
if Capybara.threadsafe
|
|
834
|
+
begin
|
|
835
|
+
previous_wait_time = config.default_max_wait_time
|
|
836
|
+
config.default_max_wait_time = seconds
|
|
837
|
+
yield
|
|
838
|
+
ensure
|
|
839
|
+
config.default_max_wait_time = previous_wait_time
|
|
840
|
+
end
|
|
841
|
+
else
|
|
842
|
+
Capybara.using_wait_time(seconds) { yield }
|
|
843
|
+
end
|
|
844
|
+
end
|
|
845
|
+
|
|
846
|
+
##
|
|
847
|
+
#
|
|
848
|
+
# Accepts a block to set the configuration options if Capybara.threadsafe == true. Note that some options only have an effect
|
|
849
|
+
# if set at initialization time, so look at the configuration block that can be passed to the initializer too
|
|
850
|
+
#
|
|
851
|
+
def configure
|
|
852
|
+
raise "Session configuration is only supported when Capybara.threadsafe == true" unless Capybara.threadsafe
|
|
853
|
+
yield config
|
|
854
|
+
end
|
|
855
|
+
|
|
856
|
+
def self.instance_created?
|
|
857
|
+
@@instance_created
|
|
858
|
+
end
|
|
859
|
+
|
|
860
|
+
def config
|
|
861
|
+
@config ||= if Capybara.threadsafe
|
|
862
|
+
Capybara.session_options.dup
|
|
863
|
+
else
|
|
864
|
+
Capybara::ReadOnlySessionConfig.new(Capybara.session_options)
|
|
865
|
+
end
|
|
866
|
+
end
|
|
716
867
|
private
|
|
717
868
|
|
|
869
|
+
@@instance_created = false
|
|
870
|
+
|
|
871
|
+
def accept_modal(type, text_or_options, options, &blk)
|
|
872
|
+
driver.accept_modal(type, modal_options(text_or_options, options), &blk)
|
|
873
|
+
end
|
|
874
|
+
|
|
875
|
+
def dismiss_modal(type, text_or_options, options, &blk)
|
|
876
|
+
driver.dismiss_modal(type, modal_options(text_or_options, options), &blk)
|
|
877
|
+
end
|
|
878
|
+
|
|
879
|
+
def modal_options(text_or_options, options)
|
|
880
|
+
text_or_options, options = nil, text_or_options if text_or_options.is_a?(Hash)
|
|
881
|
+
options[:text] ||= text_or_options unless text_or_options.nil?
|
|
882
|
+
options[:wait] ||= config.default_max_wait_time
|
|
883
|
+
options
|
|
884
|
+
end
|
|
885
|
+
|
|
886
|
+
|
|
718
887
|
def open_file(path)
|
|
719
888
|
begin
|
|
720
889
|
require "launchy"
|
|
@@ -726,19 +895,85 @@ module Capybara
|
|
|
726
895
|
end
|
|
727
896
|
|
|
728
897
|
def prepare_path(path, extension)
|
|
729
|
-
|
|
898
|
+
if config.save_path || config.save_and_open_page_path.nil?
|
|
899
|
+
path = File.expand_path(path || default_fn(extension), config.save_path)
|
|
900
|
+
else
|
|
901
|
+
path = File.expand_path(default_fn(extension), config.save_and_open_page_path) if path.nil?
|
|
902
|
+
end
|
|
730
903
|
FileUtils.mkdir_p(File.dirname(path))
|
|
731
904
|
path
|
|
732
905
|
end
|
|
733
906
|
|
|
734
|
-
def
|
|
907
|
+
def default_fn(extension)
|
|
735
908
|
timestamp = Time.new.strftime("%Y%m%d%H%M%S")
|
|
736
|
-
|
|
737
|
-
File.expand_path(path, Capybara.save_and_open_page_path)
|
|
909
|
+
"capybara-#{timestamp}#{rand(10**10)}.#{extension}"
|
|
738
910
|
end
|
|
739
911
|
|
|
740
912
|
def scopes
|
|
741
913
|
@scopes ||= [nil]
|
|
742
914
|
end
|
|
915
|
+
|
|
916
|
+
def element_script_result(arg)
|
|
917
|
+
case arg
|
|
918
|
+
when Array
|
|
919
|
+
arg.map { |e| element_script_result(e) }
|
|
920
|
+
when Hash
|
|
921
|
+
arg.each { |k, v| arg[k] = element_script_result(v) }
|
|
922
|
+
when Capybara::Driver::Node
|
|
923
|
+
Capybara::Node::Element.new(self, arg, nil, nil)
|
|
924
|
+
else
|
|
925
|
+
arg
|
|
926
|
+
end
|
|
927
|
+
end
|
|
928
|
+
|
|
929
|
+
def _find_frame(*args)
|
|
930
|
+
within(document) do # Previous 2.x versions ignored current scope when finding frames - consider changing in 3.0
|
|
931
|
+
case args[0]
|
|
932
|
+
when Capybara::Node::Element
|
|
933
|
+
args[0]
|
|
934
|
+
when String, Hash
|
|
935
|
+
find(:frame, *args)
|
|
936
|
+
when Symbol
|
|
937
|
+
find(*args)
|
|
938
|
+
when Integer
|
|
939
|
+
idx = args[0]
|
|
940
|
+
all(:frame, minimum: idx+1)[idx]
|
|
941
|
+
else
|
|
942
|
+
raise TypeError
|
|
943
|
+
end
|
|
944
|
+
end
|
|
945
|
+
end
|
|
946
|
+
|
|
947
|
+
def _switch_to_window(window = nil, options= {})
|
|
948
|
+
options, window = window, nil if window.is_a? Hash
|
|
949
|
+
|
|
950
|
+
raise Capybara::ScopeError, "Window cannot be switched inside a `within_frame` block" if scopes.include?(:frame)
|
|
951
|
+
raise Capybara::ScopeError, "Window cannot be switch inside a `within` block" unless scopes.last.nil?
|
|
952
|
+
|
|
953
|
+
if window
|
|
954
|
+
driver.switch_to_window(window.handle)
|
|
955
|
+
window
|
|
956
|
+
else
|
|
957
|
+
wait_time = Capybara::Queries::BaseQuery.wait(options, config.default_max_wait_time)
|
|
958
|
+
document.synchronize(wait_time, errors: [Capybara::WindowError]) do
|
|
959
|
+
original_window_handle = driver.current_window_handle
|
|
960
|
+
begin
|
|
961
|
+
driver.window_handles.each do |handle|
|
|
962
|
+
driver.switch_to_window handle
|
|
963
|
+
if yield
|
|
964
|
+
return Window.new(self, handle)
|
|
965
|
+
end
|
|
966
|
+
end
|
|
967
|
+
rescue => e
|
|
968
|
+
driver.switch_to_window(original_window_handle)
|
|
969
|
+
raise e
|
|
970
|
+
else
|
|
971
|
+
driver.switch_to_window(original_window_handle)
|
|
972
|
+
raise Capybara::WindowError, "Could not find a window matching block/lambda"
|
|
973
|
+
end
|
|
974
|
+
end
|
|
975
|
+
end
|
|
976
|
+
end
|
|
977
|
+
|
|
743
978
|
end
|
|
744
979
|
end
|