capybara 3.35.2 → 3.37.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 +59 -4
- 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 +2 -11
- 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 +2 -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 +41 -6
- 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.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/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 +24 -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 +14 -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 +50 -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 +1 -1
- 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
|
@@ -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')
|
|
@@ -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
|
|
@@ -18,6 +18,18 @@ Capybara::SpecHelper.spec '#has_link?' do
|
|
|
18
18
|
expect(@session).not_to have_link('A link', href: '/nonexistent-href')
|
|
19
19
|
expect(@session).not_to have_link('A link', href: /nonexistent/)
|
|
20
20
|
end
|
|
21
|
+
|
|
22
|
+
context 'with focused:', requires: [:active_element] do
|
|
23
|
+
it 'should be true if the given link is on the page and has focus' do
|
|
24
|
+
@session.send_keys(:tab)
|
|
25
|
+
|
|
26
|
+
expect(@session).to have_link('labore', focused: true)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'should be false if the given link is on the page and does not have focus' do
|
|
30
|
+
expect(@session).to have_link('labore', focused: false)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
21
33
|
end
|
|
22
34
|
|
|
23
35
|
Capybara::SpecHelper.spec '#has_no_link?' do
|
|
@@ -36,4 +48,16 @@ Capybara::SpecHelper.spec '#has_no_link?' do
|
|
|
36
48
|
expect(@session).to have_no_link('A link', href: '/nonexistent-href')
|
|
37
49
|
expect(@session).to have_no_link('A link', href: %r{/nonexistent-href})
|
|
38
50
|
end
|
|
51
|
+
|
|
52
|
+
context 'with focused:', requires: [:active_element] do
|
|
53
|
+
it 'should be true if the given link is on the page and has focus' do
|
|
54
|
+
expect(@session).to have_no_link('labore', focused: true)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it 'should be false if the given link is on the page and does not have focus' do
|
|
58
|
+
@session.send_keys(:tab)
|
|
59
|
+
|
|
60
|
+
expect(@session).to have_no_link('labore', focused: false)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
39
63
|
end
|
|
@@ -180,9 +180,9 @@ Capybara::SpecHelper.spec '#has_select?' do
|
|
|
180
180
|
end
|
|
181
181
|
|
|
182
182
|
it 'should support locator-less usage' do
|
|
183
|
-
expect(@session.has_select?(with_options: %w[Norway Sweden])).to
|
|
183
|
+
expect(@session.has_select?(with_options: %w[Norway Sweden])).to be true
|
|
184
184
|
expect(@session).to have_select(with_options: ['London'])
|
|
185
|
-
expect(@session.has_select?(with_selected: %w[Commando Boxerbriefs])).to
|
|
185
|
+
expect(@session.has_select?(with_selected: %w[Commando Boxerbriefs])).to be true
|
|
186
186
|
expect(@session).to have_select(with_selected: ['Briefs'])
|
|
187
187
|
end
|
|
188
188
|
end
|
|
@@ -302,9 +302,9 @@ Capybara::SpecHelper.spec '#has_no_select?' do
|
|
|
302
302
|
end
|
|
303
303
|
|
|
304
304
|
it 'should support locator-less usage' do
|
|
305
|
-
expect(@session.has_no_select?(with_options: %w[Norway Sweden Finland Latvia])).to
|
|
305
|
+
expect(@session.has_no_select?(with_options: %w[Norway Sweden Finland Latvia])).to be true
|
|
306
306
|
expect(@session).to have_no_select(with_options: ['New London'])
|
|
307
|
-
expect(@session.has_no_select?(id: 'form_underwear', with_selected: ['Boxers'])).to
|
|
307
|
+
expect(@session.has_no_select?(id: 'form_underwear', with_selected: ['Boxers'])).to be true
|
|
308
308
|
expect(@session).to have_no_select(id: 'form_underwear', with_selected: %w[Commando Boxers])
|
|
309
309
|
end
|
|
310
310
|
end
|
|
@@ -117,6 +117,21 @@ Capybara::SpecHelper.spec '#has_selector?' do
|
|
|
117
117
|
expect(@session).to have_selector(:id, 'h2one', text: 'Header Class Test One', exact_text: false)
|
|
118
118
|
expect(@session).to have_selector(:id, 'h2one', text: 'Header Class Test', exact_text: false)
|
|
119
119
|
end
|
|
120
|
+
|
|
121
|
+
it 'should warn if text option is a regexp that it is ignoring exact_text' do
|
|
122
|
+
allow(Capybara::Helpers).to receive(:warn)
|
|
123
|
+
expect(@session).to have_selector(:id, 'h2one', text: /Class Test/, exact_text: true)
|
|
124
|
+
expect(Capybara::Helpers).to have_received(:warn).with(/'exact_text' option is not supported/)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
context 'regexp' do
|
|
129
|
+
it 'should only match when it fully matches' do
|
|
130
|
+
expect(@session).to have_selector(:id, 'h2one', exact_text: /Header Class Test One/)
|
|
131
|
+
expect(@session).to have_no_selector(:id, 'h2one', exact_text: /Header Class Test/)
|
|
132
|
+
expect(@session).to have_no_selector(:id, 'h2one', exact_text: /Class Test One/)
|
|
133
|
+
expect(@session).to have_no_selector(:id, 'h2one', exact_text: /Class Test/)
|
|
134
|
+
end
|
|
120
135
|
end
|
|
121
136
|
end
|
|
122
137
|
|
|
@@ -127,11 +127,7 @@ Capybara::SpecHelper.spec '#has_text?' do
|
|
|
127
127
|
def to_hash; { value: 'Other hash' } end
|
|
128
128
|
end.new
|
|
129
129
|
@session.visit('/with_html')
|
|
130
|
-
|
|
131
|
-
expect(@session).to have_text(:visible, with_to_hash, **{})
|
|
132
|
-
else
|
|
133
|
-
expect(@session).to have_text(:visible, with_to_hash, {})
|
|
134
|
-
end
|
|
130
|
+
expect(@session).to have_text(:visible, with_to_hash, **{})
|
|
135
131
|
end
|
|
136
132
|
end
|
|
137
133
|
|
|
@@ -356,7 +352,7 @@ Capybara::SpecHelper.spec '#has_no_text?' do
|
|
|
356
352
|
expect(@session).to have_no_text(/xxxxyzzz/)
|
|
357
353
|
end
|
|
358
354
|
|
|
359
|
-
it 'should be false if the text in the page
|
|
355
|
+
it 'should be false if the text in the page matches given regexp' do
|
|
360
356
|
@session.visit('/with_html')
|
|
361
357
|
expect(@session).not_to have_no_text(/Lorem/)
|
|
362
358
|
end
|
|
@@ -1115,7 +1115,7 @@ Capybara::SpecHelper.spec 'node' do
|
|
|
1115
1115
|
end
|
|
1116
1116
|
|
|
1117
1117
|
describe '#evaluate_script', requires: %i[js es_args] do
|
|
1118
|
-
it 'should evaluate the given script in the context of the element and
|
|
1118
|
+
it 'should evaluate the given script in the context of the element and return whatever it produces' do
|
|
1119
1119
|
@session.visit('/with_js')
|
|
1120
1120
|
el = @session.find(:css, '#with_change_event')
|
|
1121
1121
|
expect(el.evaluate_script('this.value')).to eq('default value')
|
|
@@ -1176,6 +1176,48 @@ Capybara::SpecHelper.spec 'node' do
|
|
|
1176
1176
|
end
|
|
1177
1177
|
end
|
|
1178
1178
|
|
|
1179
|
+
describe '#shadow_root', requires: %i[js] do
|
|
1180
|
+
it 'should get the shadow root' do
|
|
1181
|
+
@session.visit('/with_shadow')
|
|
1182
|
+
expect do
|
|
1183
|
+
shadow_root = @session.find(:css, '#shadow_host').shadow_root
|
|
1184
|
+
expect(shadow_root).not_to be_nil
|
|
1185
|
+
end.not_to raise_error
|
|
1186
|
+
end
|
|
1187
|
+
|
|
1188
|
+
it 'should find elements inside the shadow dom using CSS' do
|
|
1189
|
+
@session.visit('/with_shadow')
|
|
1190
|
+
shadow_root = @session.find(:css, '#shadow_host').shadow_root
|
|
1191
|
+
expect(shadow_root).to have_css('#shadow_content', text: 'some text')
|
|
1192
|
+
end
|
|
1193
|
+
|
|
1194
|
+
it 'should find nested shadow roots' do
|
|
1195
|
+
@session.visit('/with_shadow')
|
|
1196
|
+
shadow_root = @session.find(:css, '#shadow_host').shadow_root
|
|
1197
|
+
nested_shadow_root = shadow_root.find(:css, '#nested_shadow_host').shadow_root
|
|
1198
|
+
expect(nested_shadow_root).to have_css('#nested_shadow_content', text: 'nested text')
|
|
1199
|
+
end
|
|
1200
|
+
|
|
1201
|
+
it 'should click on elements' do
|
|
1202
|
+
@session.visit('/with_shadow')
|
|
1203
|
+
shadow_root = @session.find(:css, '#shadow_host').shadow_root
|
|
1204
|
+
checkbox = shadow_root.find(:css, 'input[type="checkbox"]')
|
|
1205
|
+
expect(checkbox).not_to be_checked
|
|
1206
|
+
checkbox.click
|
|
1207
|
+
expect(checkbox).to be_checked
|
|
1208
|
+
end
|
|
1209
|
+
|
|
1210
|
+
it 'should use convenience methods once moved to a descendant of the shadow root' do
|
|
1211
|
+
@session.visit('/with_shadow')
|
|
1212
|
+
shadow_root = @session.find(:css, '#shadow_host').shadow_root
|
|
1213
|
+
descendant = shadow_root.find(:css, '#controls_wrapper')
|
|
1214
|
+
expect do
|
|
1215
|
+
descendant.check('shadow_checkbox')
|
|
1216
|
+
end.not_to raise_error
|
|
1217
|
+
expect(descendant).to have_checked_field('shadow_checkbox')
|
|
1218
|
+
end
|
|
1219
|
+
end
|
|
1220
|
+
|
|
1179
1221
|
describe '#reload', requires: [:js] do
|
|
1180
1222
|
it 'should reload elements found via ancestor with CSS' do
|
|
1181
1223
|
@session.visit('/with_js')
|