capybara 3.32.0 → 3.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/History.md +99 -15
- 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/helpers.rb +25 -1
- data/lib/capybara/minitest.rb +2 -3
- data/lib/capybara/minitest/spec.rb +14 -11
- data/lib/capybara/node/actions.rb +16 -21
- data/lib/capybara/node/base.rb +6 -6
- data/lib/capybara/node/element.rb +1 -5
- data/lib/capybara/node/finders.rb +7 -6
- data/lib/capybara/node/matchers.rb +12 -12
- data/lib/capybara/node/simple.rb +5 -1
- data/lib/capybara/queries/ancestor_query.rb +1 -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 +7 -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 +1 -1
- 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 +10 -11
- data/lib/capybara/rspec.rb +2 -0
- data/lib/capybara/rspec/matcher_proxies.rb +1 -1
- data/lib/capybara/rspec/matchers.rb +7 -6
- data/lib/capybara/rspec/matchers/have_current_path.rb +2 -2
- data/lib/capybara/rspec/matchers/have_text.rb +1 -1
- data/lib/capybara/rspec/matchers/match_style.rb +5 -0
- data/lib/capybara/selector.rb +12 -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 +1 -1
- data/lib/capybara/selector/definition/link.rb +8 -0
- data/lib/capybara/selector/definition/select.rb +1 -1
- 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/src/isDisplayed.js +1 -1
- data/lib/capybara/selenium/driver.rb +51 -7
- data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +9 -11
- 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/scroll.rb +8 -10
- data/lib/capybara/selenium/logger_suppressor.rb +1 -1
- data/lib/capybara/selenium/node.rb +23 -6
- data/lib/capybara/selenium/nodes/chrome_node.rb +23 -5
- data/lib/capybara/selenium/nodes/firefox_node.rb +7 -2
- data/lib/capybara/selenium/nodes/safari_node.rb +1 -1
- data/lib/capybara/selenium/patches/action_pauser.rb +4 -1
- 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 +23 -14
- data/lib/capybara/session/config.rb +3 -1
- data/lib/capybara/session/matchers.rb +11 -11
- data/lib/capybara/spec/public/test.js +13 -1
- data/lib/capybara/spec/session/accept_alert_spec.rb +1 -1
- 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/current_url_spec.rb +11 -1
- data/lib/capybara/spec/session/has_button_spec.rb +51 -0
- data/lib/capybara/spec/session/has_css_spec.rb +2 -1
- 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 +4 -4
- data/lib/capybara/spec/session/has_selector_spec.rb +4 -4
- data/lib/capybara/spec/session/has_text_spec.rb +0 -11
- 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 +29 -9
- 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 +1 -1
- data/lib/capybara/spec/session/window/windows_spec.rb +1 -1
- data/lib/capybara/spec/spec_helper.rb +12 -12
- data/lib/capybara/spec/test_app.rb +23 -21
- data/lib/capybara/spec/views/form.erb +28 -1
- 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_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 +16 -5
- data/spec/result_spec.rb +1 -17
- 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 +39 -20
- data/spec/selenium_spec_chrome_remote.rb +5 -1
- data/spec/selenium_spec_firefox.rb +15 -13
- data/spec/server_spec.rb +60 -49
- data/spec/shared_selenium_node.rb +10 -0
- data/spec/shared_selenium_session.rb +98 -7
- data/spec/spec_helper.rb +1 -1
- metadata +50 -15
- data/lib/capybara/spec/session/source_spec.rb +0 -0
@@ -5,7 +5,7 @@ require 'capybara/selenium/nodes/edge_node'
|
|
5
5
|
module Capybara::Selenium::Driver::EdgeDriver
|
6
6
|
def self.extended(base)
|
7
7
|
bridge = base.send(:bridge)
|
8
|
-
bridge.extend Capybara::Selenium::IsDisplayed unless bridge.
|
8
|
+
bridge.extend Capybara::Selenium::IsDisplayed unless bridge.send(:commands, :is_element_displayed)
|
9
9
|
base.options[:native_displayed] = false if base.options[:native_displayed].nil?
|
10
10
|
end
|
11
11
|
|
@@ -13,21 +13,19 @@ module Capybara::Selenium::Driver::EdgeDriver
|
|
13
13
|
return super if edgedriver_version < 75
|
14
14
|
|
15
15
|
within_given_window(handle) do
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
result['value']
|
23
|
-
end
|
16
|
+
super
|
17
|
+
rescue NoMethodError => e
|
18
|
+
raise unless e.message.include?('full_screen_window')
|
19
|
+
|
20
|
+
result = bridge.http.call(:post, "session/#{bridge.session_id}/window/fullscreen", {})
|
21
|
+
result['value']
|
24
22
|
end
|
25
23
|
end
|
26
24
|
|
27
25
|
def resize_window_to(handle, width, height)
|
28
26
|
super
|
29
27
|
rescue Selenium::WebDriver::Error::UnknownError => e
|
30
|
-
raise unless e.message.
|
28
|
+
raise unless e.message.include?('failed to change window state')
|
31
29
|
|
32
30
|
# Chromedriver doesn't wait long enough for state to change when coming out of fullscreen
|
33
31
|
# and raises unnecessary error. Wait a bit and try again.
|
@@ -74,7 +72,7 @@ private
|
|
74
72
|
end
|
75
73
|
|
76
74
|
def clear_all_storage?
|
77
|
-
storage_clears.none?
|
75
|
+
storage_clears.none? false
|
78
76
|
end
|
79
77
|
|
80
78
|
def uniform_storage_clear?
|
@@ -6,7 +6,7 @@ module Capybara::Selenium::Driver::FirefoxDriver
|
|
6
6
|
def self.extended(driver)
|
7
7
|
driver.extend Capybara::Selenium::Driver::W3CFirefoxDriver if w3c?(driver)
|
8
8
|
bridge = driver.send(:bridge)
|
9
|
-
bridge.extend Capybara::Selenium::IsDisplayed unless bridge.
|
9
|
+
bridge.extend Capybara::Selenium::IsDisplayed unless bridge.send(:commands, :is_element_displayed)
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.w3c?(driver)
|
@@ -46,7 +46,7 @@ module Capybara::Selenium::Driver::W3CFirefoxDriver
|
|
46
46
|
begin
|
47
47
|
# Firefox 68 hangs if we try to switch windows while a modal is visible
|
48
48
|
browser.switch_to.alert&.dismiss
|
49
|
-
rescue Selenium::WebDriver::Error::NoSuchAlertError
|
49
|
+
rescue Selenium::WebDriver::Error::NoSuchAlertError
|
50
50
|
# Swallow
|
51
51
|
end
|
52
52
|
end
|
@@ -61,7 +61,7 @@ module Capybara::Selenium::Driver::W3CFirefoxDriver
|
|
61
61
|
accept_modal :confirm, wait: 0.1 do
|
62
62
|
super
|
63
63
|
end
|
64
|
-
rescue Capybara::ModalNotFound
|
64
|
+
rescue Capybara::ModalNotFound
|
65
65
|
# No modal was opened - page has refreshed - ignore
|
66
66
|
end
|
67
67
|
|
@@ -28,7 +28,7 @@ module Capybara
|
|
28
28
|
hints_js, functions = build_hints_js(uses_visibility, styles, position)
|
29
29
|
return [] unless functions.any?
|
30
30
|
|
31
|
-
es_context.execute_script(hints_js, elements).map! do |results|
|
31
|
+
(es_context.execute_script(hints_js, elements) || []).map! do |results|
|
32
32
|
hint = {}
|
33
33
|
hint[:style] = results.pop if functions.include?(:style_func)
|
34
34
|
hint[:position] = results.pop if functions.include?(:position_func)
|
@@ -100,9 +100,9 @@ module Capybara
|
|
100
100
|
def is_displayed_atom # rubocop:disable Naming/PredicateName
|
101
101
|
@@is_displayed_atom ||= begin # rubocop:disable Style/ClassVars
|
102
102
|
browser.send(:bridge).send(:read_atom, 'isDisplayed')
|
103
|
-
|
104
|
-
|
105
|
-
|
103
|
+
rescue StandardError
|
104
|
+
# If the atom doesn't exist or other error
|
105
|
+
''
|
106
106
|
end
|
107
107
|
end
|
108
108
|
end
|
@@ -45,20 +45,18 @@ module Capybara
|
|
45
45
|
JS
|
46
46
|
end
|
47
47
|
|
48
|
+
SCROLL_POSITIONS = {
|
49
|
+
top: '0',
|
50
|
+
bottom: 'arguments[0].scrollHeight',
|
51
|
+
center: '(arguments[0].scrollHeight - arguments[0].clientHeight)/2'
|
52
|
+
}.freeze
|
53
|
+
|
48
54
|
def scroll_to_location(location)
|
49
|
-
scroll_y = case location
|
50
|
-
when :top
|
51
|
-
'0'
|
52
|
-
when :bottom
|
53
|
-
'arguments[0].scrollHeight'
|
54
|
-
when :center
|
55
|
-
'(arguments[0].scrollHeight - arguments[0].clientHeight)/2'
|
56
|
-
end
|
57
55
|
driver.execute_script <<~JS, self
|
58
56
|
if (arguments[0].scrollTo){
|
59
|
-
arguments[0].scrollTo(0, #{
|
57
|
+
arguments[0].scrollTo(0, #{SCROLL_POSITIONS[location]});
|
60
58
|
} else {
|
61
|
-
arguments[0].scrollTop = #{
|
59
|
+
arguments[0].scrollTop = #{SCROLL_POSITIONS[location]};
|
62
60
|
}
|
63
61
|
JS
|
64
62
|
end
|
@@ -120,7 +120,7 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
|
|
120
120
|
end
|
121
121
|
rescue StandardError => e
|
122
122
|
if e.is_a?(::Selenium::WebDriver::Error::ElementClickInterceptedError) ||
|
123
|
-
e.message.
|
123
|
+
e.message.include?('Other element would receive the click')
|
124
124
|
scroll_to_center
|
125
125
|
end
|
126
126
|
|
@@ -237,7 +237,7 @@ protected
|
|
237
237
|
JS
|
238
238
|
begin
|
239
239
|
driver.execute_script(script, self)
|
240
|
-
rescue StandardError
|
240
|
+
rescue StandardError
|
241
241
|
# Swallow error if scrollIntoView with options isn't supported
|
242
242
|
end
|
243
243
|
end
|
@@ -279,9 +279,9 @@ private
|
|
279
279
|
send_keys(*clear, value)
|
280
280
|
else
|
281
281
|
driver.execute_script 'arguments[0].select()', self unless clear == :none
|
282
|
-
if rapid == true || (value.length >
|
282
|
+
if rapid == true || ((value.length > auto_rapid_set_length) && rapid != false)
|
283
283
|
send_keys(value[0..3])
|
284
|
-
driver.execute_script
|
284
|
+
driver.execute_script RAPID_APPEND_TEXT, self, value[4...-3]
|
285
285
|
send_keys(value[-3..-1])
|
286
286
|
else
|
287
287
|
send_keys(value)
|
@@ -289,6 +289,10 @@ private
|
|
289
289
|
end
|
290
290
|
end
|
291
291
|
|
292
|
+
def auto_rapid_set_length
|
293
|
+
30
|
294
|
+
end
|
295
|
+
|
292
296
|
def perform_with_options(click_options, &block)
|
293
297
|
raise ArgumentError, 'A block must be provided' unless block
|
294
298
|
|
@@ -460,8 +464,8 @@ private
|
|
460
464
|
end
|
461
465
|
end
|
462
466
|
|
463
|
-
def each_key(keys)
|
464
|
-
normalize_keys(keys).each
|
467
|
+
def each_key(keys, &block)
|
468
|
+
normalize_keys(keys).each(&block)
|
465
469
|
end
|
466
470
|
|
467
471
|
def find_context
|
@@ -489,6 +493,9 @@ private
|
|
489
493
|
var xpath = '';
|
490
494
|
var pos, tempitem2;
|
491
495
|
|
496
|
+
if (el.getRootNode && el.getRootNode() instanceof ShadowRoot) {
|
497
|
+
return "(: Shadow DOM element - no XPath :)";
|
498
|
+
};
|
492
499
|
while(el !== xml.documentElement) {
|
493
500
|
pos = 0;
|
494
501
|
tempitem2 = el;
|
@@ -530,6 +537,16 @@ private
|
|
530
537
|
})(arguments[0], arguments[1], arguments[2])
|
531
538
|
JS
|
532
539
|
|
540
|
+
RAPID_APPEND_TEXT = <<~'JS'
|
541
|
+
(function(el, value) {
|
542
|
+
value = el.value + value;
|
543
|
+
if (el.maxLength && el.maxLength != -1){
|
544
|
+
value = value.slice(0, el.maxLength);
|
545
|
+
}
|
546
|
+
el.value = value;
|
547
|
+
})(arguments[0], arguments[1])
|
548
|
+
JS
|
549
|
+
|
533
550
|
# SettableValue encapsulates time/date field formatting
|
534
551
|
class SettableValue
|
535
552
|
attr_reader :value
|
@@ -42,7 +42,7 @@ class Capybara::Selenium::ChromeNode < Capybara::Selenium::Node
|
|
42
42
|
raise
|
43
43
|
rescue ::Selenium::WebDriver::Error::WebDriverError => e
|
44
44
|
# chromedriver 74 (at least on mac) raises the wrong error for this
|
45
|
-
if e.message.
|
45
|
+
if e.message.include?('element click intercepted')
|
46
46
|
raise ::Selenium::WebDriver::Error::ElementClickInterceptedError, e.message
|
47
47
|
end
|
48
48
|
|
@@ -73,6 +73,24 @@ class Capybara::Selenium::ChromeNode < Capybara::Selenium::Node
|
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
76
|
+
def send_keys(*args)
|
77
|
+
args.chunk { |inp| inp.is_a?(String) && inp.match?(/\p{Emoji Presentation}/) }
|
78
|
+
.each do |contains_emoji, inputs|
|
79
|
+
if contains_emoji
|
80
|
+
inputs.join.grapheme_clusters.chunk { |gc| gc.match?(/\p{Emoji Presentation}/) }
|
81
|
+
.each do |emoji, clusters|
|
82
|
+
if emoji
|
83
|
+
driver.send(:execute_cdp, 'Input.insertText', text: clusters.join)
|
84
|
+
else
|
85
|
+
super(clusters.join)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
else
|
89
|
+
super(*inputs)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
76
94
|
private
|
77
95
|
|
78
96
|
def perform_legacy_drag(element, drop_modifiers)
|
@@ -92,7 +110,7 @@ private
|
|
92
110
|
end
|
93
111
|
end
|
94
112
|
|
95
|
-
def browser_version(to_float
|
113
|
+
def browser_version(to_float: true)
|
96
114
|
caps = capabilities
|
97
115
|
ver = (caps[:browser_version] || caps[:version])
|
98
116
|
ver = ver.to_f if to_float
|
@@ -100,15 +118,15 @@ private
|
|
100
118
|
end
|
101
119
|
|
102
120
|
def chromedriver_fixed_actions_key_state?
|
103
|
-
Gem::
|
121
|
+
Gem::Requirement.new('>= 76.0.3809.68').satisfied_by?(chromedriver_version)
|
104
122
|
end
|
105
123
|
|
106
124
|
def chromedriver_supports_displayed_endpoint?
|
107
|
-
Gem::
|
125
|
+
Gem::Requirement.new('>= 76.0.3809.25').satisfied_by?(chromedriver_version)
|
108
126
|
end
|
109
127
|
|
110
128
|
def chromedriver_version
|
111
|
-
capabilities['chrome']['chromedriverVersion'].split(' ')[0]
|
129
|
+
Gem::Version.new(capabilities['chrome']['chromedriverVersion'].split(' ')[0]) # rubocop:disable Style/RedundantArgument
|
112
130
|
end
|
113
131
|
|
114
132
|
def native_displayed?
|
@@ -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
|
|
@@ -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/, '')
|
@@ -20,4 +20,7 @@ module ActionPauser
|
|
20
20
|
private_constant :Pauser
|
21
21
|
end
|
22
22
|
|
23
|
-
::Selenium::WebDriver::
|
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
|
@@ -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
|
@@ -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
|
@@ -788,7 +797,7 @@ module Capybara
|
|
788
797
|
#
|
789
798
|
# Yield a block using a specific maximum wait time.
|
790
799
|
#
|
791
|
-
def using_wait_time(seconds)
|
800
|
+
def using_wait_time(seconds, &block)
|
792
801
|
if Capybara.threadsafe
|
793
802
|
begin
|
794
803
|
previous_wait_time = config.default_max_wait_time
|
@@ -798,7 +807,7 @@ module Capybara
|
|
798
807
|
config.default_max_wait_time = previous_wait_time
|
799
808
|
end
|
800
809
|
else
|
801
|
-
Capybara.using_wait_time(seconds)
|
810
|
+
Capybara.using_wait_time(seconds, &block)
|
802
811
|
end
|
803
812
|
end
|
804
813
|
|