capybara 2.15.0 → 3.0.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/History.md +137 -2
- data/README.md +36 -25
- data/lib/capybara/config.rb +11 -57
- data/lib/capybara/cucumber.rb +2 -3
- data/lib/capybara/driver/base.rb +19 -16
- data/lib/capybara/driver/node.rb +5 -4
- data/lib/capybara/dsl.rb +1 -0
- data/lib/capybara/helpers.rb +19 -29
- data/lib/capybara/minitest/spec.rb +16 -13
- data/lib/capybara/minitest.rb +140 -137
- data/lib/capybara/node/actions.rb +68 -89
- data/lib/capybara/node/base.rb +11 -18
- data/lib/capybara/node/document.rb +2 -2
- data/lib/capybara/node/document_matchers.rb +8 -8
- data/lib/capybara/node/element.rb +32 -42
- data/lib/capybara/node/finders.rb +64 -71
- data/lib/capybara/node/matchers.rb +50 -71
- data/lib/capybara/node/simple.rb +11 -17
- data/lib/capybara/queries/ancestor_query.rb +12 -8
- data/lib/capybara/queries/base_query.rb +22 -18
- data/lib/capybara/queries/current_path_query.rb +12 -25
- data/lib/capybara/queries/match_query.rb +3 -7
- data/lib/capybara/queries/selector_query.rb +100 -96
- data/lib/capybara/queries/sibling_query.rb +5 -5
- data/lib/capybara/queries/text_query.rb +35 -35
- data/lib/capybara/queries/title_query.rb +8 -11
- data/lib/capybara/rack_test/browser.rb +15 -18
- data/lib/capybara/rack_test/css_handlers.rb +6 -4
- data/lib/capybara/rack_test/driver.rb +6 -10
- data/lib/capybara/rack_test/form.rb +52 -39
- data/lib/capybara/rack_test/node.rb +93 -63
- data/lib/capybara/rails.rb +2 -6
- data/lib/capybara/result.rb +22 -22
- data/lib/capybara/rspec/compound.rb +5 -10
- data/lib/capybara/rspec/features.rb +17 -48
- data/lib/capybara/rspec/matcher_proxies.rb +31 -15
- data/lib/capybara/rspec/matchers.rb +116 -58
- data/lib/capybara/rspec.rb +5 -10
- data/lib/capybara/selector/css.rb +6 -11
- data/lib/capybara/selector/filter.rb +1 -17
- data/lib/capybara/selector/filter_set.rb +18 -15
- data/lib/capybara/selector/filters/base.rb +7 -6
- data/lib/capybara/selector/filters/expression_filter.rb +6 -23
- data/lib/capybara/selector/filters/node_filter.rb +2 -12
- data/lib/capybara/selector/selector.rb +28 -34
- data/lib/capybara/selector.rb +129 -117
- data/lib/capybara/selenium/driver.rb +172 -163
- data/lib/capybara/selenium/node.rb +218 -104
- data/lib/capybara/server.rb +3 -2
- data/lib/capybara/session/config.rb +47 -59
- data/lib/capybara/session/matchers.rb +23 -14
- data/lib/capybara/session.rb +175 -229
- data/lib/capybara/spec/fixtures/no_extension +1 -0
- data/lib/capybara/spec/public/test.js +38 -6
- data/lib/capybara/spec/session/accept_alert_spec.rb +1 -0
- data/lib/capybara/spec/session/accept_confirm_spec.rb +3 -2
- data/lib/capybara/spec/session/accept_prompt_spec.rb +30 -1
- data/lib/capybara/spec/session/all_spec.rb +31 -18
- data/lib/capybara/spec/session/ancestor_spec.rb +6 -8
- data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +6 -5
- data/lib/capybara/spec/session/assert_current_path.rb +12 -11
- data/lib/capybara/spec/session/assert_selector.rb +1 -0
- data/lib/capybara/spec/session/assert_text.rb +31 -23
- data/lib/capybara/spec/session/assert_title.rb +13 -3
- data/lib/capybara/spec/session/attach_file_spec.rb +57 -29
- data/lib/capybara/spec/session/body_spec.rb +1 -0
- data/lib/capybara/spec/session/check_spec.rb +7 -6
- data/lib/capybara/spec/session/choose_spec.rb +5 -4
- data/lib/capybara/spec/session/click_button_spec.rb +24 -32
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +8 -7
- data/lib/capybara/spec/session/click_link_spec.rb +8 -7
- data/lib/capybara/spec/session/current_scope_spec.rb +4 -3
- data/lib/capybara/spec/session/current_url_spec.rb +19 -8
- data/lib/capybara/spec/session/dismiss_confirm_spec.rb +1 -1
- data/lib/capybara/spec/session/dismiss_prompt_spec.rb +1 -0
- data/lib/capybara/spec/session/element/assert_match_selector.rb +1 -1
- data/lib/capybara/spec/session/element/match_xpath_spec.rb +1 -1
- data/lib/capybara/spec/session/element/matches_selector_spec.rb +5 -5
- data/lib/capybara/spec/session/evaluate_async_script_spec.rb +23 -0
- data/lib/capybara/spec/session/evaluate_script_spec.rb +5 -4
- data/lib/capybara/spec/session/execute_script_spec.rb +4 -3
- data/lib/capybara/spec/session/fill_in_spec.rb +30 -5
- data/lib/capybara/spec/session/find_button_spec.rb +4 -3
- data/lib/capybara/spec/session/find_by_id_spec.rb +2 -1
- data/lib/capybara/spec/session/find_field_spec.rb +9 -15
- data/lib/capybara/spec/session/find_link_spec.rb +6 -5
- data/lib/capybara/spec/session/find_spec.rb +37 -31
- data/lib/capybara/spec/session/first_spec.rb +60 -33
- data/lib/capybara/spec/session/frame/frame_title_spec.rb +23 -0
- data/lib/capybara/spec/session/frame/frame_url_spec.rb +23 -0
- data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +2 -1
- data/lib/capybara/spec/session/frame/within_frame_spec.rb +9 -16
- data/lib/capybara/spec/session/go_back_spec.rb +1 -0
- data/lib/capybara/spec/session/go_forward_spec.rb +1 -0
- data/lib/capybara/spec/session/has_all_selectors_spec.rb +69 -0
- data/lib/capybara/spec/session/has_button_spec.rb +2 -1
- data/lib/capybara/spec/session/has_css_spec.rb +3 -2
- data/lib/capybara/spec/session/has_current_path_spec.rb +49 -22
- data/lib/capybara/spec/session/has_field_spec.rb +4 -3
- data/lib/capybara/spec/session/has_link_spec.rb +5 -4
- data/lib/capybara/spec/session/has_none_selectors_spec.rb +76 -0
- data/lib/capybara/spec/session/has_select_spec.rb +32 -31
- data/lib/capybara/spec/session/has_selector_spec.rb +5 -4
- data/lib/capybara/spec/session/has_table_spec.rb +2 -1
- data/lib/capybara/spec/session/has_text_spec.rb +9 -13
- data/lib/capybara/spec/session/has_title_spec.rb +1 -0
- data/lib/capybara/spec/session/has_xpath_spec.rb +1 -0
- data/lib/capybara/spec/session/headers.rb +2 -1
- data/lib/capybara/spec/session/html_spec.rb +1 -0
- data/lib/capybara/spec/session/node_spec.rb +107 -58
- data/lib/capybara/spec/session/node_wrapper_spec.rb +36 -0
- data/lib/capybara/spec/session/refresh_spec.rb +6 -2
- data/lib/capybara/spec/session/reset_session_spec.rb +19 -0
- data/lib/capybara/spec/session/response_code.rb +1 -0
- 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 -11
- data/lib/capybara/spec/session/save_page_spec.rb +1 -17
- data/lib/capybara/spec/session/save_screenshot_spec.rb +3 -3
- data/lib/capybara/spec/session/select_spec.rb +21 -20
- data/lib/capybara/spec/session/selectors_spec.rb +2 -2
- data/lib/capybara/spec/session/sibling_spec.rb +1 -1
- data/lib/capybara/spec/session/text_spec.rb +17 -3
- data/lib/capybara/spec/session/title_spec.rb +11 -1
- data/lib/capybara/spec/session/uncheck_spec.rb +4 -3
- data/lib/capybara/spec/session/unselect_spec.rb +7 -6
- data/lib/capybara/spec/session/visit_spec.rb +64 -3
- data/lib/capybara/spec/session/window/become_closed_spec.rb +2 -1
- 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 +2 -1
- data/lib/capybara/spec/session/window/window_opened_by_spec.rb +2 -1
- data/lib/capybara/spec/session/window/window_spec.rb +12 -12
- data/lib/capybara/spec/session/window/windows_spec.rb +2 -3
- data/lib/capybara/spec/session/window/within_window_spec.rb +15 -71
- data/lib/capybara/spec/session/within_spec.rb +1 -0
- data/lib/capybara/spec/spec_helper.rb +36 -18
- data/lib/capybara/spec/test_app.rb +17 -9
- data/lib/capybara/spec/views/form.erb +7 -0
- data/lib/capybara/spec/views/initial_alert.erb +10 -0
- data/lib/capybara/spec/views/with_fixed_header_footer.erb +17 -0
- data/lib/capybara/spec/views/with_hover.erb +5 -0
- data/lib/capybara/spec/views/with_html.erb +27 -1
- data/lib/capybara/spec/views/with_js.erb +11 -0
- data/lib/capybara/spec/views/within_frames.erb +4 -1
- data/lib/capybara/version.rb +2 -1
- data/lib/capybara/window.rb +6 -10
- data/lib/capybara.rb +29 -26
- data/spec/basic_node_spec.rb +1 -0
- data/spec/capybara_spec.rb +16 -69
- data/spec/dsl_spec.rb +5 -13
- data/spec/filter_set_spec.rb +5 -4
- data/spec/fixtures/selenium_driver_rspec_failure.rb +2 -1
- data/spec/fixtures/selenium_driver_rspec_success.rb +3 -2
- data/spec/minitest_spec.rb +13 -4
- data/spec/minitest_spec_spec.rb +12 -3
- data/spec/per_session_config_spec.rb +9 -8
- data/spec/rack_test_spec.rb +21 -20
- data/spec/result_spec.rb +17 -16
- data/spec/rspec/features_spec.rb +17 -14
- data/spec/rspec/scenarios_spec.rb +5 -7
- data/spec/rspec/shared_spec_matchers.rb +96 -99
- data/spec/rspec/views_spec.rb +2 -1
- data/spec/rspec_matchers_spec.rb +18 -2
- data/spec/rspec_spec.rb +11 -15
- data/spec/selector_spec.rb +5 -6
- data/spec/selenium_spec_chrome.rb +20 -11
- data/spec/selenium_spec_edge.rb +27 -0
- data/spec/selenium_spec_ie.rb +31 -0
- data/spec/selenium_spec_marionette.rb +38 -12
- data/spec/server_spec.rb +33 -33
- data/spec/session_spec.rb +2 -1
- data/spec/shared_selenium_session.rb +82 -22
- data/spec/spec_helper.rb +3 -6
- metadata +76 -81
- data/lib/capybara/query.rb +0 -7
- data/spec/selenium_spec_firefox.rb +0 -68
data/lib/capybara/session.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'capybara/session/matchers'
|
3
4
|
require 'addressable/uri'
|
4
5
|
|
5
6
|
module Capybara
|
6
|
-
|
7
7
|
##
|
8
8
|
#
|
9
9
|
# The Session class represents a single user's interaction with the system. The Session can use
|
@@ -38,64 +38,63 @@ module Capybara
|
|
38
38
|
class Session
|
39
39
|
include Capybara::SessionMatchers
|
40
40
|
|
41
|
-
NODE_METHODS = [
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
]
|
41
|
+
NODE_METHODS = %i[
|
42
|
+
all first attach_file text check choose
|
43
|
+
click_link_or_button click_button click_link
|
44
|
+
fill_in find find_all find_button find_by_id find_field find_link
|
45
|
+
has_content? has_text? has_css? has_no_content? has_no_text?
|
46
|
+
has_no_css? has_no_xpath? resolve has_xpath? select uncheck
|
47
|
+
has_link? has_no_link? has_button? has_no_button? has_field?
|
48
|
+
has_no_field? has_checked_field? has_unchecked_field?
|
49
|
+
has_no_table? has_table? unselect has_select? has_no_select?
|
50
|
+
has_selector? has_no_selector? click_on has_no_checked_field?
|
51
|
+
has_no_unchecked_field? query assert_selector assert_no_selector
|
52
|
+
assert_all_of_selectors assert_none_of_selectors
|
53
|
+
refute_selector assert_text assert_no_text
|
54
|
+
].freeze
|
55
55
|
# @api private
|
56
|
-
DOCUMENT_METHODS = [
|
57
|
-
|
58
|
-
]
|
59
|
-
SESSION_METHODS = [
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
] + DOCUMENT_METHODS
|
69
|
-
MODAL_METHODS = [
|
70
|
-
|
71
|
-
|
72
|
-
]
|
56
|
+
DOCUMENT_METHODS = %i[
|
57
|
+
title assert_title assert_no_title has_title? has_no_title?
|
58
|
+
].freeze
|
59
|
+
SESSION_METHODS = %i[
|
60
|
+
body html source current_url current_host current_path
|
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
|
64
|
+
save_page save_and_open_page save_screenshot
|
65
|
+
save_and_open_screenshot reset_session! response_headers
|
66
|
+
status_code current_scope
|
67
|
+
assert_current_path assert_no_current_path has_current_path? has_no_current_path?
|
68
|
+
].freeze + DOCUMENT_METHODS
|
69
|
+
MODAL_METHODS = %i[
|
70
|
+
accept_alert accept_confirm dismiss_confirm accept_prompt dismiss_prompt
|
71
|
+
].freeze
|
73
72
|
DSL_METHODS = NODE_METHODS + SESSION_METHODS + MODAL_METHODS
|
74
73
|
|
75
74
|
attr_reader :mode, :app, :server
|
76
75
|
attr_accessor :synchronized
|
77
76
|
|
78
|
-
def initialize(mode, app=nil)
|
77
|
+
def initialize(mode, app = nil)
|
79
78
|
raise TypeError, "The second parameter to Session::new should be a rack app if passed." if app && !app.respond_to?(:call)
|
80
79
|
@@instance_created = true
|
81
80
|
@mode = mode
|
82
81
|
@app = app
|
83
82
|
if block_given?
|
84
83
|
raise "A configuration block is only accepted when Capybara.threadsafe == true" unless Capybara.threadsafe
|
85
|
-
yield config
|
84
|
+
yield config
|
86
85
|
end
|
87
|
-
if config.run_server and @app and driver.needs_server?
|
88
|
-
|
86
|
+
@server = if config.run_server and @app and driver.needs_server?
|
87
|
+
Capybara::Server.new(@app, config.server_port, config.server_host, config.server_errors).boot
|
89
88
|
else
|
90
|
-
|
89
|
+
nil
|
91
90
|
end
|
92
91
|
@touched = false
|
93
92
|
end
|
94
93
|
|
95
94
|
def driver
|
96
95
|
@driver ||= begin
|
97
|
-
unless Capybara.drivers.
|
98
|
-
other_drivers = Capybara.drivers.keys.map
|
96
|
+
unless Capybara.drivers.key?(mode)
|
97
|
+
other_drivers = Capybara.drivers.keys.map(&:inspect)
|
99
98
|
raise Capybara::DriverNotFoundError, "no driver called #{mode.inspect} was found, available drivers: #{other_drivers.join(', ')}"
|
100
99
|
end
|
101
100
|
driver = Capybara.drivers[mode].call(app)
|
@@ -145,7 +144,7 @@ module Capybara
|
|
145
144
|
raise CapybaraError, "Your application server raised an error - It has been raised in your test code because Capybara.raise_server_errors == true"
|
146
145
|
end
|
147
146
|
rescue CapybaraError
|
148
|
-
#needed to get the cause set correctly in JRuby -- otherwise we could just do raise @server.error
|
147
|
+
# needed to get the cause set correctly in JRuby -- otherwise we could just do raise @server.error
|
149
148
|
raise @server.error, @server.error.message, @server.error.backtrace
|
150
149
|
ensure
|
151
150
|
@server.reset_error!
|
@@ -196,8 +195,9 @@ module Capybara
|
|
196
195
|
|
197
196
|
# Addressable doesn't support opaque URIs - we want nil here
|
198
197
|
return nil if uri.scheme == "about"
|
198
|
+
|
199
199
|
path = uri.path
|
200
|
-
path if path
|
200
|
+
path if path && !path.empty?
|
201
201
|
end
|
202
202
|
|
203
203
|
##
|
@@ -247,24 +247,29 @@ module Capybara
|
|
247
247
|
raise_server_error!
|
248
248
|
@touched = true
|
249
249
|
|
250
|
-
visit_uri = URI.parse(visit_uri.to_s)
|
250
|
+
visit_uri = ::Addressable::URI.parse(visit_uri.to_s)
|
251
251
|
|
252
252
|
uri_base = if @server
|
253
|
-
|
254
|
-
URI.parse(config.app_host || "http://#{@server.host}:#{@server.port}")
|
253
|
+
::Addressable::URI.parse(config.app_host || "http://#{@server.host}:#{@server.port}")
|
255
254
|
else
|
256
|
-
config.app_host && URI.parse(config.app_host)
|
255
|
+
config.app_host && ::Addressable::URI.parse(config.app_host)
|
257
256
|
end
|
258
257
|
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
visit_uri.path = uri_base.path + visit_uri.path
|
265
|
-
end
|
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? }
|
266
263
|
|
267
|
-
|
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
|
267
|
+
|
268
|
+
visit_uri = uri_base.merge(visit_uri_parts)
|
269
|
+
elsif @server && config.always_include_port
|
270
|
+
visit_uri.port ||= @server.port
|
271
|
+
end
|
272
|
+
end
|
268
273
|
|
269
274
|
driver.visit(visit_uri.to_s)
|
270
275
|
end
|
@@ -330,7 +335,7 @@ module Capybara
|
|
330
335
|
# @raise [Capybara::ElementNotFound] If the scope can't be found before time expires
|
331
336
|
#
|
332
337
|
def within(*args)
|
333
|
-
new_scope =
|
338
|
+
new_scope = args.first.respond_to?(:to_capybara_node) ? args.first.to_capybara_node : find(*args)
|
334
339
|
begin
|
335
340
|
scopes.push(new_scope)
|
336
341
|
yield
|
@@ -347,9 +352,7 @@ module Capybara
|
|
347
352
|
# @param [String] locator Id or legend of the fieldset
|
348
353
|
#
|
349
354
|
def within_fieldset(locator)
|
350
|
-
within
|
351
|
-
yield
|
352
|
-
end
|
355
|
+
within(:fieldset, locator) { yield }
|
353
356
|
end
|
354
357
|
|
355
358
|
##
|
@@ -359,9 +362,7 @@ module Capybara
|
|
359
362
|
# @param [String] locator Id or caption of the table
|
360
363
|
#
|
361
364
|
def within_table(locator)
|
362
|
-
within
|
363
|
-
yield
|
364
|
-
end
|
365
|
+
within(:table, locator) { yield }
|
365
366
|
end
|
366
367
|
|
367
368
|
##
|
@@ -385,15 +386,19 @@ module Capybara
|
|
385
386
|
driver.switch_to_frame(frame)
|
386
387
|
scopes.push(:frame)
|
387
388
|
when :parent
|
388
|
-
|
389
|
-
|
389
|
+
if scopes.last != :frame
|
390
|
+
raise Capybara::ScopeError, "`switch_to_frame(:parent)` cannot be called from inside a descendant frame's "\
|
391
|
+
"`within` block."
|
392
|
+
end
|
390
393
|
scopes.pop
|
391
394
|
driver.switch_to_frame(:parent)
|
392
395
|
when :top
|
393
396
|
idx = scopes.index(:frame)
|
394
397
|
if idx
|
395
|
-
|
396
|
-
|
398
|
+
if scopes.slice(idx..-1).any? { |scope| ![:frame, nil].include?(scope) }
|
399
|
+
raise Capybara::ScopeError, "`switch_to_frame(:top)` cannot be called from inside a descendant frame's "\
|
400
|
+
"`within` block."
|
401
|
+
end
|
397
402
|
scopes.slice!(idx..-1)
|
398
403
|
driver.switch_to_frame(:top)
|
399
404
|
end
|
@@ -408,34 +413,16 @@ module Capybara
|
|
408
413
|
# @overload within_frame(element)
|
409
414
|
# @param [Capybara::Node::Element] frame element
|
410
415
|
# @overload within_frame([kind = :frame], locator, options = {})
|
411
|
-
# @param [
|
416
|
+
# @param [Symbol] kind Optional selector type (:css, :xpath, :field, etc.) - Defaults to :frame
|
412
417
|
# @param [String] locator The locator for the given selector kind. For :frame this is the name/id of a frame/iframe element
|
413
418
|
# @overload within_frame(index)
|
414
419
|
# @param [Integer] index index of a frame (0 based)
|
415
420
|
def within_frame(*args)
|
416
|
-
|
417
|
-
|
421
|
+
switch_to_frame(_find_frame(*args))
|
418
422
|
begin
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
ensure
|
423
|
-
switch_to_frame(:parent)
|
424
|
-
end
|
425
|
-
rescue Capybara::NotSupportedByDriverError
|
426
|
-
# Support older driver frame API for now
|
427
|
-
if driver.respond_to?(:within_frame)
|
428
|
-
begin
|
429
|
-
scopes.push(:frame)
|
430
|
-
driver.within_frame(frame) do
|
431
|
-
yield
|
432
|
-
end
|
433
|
-
ensure
|
434
|
-
scopes.pop
|
435
|
-
end
|
436
|
-
else
|
437
|
-
raise
|
438
|
-
end
|
423
|
+
yield
|
424
|
+
ensure
|
425
|
+
switch_to_frame(:parent)
|
439
426
|
end
|
440
427
|
end
|
441
428
|
|
@@ -481,22 +468,18 @@ module Capybara
|
|
481
468
|
# @raise [Capybara::WindowError] if no window matches given block
|
482
469
|
# @overload switch_to_window(window)
|
483
470
|
# @param window [Capybara::Window] window that should be switched to
|
484
|
-
# @raise [Capybara::Driver::Base#no_such_window_error] if
|
471
|
+
# @raise [Capybara::Driver::Base#no_such_window_error] if nonexistent (e.g. closed) window was passed
|
485
472
|
#
|
486
473
|
# @return [Capybara::Window] window that has been switched to
|
487
474
|
# @raise [Capybara::ScopeError] if this method is invoked inside `within` or
|
488
475
|
# `within_frame` methods
|
489
476
|
# @raise [ArgumentError] if both or neither arguments were provided
|
490
477
|
#
|
491
|
-
def switch_to_window(window = nil, options
|
492
|
-
options, window = window, nil if window.is_a? Hash
|
493
|
-
|
478
|
+
def switch_to_window(window = nil, **options, &window_locator)
|
494
479
|
block_given = block_given?
|
495
|
-
if window && block_given
|
496
|
-
|
497
|
-
|
498
|
-
raise ArgumentError, "`switch_to_window`: either window or block should be provided"
|
499
|
-
elsif !scopes.last.nil?
|
480
|
+
raise ArgumentError, "`switch_to_window` can take either a block or a window, not both" if window && block_given
|
481
|
+
raise ArgumentError, "`switch_to_window`: either window or block should be provided" if !window && !block_given
|
482
|
+
unless scopes.last.nil?
|
500
483
|
raise Capybara::ScopeError, "`switch_to_window` is not supposed to be invoked from "\
|
501
484
|
"`within` or `within_frame` blocks."
|
502
485
|
end
|
@@ -514,58 +497,37 @@ module Capybara
|
|
514
497
|
# @overload within_window(window) { do_something }
|
515
498
|
# @param window [Capybara::Window] instance of `Capybara::Window` class
|
516
499
|
# that will be switched to
|
517
|
-
# @raise [driver#no_such_window_error] if
|
500
|
+
# @raise [driver#no_such_window_error] if nonexistent (e.g. closed) window was passed
|
518
501
|
# @overload within_window(proc_or_lambda) { do_something }
|
519
502
|
# @param lambda [Proc] lambda. First window for which lambda
|
520
503
|
# returns a value other than false or nil will be switched to.
|
521
504
|
# @example
|
522
505
|
# within_window(->{ page.title == 'Page title' }) { click_button 'Submit' }
|
523
506
|
# @raise [Capybara::WindowError] if no window matching lambda was found
|
524
|
-
# @overload within_window(string) { do_something }
|
525
|
-
# @deprecated Pass window or lambda instead
|
526
|
-
# @param [String] handle, name, url or title of the window
|
527
507
|
#
|
528
508
|
# @raise [Capybara::ScopeError] if this method is invoked inside `within_frame` method
|
529
509
|
# @return value returned by the block
|
530
510
|
#
|
531
|
-
def within_window(
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
ensure
|
543
|
-
scopes.pop
|
544
|
-
end
|
545
|
-
elsif window_or_handle.is_a?(Proc)
|
546
|
-
original = current_window
|
547
|
-
scopes << nil
|
548
|
-
begin
|
549
|
-
_switch_to_window { window_or_handle.call }
|
550
|
-
begin
|
551
|
-
yield
|
552
|
-
ensure
|
553
|
-
_switch_to_window(original)
|
554
|
-
end
|
555
|
-
ensure
|
556
|
-
scopes.pop
|
511
|
+
def within_window(window_or_proc)
|
512
|
+
original = current_window
|
513
|
+
scopes << nil
|
514
|
+
begin
|
515
|
+
case window_or_proc
|
516
|
+
when Capybara::Window
|
517
|
+
_switch_to_window(window_or_proc) unless original == window_or_proc
|
518
|
+
when Proc
|
519
|
+
_switch_to_window { window_or_proc.call }
|
520
|
+
else
|
521
|
+
raise ArgumentError("`#within_window` requires a `Capybara::Window` instance or a lambda")
|
557
522
|
end
|
558
|
-
|
559
|
-
offending_line = caller.first
|
560
|
-
file_line = offending_line.match(/^(.+?):(\d+)/)[0]
|
561
|
-
warn "DEPRECATION WARNING: Passing string argument to #within_window is deprecated. "\
|
562
|
-
"Pass window object or lambda. (called from #{file_line})"
|
523
|
+
|
563
524
|
begin
|
564
|
-
|
565
|
-
driver.within_window(window_or_handle) { yield }
|
525
|
+
yield
|
566
526
|
ensure
|
567
|
-
|
527
|
+
_switch_to_window(original) unless original == window_or_proc
|
568
528
|
end
|
529
|
+
ensure
|
530
|
+
scopes.pop
|
569
531
|
end
|
570
532
|
end
|
571
533
|
|
@@ -575,15 +537,16 @@ module Capybara
|
|
575
537
|
# It's better to use this method than `windows.last`
|
576
538
|
# {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}
|
577
539
|
#
|
578
|
-
# @
|
579
|
-
#
|
580
|
-
#
|
581
|
-
#
|
582
|
-
#
|
540
|
+
# @overload window_opened_by(**options, &block)
|
541
|
+
# @param options [Hash]
|
542
|
+
# @option options [Numeric] :wait (Capybara.default_max_wait_time) maximum wait time
|
543
|
+
# @return [Capybara::Window] the window that has been opened within a block
|
544
|
+
# @raise [Capybara::WindowError] if block passed to window hasn't opened window
|
545
|
+
# or opened more than one window
|
583
546
|
#
|
584
|
-
def window_opened_by(options
|
547
|
+
def window_opened_by(**options)
|
585
548
|
old_handles = driver.window_handles
|
586
|
-
|
549
|
+
yield
|
587
550
|
|
588
551
|
wait_time = Capybara::Queries::BaseQuery.wait(options, config.default_max_wait_time)
|
589
552
|
document.synchronize(wait_time, errors: [Capybara::WindowError]) do
|
@@ -607,12 +570,7 @@ module Capybara
|
|
607
570
|
#
|
608
571
|
def execute_script(script, *args)
|
609
572
|
@touched = true
|
610
|
-
|
611
|
-
driver.execute_script(script)
|
612
|
-
else
|
613
|
-
raise Capybara::NotSupportedByDriverError, "The current driver does not support execute_script arguments" if driver.method(:execute_script).arity == 1
|
614
|
-
driver.execute_script(script, *args.map { |arg| arg.is_a?(Capybara::Node::Element) ? arg.base : arg} )
|
615
|
-
end
|
573
|
+
driver.execute_script(script, *args.map { |arg| arg.is_a?(Capybara::Node::Element) ? arg.base : arg })
|
616
574
|
end
|
617
575
|
|
618
576
|
##
|
@@ -626,12 +584,20 @@ module Capybara
|
|
626
584
|
#
|
627
585
|
def evaluate_script(script, *args)
|
628
586
|
@touched = true
|
629
|
-
result =
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
587
|
+
result = driver.evaluate_script(script, *args.map { |arg| arg.is_a?(Capybara::Node::Element) ? arg.base : arg })
|
588
|
+
element_script_result(result)
|
589
|
+
end
|
590
|
+
|
591
|
+
##
|
592
|
+
#
|
593
|
+
# Evaluate the given JavaScript and obtain the result from a callback function which will be passed as the last argument to the script.
|
594
|
+
#
|
595
|
+
# @param [String] script A string of JavaScript to evaluate
|
596
|
+
# @return [Object] The result of the evaluated JavaScript (may be driver specific)
|
597
|
+
#
|
598
|
+
def evaluate_async_script(script, *args)
|
599
|
+
@touched = true
|
600
|
+
result = driver.evaluate_async_script(script, *args.map { |arg| arg.is_a?(Capybara::Node::Element) ? arg.base : arg })
|
635
601
|
element_script_result(result)
|
636
602
|
end
|
637
603
|
|
@@ -640,15 +606,23 @@ module Capybara
|
|
640
606
|
# Execute the block, accepting a alert.
|
641
607
|
#
|
642
608
|
# @!macro modal_params
|
609
|
+
# Expects a block whose actions will trigger the display modal to appear
|
610
|
+
# @example
|
611
|
+
# $0 do
|
612
|
+
# click_link('link that triggers appearance of system modal')
|
613
|
+
# end
|
643
614
|
# @overload $0(text, options = {}, &blk)
|
644
615
|
# @param text [String, Regexp] Text or regex to match against the text in the modal. If not provided any modal is matched
|
616
|
+
# @option options [Numeric] :wait (Capybara.default_max_wait_time) Maximum time to wait for the modal to appear after executing the block.
|
617
|
+
# @yield Block whose actions will trigger the system modal
|
645
618
|
# @overload $0(options = {}, &blk)
|
646
|
-
#
|
619
|
+
# @option options [Numeric] :wait (Capybara.default_max_wait_time) Maximum time to wait for the modal to appear after executing the block.
|
620
|
+
# @yield Block whose actions will trigger the system modal
|
647
621
|
# @return [String] the message shown in the modal
|
648
622
|
# @raise [Capybara::ModalNotFound] if modal dialog hasn't been found
|
649
623
|
#
|
650
|
-
def accept_alert(
|
651
|
-
accept_modal(:alert,
|
624
|
+
def accept_alert(text = nil, **options, &blk)
|
625
|
+
accept_modal(:alert, text, options, &blk)
|
652
626
|
end
|
653
627
|
|
654
628
|
##
|
@@ -657,8 +631,8 @@ module Capybara
|
|
657
631
|
#
|
658
632
|
# @macro modal_params
|
659
633
|
#
|
660
|
-
def accept_confirm(
|
661
|
-
accept_modal(:confirm,
|
634
|
+
def accept_confirm(text = nil, **options, &blk)
|
635
|
+
accept_modal(:confirm, text, options, &blk)
|
662
636
|
end
|
663
637
|
|
664
638
|
##
|
@@ -667,8 +641,8 @@ module Capybara
|
|
667
641
|
#
|
668
642
|
# @macro modal_params
|
669
643
|
#
|
670
|
-
def dismiss_confirm(
|
671
|
-
dismiss_modal(:confirm,
|
644
|
+
def dismiss_confirm(text = nil, **options, &blk)
|
645
|
+
dismiss_modal(:confirm, text, options, &blk)
|
672
646
|
end
|
673
647
|
|
674
648
|
##
|
@@ -678,8 +652,8 @@ module Capybara
|
|
678
652
|
# @macro modal_params
|
679
653
|
# @option options [String] :with Response to provide to the prompt
|
680
654
|
#
|
681
|
-
def accept_prompt(
|
682
|
-
accept_modal(:prompt,
|
655
|
+
def accept_prompt(text = nil, **options, &blk)
|
656
|
+
accept_modal(:prompt, text, options, &blk)
|
683
657
|
end
|
684
658
|
|
685
659
|
##
|
@@ -688,8 +662,8 @@ module Capybara
|
|
688
662
|
#
|
689
663
|
# @macro modal_params
|
690
664
|
#
|
691
|
-
def dismiss_prompt(
|
692
|
-
dismiss_modal(:prompt,
|
665
|
+
def dismiss_prompt(text = nil, **options, &blk)
|
666
|
+
dismiss_modal(:prompt, text, options, &blk)
|
693
667
|
end
|
694
668
|
|
695
669
|
##
|
@@ -699,17 +673,15 @@ module Capybara
|
|
699
673
|
#
|
700
674
|
# If invoked without arguments it will save file to `Capybara.save_path`
|
701
675
|
# and file will be given randomly generated filename. If invoked with a relative path
|
702
|
-
# the path will be relative to `Capybara.save_path
|
703
|
-
# the previous behavior with `Capybara.save_and_open_page_path` where the relative path was
|
704
|
-
# relative to Dir.pwd
|
676
|
+
# the path will be relative to `Capybara.save_path`
|
705
677
|
#
|
706
678
|
# @param [String] path the path to where it should be saved
|
707
679
|
# @return [String] the path to which the file was saved
|
708
680
|
#
|
709
681
|
def save_page(path = nil)
|
710
|
-
|
711
|
-
|
712
|
-
|
682
|
+
prepare_path(path, 'html').tap do |p|
|
683
|
+
File.write(p, Capybara::Helpers.inject_asset_host(body, host: config.asset_host), mode: 'wb')
|
684
|
+
end
|
713
685
|
end
|
714
686
|
|
715
687
|
##
|
@@ -718,15 +690,12 @@ module Capybara
|
|
718
690
|
#
|
719
691
|
# If invoked without arguments it will save file to `Capybara.save_path`
|
720
692
|
# and file will be given randomly generated filename. If invoked with a relative path
|
721
|
-
# the path will be relative to `Capybara.save_path
|
722
|
-
# the previous behavior with `Capybara.save_and_open_page_path` where the relative path was
|
723
|
-
# relative to Dir.pwd
|
693
|
+
# the path will be relative to `Capybara.save_path`
|
724
694
|
#
|
725
695
|
# @param [String] path the path to where it should be saved
|
726
696
|
#
|
727
697
|
def save_and_open_page(path = nil)
|
728
|
-
path
|
729
|
-
open_file(path)
|
698
|
+
save_page(path).tap { |p| open_file(p) }
|
730
699
|
end
|
731
700
|
|
732
701
|
##
|
@@ -735,17 +704,13 @@ module Capybara
|
|
735
704
|
#
|
736
705
|
# If invoked without arguments it will save file to `Capybara.save_path`
|
737
706
|
# and file will be given randomly generated filename. If invoked with a relative path
|
738
|
-
# the path will be relative to `Capybara.save_path
|
739
|
-
# the previous behavior with `Capybara.save_and_open_page_path` where the relative path was
|
740
|
-
# relative to Dir.pwd
|
707
|
+
# the path will be relative to `Capybara.save_path`
|
741
708
|
#
|
742
709
|
# @param [String] path the path to where it should be saved
|
743
710
|
# @param [Hash] options a customizable set of options
|
744
711
|
# @return [String] the path to which the file was saved
|
745
|
-
def save_screenshot(path = nil, options
|
746
|
-
|
747
|
-
driver.save_screenshot(path, options)
|
748
|
-
path
|
712
|
+
def save_screenshot(path = nil, **options)
|
713
|
+
prepare_path(path, 'png').tap { |p| driver.save_screenshot(p, options) }
|
749
714
|
end
|
750
715
|
|
751
716
|
##
|
@@ -754,16 +719,15 @@ module Capybara
|
|
754
719
|
#
|
755
720
|
# If invoked without arguments it will save file to `Capybara.save_path`
|
756
721
|
# and file will be given randomly generated filename. If invoked with a relative path
|
757
|
-
# the path will be relative to `Capybara.save_path
|
758
|
-
# the previous behavior with `Capybara.save_and_open_page_path` where the relative path was
|
759
|
-
# relative to Dir.pwd
|
722
|
+
# the path will be relative to `Capybara.save_path`
|
760
723
|
#
|
761
724
|
# @param [String] path the path to where it should be saved
|
762
725
|
# @param [Hash] options a customizable set of options
|
763
726
|
#
|
764
|
-
def save_and_open_screenshot(path = nil, options
|
765
|
-
|
766
|
-
|
727
|
+
def save_and_open_screenshot(path = nil, **options)
|
728
|
+
# rubocop:disable Lint/Debugger
|
729
|
+
save_screenshot(path, options).tap { |p| open_file(p) }
|
730
|
+
# rubocop:enable Lint/Debugger
|
767
731
|
end
|
768
732
|
|
769
733
|
def document
|
@@ -789,8 +753,7 @@ module Capybara
|
|
789
753
|
|
790
754
|
def current_scope
|
791
755
|
scope = scopes.last
|
792
|
-
|
793
|
-
scope
|
756
|
+
[nil, :frame].include?(scope) ? document : scope
|
794
757
|
end
|
795
758
|
|
796
759
|
##
|
@@ -832,6 +795,7 @@ module Capybara
|
|
832
795
|
Capybara::ReadOnlySessionConfig.new(Capybara.session_options)
|
833
796
|
end
|
834
797
|
end
|
798
|
+
|
835
799
|
private
|
836
800
|
|
837
801
|
@@instance_created = false
|
@@ -844,32 +808,21 @@ module Capybara
|
|
844
808
|
driver.dismiss_modal(type, modal_options(text_or_options, options), &blk)
|
845
809
|
end
|
846
810
|
|
847
|
-
def modal_options(
|
848
|
-
|
849
|
-
options[:text] ||= text_or_options unless text_or_options.nil?
|
811
|
+
def modal_options(text = nil, **options)
|
812
|
+
options[:text] ||= text unless text.nil?
|
850
813
|
options[:wait] ||= config.default_max_wait_time
|
851
814
|
options
|
852
815
|
end
|
853
816
|
|
854
|
-
|
855
817
|
def open_file(path)
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
warn "File saved to #{path}."
|
861
|
-
warn "Please install the launchy gem to open the file automatically."
|
862
|
-
end
|
818
|
+
require "launchy"
|
819
|
+
Launchy.open(path)
|
820
|
+
rescue LoadError
|
821
|
+
warn "File saved to #{path}.\nPlease install the launchy gem to open the file automatically."
|
863
822
|
end
|
864
823
|
|
865
824
|
def prepare_path(path, extension)
|
866
|
-
|
867
|
-
path = File.expand_path(path || default_fn(extension), config.save_path)
|
868
|
-
else
|
869
|
-
path = File.expand_path(default_fn(extension), config.save_and_open_page_path) if path.nil?
|
870
|
-
end
|
871
|
-
FileUtils.mkdir_p(File.dirname(path))
|
872
|
-
path
|
825
|
+
File.expand_path(path || default_fn(extension), config.save_path).tap { |p| FileUtils.mkdir_p(File.dirname(p)) }
|
873
826
|
end
|
874
827
|
|
875
828
|
def default_fn(extension)
|
@@ -895,26 +848,22 @@ module Capybara
|
|
895
848
|
end
|
896
849
|
|
897
850
|
def _find_frame(*args)
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
raise TypeError
|
911
|
-
end
|
851
|
+
case args[0]
|
852
|
+
when Capybara::Node::Element
|
853
|
+
args[0]
|
854
|
+
when String, Hash
|
855
|
+
find(:frame, *args)
|
856
|
+
when Symbol
|
857
|
+
find(*args)
|
858
|
+
when Integer
|
859
|
+
idx = args[0]
|
860
|
+
all(:frame, minimum: idx + 1)[idx]
|
861
|
+
else
|
862
|
+
raise TypeError
|
912
863
|
end
|
913
864
|
end
|
914
865
|
|
915
|
-
def _switch_to_window(window = nil, options
|
916
|
-
options, window = window, nil if window.is_a? Hash
|
917
|
-
|
866
|
+
def _switch_to_window(window = nil, **options)
|
918
867
|
raise Capybara::ScopeError, "Window cannot be switched inside a `within_frame` block" if scopes.include?(:frame)
|
919
868
|
raise Capybara::ScopeError, "Window cannot be switch inside a `within` block" unless scopes.last.nil?
|
920
869
|
|
@@ -928,9 +877,7 @@ module Capybara
|
|
928
877
|
begin
|
929
878
|
driver.window_handles.each do |handle|
|
930
879
|
driver.switch_to_window handle
|
931
|
-
if yield
|
932
|
-
return Window.new(self, handle)
|
933
|
-
end
|
880
|
+
return Window.new(self, handle) if yield
|
934
881
|
end
|
935
882
|
rescue => e
|
936
883
|
driver.switch_to_window(original_window_handle)
|
@@ -942,6 +889,5 @@ module Capybara
|
|
942
889
|
end
|
943
890
|
end
|
944
891
|
end
|
945
|
-
|
946
892
|
end
|
947
893
|
end
|