capybara 2.13.0 → 2.14.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 +82 -17
- data/README.md +29 -0
- data/lib/capybara.rb +81 -116
- data/lib/capybara/config.rb +121 -0
- data/lib/capybara/cucumber.rb +1 -0
- data/lib/capybara/driver/base.rb +6 -0
- data/lib/capybara/dsl.rb +1 -3
- data/lib/capybara/helpers.rb +3 -3
- data/lib/capybara/node/actions.rb +2 -2
- data/lib/capybara/node/base.rb +7 -2
- data/lib/capybara/node/element.rb +7 -1
- data/lib/capybara/node/finders.rb +13 -3
- data/lib/capybara/node/matchers.rb +15 -4
- data/lib/capybara/node/simple.rb +5 -0
- data/lib/capybara/queries/base_query.rb +8 -3
- data/lib/capybara/queries/selector_query.rb +11 -9
- data/lib/capybara/queries/text_query.rb +9 -4
- data/lib/capybara/rack_test/browser.rb +8 -5
- data/lib/capybara/rspec.rb +3 -1
- data/lib/capybara/rspec/matcher_proxies.rb +41 -0
- data/lib/capybara/rspec/matchers.rb +19 -5
- data/lib/capybara/selector.rb +13 -4
- data/lib/capybara/selector/selector.rb +3 -3
- data/lib/capybara/selenium/driver.rb +20 -6
- data/lib/capybara/selenium/node.rb +6 -2
- data/lib/capybara/server.rb +6 -5
- data/lib/capybara/session.rb +71 -14
- data/lib/capybara/session/config.rb +100 -0
- data/lib/capybara/spec/public/test.js +1 -1
- data/lib/capybara/spec/session/all_spec.rb +11 -0
- data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +24 -8
- data/lib/capybara/spec/session/fill_in_spec.rb +6 -0
- data/lib/capybara/spec/session/find_field_spec.rb +1 -0
- data/lib/capybara/spec/session/find_spec.rb +4 -3
- data/lib/capybara/spec/session/has_selector_spec.rb +1 -3
- data/lib/capybara/spec/session/node_spec.rb +23 -17
- data/lib/capybara/spec/session/reset_session_spec.rb +1 -1
- data/lib/capybara/spec/session/window/become_closed_spec.rb +4 -4
- data/lib/capybara/spec/spec_helper.rb +22 -0
- data/lib/capybara/spec/views/form.erb +6 -1
- data/lib/capybara/spec/views/with_html.erb +1 -0
- data/lib/capybara/version.rb +1 -1
- data/lib/capybara/window.rb +1 -1
- data/spec/capybara_spec.rb +14 -2
- data/spec/dsl_spec.rb +1 -0
- data/spec/per_session_config_spec.rb +67 -0
- data/spec/rspec/shared_spec_matchers.rb +2 -2
- data/spec/rspec/views_spec.rb +4 -0
- data/spec/rspec_spec.rb +77 -0
- data/spec/session_spec.rb +44 -0
- data/spec/shared_selenium_session.rb +9 -0
- data/spec/spec_helper.rb +4 -0
- metadata +7 -3
@@ -0,0 +1,100 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'delegate'
|
3
|
+
|
4
|
+
module Capybara
|
5
|
+
class SessionConfig
|
6
|
+
OPTIONS = [:always_include_port, :run_server, :default_selector, :default_max_wait_time, :ignore_hidden_elements,
|
7
|
+
:automatic_reload, :match, :exact, :exact_text, :raise_server_errors, :visible_text_only, :wait_on_first_by_default,
|
8
|
+
:automatic_label_click, :enable_aria_label, :save_path, :exact_options, :asset_host, :default_host, :app_host,
|
9
|
+
:save_and_open_page_path, :server_host, :server_port, :server_errors]
|
10
|
+
|
11
|
+
attr_accessor *OPTIONS
|
12
|
+
|
13
|
+
##
|
14
|
+
#@!method always_include_port
|
15
|
+
# See {Capybara#configure}
|
16
|
+
#@!method run_server
|
17
|
+
# See {Capybara#configure}
|
18
|
+
#@!method default_selector
|
19
|
+
# See {Capybara#configure}
|
20
|
+
#@!method default_max_wait_time
|
21
|
+
# See {Capybara#configure}
|
22
|
+
#@!method ignore_hidden_elements
|
23
|
+
# See {Capybara#configure}
|
24
|
+
#@!method automatic_reload
|
25
|
+
# See {Capybara#configure}
|
26
|
+
#@!method match
|
27
|
+
# See {Capybara#configure}
|
28
|
+
#@!method exact
|
29
|
+
# See {Capybara#configure}
|
30
|
+
#@!method raise_server_errors
|
31
|
+
# See {Capybara#configure}
|
32
|
+
#@!method visible_text_only
|
33
|
+
# See {Capybara#configure}
|
34
|
+
#@!method wait_on_first_by_default
|
35
|
+
# See {Capybara#configure}
|
36
|
+
#@!method automatic_label_click
|
37
|
+
# See {Capybara#configure}
|
38
|
+
#@!method enable_aria_label
|
39
|
+
# See {Capybara#configure}
|
40
|
+
#@!method save_path
|
41
|
+
# See {Capybara#configure}
|
42
|
+
#@!method exact_options
|
43
|
+
# See {Capybara#configure}
|
44
|
+
#@!method asset_host
|
45
|
+
# See {Capybara#configure}
|
46
|
+
#@!method default_host
|
47
|
+
# See {Capybara#configure}
|
48
|
+
#@!method app_host
|
49
|
+
# See {Capybara#configure}
|
50
|
+
#@!method save_and_open_page_path
|
51
|
+
# See {Capybara#configure}
|
52
|
+
#@!method server_host
|
53
|
+
# See {Capybara#configure}
|
54
|
+
#@!method server_port
|
55
|
+
# See {Capybara#configure}
|
56
|
+
#@!method server_errors
|
57
|
+
# See {Capybara#configure}
|
58
|
+
|
59
|
+
##
|
60
|
+
#
|
61
|
+
# @return [String] The IP address bound by default server
|
62
|
+
#
|
63
|
+
def server_host
|
64
|
+
@server_host || '127.0.0.1'
|
65
|
+
end
|
66
|
+
|
67
|
+
def server_errors=(errors)
|
68
|
+
(@server_errors ||= []).replace(errors.dup)
|
69
|
+
end
|
70
|
+
|
71
|
+
def app_host=(url)
|
72
|
+
raise ArgumentError.new("Capybara.app_host should be set to a url (http://www.example.com)") unless url.nil? || (url =~ URI::Parser.new.make_regexp)
|
73
|
+
@app_host = url
|
74
|
+
end
|
75
|
+
|
76
|
+
def default_host=(url)
|
77
|
+
raise ArgumentError.new("Capybara.default_host should be set to a url (http://www.example.com)") unless url.nil? || (url =~ URI::Parser.new.make_regexp)
|
78
|
+
@default_host = url
|
79
|
+
end
|
80
|
+
|
81
|
+
def save_and_open_page_path=(path)
|
82
|
+
warn "DEPRECATED: #save_and_open_page_path is deprecated, please use #save_path instead. \n"\
|
83
|
+
"Note: Behavior is slightly different with relative paths - see documentation" unless path.nil?
|
84
|
+
@save_and_open_page_path = path
|
85
|
+
end
|
86
|
+
|
87
|
+
def initialize_copy(other)
|
88
|
+
super
|
89
|
+
@server_errors = @server_errors.dup
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
class ReadOnlySessionConfig < SimpleDelegator
|
94
|
+
SessionConfig::OPTIONS.each do |m|
|
95
|
+
define_method "#{m}=" do |val|
|
96
|
+
raise "Per session settings are only supported when Capybara.threadsafe == true"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -66,6 +66,17 @@ Capybara::SpecHelper.spec "#all" do
|
|
66
66
|
Capybara.ignore_hidden_elements = false
|
67
67
|
expect(@session.all(:css, "a.simple").size).to eq(2)
|
68
68
|
end
|
69
|
+
|
70
|
+
context "with per session config", requires: [:psc] do
|
71
|
+
it "should use the sessions ignore_hidden_elements", psc: true do
|
72
|
+
Capybara.ignore_hidden_elements = true
|
73
|
+
@session.config.ignore_hidden_elements = false
|
74
|
+
expect(Capybara.ignore_hidden_elements).to eq(true)
|
75
|
+
expect(@session.all(:css, "a.simple").size).to eq(2)
|
76
|
+
@session.config.ignore_hidden_elements = true
|
77
|
+
expect(@session.all(:css, "a.simple").size).to eq(1)
|
78
|
+
end
|
79
|
+
end
|
69
80
|
end
|
70
81
|
|
71
82
|
context 'with element count filters' do
|
@@ -18,10 +18,18 @@ Capybara::SpecHelper.spec '#assert_all_of_selectors' do
|
|
18
18
|
@session.assert_all_of_selectors("p a#foo", "h2#h2two", "h2#h2one" )
|
19
19
|
end
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
@session.
|
24
|
-
|
21
|
+
context "should respect scopes" do
|
22
|
+
it "when used with `within`" do
|
23
|
+
@session.within "//p[@id='first']" do
|
24
|
+
@session.assert_all_of_selectors(".//a[@id='foo']")
|
25
|
+
expect { @session.assert_all_of_selectors(".//a[@id='red']") }.to raise_error(Capybara::ElementNotFound)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it "when called on elements" do
|
30
|
+
el = @session.find "//p[@id='first']"
|
31
|
+
el.assert_all_of_selectors(".//a[@id='foo']")
|
32
|
+
expect { el.assert_all_of_selectors(".//a[@id='red']") }.to raise_error(Capybara::ElementNotFound)
|
25
33
|
end
|
26
34
|
end
|
27
35
|
|
@@ -65,10 +73,18 @@ Capybara::SpecHelper.spec '#assert_none_of_selectors' do
|
|
65
73
|
expect { @session.assert_none_of_selectors("abbr", "p a#foo") }.to raise_error(Capybara::ElementNotFound)
|
66
74
|
end
|
67
75
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
76
|
+
context "should respect scopes" do
|
77
|
+
it "when used with `within`" do
|
78
|
+
@session.within "//p[@id='first']" do
|
79
|
+
expect { @session.assert_none_of_selectors(".//a[@id='foo']") }.to raise_error(Capybara::ElementNotFound)
|
80
|
+
@session.assert_none_of_selectors(".//a[@id='red']")
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
it "when called on an element" do
|
85
|
+
el = @session.find "//p[@id='first']"
|
86
|
+
expect { el.assert_none_of_selectors(".//a[@id='foo']") }.to raise_error(Capybara::ElementNotFound)
|
87
|
+
el.assert_none_of_selectors(".//a[@id='red']")
|
72
88
|
end
|
73
89
|
end
|
74
90
|
|
@@ -106,6 +106,12 @@ Capybara::SpecHelper.spec "#fill_in" do
|
|
106
106
|
expect(extract_results(@session)['first_name']).to eq('Thomas')
|
107
107
|
end
|
108
108
|
|
109
|
+
it "should fill in a field based on type" do
|
110
|
+
@session.fill_in(type: 'schmooo', with: 'Schmooo for all')
|
111
|
+
@session.click_button('awesome')
|
112
|
+
expect(extract_results(@session)['schmooo']).to eq('Schmooo for all')
|
113
|
+
end
|
114
|
+
|
109
115
|
it "should throw an exception if a hash containing 'with' is not provided" do
|
110
116
|
expect {@session.fill_in 'Name', 'ignu'}.to raise_error(RuntimeError, /with/)
|
111
117
|
end
|
@@ -8,6 +8,7 @@ Capybara::SpecHelper.spec '#find_field' do
|
|
8
8
|
expect(@session.find_field('Dog').value).to eq('dog')
|
9
9
|
expect(@session.find_field('form_description').text).to eq('Descriptive text goes here')
|
10
10
|
expect(@session.find_field('Region')[:name]).to eq('form[region]')
|
11
|
+
expect(@session.find_field('With Asterisk*')).to be
|
11
12
|
end
|
12
13
|
|
13
14
|
context "aria_label attribute with Capybara.enable_aria_label" do
|
@@ -421,8 +421,9 @@ Capybara::SpecHelper.spec '#find' do
|
|
421
421
|
end
|
422
422
|
end
|
423
423
|
|
424
|
-
it "should
|
425
|
-
|
426
|
-
|
424
|
+
it "should raise if selector type is unknown" do
|
425
|
+
expect do
|
426
|
+
@session.find(:unknown, '//h1')
|
427
|
+
end.to raise_error(ArgumentError)
|
427
428
|
end
|
428
429
|
end
|
@@ -131,9 +131,7 @@ Capybara::SpecHelper.spec '#has_no_selector?' do
|
|
131
131
|
end
|
132
132
|
|
133
133
|
it "should accept a filter block" do
|
134
|
-
|
135
|
-
skip "RSpec < 3 doesn't pass the block along to the matcher for the Builtin::Has matcher"
|
136
|
-
end
|
134
|
+
skip "RSpec < 3 doesn't pass the block along to the matcher for the Builtin::Has matcher" if rspec2?
|
137
135
|
expect(@session).to have_no_selector(:css, "a#foo") { |el| el[:id] != "foo" }
|
138
136
|
end
|
139
137
|
|
@@ -122,23 +122,25 @@ Capybara::SpecHelper.spec "node" do
|
|
122
122
|
expect(@session.first('//textarea[@readonly]').set('changed')).to raise_error(Capybara::ReadOnlyElementError)
|
123
123
|
end if Capybara::VERSION.to_f > 3.0
|
124
124
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
125
|
+
context "with a contenteditable element", requires: [:js] do
|
126
|
+
it 'should allow me to change the contents' do
|
127
|
+
@session.visit('/with_js')
|
128
|
+
@session.find(:css,'#existing_content_editable').set('WYSIWYG')
|
129
|
+
expect(@session.find(:css,'#existing_content_editable').text).to eq('WYSIWYG')
|
130
|
+
end
|
130
131
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
132
|
+
it 'should allow me to set the contents' do
|
133
|
+
@session.visit('/with_js')
|
134
|
+
@session.find(:css,'#blank_content_editable').set('WYSIWYG')
|
135
|
+
expect(@session.find(:css,'#blank_content_editable').text).to eq('WYSIWYG')
|
136
|
+
end
|
136
137
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
138
|
+
it 'should allow me to change the contents of a child element' do
|
139
|
+
@session.visit('/with_js')
|
140
|
+
@session.find(:css,'#existing_content_editable_child').set('WYSIWYG')
|
141
|
+
expect(@session.find(:css,'#existing_content_editable_child').text).to eq('WYSIWYG')
|
142
|
+
expect(@session.find(:css,'#existing_content_editable_child_parent').text).to eq('Some content WYSIWYG')
|
143
|
+
end
|
142
144
|
end
|
143
145
|
end
|
144
146
|
|
@@ -289,7 +291,6 @@ Capybara::SpecHelper.spec "node" do
|
|
289
291
|
|
290
292
|
describe '#drag_to', requires: [:js, :drag] do
|
291
293
|
it "should drag and drop an object" do
|
292
|
-
pending "selenium-webdriver/geckodriver doesn't support mouse move_to" if marionette?(@session)
|
293
294
|
@session.visit('/with_js')
|
294
295
|
element = @session.find('//div[@id="drag"]')
|
295
296
|
target = @session.find('//div[@id="drop"]')
|
@@ -300,7 +301,6 @@ Capybara::SpecHelper.spec "node" do
|
|
300
301
|
|
301
302
|
describe '#hover', requires: [:hover] do
|
302
303
|
it "should allow hovering on an element" do
|
303
|
-
pending "selenium-webdriver/geckodriver doesn't support mouse move_to" if marionette?(@session)
|
304
304
|
@session.visit('/with_hover')
|
305
305
|
expect(@session.find(:css,'.hidden_until_hover', visible: false)).not_to be_visible
|
306
306
|
@session.find(:css,'.wrapper').hover
|
@@ -314,6 +314,12 @@ Capybara::SpecHelper.spec "node" do
|
|
314
314
|
expect(@session.current_url).to match(%r{/with_html$})
|
315
315
|
end
|
316
316
|
|
317
|
+
it "should go to the same page if href is blank" do
|
318
|
+
@session.find(:css, '#link_blank_href').click
|
319
|
+
sleep 1
|
320
|
+
expect(@session).to have_current_path('/with_html')
|
321
|
+
end
|
322
|
+
|
317
323
|
it "should be able to check a checkbox" do
|
318
324
|
@session.visit('form')
|
319
325
|
cbox = @session.find(:checkbox, 'form_terms_of_use')
|
@@ -88,7 +88,7 @@ Capybara::SpecHelper.spec '#reset_session!' do
|
|
88
88
|
end
|
89
89
|
|
90
90
|
it "raises configured errors caught inside the server", requires: [:server] do
|
91
|
-
prev_errors = Capybara.server_errors
|
91
|
+
prev_errors = Capybara.server_errors.dup
|
92
92
|
|
93
93
|
Capybara.server_errors = [LoadError]
|
94
94
|
quietly { @session.visit("/error") }
|
@@ -60,18 +60,18 @@ Capybara::SpecHelper.spec '#become_closed', requires: [:windows, :js] do
|
|
60
60
|
end
|
61
61
|
|
62
62
|
context 'with not_to' do
|
63
|
-
it
|
63
|
+
it "should not raise error if window doesn't close before default_max_wait_time" do
|
64
64
|
@session.within_window @other_window do
|
65
|
-
@session.execute_script('setTimeout(function(){ window.close(); },
|
65
|
+
@session.execute_script('setTimeout(function(){ window.close(); }, 1000);')
|
66
66
|
end
|
67
|
-
Capybara.using_wait_time 0.
|
67
|
+
Capybara.using_wait_time 0.3 do
|
68
68
|
expect do
|
69
69
|
expect(@other_window).not_to become_closed
|
70
70
|
end
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
74
|
-
it 'should raise error if
|
74
|
+
it 'should raise error if window closes before default_max_wait_time' do
|
75
75
|
@session.within_window @other_window do
|
76
76
|
@session.execute_script('setTimeout(function(){ window.close(); }, 700);')
|
77
77
|
end
|
@@ -39,6 +39,7 @@ module Capybara
|
|
39
39
|
Capybara.match = :smart
|
40
40
|
Capybara.wait_on_first_by_default = false
|
41
41
|
Capybara.enable_aria_label = false
|
42
|
+
reset_threadsafe
|
42
43
|
end
|
43
44
|
|
44
45
|
def filter(requires, metadata)
|
@@ -64,9 +65,19 @@ module Capybara
|
|
64
65
|
before do
|
65
66
|
@session = session
|
66
67
|
end
|
68
|
+
|
67
69
|
after do
|
68
70
|
@session.reset_session!
|
69
71
|
end
|
72
|
+
|
73
|
+
before :each, psc: true do
|
74
|
+
SpecHelper.reset_threadsafe(true, @session)
|
75
|
+
end
|
76
|
+
|
77
|
+
after psc: true do
|
78
|
+
SpecHelper.reset_threadsafe(false, @session)
|
79
|
+
end
|
80
|
+
|
70
81
|
specs.each do |spec_name, spec_options, block|
|
71
82
|
describe spec_name, spec_options do
|
72
83
|
class_eval(&block)
|
@@ -74,6 +85,13 @@ module Capybara
|
|
74
85
|
end
|
75
86
|
end
|
76
87
|
end
|
88
|
+
|
89
|
+
def reset_threadsafe(bool = false, session = nil)
|
90
|
+
Capybara::Session.class_variable_set(:@@instance_created, false) # Work around limit on when threadsafe can be changed
|
91
|
+
Capybara.threadsafe = bool
|
92
|
+
session = session.current_session if session.respond_to?(:current_session)
|
93
|
+
session.instance_variable_set(:@config, nil) if session
|
94
|
+
end
|
77
95
|
end # class << self
|
78
96
|
|
79
97
|
def silence_stream(stream)
|
@@ -101,6 +119,10 @@ module Capybara
|
|
101
119
|
def marionette?(session)
|
102
120
|
session.driver.respond_to?(:marionette?) && session.driver.marionette?
|
103
121
|
end
|
122
|
+
|
123
|
+
def rspec2?
|
124
|
+
!defined?(::RSpec::Expectations::Version) || (Gem::Version.new(RSpec::Expectations::Version::STRING) < Gem::Version.new('3.0'))
|
125
|
+
end
|
104
126
|
end
|
105
127
|
end
|
106
128
|
|
@@ -586,6 +586,11 @@ New line after and before textarea tag
|
|
586
586
|
</label>
|
587
587
|
|
588
588
|
<label>Confusion
|
589
|
-
<textarea id="confusion_textarea" class="confusion confusion-textarea"
|
589
|
+
<textarea id="confusion_textarea" class="confusion confusion-textarea"></textarea>
|
590
590
|
</label>
|
591
591
|
|
592
|
+
<p>
|
593
|
+
<label for="asterisk_input">With Asterisk<abbr title="required">*</abbr></label>
|
594
|
+
<input id="asterisk_input" type="number"value="2016"/>
|
595
|
+
</p>
|
596
|
+
|
data/lib/capybara/version.rb
CHANGED
data/lib/capybara/window.rb
CHANGED
@@ -115,7 +115,7 @@ module Capybara
|
|
115
115
|
|
116
116
|
private
|
117
117
|
|
118
|
-
def wait_for_stable_size(seconds=
|
118
|
+
def wait_for_stable_size(seconds=session.config.default_max_wait_time)
|
119
119
|
res = yield if block_given?
|
120
120
|
prev_size = size
|
121
121
|
start_time = Capybara::Helpers.monotonic_time
|
data/spec/capybara_spec.rb
CHANGED
@@ -14,8 +14,8 @@ RSpec.describe Capybara do
|
|
14
14
|
end
|
15
15
|
|
16
16
|
it "should be accesible as the deprecated default_wait_time" do
|
17
|
-
expect(Capybara).to receive(:warn).ordered.with('DEPRECATED: #default_wait_time= is deprecated, please use #default_max_wait_time= instead')
|
18
|
-
expect(Capybara).to receive(:warn).ordered.with('DEPRECATED: #default_wait_time is deprecated, please use #default_max_wait_time instead')
|
17
|
+
expect(Capybara.send(:config)).to receive(:warn).ordered.with('DEPRECATED: #default_wait_time= is deprecated, please use #default_max_wait_time= instead')
|
18
|
+
expect(Capybara.send(:config)).to receive(:warn).ordered.with('DEPRECATED: #default_wait_time is deprecated, please use #default_max_wait_time instead')
|
19
19
|
@previous_default_time = Capybara.default_max_wait_time
|
20
20
|
Capybara.default_wait_time = 5
|
21
21
|
expect(Capybara.default_wait_time).to eq(5)
|
@@ -114,6 +114,18 @@ RSpec.describe Capybara do
|
|
114
114
|
expect { Capybara.default_host = "http://www.example.com" }.not_to raise_error
|
115
115
|
end
|
116
116
|
end
|
117
|
+
|
118
|
+
describe "configure" do
|
119
|
+
it 'deprecates calling non configuration option methods in configure' do
|
120
|
+
expect_any_instance_of(Kernel).to receive(:warn).
|
121
|
+
with('Calling register_driver from Capybara.configure is deprecated - please call it on Capybara directly ( Capybara.register_driver(...) )')
|
122
|
+
Capybara.configure do |config|
|
123
|
+
config.register_driver(:random_name) do
|
124
|
+
#just a random block
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
117
129
|
end
|
118
130
|
|
119
131
|
RSpec.describe Capybara::Session do
|