capybara 3.35.3 → 3.37.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.md +57 -1
- data/README.md +5 -1
- data/lib/capybara/config.rb +16 -4
- data/lib/capybara/driver/base.rb +4 -0
- data/lib/capybara/driver/node.rb +5 -1
- data/lib/capybara/dsl.rb +4 -10
- data/lib/capybara/helpers.rb +3 -12
- data/lib/capybara/minitest/spec.rb +2 -2
- data/lib/capybara/node/actions.rb +10 -5
- data/lib/capybara/node/document.rb +2 -2
- data/lib/capybara/node/element.rb +13 -2
- data/lib/capybara/node/finders.rb +9 -2
- data/lib/capybara/node/simple.rb +5 -1
- data/lib/capybara/queries/active_element_query.rb +18 -0
- data/lib/capybara/queries/ancestor_query.rb +2 -1
- data/lib/capybara/queries/current_path_query.rb +1 -1
- data/lib/capybara/queries/selector_query.rb +34 -8
- data/lib/capybara/queries/sibling_query.rb +2 -1
- data/lib/capybara/rack_test/browser.rb +56 -7
- data/lib/capybara/rack_test/driver.rb +4 -4
- data/lib/capybara/rack_test/node.rb +10 -7
- data/lib/capybara/registration_container.rb +0 -3
- data/lib/capybara/registrations/drivers.rb +3 -3
- data/lib/capybara/rspec/matcher_proxies.rb +3 -3
- data/lib/capybara/rspec/matchers/have_selector.rb +5 -5
- data/lib/capybara/rspec/matchers.rb +14 -14
- data/lib/capybara/selector/builders/css_builder.rb +1 -1
- data/lib/capybara/selector/builders/xpath_builder.rb +1 -1
- data/lib/capybara/selector/css.rb +1 -1
- data/lib/capybara/selector/definition/button.rb +9 -4
- data/lib/capybara/selector/definition/checkbox.rb +1 -1
- data/lib/capybara/selector/definition/file_field.rb +1 -1
- data/lib/capybara/selector/definition/fillable_field.rb +1 -1
- data/lib/capybara/selector/definition/radio_button.rb +1 -1
- data/lib/capybara/selector/definition.rb +3 -1
- data/lib/capybara/selector/filter_set.rb +4 -6
- data/lib/capybara/selector/selector.rb +5 -1
- data/lib/capybara/selector.rb +1 -0
- data/lib/capybara/selenium/driver.rb +25 -11
- data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +1 -1
- data/lib/capybara/selenium/driver_specializations/edge_driver.rb +1 -1
- data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +1 -1
- data/lib/capybara/selenium/node.rb +22 -8
- data/lib/capybara/selenium/nodes/chrome_node.rb +1 -1
- data/lib/capybara/selenium/nodes/edge_node.rb +1 -1
- data/lib/capybara/selenium/nodes/firefox_node.rb +1 -1
- data/lib/capybara/selenium/nodes/safari_node.rb +2 -2
- data/lib/capybara/server/animation_disabler.rb +35 -17
- data/lib/capybara/session/config.rb +1 -1
- data/lib/capybara/session.rb +20 -23
- data/lib/capybara/spec/session/active_element_spec.rb +31 -0
- data/lib/capybara/spec/session/all_spec.rb +9 -13
- data/lib/capybara/spec/session/assert_text_spec.rb +17 -17
- data/lib/capybara/spec/session/check_spec.rb +9 -0
- data/lib/capybara/spec/session/choose_spec.rb +6 -0
- data/lib/capybara/spec/session/find_spec.rb +6 -0
- data/lib/capybara/spec/session/has_any_selectors_spec.rb +4 -0
- data/lib/capybara/spec/session/has_button_spec.rb +24 -0
- data/lib/capybara/spec/session/has_current_path_spec.rb +2 -2
- data/lib/capybara/spec/session/has_field_spec.rb +25 -1
- data/lib/capybara/spec/session/has_link_spec.rb +30 -0
- data/lib/capybara/spec/session/has_select_spec.rb +4 -4
- data/lib/capybara/spec/session/has_selector_spec.rb +15 -0
- data/lib/capybara/spec/session/has_text_spec.rb +2 -6
- data/lib/capybara/spec/session/node_spec.rb +43 -1
- data/lib/capybara/spec/session/scroll_spec.rb +4 -4
- data/lib/capybara/spec/session/visit_spec.rb +20 -0
- data/lib/capybara/spec/session/window/window_spec.rb +1 -1
- data/lib/capybara/spec/spec_helper.rb +4 -3
- data/lib/capybara/spec/test_app.rb +66 -8
- data/lib/capybara/spec/views/animated.erb +1 -1
- data/lib/capybara/spec/views/form.erb +11 -3
- data/lib/capybara/spec/views/frame_child.erb +1 -1
- data/lib/capybara/spec/views/frame_one.erb +1 -1
- data/lib/capybara/spec/views/frame_parent.erb +1 -1
- data/lib/capybara/spec/views/frame_two.erb +1 -1
- data/lib/capybara/spec/views/initial_alert.erb +2 -1
- data/lib/capybara/spec/views/layout.erb +10 -0
- data/lib/capybara/spec/views/obscured.erb +1 -1
- data/lib/capybara/spec/views/offset.erb +2 -1
- data/lib/capybara/spec/views/path.erb +2 -2
- data/lib/capybara/spec/views/popup_one.erb +1 -1
- data/lib/capybara/spec/views/popup_two.erb +1 -1
- data/lib/capybara/spec/views/react.erb +2 -2
- data/lib/capybara/spec/views/scroll.erb +2 -1
- data/lib/capybara/spec/views/spatial.erb +1 -1
- data/lib/capybara/spec/views/with_animation.erb +2 -3
- data/lib/capybara/spec/views/with_base_tag.erb +2 -2
- data/lib/capybara/spec/views/with_dragula.erb +2 -2
- data/lib/capybara/spec/views/with_fixed_header_footer.erb +2 -1
- data/lib/capybara/spec/views/with_hover.erb +2 -2
- data/lib/capybara/spec/views/with_html.erb +1 -1
- data/lib/capybara/spec/views/with_jquery_animation.erb +1 -1
- data/lib/capybara/spec/views/with_js.erb +2 -3
- data/lib/capybara/spec/views/with_jstree.erb +1 -1
- data/lib/capybara/spec/views/with_namespace.erb +1 -0
- data/lib/capybara/spec/views/with_shadow.erb +31 -0
- data/lib/capybara/spec/views/with_slow_unload.erb +2 -1
- data/lib/capybara/spec/views/with_sortable_js.erb +2 -2
- data/lib/capybara/spec/views/with_unload_alert.erb +1 -0
- data/lib/capybara/spec/views/with_windows.erb +1 -1
- data/lib/capybara/spec/views/within_frames.erb +1 -1
- data/lib/capybara/version.rb +1 -1
- data/lib/capybara/window.rb +1 -1
- data/lib/capybara.rb +19 -22
- data/spec/basic_node_spec.rb +16 -3
- data/spec/dsl_spec.rb +3 -3
- data/spec/fixtures/selenium_driver_rspec_failure.rb +2 -2
- data/spec/fixtures/selenium_driver_rspec_success.rb +2 -2
- data/spec/rack_test_spec.rb +20 -10
- data/spec/result_spec.rb +32 -35
- data/spec/rspec/features_spec.rb +3 -3
- data/spec/rspec/scenarios_spec.rb +1 -1
- data/spec/rspec/shared_spec_matchers.rb +2 -2
- data/spec/sauce_spec_chrome.rb +3 -3
- data/spec/selector_spec.rb +2 -2
- data/spec/selenium_spec_chrome.rb +9 -10
- data/spec/selenium_spec_chrome_remote.rb +9 -8
- data/spec/selenium_spec_firefox.rb +8 -3
- data/spec/selenium_spec_firefox_remote.rb +2 -2
- data/spec/selenium_spec_ie.rb +3 -6
- data/spec/selenium_spec_safari.rb +31 -19
- data/spec/server_spec.rb +5 -5
- data/spec/shared_selenium_node.rb +0 -4
- data/spec/shared_selenium_session.rb +20 -10
- data/spec/spec_helper.rb +1 -1
- metadata +37 -14
- data/lib/capybara/spec/views/with_title.erb +0 -5
@@ -14,7 +14,7 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def all_text
|
17
|
-
text = driver.evaluate_script('arguments[0].textContent', self)
|
17
|
+
text = driver.evaluate_script('arguments[0].textContent', self) || ''
|
18
18
|
text.gsub(/[\u200b\u200e\u200f]/, '')
|
19
19
|
.gsub(/[\ \n\f\t\v\u2028\u2029]+/, ' ')
|
20
20
|
.gsub(/\A[[:space:]&&[^\u00a0]]+/, '')
|
@@ -53,6 +53,11 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
|
|
53
53
|
# :none => append the new value to the existing value <br/>
|
54
54
|
# :backspace => send backspace keystrokes to clear the field <br/>
|
55
55
|
# Array => an array of keys to send before the value being set, e.g. [[:command, 'a'], :backspace]
|
56
|
+
# @option options [Boolean] :rapid (nil) Whether setting text inputs should use a faster "rapid" mode<br/>
|
57
|
+
# nil => Text inputs with length greater than 30 characters will be set using a faster driver script mode<br/>
|
58
|
+
# true => Rapid mode will be used regardless of input length<br/>
|
59
|
+
# false => Sends keys via conventional mode. This may be required to avoid losing key-presses if you have certain
|
60
|
+
# Javascript interactions on form inputs<br/>
|
56
61
|
def set(value, **options)
|
57
62
|
if value.is_a?(Array) && !multiple?
|
58
63
|
raise ArgumentError, "Value cannot be an Array when 'multiple' attribute is not present. Not a #{value.class}"
|
@@ -199,10 +204,6 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
|
|
199
204
|
native.attribute('isContentEditable') == 'true'
|
200
205
|
end
|
201
206
|
|
202
|
-
def ==(other)
|
203
|
-
native == other.native
|
204
|
-
end
|
205
|
-
|
206
207
|
def path
|
207
208
|
driver.evaluate_script GET_XPATH_SCRIPT, self
|
208
209
|
end
|
@@ -218,6 +219,13 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
|
|
218
219
|
native.rect
|
219
220
|
end
|
220
221
|
|
222
|
+
def shadow_root
|
223
|
+
raise_error 'You must be using Selenium 4.1+ for shadow_root support' unless native.respond_to? :shadow_root
|
224
|
+
|
225
|
+
root = native.shadow_root
|
226
|
+
root && build_node(native.shadow_root)
|
227
|
+
end
|
228
|
+
|
221
229
|
protected
|
222
230
|
|
223
231
|
def scroll_if_needed
|
@@ -274,7 +282,7 @@ private
|
|
274
282
|
elsif clear == :backspace
|
275
283
|
# Clear field by sending the correct number of backspace keys.
|
276
284
|
backspaces = [:backspace] * self.value.to_s.length
|
277
|
-
send_keys(
|
285
|
+
send_keys(:end, *backspaces, value)
|
278
286
|
elsif clear.is_a? Array
|
279
287
|
send_keys(*clear, value)
|
280
288
|
else
|
@@ -282,7 +290,7 @@ private
|
|
282
290
|
if rapid == true || ((value.length > auto_rapid_set_length) && rapid != false)
|
283
291
|
send_keys(value[0..3])
|
284
292
|
driver.execute_script RAPID_APPEND_TEXT, self, value[4...-3]
|
285
|
-
send_keys(value[-3
|
293
|
+
send_keys(value[-3..])
|
286
294
|
else
|
287
295
|
send_keys(value)
|
288
296
|
end
|
@@ -298,7 +306,7 @@ private
|
|
298
306
|
|
299
307
|
scroll_if_needed do
|
300
308
|
action_with_modifiers(click_options) do |action|
|
301
|
-
if
|
309
|
+
if block
|
302
310
|
yield action
|
303
311
|
else
|
304
312
|
click_options.coords? ? action.click : action.click(native)
|
@@ -488,6 +496,12 @@ private
|
|
488
496
|
JS
|
489
497
|
end
|
490
498
|
|
499
|
+
def native_id
|
500
|
+
# Selenium 3 -> 4 changed the return of ref
|
501
|
+
type_or_id, id = native.ref
|
502
|
+
id || type_or_id
|
503
|
+
end
|
504
|
+
|
491
505
|
GET_XPATH_SCRIPT = <<~'JS'
|
492
506
|
(function(el, xml){
|
493
507
|
var xpath = '';
|
@@ -65,7 +65,7 @@ class Capybara::Selenium::ChromeNode < Capybara::Selenium::Node
|
|
65
65
|
return super unless native_displayed?
|
66
66
|
|
67
67
|
begin
|
68
|
-
bridge.send(:execute, :is_element_displayed, id:
|
68
|
+
bridge.send(:execute, :is_element_displayed, id: native_id)
|
69
69
|
rescue Selenium::WebDriver::Error::UnknownCommandError
|
70
70
|
# If the is_element_displayed command is unknown, no point in trying again
|
71
71
|
driver.options[:native_displayed] = false
|
@@ -69,7 +69,7 @@ class Capybara::Selenium::EdgeNode < Capybara::Selenium::Node
|
|
69
69
|
return super unless chrome_edge? && native_displayed?
|
70
70
|
|
71
71
|
begin
|
72
|
-
bridge.send(:execute, :is_element_displayed, id:
|
72
|
+
bridge.send(:execute, :is_element_displayed, id: native_id)
|
73
73
|
rescue Selenium::WebDriver::Error::UnknownCommandError
|
74
74
|
# If the is_element_displayed command is unknown, no point in trying again
|
75
75
|
driver.options[:native_displayed] = false
|
@@ -76,7 +76,7 @@ class Capybara::Selenium::FirefoxNode < Capybara::Selenium::Node
|
|
76
76
|
return super unless native_displayed?
|
77
77
|
|
78
78
|
begin
|
79
|
-
bridge.send(:execute, :is_element_displayed, id:
|
79
|
+
bridge.send(:execute, :is_element_displayed, id: native_id)
|
80
80
|
rescue Selenium::WebDriver::Error::UnknownCommandError
|
81
81
|
# If the is_element_displayed command is unknown, no point in trying again
|
82
82
|
driver.options[:native_displayed] = false
|
@@ -14,7 +14,7 @@ class Capybara::Selenium::SafariNode < Capybara::Selenium::Node
|
|
14
14
|
warn 'You are attempting to click a table row which has issues in safaridriver - '\
|
15
15
|
'Your test should probably be clicking on a table cell like a user would. '\
|
16
16
|
'Clicking the first cell in the row instead.'
|
17
|
-
return find_css('th:first-child,td:first-child')[0].click(keys, options)
|
17
|
+
return find_css('th:first-child,td:first-child')[0].click(keys, **options)
|
18
18
|
end
|
19
19
|
raise
|
20
20
|
rescue ::Selenium::WebDriver::Error::WebDriverError => e
|
@@ -74,7 +74,7 @@ class Capybara::Selenium::SafariNode < Capybara::Selenium::Node
|
|
74
74
|
if clear == :backspace
|
75
75
|
# Clear field by sending the correct number of backspace keys.
|
76
76
|
backspaces = [:backspace] * self.value.to_s.length
|
77
|
-
send_keys(
|
77
|
+
send_keys([:control, 'e'], *backspaces, value)
|
78
78
|
else
|
79
79
|
super.tap do
|
80
80
|
# React doesn't see the safaridriver element clear
|
@@ -16,16 +16,20 @@ module Capybara
|
|
16
16
|
|
17
17
|
def initialize(app)
|
18
18
|
@app = app
|
19
|
-
@
|
19
|
+
@disable_css_markup = format(DISABLE_CSS_MARKUP_TEMPLATE,
|
20
|
+
selector: self.class.selector_for(Capybara.disable_animation))
|
21
|
+
@disable_js_markup = format(DISABLE_JS_MARKUP_TEMPLATE,
|
22
|
+
selector: self.class.selector_for(Capybara.disable_animation))
|
20
23
|
end
|
21
24
|
|
22
25
|
def call(env)
|
23
26
|
@status, @headers, @body = @app.call(env)
|
24
27
|
return [@status, @headers, @body] unless html_content?
|
25
28
|
|
29
|
+
nonces = directive_nonces.transform_values { |nonce| "nonce=\"#{nonce}\"" if nonce && !nonce.empty? }
|
26
30
|
response = Rack::Response.new([], @status, @headers)
|
27
31
|
|
28
|
-
@body.each { |html| response.write insert_disable(html) }
|
32
|
+
@body.each { |html| response.write insert_disable(html, nonces) }
|
29
33
|
@body.close if @body.respond_to?(:close)
|
30
34
|
|
31
35
|
response.finish
|
@@ -33,31 +37,45 @@ module Capybara
|
|
33
37
|
|
34
38
|
private
|
35
39
|
|
36
|
-
attr_reader :
|
40
|
+
attr_reader :disable_css_markup, :disable_js_markup
|
37
41
|
|
38
42
|
def html_content?
|
39
43
|
/html/.match?(@headers['Content-Type'])
|
40
44
|
end
|
41
45
|
|
42
|
-
def insert_disable(html)
|
43
|
-
html.sub(%r{(</
|
46
|
+
def insert_disable(html, nonces)
|
47
|
+
html.sub(%r{(</head>)}, "<style #{nonces['style-src']}>#{disable_css_markup}</style>\\1")
|
48
|
+
.sub(%r{(</body>)}, "<script #{nonces['script-src']}>#{disable_js_markup}</script>\\1")
|
44
49
|
end
|
45
50
|
|
46
|
-
|
47
|
-
|
51
|
+
def directive_nonces
|
52
|
+
@headers.fetch('Content-Security-Policy', '')
|
53
|
+
.split(';')
|
54
|
+
.map(&:split)
|
55
|
+
.to_h do |s|
|
56
|
+
[
|
57
|
+
s[0], s[1..].filter_map do |value|
|
58
|
+
/^'nonce-(?<nonce>.+)'/ =~ value
|
59
|
+
nonce
|
60
|
+
end[0]
|
61
|
+
]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
DISABLE_CSS_MARKUP_TEMPLATE = <<~CSS
|
66
|
+
%<selector>s, %<selector>s::before, %<selector>s::after {
|
67
|
+
transition: none !important;
|
68
|
+
animation-duration: 0s !important;
|
69
|
+
animation-delay: 0s !important;
|
70
|
+
scroll-behavior: auto !important;
|
71
|
+
}
|
72
|
+
CSS
|
73
|
+
|
74
|
+
DISABLE_JS_MARKUP_TEMPLATE = <<~SCRIPT
|
48
75
|
//<![CDATA[
|
49
76
|
(typeof jQuery !== 'undefined') && (jQuery.fx.off = true);
|
50
77
|
//]]>
|
51
|
-
|
52
|
-
<style>
|
53
|
-
%<selector>s, %<selector>s::before, %<selector>s::after {
|
54
|
-
transition: none !important;
|
55
|
-
animation-duration: 0s !important;
|
56
|
-
animation-delay: 0s !important;
|
57
|
-
scroll-behavior: auto !important;
|
58
|
-
}
|
59
|
-
</style>
|
60
|
-
HTML
|
78
|
+
SCRIPT
|
61
79
|
end
|
62
80
|
end
|
63
81
|
end
|
@@ -100,7 +100,7 @@ module Capybara
|
|
100
100
|
remove_method :test_id=
|
101
101
|
##
|
102
102
|
#
|
103
|
-
# Set an
|
103
|
+
# Set an attribute to be optionally matched against the locator for builtin selector types.
|
104
104
|
# This attribute will be checked by builtin selector types whenever id would normally be checked.
|
105
105
|
# If `nil` then it will be ignored.
|
106
106
|
#
|
data/lib/capybara/session.rb
CHANGED
@@ -311,6 +311,16 @@ module Capybara
|
|
311
311
|
driver.send_keys(*args, **kw_args)
|
312
312
|
end
|
313
313
|
|
314
|
+
##
|
315
|
+
#
|
316
|
+
# Returns the element with focus.
|
317
|
+
#
|
318
|
+
# Not supported by Rack Test
|
319
|
+
#
|
320
|
+
def active_element
|
321
|
+
Capybara::Queries::ActiveElementQuery.new.resolve_for(self)[0].tap(&:allow_reload!)
|
322
|
+
end
|
323
|
+
|
314
324
|
##
|
315
325
|
#
|
316
326
|
# Executes the given block within the context of a node. {#within} takes the
|
@@ -408,11 +418,11 @@ module Capybara
|
|
408
418
|
idx = scopes.index(:frame)
|
409
419
|
top_level_scopes = [:frame, nil]
|
410
420
|
if idx
|
411
|
-
if scopes.slice(idx
|
421
|
+
if scopes.slice(idx..).any? { |scope| !top_level_scopes.include?(scope) }
|
412
422
|
raise Capybara::ScopeError, "`switch_to_frame(:top)` cannot be called from inside a descendant frame's "\
|
413
423
|
'`within` block.'
|
414
424
|
end
|
415
|
-
scopes.slice!(idx
|
425
|
+
scopes.slice!(idx..)
|
416
426
|
driver.switch_to_frame(:top)
|
417
427
|
end
|
418
428
|
else
|
@@ -755,33 +765,20 @@ module Capybara
|
|
755
765
|
end
|
756
766
|
|
757
767
|
NODE_METHODS.each do |method|
|
758
|
-
|
759
|
-
|
760
|
-
def #{method}(...)
|
761
|
-
@touched = true
|
762
|
-
current_scope.#{method}(...)
|
763
|
-
end
|
764
|
-
METHOD
|
765
|
-
else
|
766
|
-
define_method method do |*args, &block|
|
768
|
+
class_eval <<~METHOD, __FILE__, __LINE__ + 1
|
769
|
+
def #{method}(...)
|
767
770
|
@touched = true
|
768
|
-
current_scope
|
771
|
+
current_scope.#{method}(...)
|
769
772
|
end
|
770
|
-
|
773
|
+
METHOD
|
771
774
|
end
|
772
775
|
|
773
776
|
DOCUMENT_METHODS.each do |method|
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
document.#{method}(...)
|
778
|
-
end
|
779
|
-
METHOD
|
780
|
-
else
|
781
|
-
define_method method do |*args, &block|
|
782
|
-
document.send(method, *args, &block)
|
777
|
+
class_eval <<~METHOD, __FILE__, __LINE__ + 1
|
778
|
+
def #{method}(...)
|
779
|
+
document.#{method}(...)
|
783
780
|
end
|
784
|
-
|
781
|
+
METHOD
|
785
782
|
end
|
786
783
|
|
787
784
|
def inspect
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Capybara::SpecHelper.spec '#active_element', requires: [:active_element] do
|
4
|
+
it 'should return the active element' do
|
5
|
+
@session.visit('/form')
|
6
|
+
@session.send_keys(:tab)
|
7
|
+
|
8
|
+
expect(@session.active_element).to match_selector(:css, '[tabindex="1"]')
|
9
|
+
|
10
|
+
@session.send_keys(:tab)
|
11
|
+
|
12
|
+
expect(@session.active_element).to match_selector(:css, '[tabindex="2"]')
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should support reloading' do
|
16
|
+
@session.visit('/form')
|
17
|
+
expect(@session.active_element).to match_selector(:css, 'body')
|
18
|
+
@session.execute_script <<-JS
|
19
|
+
window.setTimeout(() => {
|
20
|
+
document.querySelector('#form_title').focus();
|
21
|
+
}, 1000)
|
22
|
+
JS
|
23
|
+
expect(@session.active_element).to match_selector(:css, 'body', wait: false)
|
24
|
+
expect(@session.active_element).to match_selector(:css, '#form_title', wait: 2)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should return a Capybara::Element' do
|
28
|
+
@session.visit('/form')
|
29
|
+
expect(@session.active_element).to be_a Capybara::Node::Element
|
30
|
+
end
|
31
|
+
end
|
@@ -132,7 +132,7 @@ Capybara::SpecHelper.spec '#all' do
|
|
132
132
|
it 'should use the sessions ignore_hidden_elements', psc: true do
|
133
133
|
Capybara.ignore_hidden_elements = true
|
134
134
|
@session.config.ignore_hidden_elements = false
|
135
|
-
expect(Capybara.ignore_hidden_elements).to
|
135
|
+
expect(Capybara.ignore_hidden_elements).to be(true)
|
136
136
|
expect(@session.all(:css, 'a.simple').size).to eq(2)
|
137
137
|
@session.config.ignore_hidden_elements = true
|
138
138
|
expect(@session.all(:css, 'a.simple').size).to eq(1)
|
@@ -203,19 +203,15 @@ Capybara::SpecHelper.spec '#all' do
|
|
203
203
|
expect { @session.all(:css, 'h1, p', between: 0..3) }.to raise_error(Capybara::ExpectationNotMet)
|
204
204
|
end
|
205
205
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
end
|
211
|
-
TEST
|
206
|
+
it 'treats an endless range as minimum' do
|
207
|
+
expect { @session.all(:css, 'h1, p', between: 2..) }.not_to raise_error
|
208
|
+
expect { @session.all(:css, 'h1, p', between: 5..) }.to raise_error(Capybara::ExpectationNotMet)
|
209
|
+
end
|
212
210
|
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
end
|
218
|
-
TEST
|
211
|
+
it 'treats a beginless range as maximum' do
|
212
|
+
expect { @session.all(:css, 'h1, p', between: ..7) }.not_to raise_error
|
213
|
+
expect { @session.all(:css, 'h1, p', between: ..3) }.to raise_error(Capybara::ExpectationNotMet)
|
214
|
+
end
|
219
215
|
end
|
220
216
|
|
221
217
|
context 'with multiple count filters' do
|
@@ -3,16 +3,16 @@
|
|
3
3
|
Capybara::SpecHelper.spec '#assert_text' do
|
4
4
|
it 'should be true if the given text is on the page' do
|
5
5
|
@session.visit('/with_html')
|
6
|
-
expect(@session.assert_text('est')).to
|
7
|
-
expect(@session.assert_text('Lorem')).to
|
8
|
-
expect(@session.assert_text('Redirect')).to
|
9
|
-
expect(@session.assert_text(:Redirect)).to
|
10
|
-
expect(@session.assert_text('text with whitespace')).to
|
6
|
+
expect(@session.assert_text('est')).to be(true)
|
7
|
+
expect(@session.assert_text('Lorem')).to be(true)
|
8
|
+
expect(@session.assert_text('Redirect')).to be(true)
|
9
|
+
expect(@session.assert_text(:Redirect)).to be(true)
|
10
|
+
expect(@session.assert_text('text with whitespace')).to be(true)
|
11
11
|
end
|
12
12
|
|
13
13
|
it 'should support collapsing whitespace' do
|
14
14
|
@session.visit('/with_html')
|
15
|
-
expect(@session.assert_text('text with whitespace', normalize_ws: true)).to
|
15
|
+
expect(@session.assert_text('text with whitespace', normalize_ws: true)).to be(true)
|
16
16
|
end
|
17
17
|
|
18
18
|
context 'with enabled default collapsing whitespace' do
|
@@ -20,19 +20,19 @@ Capybara::SpecHelper.spec '#assert_text' do
|
|
20
20
|
|
21
21
|
it 'should be true if the given unnormalized text is on the page' do
|
22
22
|
@session.visit('/with_html')
|
23
|
-
expect(@session.assert_text('text with whitespace', normalize_ws: false)).to
|
23
|
+
expect(@session.assert_text('text with whitespace', normalize_ws: false)).to be(true)
|
24
24
|
end
|
25
25
|
|
26
26
|
it 'should support collapsing whitespace' do
|
27
27
|
@session.visit('/with_html')
|
28
|
-
expect(@session.assert_text('text with whitespace')).to
|
28
|
+
expect(@session.assert_text('text with whitespace')).to be(true)
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
32
|
it 'should take scopes into account' do
|
33
33
|
@session.visit('/with_html')
|
34
34
|
@session.within("//a[@title='awesome title']") do
|
35
|
-
expect(@session.assert_text('labore')).to
|
35
|
+
expect(@session.assert_text('labore')).to be(true)
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
@@ -47,13 +47,13 @@ Capybara::SpecHelper.spec '#assert_text' do
|
|
47
47
|
|
48
48
|
it 'should be true if :all given and text is invisible.' do
|
49
49
|
@session.visit('/with_html')
|
50
|
-
expect(@session.assert_text(:all, 'Some of this text is hidden!')).to
|
50
|
+
expect(@session.assert_text(:all, 'Some of this text is hidden!')).to be(true)
|
51
51
|
end
|
52
52
|
|
53
53
|
it 'should be true if `Capybara.ignore_hidden_elements = true` and text is invisible.' do
|
54
54
|
Capybara.ignore_hidden_elements = false
|
55
55
|
@session.visit('/with_html')
|
56
|
-
expect(@session.assert_text('Some of this text is hidden!')).to
|
56
|
+
expect(@session.assert_text('Some of this text is hidden!')).to be(true)
|
57
57
|
end
|
58
58
|
|
59
59
|
it 'should raise error with a helpful message if the requested text is present but invisible' do
|
@@ -88,7 +88,7 @@ Capybara::SpecHelper.spec '#assert_text' do
|
|
88
88
|
|
89
89
|
it 'should be true if the text in the page matches given regexp' do
|
90
90
|
@session.visit('/with_html')
|
91
|
-
expect(@session.assert_text(/Lorem/)).to
|
91
|
+
expect(@session.assert_text(/Lorem/)).to be(true)
|
92
92
|
end
|
93
93
|
|
94
94
|
it "should raise error if the text in the page doesn't match given regexp" do
|
@@ -109,13 +109,13 @@ Capybara::SpecHelper.spec '#assert_text' do
|
|
109
109
|
Capybara.default_max_wait_time = 2
|
110
110
|
@session.visit('/with_js')
|
111
111
|
@session.click_link('Click me')
|
112
|
-
expect(@session.assert_text('Has been clicked')).to
|
112
|
+
expect(@session.assert_text('Has been clicked')).to be(true)
|
113
113
|
end
|
114
114
|
|
115
115
|
context 'with between' do
|
116
116
|
it 'should be true if the text occurs within the range given' do
|
117
117
|
@session.visit('/with_count')
|
118
|
-
expect(@session.assert_text('count', between: 1..3)).to
|
118
|
+
expect(@session.assert_text('count', between: 1..3)).to be(true)
|
119
119
|
end
|
120
120
|
|
121
121
|
it 'should be false if the text occurs more or fewer times than range' do
|
@@ -203,13 +203,13 @@ Capybara::SpecHelper.spec '#assert_no_text' do
|
|
203
203
|
it 'should be true if scoped to an element which does not have the text' do
|
204
204
|
@session.visit('/with_html')
|
205
205
|
@session.within("//a[@title='awesome title']") do
|
206
|
-
expect(@session.assert_no_text('monkey')).to
|
206
|
+
expect(@session.assert_no_text('monkey')).to be(true)
|
207
207
|
end
|
208
208
|
end
|
209
209
|
|
210
210
|
it 'should be true if the given text is on the page but not visible' do
|
211
211
|
@session.visit('/with_html')
|
212
|
-
expect(@session.assert_no_text('Inside element with hidden ancestor')).to
|
212
|
+
expect(@session.assert_no_text('Inside element with hidden ancestor')).to be(true)
|
213
213
|
end
|
214
214
|
|
215
215
|
it 'should raise error if :all given and text is invisible.' do
|
@@ -236,7 +236,7 @@ Capybara::SpecHelper.spec '#assert_no_text' do
|
|
236
236
|
context 'with count' do
|
237
237
|
it 'should be true if the text occurs within the range given' do
|
238
238
|
@session.visit('/with_count')
|
239
|
-
expect(@session.assert_text('count', count: 2)).to
|
239
|
+
expect(@session.assert_text('count', count: 2)).to be(true)
|
240
240
|
end
|
241
241
|
|
242
242
|
it 'should be false if the text occurs more or fewer times than range' do
|
@@ -236,6 +236,15 @@ Capybara::SpecHelper.spec '#check' do
|
|
236
236
|
expect(@session).to have_field('multi_label_checkbox', checked: true, visible: :hidden)
|
237
237
|
end
|
238
238
|
end
|
239
|
+
|
240
|
+
context 'with allow_label_click options', requires: [:js] do
|
241
|
+
it 'should allow offsets to click location on label' do
|
242
|
+
expect(@session.find(:checkbox, 'form_cars_lotus', unchecked: true, visible: :hidden)).to be_truthy
|
243
|
+
@session.check('form_cars_lotus', allow_label_click: { x: 90, y: 10 })
|
244
|
+
@session.click_button('awesome')
|
245
|
+
expect(extract_results(@session)['cars']).to include('lotus')
|
246
|
+
end
|
247
|
+
end
|
239
248
|
end
|
240
249
|
end
|
241
250
|
end
|
@@ -11,6 +11,12 @@ Capybara::SpecHelper.spec '#choose' do
|
|
11
11
|
expect(extract_results(@session)['gender']).to eq('male')
|
12
12
|
end
|
13
13
|
|
14
|
+
it 'ignores readonly attribute on radio buttons' do
|
15
|
+
@session.choose('gender_both')
|
16
|
+
@session.click_button('awesome')
|
17
|
+
expect(extract_results(@session)['gender']).to eq('both')
|
18
|
+
end
|
19
|
+
|
14
20
|
it 'should choose a radio button by label' do
|
15
21
|
@session.choose('Both')
|
16
22
|
@session.click_button('awesome')
|
@@ -528,4 +528,10 @@ Capybara::SpecHelper.spec '#find' do
|
|
528
528
|
expect(@session.find(:link, 'test-foo')[:id]).to eq 'foo'
|
529
529
|
end
|
530
530
|
end
|
531
|
+
|
532
|
+
it 'should warn if passed count options' do
|
533
|
+
allow(Capybara::Helpers).to receive(:warn)
|
534
|
+
@session.find('//h1', count: 44)
|
535
|
+
expect(Capybara::Helpers).to have_received(:warn).with(/'find' does not support count options/)
|
536
|
+
end
|
531
537
|
end
|
@@ -22,4 +22,8 @@ Capybara::SpecHelper.spec '#have_any_of_selectors' do
|
|
22
22
|
expect(@session).to have_any_of_selectors('p a#blah', 'h2#h2three')
|
23
23
|
end.to raise_error ::RSpec::Expectations::ExpectationNotMetError
|
24
24
|
end
|
25
|
+
|
26
|
+
it 'should be negateable' do
|
27
|
+
expect(@session).not_to have_any_of_selectors(:css, 'span a#foo', 'h2#h2nope', 'h2#h2one_no')
|
28
|
+
end
|
25
29
|
end
|
@@ -65,6 +65,18 @@ Capybara::SpecHelper.spec '#has_button?' do
|
|
65
65
|
it 'should not affect other selectors when enable_aria_role: false' do
|
66
66
|
expect(@session).to have_button('Click me!', enable_aria_role: false)
|
67
67
|
end
|
68
|
+
|
69
|
+
context 'with focused:', requires: [:active_element] do
|
70
|
+
it 'should be true if a field has focus when focused: true' do
|
71
|
+
@session.send_keys(:tab)
|
72
|
+
|
73
|
+
expect(@session).to have_button('A Button', focused: true)
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'should be true if a field does not have focus when focused: false' do
|
77
|
+
expect(@session).to have_button('A Button', focused: false)
|
78
|
+
end
|
79
|
+
end
|
68
80
|
end
|
69
81
|
|
70
82
|
Capybara::SpecHelper.spec '#has_no_button?' do
|
@@ -117,4 +129,16 @@ Capybara::SpecHelper.spec '#has_no_button?' do
|
|
117
129
|
it 'should not affect other selectors when enable_aria_role: false' do
|
118
130
|
expect(@session).to have_no_button('Junk button that does not exist', enable_aria_role: false)
|
119
131
|
end
|
132
|
+
|
133
|
+
context 'with focused:', requires: [:active_element] do
|
134
|
+
it 'should be true if a button does not have focus when focused: true' do
|
135
|
+
expect(@session).to have_no_button('A Button', focused: true)
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'should be false if a button has focus when focused: false' do
|
139
|
+
@session.send_keys(:tab)
|
140
|
+
|
141
|
+
expect(@session).to have_no_button('A Button', focused: false)
|
142
|
+
end
|
143
|
+
end
|
120
144
|
end
|
@@ -16,8 +16,8 @@ Capybara::SpecHelper.spec '#has_current_path?' do
|
|
16
16
|
|
17
17
|
it 'should not raise an error when non-http' do
|
18
18
|
@session.reset_session!
|
19
|
-
expect(@session.has_current_path?(/monkey/)).to
|
20
|
-
expect(@session.has_current_path?('/with_js')).to
|
19
|
+
expect(@session.has_current_path?(/monkey/)).to be false
|
20
|
+
expect(@session.has_current_path?('/with_js')).to be false
|
21
21
|
end
|
22
22
|
|
23
23
|
it 'should handle non-escaped query options' do
|
@@ -110,6 +110,18 @@ Capybara::SpecHelper.spec '#has_field' do
|
|
110
110
|
end
|
111
111
|
end
|
112
112
|
|
113
|
+
context 'with focused:', requires: [:active_element] do
|
114
|
+
it 'should be true if a field has focus' do
|
115
|
+
2.times { @session.send_keys(:tab) }
|
116
|
+
|
117
|
+
expect(@session).to have_field('An Input', focused: true)
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'should be false if a field does not have focus' do
|
121
|
+
expect(@session).to have_field('An Input', focused: false)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
113
125
|
context 'with valid', requires: [:js] do
|
114
126
|
it 'should be true if field is valid' do
|
115
127
|
@session.fill_in 'required', with: 'something'
|
@@ -184,6 +196,18 @@ Capybara::SpecHelper.spec '#has_no_field' do
|
|
184
196
|
expect(@session).to have_no_field('Languages', type: 'textarea')
|
185
197
|
end
|
186
198
|
end
|
199
|
+
|
200
|
+
context 'with focused:', requires: [:active_element] do
|
201
|
+
it 'should be true if a field does not have focus when focused: true' do
|
202
|
+
expect(@session).to have_no_field('An Input', focused: true)
|
203
|
+
end
|
204
|
+
|
205
|
+
it 'should be false if a field has focus when focused: true' do
|
206
|
+
2.times { @session.send_keys(:tab) }
|
207
|
+
|
208
|
+
expect(@session).not_to have_no_field('An Input', focused: true)
|
209
|
+
end
|
210
|
+
end
|
187
211
|
end
|
188
212
|
|
189
213
|
Capybara::SpecHelper.spec '#has_checked_field?' do
|
@@ -359,7 +383,7 @@ Capybara::SpecHelper.spec '#has_no_unchecked_field?' do
|
|
359
383
|
end
|
360
384
|
|
361
385
|
it 'should support locator-less usage' do
|
362
|
-
expect(@session.has_no_unchecked_field?(disabled: false, id: 'form_disabled_unchecked_checkbox')).to
|
386
|
+
expect(@session.has_no_unchecked_field?(disabled: false, id: 'form_disabled_unchecked_checkbox')).to be true
|
363
387
|
expect(@session).to have_no_unchecked_field(disabled: false, id: 'form_disabled_unchecked_checkbox')
|
364
388
|
end
|
365
389
|
end
|