capybara 3.30.0 → 3.35.3
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/History.md +153 -13
- data/README.md +9 -4
- data/lib/capybara.rb +18 -8
- data/lib/capybara/config.rb +4 -6
- data/lib/capybara/cucumber.rb +1 -1
- data/lib/capybara/driver/base.rb +4 -0
- data/lib/capybara/dsl.rb +10 -2
- data/lib/capybara/helpers.rb +25 -1
- data/lib/capybara/minitest.rb +232 -144
- data/lib/capybara/minitest/spec.rb +156 -97
- data/lib/capybara/node/actions.rb +16 -21
- data/lib/capybara/node/base.rb +6 -6
- data/lib/capybara/node/element.rb +14 -13
- data/lib/capybara/node/finders.rb +12 -7
- data/lib/capybara/node/matchers.rb +36 -27
- data/lib/capybara/node/simple.rb +6 -2
- data/lib/capybara/queries/ancestor_query.rb +1 -1
- data/lib/capybara/queries/base_query.rb +2 -1
- data/lib/capybara/queries/current_path_query.rb +14 -4
- data/lib/capybara/queries/selector_query.rb +40 -18
- data/lib/capybara/queries/sibling_query.rb +1 -1
- data/lib/capybara/queries/style_query.rb +1 -1
- data/lib/capybara/queries/text_query.rb +7 -1
- data/lib/capybara/rack_test/browser.rb +9 -3
- data/lib/capybara/rack_test/driver.rb +1 -0
- data/lib/capybara/rack_test/form.rb +1 -1
- data/lib/capybara/rack_test/node.rb +35 -10
- data/lib/capybara/registration_container.rb +44 -0
- data/lib/capybara/registrations/drivers.rb +18 -12
- data/lib/capybara/registrations/patches/puma_ssl.rb +3 -1
- data/lib/capybara/registrations/servers.rb +3 -2
- data/lib/capybara/result.rb +35 -15
- data/lib/capybara/rspec.rb +2 -0
- data/lib/capybara/rspec/matcher_proxies.rb +5 -5
- data/lib/capybara/rspec/matchers.rb +33 -32
- data/lib/capybara/rspec/matchers/base.rb +12 -6
- data/lib/capybara/rspec/matchers/count_sugar.rb +2 -1
- data/lib/capybara/rspec/matchers/have_ancestor.rb +4 -3
- data/lib/capybara/rspec/matchers/have_current_path.rb +2 -2
- data/lib/capybara/rspec/matchers/have_selector.rb +15 -7
- data/lib/capybara/rspec/matchers/have_sibling.rb +3 -3
- data/lib/capybara/rspec/matchers/have_text.rb +3 -3
- 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 +2 -1
- data/lib/capybara/selector.rb +14 -3
- data/lib/capybara/selector/builders/css_builder.rb +1 -1
- data/lib/capybara/selector/builders/xpath_builder.rb +3 -1
- data/lib/capybara/selector/definition.rb +11 -9
- data/lib/capybara/selector/definition/button.rb +26 -14
- data/lib/capybara/selector/definition/css.rb +1 -1
- data/lib/capybara/selector/definition/datalist_input.rb +1 -1
- data/lib/capybara/selector/definition/element.rb +2 -1
- data/lib/capybara/selector/definition/fillable_field.rb +1 -1
- data/lib/capybara/selector/definition/label.rb +2 -2
- data/lib/capybara/selector/definition/link.rb +8 -0
- data/lib/capybara/selector/definition/select.rb +32 -13
- data/lib/capybara/selector/definition/table.rb +1 -1
- data/lib/capybara/selector/definition/table_row.rb +2 -2
- data/lib/capybara/selector/filter_set.rb +2 -2
- data/lib/capybara/selector/selector.rb +9 -1
- data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -1
- data/lib/capybara/selenium/atoms/src/getAttribute.js +1 -1
- data/lib/capybara/selenium/atoms/src/isDisplayed.js +1 -1
- data/lib/capybara/selenium/driver.rb +52 -7
- data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +10 -12
- data/lib/capybara/selenium/driver_specializations/edge_driver.rb +9 -11
- data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +3 -3
- data/lib/capybara/selenium/extensions/find.rb +4 -4
- data/lib/capybara/selenium/extensions/html5_drag.rb +24 -8
- data/lib/capybara/selenium/extensions/scroll.rb +8 -10
- data/lib/capybara/selenium/logger_suppressor.rb +8 -2
- data/lib/capybara/selenium/node.rb +96 -16
- data/lib/capybara/selenium/nodes/chrome_node.rb +27 -16
- data/lib/capybara/selenium/nodes/edge_node.rb +1 -1
- data/lib/capybara/selenium/nodes/firefox_node.rb +9 -4
- data/lib/capybara/selenium/nodes/safari_node.rb +1 -1
- data/lib/capybara/selenium/patches/action_pauser.rb +26 -0
- data/lib/capybara/selenium/patches/atoms.rb +4 -4
- data/lib/capybara/selenium/patches/logs.rb +7 -9
- data/lib/capybara/server/animation_disabler.rb +8 -3
- data/lib/capybara/server/middleware.rb +4 -2
- data/lib/capybara/session.rb +53 -29
- data/lib/capybara/session/config.rb +3 -1
- data/lib/capybara/session/matchers.rb +11 -11
- data/lib/capybara/spec/public/test.js +64 -7
- data/lib/capybara/spec/session/accept_alert_spec.rb +1 -1
- data/lib/capybara/spec/session/all_spec.rb +45 -5
- data/lib/capybara/spec/session/assert_text_spec.rb +5 -5
- data/lib/capybara/spec/session/check_spec.rb +6 -0
- data/lib/capybara/spec/session/click_button_spec.rb +11 -0
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +9 -0
- data/lib/capybara/spec/session/current_url_spec.rb +11 -1
- data/lib/capybara/spec/session/fill_in_spec.rb +29 -0
- data/lib/capybara/spec/session/find_spec.rb +11 -8
- data/lib/capybara/spec/session/has_button_spec.rb +51 -0
- data/lib/capybara/spec/session/has_css_spec.rb +14 -10
- data/lib/capybara/spec/session/has_current_path_spec.rb +15 -2
- data/lib/capybara/spec/session/has_field_spec.rb +16 -0
- data/lib/capybara/spec/session/has_select_spec.rb +32 -4
- data/lib/capybara/spec/session/has_selector_spec.rb +4 -4
- data/lib/capybara/spec/session/has_text_spec.rb +5 -12
- data/lib/capybara/spec/session/html_spec.rb +1 -1
- data/lib/capybara/spec/session/matches_style_spec.rb +2 -2
- data/lib/capybara/spec/session/node_spec.rb +169 -33
- data/lib/capybara/spec/session/refresh_spec.rb +2 -1
- data/lib/capybara/spec/session/save_page_spec.rb +4 -4
- 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 +8 -8
- data/lib/capybara/spec/session/window/windows_spec.rb +1 -1
- data/lib/capybara/spec/spec_helper.rb +13 -14
- data/lib/capybara/spec/test_app.rb +23 -21
- data/lib/capybara/spec/views/form.erb +36 -3
- data/lib/capybara/spec/views/with_animation.erb +8 -0
- data/lib/capybara/spec/views/with_dragula.erb +3 -1
- data/lib/capybara/spec/views/with_html.erb +2 -2
- data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
- data/lib/capybara/spec/views/with_js.erb +3 -0
- data/lib/capybara/spec/views/with_sortable_js.erb +1 -1
- data/lib/capybara/version.rb +1 -1
- data/lib/capybara/window.rb +3 -7
- data/spec/basic_node_spec.rb +9 -8
- data/spec/capybara_spec.rb +1 -1
- data/spec/dsl_spec.rb +14 -1
- data/spec/fixtures/selenium_driver_rspec_success.rb +1 -1
- data/spec/minitest_spec.rb +3 -2
- data/spec/rack_test_spec.rb +28 -6
- data/spec/regexp_dissassembler_spec.rb +0 -4
- data/spec/result_spec.rb +40 -29
- data/spec/rspec/features_spec.rb +3 -1
- data/spec/rspec/scenarios_spec.rb +4 -0
- data/spec/rspec/shared_spec_matchers.rb +63 -51
- data/spec/rspec_spec.rb +4 -0
- data/spec/selector_spec.rb +17 -2
- data/spec/selenium_spec_chrome.rb +45 -21
- data/spec/selenium_spec_chrome_remote.rb +7 -1
- data/spec/selenium_spec_firefox.rb +15 -13
- data/spec/server_spec.rb +60 -49
- data/spec/shared_selenium_node.rb +18 -0
- data/spec/shared_selenium_session.rb +98 -7
- data/spec/spec_helper.rb +1 -1
- metadata +50 -14
- data/lib/capybara/spec/session/source_spec.rb +0 -0
|
@@ -18,7 +18,7 @@ class Capybara::Selenium::EdgeNode < Capybara::Selenium::Node
|
|
|
18
18
|
# In Chrome 75+ files are appended (due to WebDriver spec - why?) so we have to clear here if its multiple and already set
|
|
19
19
|
if chrome_edge?
|
|
20
20
|
driver.execute_script(<<~JS, self)
|
|
21
|
-
if (arguments[0].multiple &&
|
|
21
|
+
if (arguments[0].multiple && arguments[0].files.length){
|
|
22
22
|
arguments[0].value = null;
|
|
23
23
|
}
|
|
24
24
|
JS
|
|
@@ -26,7 +26,7 @@ class Capybara::Selenium::FirefoxNode < Capybara::Selenium::Node
|
|
|
26
26
|
def set_file(value) # rubocop:disable Naming/AccessorMethodName
|
|
27
27
|
# By default files are appended so we have to clear here if its multiple and already set
|
|
28
28
|
driver.execute_script(<<~JS, self)
|
|
29
|
-
if (arguments[0].multiple &&
|
|
29
|
+
if (arguments[0].multiple && arguments[0].files.length){
|
|
30
30
|
arguments[0].value = null;
|
|
31
31
|
}
|
|
32
32
|
JS
|
|
@@ -40,11 +40,16 @@ class Capybara::Selenium::FirefoxNode < Capybara::Selenium::Node
|
|
|
40
40
|
path_names.each { |path| native.send_keys(path) }
|
|
41
41
|
end
|
|
42
42
|
|
|
43
|
+
def focused?
|
|
44
|
+
driver.evaluate_script('arguments[0] == document.activeElement', self)
|
|
45
|
+
end
|
|
46
|
+
|
|
43
47
|
def send_keys(*args)
|
|
44
48
|
# https://github.com/mozilla/geckodriver/issues/846
|
|
45
|
-
return super(*args.map { |arg| arg == :space ? ' ' : arg }) if args.none?
|
|
49
|
+
return super(*args.map { |arg| arg == :space ? ' ' : arg }) if args.none?(Array)
|
|
50
|
+
|
|
51
|
+
native.click unless focused?
|
|
46
52
|
|
|
47
|
-
native.click
|
|
48
53
|
_send_keys(args).perform
|
|
49
54
|
end
|
|
50
55
|
|
|
@@ -85,7 +90,7 @@ private
|
|
|
85
90
|
(driver.options[:native_displayed] != false) && !ENV['DISABLE_CAPYBARA_SELENIUM_OPTIMIZATIONS']
|
|
86
91
|
end
|
|
87
92
|
|
|
88
|
-
def
|
|
93
|
+
def perform_with_options(click_options)
|
|
89
94
|
# Firefox/marionette has an issue clicking with offset near viewport edge
|
|
90
95
|
# scroll element to middle just in case
|
|
91
96
|
scroll_to_center if click_options.coords?
|
|
@@ -43,7 +43,7 @@ class Capybara::Selenium::SafariNode < Capybara::Selenium::Node
|
|
|
43
43
|
return '' unless visible?
|
|
44
44
|
|
|
45
45
|
vis_text = driver.execute_script('return arguments[0].innerText', self)
|
|
46
|
-
vis_text.
|
|
46
|
+
vis_text.squeeze(' ')
|
|
47
47
|
.gsub(/[\ \n]*\n[\ \n]*/, "\n")
|
|
48
48
|
.gsub(/\A[[:space:]&&[^\u00a0]]+/, '')
|
|
49
49
|
.gsub(/[[:space:]&&[^\u00a0]]+\z/, '')
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActionPauser
|
|
4
|
+
def initialize(mouse, keyboard)
|
|
5
|
+
super
|
|
6
|
+
@devices[:pauser] = Pauser.new
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def pause(duration)
|
|
10
|
+
@actions << [:pauser, :pause, [duration]]
|
|
11
|
+
self
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class Pauser
|
|
15
|
+
def pause(duration)
|
|
16
|
+
sleep duration
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private_constant :Pauser
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
if defined?(::Selenium::WebDriver::VERSION) && (::Selenium::WebDriver::VERSION.to_f < 4) &&
|
|
24
|
+
defined?(::Selenium::WebDriver::ActionBuilder)
|
|
25
|
+
::Selenium::WebDriver::ActionBuilder.prepend(ActionPauser)
|
|
26
|
+
end
|
|
@@ -6,10 +6,10 @@ private
|
|
|
6
6
|
def read_atom(function)
|
|
7
7
|
@atoms ||= Hash.new do |hash, key|
|
|
8
8
|
hash[key] = begin
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
File.read(File.expand_path("../../atoms/#{key}.min.js", __FILE__))
|
|
10
|
+
rescue Errno::ENOENT
|
|
11
|
+
super
|
|
12
|
+
end
|
|
13
13
|
end
|
|
14
14
|
@atoms[function]
|
|
15
15
|
end
|
|
@@ -27,17 +27,15 @@ module Capybara
|
|
|
27
27
|
|
|
28
28
|
def log(type)
|
|
29
29
|
data = begin
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
execute :get_log, {}, type: type.to_s
|
|
31
|
+
rescue ::Selenium::WebDriver::Error::UnknownCommandError
|
|
32
|
+
execute :get_log_legacy, {}, type: type.to_s
|
|
33
|
+
end
|
|
34
34
|
|
|
35
35
|
Array(data).map do |l|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
next
|
|
40
|
-
end
|
|
36
|
+
::Selenium::WebDriver::LogEntry.new l.fetch('level', 'UNKNOWN'), l.fetch('timestamp'), l.fetch('message')
|
|
37
|
+
rescue KeyError
|
|
38
|
+
next
|
|
41
39
|
end
|
|
42
40
|
rescue ::Selenium::WebDriver::Error::UnknownCommandError
|
|
43
41
|
raise NotImplementedError, LOG_MSG
|
|
@@ -40,16 +40,21 @@ module Capybara
|
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
def insert_disable(html)
|
|
43
|
-
html.sub(%r{(</
|
|
43
|
+
html.sub(%r{(</body>)}, "#{disable_markup}\\1")
|
|
44
44
|
end
|
|
45
45
|
|
|
46
46
|
DISABLE_MARKUP_TEMPLATE = <<~HTML
|
|
47
|
-
<script
|
|
47
|
+
<script>
|
|
48
|
+
//<![CDATA[
|
|
49
|
+
(typeof jQuery !== 'undefined') && (jQuery.fx.off = true);
|
|
50
|
+
//]]>
|
|
51
|
+
</script>
|
|
48
52
|
<style>
|
|
49
|
-
|
|
53
|
+
%<selector>s, %<selector>s::before, %<selector>s::after {
|
|
50
54
|
transition: none !important;
|
|
51
55
|
animation-duration: 0s !important;
|
|
52
56
|
animation-delay: 0s !important;
|
|
57
|
+
scroll-behavior: auto !important;
|
|
53
58
|
}
|
|
54
59
|
</style>
|
|
55
60
|
HTML
|
|
@@ -53,14 +53,16 @@ module Capybara
|
|
|
53
53
|
if env['PATH_INFO'] == '/__identify__'
|
|
54
54
|
[200, {}, [@app.object_id.to_s]]
|
|
55
55
|
else
|
|
56
|
-
|
|
56
|
+
request_uri = env['REQUEST_URI']
|
|
57
|
+
@counter.increment(request_uri)
|
|
58
|
+
|
|
57
59
|
begin
|
|
58
60
|
@extended_app.call(env)
|
|
59
61
|
rescue *@server_errors => e
|
|
60
62
|
@error ||= e
|
|
61
63
|
raise e
|
|
62
64
|
ensure
|
|
63
|
-
@counter.decrement(
|
|
65
|
+
@counter.decrement(request_uri)
|
|
64
66
|
end
|
|
65
67
|
end
|
|
66
68
|
end
|
data/lib/capybara/session.rb
CHANGED
|
@@ -58,7 +58,7 @@ module Capybara
|
|
|
58
58
|
].freeze
|
|
59
59
|
SESSION_METHODS = %i[
|
|
60
60
|
body html source current_url current_host current_path
|
|
61
|
-
execute_script evaluate_script visit refresh go_back go_forward
|
|
61
|
+
execute_script evaluate_script visit refresh go_back go_forward send_keys
|
|
62
62
|
within within_element within_fieldset within_table within_frame switch_to_frame
|
|
63
63
|
current_window windows open_new_window switch_to_window within_window window_opened_by
|
|
64
64
|
save_page save_and_open_page save_screenshot
|
|
@@ -97,8 +97,8 @@ module Capybara
|
|
|
97
97
|
|
|
98
98
|
def driver
|
|
99
99
|
@driver ||= begin
|
|
100
|
-
unless Capybara.drivers
|
|
101
|
-
other_drivers = Capybara.drivers.
|
|
100
|
+
unless Capybara.drivers[mode]
|
|
101
|
+
other_drivers = Capybara.drivers.names.map(&:inspect)
|
|
102
102
|
raise Capybara::DriverNotFoundError, "no driver called #{mode.inspect} was found, available drivers: #{other_drivers.join(', ')}"
|
|
103
103
|
end
|
|
104
104
|
driver = Capybara.drivers[mode].call(app)
|
|
@@ -192,7 +192,7 @@ module Capybara
|
|
|
192
192
|
# @return [String] A snapshot of the DOM of the current document, as it looks right now (potentially modified by JavaScript).
|
|
193
193
|
#
|
|
194
194
|
def html
|
|
195
|
-
driver.html
|
|
195
|
+
driver.html || ''
|
|
196
196
|
end
|
|
197
197
|
alias_method :body, :html
|
|
198
198
|
alias_method :source, :html
|
|
@@ -303,6 +303,14 @@ module Capybara
|
|
|
303
303
|
driver.go_forward
|
|
304
304
|
end
|
|
305
305
|
|
|
306
|
+
##
|
|
307
|
+
# @!method send_keys
|
|
308
|
+
# @see Capybara::Node::Element#send_keys
|
|
309
|
+
#
|
|
310
|
+
def send_keys(*args, **kw_args)
|
|
311
|
+
driver.send_keys(*args, **kw_args)
|
|
312
|
+
end
|
|
313
|
+
|
|
306
314
|
##
|
|
307
315
|
#
|
|
308
316
|
# Executes the given block within the context of a node. {#within} takes the
|
|
@@ -338,8 +346,8 @@ module Capybara
|
|
|
338
346
|
#
|
|
339
347
|
# @raise [Capybara::ElementNotFound] If the scope can't be found before time expires
|
|
340
348
|
#
|
|
341
|
-
def within(*args)
|
|
342
|
-
new_scope = args.first.respond_to?(:to_capybara_node) ? args.first.to_capybara_node : find(*args)
|
|
349
|
+
def within(*args, **kw_args)
|
|
350
|
+
new_scope = args.first.respond_to?(:to_capybara_node) ? args.first.to_capybara_node : find(*args, **kw_args)
|
|
343
351
|
begin
|
|
344
352
|
scopes.push(new_scope)
|
|
345
353
|
yield if block_given?
|
|
@@ -355,8 +363,8 @@ module Capybara
|
|
|
355
363
|
#
|
|
356
364
|
# @param [String] locator Id or legend of the fieldset
|
|
357
365
|
#
|
|
358
|
-
def within_fieldset(locator)
|
|
359
|
-
within(:fieldset, locator)
|
|
366
|
+
def within_fieldset(locator, &block)
|
|
367
|
+
within(:fieldset, locator, &block)
|
|
360
368
|
end
|
|
361
369
|
|
|
362
370
|
##
|
|
@@ -365,8 +373,8 @@ module Capybara
|
|
|
365
373
|
#
|
|
366
374
|
# @param [String] locator Id or caption of the table
|
|
367
375
|
#
|
|
368
|
-
def within_table(locator)
|
|
369
|
-
within(:table, locator)
|
|
376
|
+
def within_table(locator, &block)
|
|
377
|
+
within(:table, locator, &block)
|
|
370
378
|
end
|
|
371
379
|
|
|
372
380
|
##
|
|
@@ -398,8 +406,9 @@ module Capybara
|
|
|
398
406
|
driver.switch_to_frame(:parent)
|
|
399
407
|
when :top
|
|
400
408
|
idx = scopes.index(:frame)
|
|
409
|
+
top_level_scopes = [:frame, nil]
|
|
401
410
|
if idx
|
|
402
|
-
if scopes.slice(idx..-1).any? { |scope| !
|
|
411
|
+
if scopes.slice(idx..-1).any? { |scope| !top_level_scopes.include?(scope) }
|
|
403
412
|
raise Capybara::ScopeError, "`switch_to_frame(:top)` cannot be called from inside a descendant frame's "\
|
|
404
413
|
'`within` block.'
|
|
405
414
|
end
|
|
@@ -423,8 +432,8 @@ module Capybara
|
|
|
423
432
|
# @param [String] locator The locator for the given selector kind. For :frame this is the name/id of a frame/iframe element
|
|
424
433
|
# @overload within_frame(index)
|
|
425
434
|
# @param [Integer] index index of a frame (0 based)
|
|
426
|
-
def within_frame(*args)
|
|
427
|
-
switch_to_frame(_find_frame(*args))
|
|
435
|
+
def within_frame(*args, **kw_args)
|
|
436
|
+
switch_to_frame(_find_frame(*args, **kw_args))
|
|
428
437
|
begin
|
|
429
438
|
yield if block_given?
|
|
430
439
|
ensure
|
|
@@ -488,8 +497,8 @@ module Capybara
|
|
|
488
497
|
# @raise [ArgumentError] if both or neither arguments were provided
|
|
489
498
|
#
|
|
490
499
|
def switch_to_window(window = nil, **options, &window_locator)
|
|
491
|
-
raise ArgumentError, '`switch_to_window` can take either a block or a window, not both' if window &&
|
|
492
|
-
raise ArgumentError, '`switch_to_window`: either window or block should be provided' if !window && !
|
|
500
|
+
raise ArgumentError, '`switch_to_window` can take either a block or a window, not both' if window && window_locator
|
|
501
|
+
raise ArgumentError, '`switch_to_window`: either window or block should be provided' if !window && !window_locator
|
|
493
502
|
|
|
494
503
|
unless scopes.last.nil?
|
|
495
504
|
raise Capybara::ScopeError, '`switch_to_window` is not supposed to be invoked from '\
|
|
@@ -738,7 +747,7 @@ module Capybara
|
|
|
738
747
|
# @param [Hash] options a customizable set of options
|
|
739
748
|
#
|
|
740
749
|
def save_and_open_screenshot(path = nil, **options)
|
|
741
|
-
save_screenshot(path, **options).tap { |s_path| open_file(s_path) }
|
|
750
|
+
save_screenshot(path, **options).tap { |s_path| open_file(s_path) }
|
|
742
751
|
end
|
|
743
752
|
|
|
744
753
|
def document
|
|
@@ -746,15 +755,32 @@ module Capybara
|
|
|
746
755
|
end
|
|
747
756
|
|
|
748
757
|
NODE_METHODS.each do |method|
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
758
|
+
if RUBY_VERSION >= '2.7'
|
|
759
|
+
class_eval <<~METHOD, __FILE__, __LINE__ + 1
|
|
760
|
+
def #{method}(...)
|
|
761
|
+
@touched = true
|
|
762
|
+
current_scope.#{method}(...)
|
|
763
|
+
end
|
|
764
|
+
METHOD
|
|
765
|
+
else
|
|
766
|
+
define_method method do |*args, &block|
|
|
767
|
+
@touched = true
|
|
768
|
+
current_scope.send(method, *args, &block)
|
|
769
|
+
end
|
|
752
770
|
end
|
|
753
771
|
end
|
|
754
772
|
|
|
755
773
|
DOCUMENT_METHODS.each do |method|
|
|
756
|
-
|
|
757
|
-
|
|
774
|
+
if RUBY_VERSION >= '2.7'
|
|
775
|
+
class_eval <<~METHOD, __FILE__, __LINE__ + 1
|
|
776
|
+
def #{method}(...)
|
|
777
|
+
document.#{method}(...)
|
|
778
|
+
end
|
|
779
|
+
METHOD
|
|
780
|
+
else
|
|
781
|
+
define_method method do |*args, &block|
|
|
782
|
+
document.send(method, *args, &block)
|
|
783
|
+
end
|
|
758
784
|
end
|
|
759
785
|
end
|
|
760
786
|
|
|
@@ -771,7 +797,7 @@ module Capybara
|
|
|
771
797
|
#
|
|
772
798
|
# Yield a block using a specific maximum wait time.
|
|
773
799
|
#
|
|
774
|
-
def using_wait_time(seconds)
|
|
800
|
+
def using_wait_time(seconds, &block)
|
|
775
801
|
if Capybara.threadsafe
|
|
776
802
|
begin
|
|
777
803
|
previous_wait_time = config.default_max_wait_time
|
|
@@ -781,7 +807,7 @@ module Capybara
|
|
|
781
807
|
config.default_max_wait_time = previous_wait_time
|
|
782
808
|
end
|
|
783
809
|
else
|
|
784
|
-
Capybara.using_wait_time(seconds)
|
|
810
|
+
Capybara.using_wait_time(seconds, &block)
|
|
785
811
|
end
|
|
786
812
|
end
|
|
787
813
|
|
|
@@ -873,16 +899,14 @@ module Capybara
|
|
|
873
899
|
uri.port ||= @server.port if @server && config.always_include_port
|
|
874
900
|
end
|
|
875
901
|
|
|
876
|
-
def _find_frame(*args)
|
|
877
|
-
return find(:frame) if args.length.zero?
|
|
878
|
-
|
|
902
|
+
def _find_frame(*args, **kw_args)
|
|
879
903
|
case args[0]
|
|
880
904
|
when Capybara::Node::Element
|
|
881
905
|
args[0]
|
|
882
|
-
when String,
|
|
883
|
-
find(:frame, *args)
|
|
906
|
+
when String, nil
|
|
907
|
+
find(:frame, *args, **kw_args)
|
|
884
908
|
when Symbol
|
|
885
|
-
find(*args)
|
|
909
|
+
find(*args, **kw_args)
|
|
886
910
|
when Integer
|
|
887
911
|
idx = args[0]
|
|
888
912
|
all(:frame, minimum: idx + 1)[idx]
|
|
@@ -8,7 +8,7 @@ module Capybara
|
|
|
8
8
|
automatic_reload match exact exact_text raise_server_errors visible_text_only
|
|
9
9
|
automatic_label_click enable_aria_label save_path asset_host default_host app_host
|
|
10
10
|
server_host server_port server_errors default_set_options disable_animation test_id
|
|
11
|
-
predicates_wait default_normalize_ws w3c_click_offset].freeze
|
|
11
|
+
predicates_wait default_normalize_ws w3c_click_offset enable_aria_role].freeze
|
|
12
12
|
|
|
13
13
|
attr_accessor(*OPTIONS)
|
|
14
14
|
|
|
@@ -37,6 +37,8 @@ module Capybara
|
|
|
37
37
|
# See {Capybara.configure}
|
|
38
38
|
# @!method enable_aria_label
|
|
39
39
|
# See {Capybara.configure}
|
|
40
|
+
# @!method enable_aria_role
|
|
41
|
+
# See {Capybara.configure}
|
|
40
42
|
# @!method save_path
|
|
41
43
|
# See {Capybara.configure}
|
|
42
44
|
# @!method asset_host
|
|
@@ -13,14 +13,14 @@ module Capybara
|
|
|
13
13
|
# @param string [String] The string that the current 'path' should equal
|
|
14
14
|
# @overload $0(regexp, **options)
|
|
15
15
|
# @param regexp [Regexp] The regexp that the current 'path' should match to
|
|
16
|
-
# @option options [Boolean] :url (true if `string`
|
|
16
|
+
# @option options [Boolean] :url (true if `string` is a full url, otherwise false) Whether the comparison should be done against the full current url or just the path
|
|
17
17
|
# @option options [Boolean] :ignore_query (false) Whether the query portion of the current url/path should be ignored
|
|
18
18
|
# @option options [Numeric] :wait (Capybara.default_max_wait_time) Maximum time that Capybara will wait for the current url/path to eq/match given string/regexp argument
|
|
19
19
|
# @raise [Capybara::ExpectationNotMet] if the assertion hasn't succeeded during wait time
|
|
20
20
|
# @return [true]
|
|
21
21
|
#
|
|
22
|
-
def assert_current_path(path, **options)
|
|
23
|
-
_verify_current_path(path, **options) do |query|
|
|
22
|
+
def assert_current_path(path, **options, &optional_filter_block)
|
|
23
|
+
_verify_current_path(path, optional_filter_block, **options) do |query|
|
|
24
24
|
raise Capybara::ExpectationNotMet, query.failure_message unless query.resolves_for?(self)
|
|
25
25
|
end
|
|
26
26
|
end
|
|
@@ -35,8 +35,8 @@ module Capybara
|
|
|
35
35
|
# @raise [Capybara::ExpectationNotMet] if the assertion hasn't succeeded during wait time
|
|
36
36
|
# @return [true]
|
|
37
37
|
#
|
|
38
|
-
def assert_no_current_path(path, **options)
|
|
39
|
-
_verify_current_path(path, **options) do |query|
|
|
38
|
+
def assert_no_current_path(path, **options, &optional_filter_block)
|
|
39
|
+
_verify_current_path(path, optional_filter_block, **options) do |query|
|
|
40
40
|
raise Capybara::ExpectationNotMet, query.negative_failure_message if query.resolves_for?(self)
|
|
41
41
|
end
|
|
42
42
|
end
|
|
@@ -50,8 +50,8 @@ module Capybara
|
|
|
50
50
|
# @macro current_path_query_params
|
|
51
51
|
# @return [Boolean]
|
|
52
52
|
#
|
|
53
|
-
def has_current_path?(path, **options)
|
|
54
|
-
make_predicate(options) { assert_current_path(path, **options) }
|
|
53
|
+
def has_current_path?(path, **options, &optional_filter_block)
|
|
54
|
+
make_predicate(options) { assert_current_path(path, **options, &optional_filter_block) }
|
|
55
55
|
end
|
|
56
56
|
|
|
57
57
|
##
|
|
@@ -63,14 +63,14 @@ module Capybara
|
|
|
63
63
|
# @macro current_path_query_params
|
|
64
64
|
# @return [Boolean]
|
|
65
65
|
#
|
|
66
|
-
def has_no_current_path?(path, **options)
|
|
67
|
-
make_predicate(options) { assert_no_current_path(path, **options) }
|
|
66
|
+
def has_no_current_path?(path, **options, &optional_filter_block)
|
|
67
|
+
make_predicate(options) { assert_no_current_path(path, **options, &optional_filter_block) }
|
|
68
68
|
end
|
|
69
69
|
|
|
70
70
|
private
|
|
71
71
|
|
|
72
|
-
def _verify_current_path(path, **options)
|
|
73
|
-
query = Capybara::Queries::CurrentPathQuery.new(path, **options)
|
|
72
|
+
def _verify_current_path(path, filter_block, **options)
|
|
73
|
+
query = Capybara::Queries::CurrentPathQuery.new(path, **options, &filter_block)
|
|
74
74
|
document.synchronize(query.wait) do
|
|
75
75
|
yield(query)
|
|
76
76
|
end
|
|
@@ -1,15 +1,40 @@
|
|
|
1
1
|
var activeRequests = 0;
|
|
2
2
|
$(function() {
|
|
3
3
|
$('#change').text('I changed it');
|
|
4
|
-
$('#drag, #drag_scroll, #drag_link').draggable(
|
|
4
|
+
$('#drag, #drag_scroll, #drag_link').draggable({
|
|
5
|
+
start: function(event, ui){
|
|
6
|
+
$(document.body).append(
|
|
7
|
+
"<div class='drag_start'>Dragged!" +
|
|
8
|
+
(event.altKey ? "-alt" : "") +
|
|
9
|
+
(event.ctrlKey ? "-ctrl" : "") +
|
|
10
|
+
(event.metaKey ? "-meta" : "") +
|
|
11
|
+
(event.shiftKey ? "-shift" : "") +
|
|
12
|
+
"</div>"
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
});
|
|
5
16
|
$('#drop, #drop_scroll').droppable({
|
|
6
17
|
tolerance: 'touch',
|
|
7
18
|
drop: function(event, ui) {
|
|
8
19
|
ui.draggable.remove();
|
|
9
|
-
$(this).html(
|
|
20
|
+
$(this).html(
|
|
21
|
+
"Dropped!" +
|
|
22
|
+
(event.altKey ? "-alt" : "") +
|
|
23
|
+
(event.ctrlKey ? "-ctrl" : "") +
|
|
24
|
+
(event.metaKey ? "-meta" : "") +
|
|
25
|
+
(event.shiftKey ? "-shift" : "")
|
|
26
|
+
);
|
|
10
27
|
}
|
|
11
28
|
});
|
|
12
29
|
$('#drag_html5, #drag_html5_scroll').on('dragstart', function(ev){
|
|
30
|
+
$(document.body).append(
|
|
31
|
+
"<div class='drag_start'>HTML5 Dragged!" +
|
|
32
|
+
(event.altKey ? "-alt" : "") +
|
|
33
|
+
(event.ctrlKey ? "-ctrl" : "") +
|
|
34
|
+
(event.metaKey ? "-meta" : "") +
|
|
35
|
+
(event.shiftKey ? "-shift" : "") +
|
|
36
|
+
"</div>"
|
|
37
|
+
);
|
|
13
38
|
ev.originalEvent.dataTransfer.setData("text", ev.target.id);
|
|
14
39
|
});
|
|
15
40
|
$('#drag_html5, #drag_html5_scroll').on('dragend', function(ev){
|
|
@@ -38,10 +63,19 @@ $(function() {
|
|
|
38
63
|
$(this).append('HTML5 Dropped file: ' + file.name);
|
|
39
64
|
} else {
|
|
40
65
|
var _this = this;
|
|
41
|
-
var callback = (function(type){
|
|
42
|
-
return function(s){
|
|
43
|
-
$(_this).append(
|
|
44
|
-
|
|
66
|
+
var callback = (function(type) {
|
|
67
|
+
return function(s) {
|
|
68
|
+
$(_this).append(
|
|
69
|
+
"HTML5 Dropped string: " +
|
|
70
|
+
type +
|
|
71
|
+
" " +
|
|
72
|
+
s +
|
|
73
|
+
(ev.altKey ? "-alt" : "") +
|
|
74
|
+
(ev.ctrlKey ? "-ctrl" : "") +
|
|
75
|
+
(ev.metaKey ? "-meta" : "") +
|
|
76
|
+
(ev.shiftKey ? "-shift" : "")
|
|
77
|
+
);
|
|
78
|
+
};
|
|
45
79
|
})(item.type);
|
|
46
80
|
item.getAsString(callback);
|
|
47
81
|
}
|
|
@@ -74,6 +108,13 @@ $(function() {
|
|
|
74
108
|
}, 4000);
|
|
75
109
|
return false;
|
|
76
110
|
});
|
|
111
|
+
$('#aria-button').click(function() {
|
|
112
|
+
var span = $(this);
|
|
113
|
+
setTimeout(function() {
|
|
114
|
+
$(span).after('<span role="button">ARIA button has been clicked</span>')
|
|
115
|
+
}, 1000);
|
|
116
|
+
return false;
|
|
117
|
+
});
|
|
77
118
|
$('#waiter').change(function() {
|
|
78
119
|
activeRequests = 1;
|
|
79
120
|
setTimeout(function() {
|
|
@@ -119,6 +160,7 @@ $(function() {
|
|
|
119
160
|
});
|
|
120
161
|
$('#click-test').on({
|
|
121
162
|
click: function(e) {
|
|
163
|
+
window.click_delay = ((new Date().getTime()) - window.mouse_down_time)/1000.0;
|
|
122
164
|
var desc = "";
|
|
123
165
|
if (e.altKey) desc += 'alt ';
|
|
124
166
|
if (e.ctrlKey) desc += 'control ';
|
|
@@ -145,6 +187,16 @@ $(function() {
|
|
|
145
187
|
if (e.shiftKey) desc += 'shift ';
|
|
146
188
|
var pos = this.getBoundingClientRect();
|
|
147
189
|
$(this).after('<a id="has-been-right-clicked" href="#">Has been ' + desc + 'right clicked at ' + (e.clientX - pos.left) + ',' + (e.clientY - pos.top) + '</a>');
|
|
190
|
+
},
|
|
191
|
+
mousedown: function(e) {
|
|
192
|
+
window.click_delay = undefined;
|
|
193
|
+
window.right_click_delay = undefined;
|
|
194
|
+
window.mouse_down_time = new Date().getTime();
|
|
195
|
+
},
|
|
196
|
+
mouseup: function(e) {
|
|
197
|
+
if (e.button == 2){
|
|
198
|
+
window.right_click_delay = ((new Date().getTime()) - window.mouse_down_time)/1000.0;
|
|
199
|
+
}
|
|
148
200
|
}
|
|
149
201
|
});
|
|
150
202
|
$('#open-alert').click(function() {
|
|
@@ -219,5 +271,10 @@ $(function() {
|
|
|
219
271
|
});
|
|
220
272
|
$('#multiple-file, #hidden_file').change(function(e){
|
|
221
273
|
$('body').append($('<p class="file_change">File input changed</p>'));
|
|
222
|
-
})
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
var shadow = document.querySelector('#shadow').attachShadow({mode: 'open'});
|
|
277
|
+
var span = document.createElement('span');
|
|
278
|
+
span.textContent = 'The things we do in the shadows';
|
|
279
|
+
shadow.appendChild(span);
|
|
223
280
|
});
|