capybara 3.1.1 → 3.2.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 +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 }
|