capybara 3.1.1 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.md +19 -0
- data/README.md +1 -1
- data/lib/capybara.rb +2 -0
- data/lib/capybara/config.rb +2 -1
- data/lib/capybara/driver/base.rb +1 -1
- data/lib/capybara/driver/node.rb +3 -3
- data/lib/capybara/node/actions.rb +90 -92
- data/lib/capybara/node/base.rb +2 -2
- data/lib/capybara/node/document_matchers.rb +5 -5
- data/lib/capybara/node/element.rb +47 -16
- data/lib/capybara/node/finders.rb +13 -13
- data/lib/capybara/node/matchers.rb +18 -17
- data/lib/capybara/node/simple.rb +6 -2
- data/lib/capybara/queries/ancestor_query.rb +1 -1
- data/lib/capybara/queries/base_query.rb +3 -3
- data/lib/capybara/queries/current_path_query.rb +1 -1
- data/lib/capybara/queries/match_query.rb +8 -0
- data/lib/capybara/queries/selector_query.rb +97 -42
- data/lib/capybara/queries/sibling_query.rb +1 -1
- data/lib/capybara/queries/text_query.rb +12 -7
- data/lib/capybara/rack_test/browser.rb +9 -7
- data/lib/capybara/rack_test/form.rb +15 -17
- data/lib/capybara/rack_test/node.rb +12 -12
- data/lib/capybara/result.rb +26 -15
- data/lib/capybara/rspec.rb +1 -2
- data/lib/capybara/rspec/compound.rb +4 -4
- data/lib/capybara/rspec/matchers.rb +2 -2
- data/lib/capybara/selector.rb +75 -225
- data/lib/capybara/selector/css.rb +2 -2
- data/lib/capybara/selector/filter_set.rb +17 -21
- data/lib/capybara/selector/filters/base.rb +24 -1
- data/lib/capybara/selector/filters/expression_filter.rb +3 -5
- data/lib/capybara/selector/filters/node_filter.rb +4 -4
- data/lib/capybara/selector/selector.rb +221 -69
- data/lib/capybara/selenium/driver.rb +15 -88
- data/lib/capybara/selenium/node.rb +25 -28
- data/lib/capybara/server.rb +10 -54
- data/lib/capybara/server/animation_disabler.rb +43 -0
- data/lib/capybara/server/middleware.rb +55 -0
- data/lib/capybara/session.rb +29 -30
- data/lib/capybara/session/config.rb +11 -1
- data/lib/capybara/session/matchers.rb +5 -5
- data/lib/capybara/spec/session/assert_text_spec.rb +1 -1
- data/lib/capybara/spec/session/body_spec.rb +10 -12
- data/lib/capybara/spec/session/click_link_spec.rb +3 -3
- data/lib/capybara/spec/session/element/assert_match_selector_spec.rb +1 -1
- data/lib/capybara/spec/session/fill_in_spec.rb +9 -0
- data/lib/capybara/spec/session/find_field_spec.rb +1 -1
- data/lib/capybara/spec/session/find_spec.rb +8 -3
- data/lib/capybara/spec/session/has_link_spec.rb +2 -2
- data/lib/capybara/spec/session/node_spec.rb +50 -0
- data/lib/capybara/spec/session/node_wrapper_spec.rb +5 -5
- data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +1 -1
- data/lib/capybara/spec/session/window/windows_spec.rb +3 -5
- data/lib/capybara/spec/spec_helper.rb +4 -2
- data/lib/capybara/spec/views/with_animation.erb +46 -0
- data/lib/capybara/version.rb +1 -1
- data/lib/capybara/window.rb +3 -2
- data/spec/filter_set_spec.rb +19 -2
- data/spec/result_spec.rb +33 -1
- data/spec/rspec/features_spec.rb +6 -10
- data/spec/rspec/shared_spec_matchers.rb +4 -4
- data/spec/selector_spec.rb +74 -4
- data/spec/selenium_spec_marionette.rb +2 -0
- data/spec/server_spec.rb +1 -1
- data/spec/session_spec.rb +12 -0
- data/spec/shared_selenium_session.rb +30 -0
- metadata +8 -9
- data/.yard/templates_custom/default/class/html/selectors.erb +0 -38
- data/.yard/templates_custom/default/class/html/setup.rb +0 -17
- data/.yard/yard_extensions.rb +0 -78
- data/.yardopts +0 -1
data/lib/capybara/session.rb
CHANGED
@@ -26,7 +26,7 @@ module Capybara
|
|
26
26
|
# end
|
27
27
|
#
|
28
28
|
# Session provides a number of methods for controlling the navigation of the page, such as +visit+,
|
29
|
-
# +current_path, and so on. It also
|
29
|
+
# +current_path, and so on. It also delegates a number of methods to a Capybara::Document, representing
|
30
30
|
# the current HTML document. This allows interaction:
|
31
31
|
#
|
32
32
|
# session.fill_in('q', with: 'Capybara')
|
@@ -83,10 +83,10 @@ module Capybara
|
|
83
83
|
raise "A configuration block is only accepted when Capybara.threadsafe == true" unless Capybara.threadsafe
|
84
84
|
yield config
|
85
85
|
end
|
86
|
-
@server = if config.run_server
|
87
|
-
|
88
|
-
|
89
|
-
|
86
|
+
@server = if config.run_server && @app && driver.needs_server?
|
87
|
+
server_options = { port: config.server_port, host: config.server_host, reportable_errors: config.server_errors }
|
88
|
+
server_options[:extra_middleware] = [Capybara::Server::AnimationDisabler] if config.disable_animation
|
89
|
+
Capybara::Server.new(@app, server_options).boot
|
90
90
|
end
|
91
91
|
@touched = false
|
92
92
|
end
|
@@ -126,7 +126,7 @@ module Capybara
|
|
126
126
|
driver.reset!
|
127
127
|
@touched = false
|
128
128
|
end
|
129
|
-
@server
|
129
|
+
@server&.wait_for_pending_requests
|
130
130
|
raise_server_error!
|
131
131
|
end
|
132
132
|
alias_method :cleanup!, :reset!
|
@@ -189,14 +189,11 @@ module Capybara
|
|
189
189
|
# Addressable parsing is more lenient than URI
|
190
190
|
uri = ::Addressable::URI.parse(current_url)
|
191
191
|
|
192
|
-
# If current_url ends up being nil, won't be able to call .path on a NilClass.
|
193
|
-
return nil if uri.nil?
|
194
|
-
|
195
192
|
# Addressable doesn't support opaque URIs - we want nil here
|
196
|
-
return nil if uri
|
193
|
+
return nil if uri&.scheme == "about"
|
197
194
|
|
198
|
-
path = uri
|
199
|
-
path
|
195
|
+
path = uri&.path
|
196
|
+
path unless path&.empty?
|
200
197
|
end
|
201
198
|
|
202
199
|
##
|
@@ -248,11 +245,10 @@ module Capybara
|
|
248
245
|
|
249
246
|
visit_uri = ::Addressable::URI.parse(visit_uri.to_s)
|
250
247
|
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
end
|
248
|
+
base = config.app_host
|
249
|
+
base ||= "http#{'s' if @server.using_ssl?}://#{@server.host}:#{@server.port}" if @server
|
250
|
+
|
251
|
+
uri_base = ::Addressable::URI.parse(base)
|
256
252
|
|
257
253
|
if uri_base && [nil, 'http', 'https'].include?(visit_uri.scheme)
|
258
254
|
if visit_uri.relative?
|
@@ -337,7 +333,7 @@ module Capybara
|
|
337
333
|
new_scope = args.first.respond_to?(:to_capybara_node) ? args.first.to_capybara_node : find(*args)
|
338
334
|
begin
|
339
335
|
scopes.push(new_scope)
|
340
|
-
yield
|
336
|
+
yield if block_given?
|
341
337
|
ensure
|
342
338
|
scopes.pop
|
343
339
|
end
|
@@ -411,7 +407,7 @@ module Capybara
|
|
411
407
|
#
|
412
408
|
# @overload within_frame(element)
|
413
409
|
# @param [Capybara::Node::Element] frame element
|
414
|
-
# @overload within_frame([kind = :frame], locator, options
|
410
|
+
# @overload within_frame([kind = :frame], locator, **options)
|
415
411
|
# @param [Symbol] kind Optional selector type (:css, :xpath, :field, etc.) - Defaults to :frame
|
416
412
|
# @param [String] locator The locator for the given selector kind. For :frame this is the name/id of a frame/iframe element
|
417
413
|
# @overload within_frame(index)
|
@@ -419,7 +415,7 @@ module Capybara
|
|
419
415
|
def within_frame(*args)
|
420
416
|
switch_to_frame(_find_frame(*args))
|
421
417
|
begin
|
422
|
-
yield
|
418
|
+
yield if block_given?
|
423
419
|
ensure
|
424
420
|
switch_to_frame(:parent)
|
425
421
|
end
|
@@ -475,9 +471,8 @@ module Capybara
|
|
475
471
|
# @raise [ArgumentError] if both or neither arguments were provided
|
476
472
|
#
|
477
473
|
def switch_to_window(window = nil, **options, &window_locator)
|
478
|
-
|
479
|
-
raise ArgumentError, "`switch_to_window
|
480
|
-
raise ArgumentError, "`switch_to_window`: either window or block should be provided" if !window && !block_given
|
474
|
+
raise ArgumentError, "`switch_to_window` can take either a block or a window, not both" if window && block_given?
|
475
|
+
raise ArgumentError, "`switch_to_window`: either window or block should be provided" if !window && !block_given?
|
481
476
|
unless scopes.last.nil?
|
482
477
|
raise Capybara::ScopeError, "`switch_to_window` is not supposed to be invoked from "\
|
483
478
|
"`within` or `within_frame` blocks."
|
@@ -521,7 +516,7 @@ module Capybara
|
|
521
516
|
end
|
522
517
|
|
523
518
|
begin
|
524
|
-
yield
|
519
|
+
yield if block_given?
|
525
520
|
ensure
|
526
521
|
_switch_to_window(original) unless original == window_or_proc
|
527
522
|
end
|
@@ -569,7 +564,7 @@ module Capybara
|
|
569
564
|
#
|
570
565
|
def execute_script(script, *args)
|
571
566
|
@touched = true
|
572
|
-
driver.execute_script(script, *args
|
567
|
+
driver.execute_script(script, *driver_args(args))
|
573
568
|
end
|
574
569
|
|
575
570
|
##
|
@@ -583,7 +578,7 @@ module Capybara
|
|
583
578
|
#
|
584
579
|
def evaluate_script(script, *args)
|
585
580
|
@touched = true
|
586
|
-
result = driver.evaluate_script(script, *args
|
581
|
+
result = driver.evaluate_script(script, *driver_args(args))
|
587
582
|
element_script_result(result)
|
588
583
|
end
|
589
584
|
|
@@ -596,7 +591,7 @@ module Capybara
|
|
596
591
|
#
|
597
592
|
def evaluate_async_script(script, *args)
|
598
593
|
@touched = true
|
599
|
-
result = driver.evaluate_async_script(script, *args
|
594
|
+
result = driver.evaluate_async_script(script, *driver_args(args))
|
600
595
|
element_script_result(result)
|
601
596
|
end
|
602
597
|
|
@@ -610,11 +605,11 @@ module Capybara
|
|
610
605
|
# $0 do
|
611
606
|
# click_link('link that triggers appearance of system modal')
|
612
607
|
# end
|
613
|
-
# @overload $0(text, options
|
608
|
+
# @overload $0(text, **options, &blk)
|
614
609
|
# @param text [String, Regexp] Text or regex to match against the text in the modal. If not provided any modal is matched
|
615
610
|
# @option options [Numeric] :wait (Capybara.default_max_wait_time) Maximum time to wait for the modal to appear after executing the block.
|
616
611
|
# @yield Block whose actions will trigger the system modal
|
617
|
-
# @overload $0(options
|
612
|
+
# @overload $0(**options, &blk)
|
618
613
|
# @option options [Numeric] :wait (Capybara.default_max_wait_time) Maximum time to wait for the modal to appear after executing the block.
|
619
614
|
# @yield Block whose actions will trigger the system modal
|
620
615
|
# @return [String] the message shown in the modal
|
@@ -799,6 +794,10 @@ module Capybara
|
|
799
794
|
|
800
795
|
@@instance_created = false
|
801
796
|
|
797
|
+
def driver_args(args)
|
798
|
+
args.map { |arg| arg.is_a?(Capybara::Node::Element) ? arg.base : arg }
|
799
|
+
end
|
800
|
+
|
802
801
|
def accept_modal(type, text_or_options, options, &blk)
|
803
802
|
driver.accept_modal(type, modal_options(text_or_options, options), &blk)
|
804
803
|
end
|
@@ -878,7 +877,7 @@ module Capybara
|
|
878
877
|
driver.switch_to_window handle
|
879
878
|
return Window.new(self, handle) if yield
|
880
879
|
end
|
881
|
-
rescue => e
|
880
|
+
rescue StandardError => e
|
882
881
|
driver.switch_to_window(original_window_handle)
|
883
882
|
raise e
|
884
883
|
else
|
@@ -7,7 +7,7 @@ module Capybara
|
|
7
7
|
OPTIONS = %i[always_include_port run_server default_selector default_max_wait_time ignore_hidden_elements
|
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
|
-
server_host server_port server_errors].freeze
|
10
|
+
server_host server_port server_errors default_set_options disable_animation].freeze
|
11
11
|
|
12
12
|
attr_accessor(*OPTIONS)
|
13
13
|
|
@@ -50,6 +50,10 @@ module Capybara
|
|
50
50
|
# See {Capybara.configure}
|
51
51
|
# @!method server_errors
|
52
52
|
# See {Capybara.configure}
|
53
|
+
# @!method default_set_options
|
54
|
+
# See {Capybara.configure}
|
55
|
+
# @!method disable_animation
|
56
|
+
# See {Capybara.configure}
|
53
57
|
|
54
58
|
remove_method :server_host
|
55
59
|
|
@@ -78,6 +82,12 @@ module Capybara
|
|
78
82
|
@default_host = url
|
79
83
|
end
|
80
84
|
|
85
|
+
remove_method :disable_animation=
|
86
|
+
def disable_animation=(bool)
|
87
|
+
warn "Capybara.disable_animation is a beta feature - it may change/disappear in a future point version" if bool
|
88
|
+
@disable_animation = bool
|
89
|
+
end
|
90
|
+
|
81
91
|
def initialize_copy(other)
|
82
92
|
super
|
83
93
|
@server_errors = @server_errors.dup
|
@@ -9,9 +9,9 @@ module Capybara
|
|
9
9
|
# the comparison will depend on the :url option
|
10
10
|
#
|
11
11
|
# @!macro current_path_query_params
|
12
|
-
# @overload $0(string, options
|
12
|
+
# @overload $0(string, **options)
|
13
13
|
# @param string [String] The string that the current 'path' should equal
|
14
|
-
# @overload $0(regexp, options
|
14
|
+
# @overload $0(regexp, **options)
|
15
15
|
# @param regexp [Regexp] The regexp that the current 'path' should match to
|
16
16
|
# @option options [Boolean] :url (true if `string` ia a full url, otherwise false) Whether the compare 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
|
@@ -49,7 +49,7 @@ module Capybara
|
|
49
49
|
def has_current_path?(path, **options)
|
50
50
|
assert_current_path(path, options)
|
51
51
|
rescue Capybara::ExpectationNotMet
|
52
|
-
|
52
|
+
false
|
53
53
|
end
|
54
54
|
|
55
55
|
##
|
@@ -64,7 +64,7 @@ module Capybara
|
|
64
64
|
def has_no_current_path?(path, **options)
|
65
65
|
assert_no_current_path(path, options)
|
66
66
|
rescue Capybara::ExpectationNotMet
|
67
|
-
|
67
|
+
false
|
68
68
|
end
|
69
69
|
|
70
70
|
private
|
@@ -74,7 +74,7 @@ module Capybara
|
|
74
74
|
document.synchronize(query.wait) do
|
75
75
|
yield(query)
|
76
76
|
end
|
77
|
-
|
77
|
+
true
|
78
78
|
end
|
79
79
|
end
|
80
80
|
end
|
@@ -76,7 +76,7 @@ Capybara::SpecHelper.spec '#assert_text' do
|
|
76
76
|
@session.visit('/with_html')
|
77
77
|
expect do
|
78
78
|
@session.assert_text(/xxxxyzzz/)
|
79
|
-
end.to raise_error(Capybara::ExpectationNotMet,
|
79
|
+
end.to raise_error(Capybara::ExpectationNotMet, %r{\Aexpected to find text matching /xxxxyzzz/ in "This is a test\\nHeader Class(.+)"\Z})
|
80
80
|
end
|
81
81
|
|
82
82
|
it "should escape any characters that would have special meaning in a regexp" do
|
@@ -7,19 +7,17 @@ Capybara::SpecHelper.spec '#body' do
|
|
7
7
|
expect(@session.body).to include('Hello world!')
|
8
8
|
end
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
end
|
10
|
+
context "encoding of response between ascii and utf8" do
|
11
|
+
it "should be valid with html entities" do
|
12
|
+
@session.visit('/with_html_entities')
|
13
|
+
expect(@session).to have_content('Encoding') # wait for content to appear if visit is async
|
14
|
+
expect { @session.body.encode!("UTF-8") }.not_to raise_error
|
15
|
+
end
|
17
16
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
end
|
17
|
+
it "should be valid without html entities" do
|
18
|
+
@session.visit('/with_html')
|
19
|
+
expect(@session).to have_content('This is a test') # wait for content to appear if visit is async
|
20
|
+
expect { @session.body.encode!("UTF-8") }.not_to raise_error
|
23
21
|
end
|
24
22
|
end
|
25
23
|
end
|
@@ -93,12 +93,12 @@ Capybara::SpecHelper.spec '#click_link' do
|
|
93
93
|
end
|
94
94
|
|
95
95
|
it "should find a link matching an exact regex pattern" do
|
96
|
-
@session.click_link('labore', href:
|
96
|
+
@session.click_link('labore', href: %r{/with_simple_html})
|
97
97
|
expect(@session).to have_content('Bar')
|
98
98
|
end
|
99
99
|
|
100
100
|
it "should find a link matching a partial regex pattern" do
|
101
|
-
@session.click_link('labore', href:
|
101
|
+
@session.click_link('labore', href: %r{/with_simple})
|
102
102
|
expect(@session).to have_content('Bar')
|
103
103
|
end
|
104
104
|
|
@@ -137,7 +137,7 @@ Capybara::SpecHelper.spec '#click_link' do
|
|
137
137
|
|
138
138
|
it "should follow redirects back to itself" do
|
139
139
|
@session.click_link('BackToMyself')
|
140
|
-
expect(@session).to have_css('#referrer', text:
|
140
|
+
expect(@session).to have_css('#referrer', text: %r{/with_html$})
|
141
141
|
expect(@session).to have_content('This is a test')
|
142
142
|
end
|
143
143
|
|
@@ -28,7 +28,7 @@ Capybara::SpecHelper.spec '#assert_matches_selector' do
|
|
28
28
|
end
|
29
29
|
|
30
30
|
it "should not accept count options" do
|
31
|
-
expect { @element.assert_matches_selector(:css, '.number', count: 1) }.to raise_error(ArgumentError)
|
31
|
+
expect { @element.assert_matches_selector(:css, '.number', count: 1) }.to raise_error(ArgumentError, /count/)
|
32
32
|
end
|
33
33
|
|
34
34
|
it "should accept a filter block" do
|
@@ -159,9 +159,18 @@ Capybara::SpecHelper.spec "#fill_in" do
|
|
159
159
|
expect(extract_results(@session)['zipcode']).to eq('12345')
|
160
160
|
end
|
161
161
|
|
162
|
+
it "fills in a field if default_set_options is nil" do
|
163
|
+
Capybara.default_set_options = nil
|
164
|
+
@session.fill_in(:form_first_name, with: 'Thomas')
|
165
|
+
@session.click_button('awesome')
|
166
|
+
expect(extract_results(@session)['first_name']).to eq('Thomas')
|
167
|
+
end
|
168
|
+
|
162
169
|
context 'on a pre-populated textfield with a reformatting onchange', requires: [:js] do
|
163
170
|
it 'should only trigger onchange once' do
|
164
171
|
@session.visit('/with_js')
|
172
|
+
# Click somewhere on the page to ensure focus is acquired. Without this FF won't generate change events for some reason???
|
173
|
+
@session.find(:css, 'body').click
|
165
174
|
@session.fill_in('with_change_event', with: 'some value')
|
166
175
|
# click outside the field to trigger the change event
|
167
176
|
@session.find(:css, 'body').click
|
@@ -39,7 +39,7 @@ Capybara::SpecHelper.spec '#find_field' do
|
|
39
39
|
it "should raise error if filter option is invalid" do
|
40
40
|
expect do
|
41
41
|
@session.find_field('Dog', disabled: nil)
|
42
|
-
end.to raise_error ArgumentError, "Invalid value nil passed to
|
42
|
+
end.to raise_error ArgumentError, "Invalid value nil passed to NodeFilter disabled"
|
43
43
|
end
|
44
44
|
|
45
45
|
context "with :exact option" do
|
@@ -127,7 +127,8 @@ Capybara::SpecHelper.spec '#find' do
|
|
127
127
|
before do
|
128
128
|
Capybara.add_selector(:beatle) do
|
129
129
|
xpath { |name| ".//li[contains(@class, 'beatle')][contains(text(), '#{name}')]" }
|
130
|
-
|
130
|
+
node_filter(:type) { |node, type| node[:class].split(/\s+/).include?(type) }
|
131
|
+
node_filter(:fail) { |_node, _val| raise Capybara::ElementNotFound, 'fail' }
|
131
132
|
end
|
132
133
|
end
|
133
134
|
|
@@ -145,13 +146,17 @@ Capybara::SpecHelper.spec '#find' do
|
|
145
146
|
expect { @session.find(:beatle, 'John', type: 'drummer') }.to raise_error(Capybara::ElementNotFound)
|
146
147
|
expect { @session.find(:beatle, 'George', type: 'drummer') }.to raise_error(Capybara::ElementNotFound)
|
147
148
|
end
|
149
|
+
|
150
|
+
it "should not raise an ElementNotFound error from in a filter" do
|
151
|
+
expect { @session.find(:beatle, 'John', fail: 'something') }.to raise_error(Capybara::ElementNotFound, /beatle "John"/)
|
152
|
+
end
|
148
153
|
end
|
149
154
|
|
150
155
|
context "with custom selector with custom filter and default" do
|
151
156
|
before do
|
152
157
|
Capybara.add_selector(:beatle) do
|
153
158
|
xpath { |name| ".//li[contains(@class, 'beatle')][contains(text(), '#{name}')]" }
|
154
|
-
|
159
|
+
node_filter(:type, default: "drummer") { |node, type| node[:class].split(/\s+/).include?(type) }
|
155
160
|
end
|
156
161
|
end
|
157
162
|
|
@@ -174,7 +179,7 @@ Capybara::SpecHelper.spec '#find' do
|
|
174
179
|
context "with alternate filter set" do
|
175
180
|
before do
|
176
181
|
Capybara::Selector::FilterSet.add(:value) do
|
177
|
-
|
182
|
+
node_filter(:with) { |node, with| node.value == with.to_s }
|
178
183
|
end
|
179
184
|
|
180
185
|
Capybara.add_selector(:id_with_field_filters) do
|
@@ -10,7 +10,7 @@ Capybara::SpecHelper.spec '#has_link?' do
|
|
10
10
|
expect(@session).to have_link('awesome title')
|
11
11
|
expect(@session).to have_link('A link', href: '/with_simple_html')
|
12
12
|
expect(@session).to have_link(:'A link', href: :'/with_simple_html')
|
13
|
-
expect(@session).to have_link('A link', href:
|
13
|
+
expect(@session).to have_link('A link', href: %r{/with_simple_html})
|
14
14
|
end
|
15
15
|
|
16
16
|
it "should be false if the given link is not on the page" do
|
@@ -34,6 +34,6 @@ Capybara::SpecHelper.spec '#has_no_link?' do
|
|
34
34
|
it "should be true if the given link is not on the page" do
|
35
35
|
expect(@session).to have_no_link('monkey')
|
36
36
|
expect(@session).to have_no_link('A link', href: '/nonexistent-href')
|
37
|
-
expect(@session).to have_no_link('A link', href:
|
37
|
+
expect(@session).to have_no_link('A link', href: %r{/nonexistent-href})
|
38
38
|
end
|
39
39
|
end
|
@@ -102,6 +102,14 @@ Capybara::SpecHelper.spec "node" do
|
|
102
102
|
expect { @session.first('//textarea[@readonly]').set('changed') }.to raise_error(Capybara::ReadOnlyElementError)
|
103
103
|
end
|
104
104
|
|
105
|
+
it 'should use global default options' do
|
106
|
+
Capybara.default_set_options = { clear: :backspace }
|
107
|
+
element = @session.first(:fillable_field, type: 'text')
|
108
|
+
allow(element.base).to receive(:set)
|
109
|
+
element.set('gorilla')
|
110
|
+
expect(element.base).to have_received(:set).with('gorilla', clear: :backspace)
|
111
|
+
end
|
112
|
+
|
105
113
|
context "with a contenteditable element", requires: [:js] do
|
106
114
|
it 'should allow me to change the contents' do
|
107
115
|
@session.visit('/with_js')
|
@@ -447,6 +455,48 @@ Capybara::SpecHelper.spec "node" do
|
|
447
455
|
end
|
448
456
|
end
|
449
457
|
|
458
|
+
describe "#execute_script", requires: %i[js es_args] do
|
459
|
+
it "should execute the given script in the context of the element and return nothing" do
|
460
|
+
@session.visit('/with_js')
|
461
|
+
expect(@session.find(:css, '#change').execute_script("this.textContent = 'Funky Doodle'")).to be_nil
|
462
|
+
expect(@session).to have_css('#change', text: 'Funky Doodle')
|
463
|
+
end
|
464
|
+
|
465
|
+
it "should pass arguments to the script" do
|
466
|
+
@session.visit('/with_js')
|
467
|
+
@session.find(:css, '#change').execute_script("this.textContent = arguments[0]", "Doodle Funk")
|
468
|
+
expect(@session).to have_css('#change', text: 'Doodle Funk')
|
469
|
+
end
|
470
|
+
end
|
471
|
+
|
472
|
+
describe "#evaluate_script", requires: %i[js es_args] do
|
473
|
+
it "should evaluate the given script in the context of the element and return whatever it produces" do
|
474
|
+
@session.visit('/with_js')
|
475
|
+
el = @session.find(:css, '#with_change_event')
|
476
|
+
expect(el.evaluate_script("this.value")).to eq('default value')
|
477
|
+
end
|
478
|
+
|
479
|
+
it "should pass arguments to the script" do
|
480
|
+
@session.visit('/with_js')
|
481
|
+
@session.find(:css, '#change').evaluate_script("this.textContent = arguments[0]", "Doodle Funk")
|
482
|
+
expect(@session).to have_css('#change', text: 'Doodle Funk')
|
483
|
+
end
|
484
|
+
|
485
|
+
it "should pass multiple arguments" do
|
486
|
+
@session.visit('/with_js')
|
487
|
+
change = @session.find(:css, '#change')
|
488
|
+
expect(change.evaluate_script("arguments[0] + arguments[1]", 2, 3)).to eq 5
|
489
|
+
end
|
490
|
+
|
491
|
+
it "should support returning elements" do
|
492
|
+
@session.visit('/with_js')
|
493
|
+
change = @session.find(:css, '#change') # ensure page has loaded and element is available
|
494
|
+
el = change.evaluate_script("this")
|
495
|
+
expect(el).to be_instance_of(Capybara::Node::Element)
|
496
|
+
expect(el).to eq(change)
|
497
|
+
end
|
498
|
+
end
|
499
|
+
|
450
500
|
describe '#reload', requires: [:js] do
|
451
501
|
context "without automatic reload" do
|
452
502
|
before { Capybara.automatic_reload = false }
|