capybara 3.16.1 → 3.17.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 +27 -0
- data/README.md +2 -2
- data/lib/capybara/config.rb +1 -2
- data/lib/capybara/node/actions.rb +5 -5
- data/lib/capybara/node/base.rb +4 -4
- data/lib/capybara/node/element.rb +5 -5
- data/lib/capybara/node/finders.rb +6 -4
- data/lib/capybara/node/simple.rb +3 -2
- data/lib/capybara/queries/selector_query.rb +5 -5
- data/lib/capybara/queries/style_query.rb +1 -1
- data/lib/capybara/rack_test/form.rb +1 -1
- data/lib/capybara/registrations/drivers.rb +36 -0
- data/lib/capybara/registrations/servers.rb +38 -0
- data/lib/capybara/result.rb +2 -2
- data/lib/capybara/rspec/matcher_proxies.rb +2 -2
- data/lib/capybara/rspec/matchers/base.rb +2 -2
- data/lib/capybara/selector/css.rb +1 -1
- data/lib/capybara/selector/filters/base.rb +1 -1
- data/lib/capybara/selector/selector.rb +1 -0
- data/lib/capybara/selector.rb +55 -32
- data/lib/capybara/selenium/driver.rb +84 -43
- data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +16 -4
- data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +23 -0
- data/lib/capybara/selenium/driver_specializations/internet_explorer_driver.rb +5 -0
- data/lib/capybara/selenium/driver_specializations/safari_driver.rb +14 -1
- data/lib/capybara/selenium/extensions/find.rb +48 -37
- data/lib/capybara/selenium/logger_suppressor.rb +29 -0
- data/lib/capybara/selenium/node.rb +22 -8
- data/lib/capybara/selenium/nodes/chrome_node.rb +8 -2
- data/lib/capybara/server/animation_disabler.rb +1 -1
- data/lib/capybara/server/checker.rb +1 -1
- data/lib/capybara/server/middleware.rb +3 -3
- data/lib/capybara/session/config.rb +2 -8
- data/lib/capybara/session.rb +1 -1
- data/lib/capybara/spec/session/attach_file_spec.rb +1 -1
- data/lib/capybara/spec/session/check_spec.rb +4 -4
- data/lib/capybara/spec/session/choose_spec.rb +2 -2
- data/lib/capybara/spec/session/click_button_spec.rb +28 -1
- data/lib/capybara/spec/session/fill_in_spec.rb +2 -2
- data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +14 -1
- data/lib/capybara/spec/session/frame/within_frame_spec.rb +12 -1
- data/lib/capybara/spec/session/node_spec.rb +18 -6
- data/lib/capybara/spec/session/uncheck_spec.rb +2 -2
- data/lib/capybara/spec/session/unselect_spec.rb +1 -1
- data/lib/capybara/spec/views/frame_child.erb +2 -1
- data/lib/capybara/spec/views/react.erb +45 -0
- data/lib/capybara/version.rb +1 -1
- data/lib/capybara/window.rb +1 -1
- data/lib/capybara.rb +2 -71
- data/spec/minitest_spec_spec.rb +1 -1
- data/spec/result_spec.rb +10 -6
- data/spec/rspec/shared_spec_matchers.rb +8 -4
- data/spec/selector_spec.rb +4 -0
- data/spec/selenium_spec_safari.rb +2 -3
- data/spec/session_spec.rb +7 -0
- data/spec/shared_selenium_session.rb +14 -11
- data/spec/spec_helper.rb +2 -1
- metadata +6 -16
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Capybara
|
|
4
|
+
module Selenium
|
|
5
|
+
module DeprecationSuppressor
|
|
6
|
+
def deprecate(*)
|
|
7
|
+
super unless @suppress_for_capybara
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def suppress_deprecations
|
|
11
|
+
prev_suppress_for_capybara, @suppress_for_capybara = @suppress_for_capybara, true
|
|
12
|
+
yield
|
|
13
|
+
ensure
|
|
14
|
+
@suppress_for_capybara = prev_suppress_for_capybara
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
module ErrorSuppressor
|
|
19
|
+
def for_code(*)
|
|
20
|
+
::Selenium::WebDriver.logger.suppress_deprecations do
|
|
21
|
+
super
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
Selenium::WebDriver::Logger.prepend Capybara::Selenium::DeprecationSuppressor
|
|
29
|
+
Selenium::WebDriver::Error.singleton_class.prepend Capybara::Selenium::ErrorSuppressor
|
|
@@ -56,9 +56,10 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
|
|
|
56
56
|
def set(value, **options)
|
|
57
57
|
raise ArgumentError, "Value cannot be an Array when 'multiple' attribute is not present. Not a #{value.class}" if value.is_a?(Array) && !multiple?
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
tag_name, type = attrs(:tagName, :type)
|
|
60
|
+
case tag_name.downcase
|
|
60
61
|
when 'input'
|
|
61
|
-
case
|
|
62
|
+
case type.downcase
|
|
62
63
|
when 'radio'
|
|
63
64
|
click
|
|
64
65
|
when 'checkbox'
|
|
@@ -96,13 +97,13 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
|
|
|
96
97
|
return native.click if click_options.empty?
|
|
97
98
|
|
|
98
99
|
click_with_options(click_options)
|
|
99
|
-
rescue StandardError =>
|
|
100
|
-
if
|
|
101
|
-
|
|
100
|
+
rescue StandardError => e
|
|
101
|
+
if e.is_a?(::Selenium::WebDriver::Error::ElementClickInterceptedError) ||
|
|
102
|
+
e.message.match?(/Other element would receive the click/)
|
|
102
103
|
scroll_to_center
|
|
103
104
|
end
|
|
104
105
|
|
|
105
|
-
raise
|
|
106
|
+
raise e
|
|
106
107
|
end
|
|
107
108
|
|
|
108
109
|
def right_click(keys = [], **options)
|
|
@@ -148,7 +149,7 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
|
|
|
148
149
|
return true unless native.enabled?
|
|
149
150
|
|
|
150
151
|
# WebDriver only defines `disabled?` for form controls but fieldset makes sense too
|
|
151
|
-
|
|
152
|
+
find_xpath('self::fieldset/ancestor-or-self::fieldset[@disabled]').any?
|
|
152
153
|
end
|
|
153
154
|
|
|
154
155
|
def content_editable?
|
|
@@ -211,7 +212,7 @@ private
|
|
|
211
212
|
# Clear field by JavaScript assignment of the value property.
|
|
212
213
|
# Script can change a readonly element which user input cannot, so
|
|
213
214
|
# don't execute if readonly.
|
|
214
|
-
driver.execute_script "arguments[0].value = ''", self unless clear == :none
|
|
215
|
+
driver.execute_script "if (!arguments[0].readOnly){ arguments[0].value = '' }", self unless clear == :none
|
|
215
216
|
send_keys(value)
|
|
216
217
|
end
|
|
217
218
|
end
|
|
@@ -269,6 +270,7 @@ private
|
|
|
269
270
|
|
|
270
271
|
def update_value_js(value)
|
|
271
272
|
driver.execute_script(<<-JS, self, value)
|
|
273
|
+
if (arguments[0].readOnly) { return };
|
|
272
274
|
if (document.activeElement !== arguments[0]){
|
|
273
275
|
arguments[0].focus();
|
|
274
276
|
}
|
|
@@ -352,6 +354,18 @@ private
|
|
|
352
354
|
self.class.new(driver, native_node, initial_cache)
|
|
353
355
|
end
|
|
354
356
|
|
|
357
|
+
def attrs(*attr_names)
|
|
358
|
+
return attr_names.map { |name| self[name.to_s] } if ENV['CAPYBARA_THOROUGH']
|
|
359
|
+
|
|
360
|
+
driver.evaluate_script <<~'JS', self, attr_names.map(&:to_s)
|
|
361
|
+
(function(el, names){
|
|
362
|
+
return names.map(function(name){
|
|
363
|
+
return el[name]
|
|
364
|
+
});
|
|
365
|
+
})(arguments[0], arguments[1]);
|
|
366
|
+
JS
|
|
367
|
+
end
|
|
368
|
+
|
|
355
369
|
GET_XPATH_SCRIPT = <<~'JS'
|
|
356
370
|
(function(el, xml){
|
|
357
371
|
var xpath = '';
|
|
@@ -14,8 +14,8 @@ class Capybara::Selenium::ChromeNode < Capybara::Selenium::Node
|
|
|
14
14
|
|
|
15
15
|
def set_file(value) # rubocop:disable Naming/AccessorMethodName
|
|
16
16
|
super(value)
|
|
17
|
-
rescue
|
|
18
|
-
raise ArgumentError, "Selenium < 3.14 with remote Chrome doesn't support multiple file upload" if
|
|
17
|
+
rescue *file_errors => e
|
|
18
|
+
raise ArgumentError, "Selenium < 3.14 with remote Chrome doesn't support multiple file upload" if e.message.match?(/File not found : .+\n.+/m)
|
|
19
19
|
|
|
20
20
|
raise
|
|
21
21
|
end
|
|
@@ -28,6 +28,12 @@ class Capybara::Selenium::ChromeNode < Capybara::Selenium::Node
|
|
|
28
28
|
|
|
29
29
|
private
|
|
30
30
|
|
|
31
|
+
def file_errors
|
|
32
|
+
@file_errors = ::Selenium::WebDriver.logger.suppress_deprecations do
|
|
33
|
+
[::Selenium::WebDriver::Error::ExpectedError]
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
31
37
|
def bridge
|
|
32
38
|
driver.browser.send(:bridge)
|
|
33
39
|
end
|
|
@@ -12,7 +12,7 @@ module Capybara
|
|
|
12
12
|
|
|
13
13
|
def request(&block)
|
|
14
14
|
ssl? ? https_request(&block) : http_request(&block)
|
|
15
|
-
rescue *TRY_HTTPS_ERRORS
|
|
15
|
+
rescue *TRY_HTTPS_ERRORS # rubocop:disable Naming/RescuedExceptionsVariableName
|
|
16
16
|
res = https_request(&block)
|
|
17
17
|
@ssl = true
|
|
18
18
|
res
|
|
@@ -77,24 +77,18 @@ module Capybara
|
|
|
77
77
|
|
|
78
78
|
remove_method :app_host=
|
|
79
79
|
def app_host=(url)
|
|
80
|
-
raise ArgumentError, "Capybara.app_host should be set to a url (http://www.example.com). Attempted to set #{url.inspect}."
|
|
80
|
+
raise ArgumentError, "Capybara.app_host should be set to a url (http://www.example.com). Attempted to set #{url.inspect}." unless url.nil? || url.match?(URI::DEFAULT_PARSER.make_regexp)
|
|
81
81
|
|
|
82
82
|
@app_host = url
|
|
83
83
|
end
|
|
84
84
|
|
|
85
85
|
remove_method :default_host=
|
|
86
86
|
def default_host=(url)
|
|
87
|
-
raise ArgumentError, "Capybara.default_host should be set to a url (http://www.example.com). Attempted to set #{url.inspect}."
|
|
87
|
+
raise ArgumentError, "Capybara.default_host should be set to a url (http://www.example.com). Attempted to set #{url.inspect}." unless url.nil? || url.match?(URI::DEFAULT_PARSER.make_regexp)
|
|
88
88
|
|
|
89
89
|
@default_host = url
|
|
90
90
|
end
|
|
91
91
|
|
|
92
|
-
remove_method :disable_animation=
|
|
93
|
-
def disable_animation=(bool_or_allowlist)
|
|
94
|
-
warn 'Capybara.disable_animation is a beta feature - it may change/disappear in a future point version' if bool_or_allowlist
|
|
95
|
-
@disable_animation = bool_or_allowlist
|
|
96
|
-
end
|
|
97
|
-
|
|
98
92
|
remove_method :test_id=
|
|
99
93
|
##
|
|
100
94
|
#
|
data/lib/capybara/session.rb
CHANGED
|
@@ -121,7 +121,7 @@ Capybara::SpecHelper.spec '#attach_file' do
|
|
|
121
121
|
|
|
122
122
|
context "with a locator that doesn't exist" do
|
|
123
123
|
it 'should raise an error' do
|
|
124
|
-
msg =
|
|
124
|
+
msg = /Unable to find file field "does not exist"/
|
|
125
125
|
expect do
|
|
126
126
|
@session.attach_file('does not exist', with_os_path_separators(test_file_path))
|
|
127
127
|
end.to raise_error(Capybara::ElementNotFound, msg)
|
|
@@ -83,7 +83,7 @@ Capybara::SpecHelper.spec '#check' do
|
|
|
83
83
|
|
|
84
84
|
context "with a locator that doesn't exist" do
|
|
85
85
|
it 'should raise an error' do
|
|
86
|
-
msg =
|
|
86
|
+
msg = /Unable to find checkbox "does not exist"/
|
|
87
87
|
expect do
|
|
88
88
|
@session.check('does not exist')
|
|
89
89
|
end.to raise_error(Capybara::ElementNotFound, msg)
|
|
@@ -171,11 +171,11 @@ Capybara::SpecHelper.spec '#check' do
|
|
|
171
171
|
end
|
|
172
172
|
|
|
173
173
|
it 'should raise original error when no label available' do
|
|
174
|
-
expect { @session.check('form_cars_ariel') }.to raise_error(Capybara::ElementNotFound,
|
|
174
|
+
expect { @session.check('form_cars_ariel') }.to raise_error(Capybara::ElementNotFound, /Unable to find visible checkbox "form_cars_ariel"/)
|
|
175
175
|
end
|
|
176
176
|
|
|
177
177
|
it 'should raise error if not allowed to click label' do
|
|
178
|
-
expect { @session.check('form_cars_mclaren', allow_label_click: false) }.to raise_error(Capybara::ElementNotFound,
|
|
178
|
+
expect { @session.check('form_cars_mclaren', allow_label_click: false) }.to raise_error(Capybara::ElementNotFound, /Unable to find visible checkbox "form_cars_mclaren"/)
|
|
179
179
|
end
|
|
180
180
|
end
|
|
181
181
|
|
|
@@ -187,7 +187,7 @@ Capybara::SpecHelper.spec '#check' do
|
|
|
187
187
|
end
|
|
188
188
|
|
|
189
189
|
it 'should raise error if checkbox not visible' do
|
|
190
|
-
expect { @session.check('form_cars_mclaren') }.to raise_error(Capybara::ElementNotFound,
|
|
190
|
+
expect { @session.check('form_cars_mclaren') }.to raise_error(Capybara::ElementNotFound, /Unable to find visible checkbox "form_cars_mclaren"/)
|
|
191
191
|
end
|
|
192
192
|
|
|
193
193
|
it 'should include node filter in error if verified' do
|
|
@@ -38,7 +38,7 @@ Capybara::SpecHelper.spec '#choose' do
|
|
|
38
38
|
|
|
39
39
|
context "with a locator that doesn't exist" do
|
|
40
40
|
it 'should raise an error' do
|
|
41
|
-
msg =
|
|
41
|
+
msg = /Unable to find radio button "does not exist"/
|
|
42
42
|
expect do
|
|
43
43
|
@session.choose('does not exist')
|
|
44
44
|
end.to raise_error(Capybara::ElementNotFound, msg)
|
|
@@ -103,7 +103,7 @@ Capybara::SpecHelper.spec '#choose' do
|
|
|
103
103
|
end
|
|
104
104
|
|
|
105
105
|
it 'should raise error if not allowed to click label' do
|
|
106
|
-
expect { @session.choose('party_democrat', allow_label_click: false) }.to raise_error(Capybara::ElementNotFound,
|
|
106
|
+
expect { @session.choose('party_democrat', allow_label_click: false) }.to raise_error(Capybara::ElementNotFound, /Unable to find visible radio button "party_democrat"/)
|
|
107
107
|
end
|
|
108
108
|
end
|
|
109
109
|
end
|
|
@@ -162,6 +162,11 @@ Capybara::SpecHelper.spec '#click_button' do
|
|
|
162
162
|
expect(extract_results(@session)['first_name']).to eq('John')
|
|
163
163
|
end
|
|
164
164
|
|
|
165
|
+
it 'should submit by specific button id' do
|
|
166
|
+
@session.click_button(id: 'awe123')
|
|
167
|
+
expect(extract_results(@session)['first_name']).to eq('John')
|
|
168
|
+
end
|
|
169
|
+
|
|
165
170
|
it 'should submit by button title' do
|
|
166
171
|
@session.click_button('What an Awesome Button')
|
|
167
172
|
expect(extract_results(@session)['first_name']).to eq('John')
|
|
@@ -171,6 +176,16 @@ Capybara::SpecHelper.spec '#click_button' do
|
|
|
171
176
|
@session.click_button('What an Awesome')
|
|
172
177
|
expect(extract_results(@session)['first_name']).to eq('John')
|
|
173
178
|
end
|
|
179
|
+
|
|
180
|
+
it 'should submit by button name' do
|
|
181
|
+
@session.click_button('form[awesome]')
|
|
182
|
+
expect(extract_results(@session)['first_name']).to eq('John')
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
it 'should submit by specific button name' do
|
|
186
|
+
@session.click_button(name: 'form[awesome]')
|
|
187
|
+
expect(extract_results(@session)['first_name']).to eq('John')
|
|
188
|
+
end
|
|
174
189
|
end
|
|
175
190
|
|
|
176
191
|
context 'with fields associated with the form using the form attribute', requires: [:form_attribute] do
|
|
@@ -314,6 +329,18 @@ Capybara::SpecHelper.spec '#click_button' do
|
|
|
314
329
|
end
|
|
315
330
|
end
|
|
316
331
|
|
|
332
|
+
context 'with name given on a button defined by <button> tag' do
|
|
333
|
+
it 'should submit the associated form when name is locator' do
|
|
334
|
+
@session.click_button('form[no_value]')
|
|
335
|
+
expect(extract_results(@session)['first_name']).to eq('John')
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
it 'should submit the associated form when name is specific' do
|
|
339
|
+
@session.click_button(name: 'form[no_value]')
|
|
340
|
+
expect(extract_results(@session)['first_name']).to eq('John')
|
|
341
|
+
end
|
|
342
|
+
end
|
|
343
|
+
|
|
317
344
|
context 'with value given on a button defined by <button> tag' do
|
|
318
345
|
it 'should submit the associated form' do
|
|
319
346
|
@session.click_button('click_me')
|
|
@@ -352,7 +379,7 @@ Capybara::SpecHelper.spec '#click_button' do
|
|
|
352
379
|
|
|
353
380
|
context "with a locator that doesn't exist" do
|
|
354
381
|
it 'should raise an error' do
|
|
355
|
-
msg =
|
|
382
|
+
msg = /Unable to find button "does not exist"/
|
|
356
383
|
expect do
|
|
357
384
|
@session.click_button('does not exist')
|
|
358
385
|
end.to raise_error(Capybara::ElementNotFound, msg)
|
|
@@ -200,7 +200,7 @@ Capybara::SpecHelper.spec '#fill_in' do
|
|
|
200
200
|
after { Capybara.ignore_hidden_elements = false }
|
|
201
201
|
|
|
202
202
|
it 'should not find a hidden field' do
|
|
203
|
-
msg =
|
|
203
|
+
msg = /Unable to find visible field "Super Secret"/
|
|
204
204
|
expect do
|
|
205
205
|
@session.fill_in('Super Secret', with: '777')
|
|
206
206
|
end.to raise_error(Capybara::ElementNotFound, msg)
|
|
@@ -209,7 +209,7 @@ Capybara::SpecHelper.spec '#fill_in' do
|
|
|
209
209
|
|
|
210
210
|
context "with a locator that doesn't exist" do
|
|
211
211
|
it 'should raise an error' do
|
|
212
|
-
msg =
|
|
212
|
+
msg = /Unable to find field "does not exist"/
|
|
213
213
|
expect do
|
|
214
214
|
@session.fill_in('does not exist', with: 'Blah blah')
|
|
215
215
|
end.to raise_error(Capybara::ElementNotFound, msg)
|
|
@@ -53,7 +53,20 @@ Capybara::SpecHelper.spec '#switch_to_frame', requires: [:frames] do
|
|
|
53
53
|
@session.switch_to_frame frame
|
|
54
54
|
frame = @session.find(:frame, 'childFrame')
|
|
55
55
|
@session.switch_to_frame frame
|
|
56
|
-
@session.click_link 'Close Window'
|
|
56
|
+
@session.click_link 'Close Window Now'
|
|
57
|
+
@session.switch_to_frame :parent # Go back to parentFrame
|
|
58
|
+
expect(@session).to have_selector(:css, 'body#parentBody')
|
|
59
|
+
expect(@session).not_to have_selector(:css, '#childFrame')
|
|
60
|
+
@session.switch_to_frame :parent # Go back to top
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it 'works if the frame is closed with a slight delay', requires: %i[frames js] do
|
|
64
|
+
frame = @session.find(:frame, 'parentFrame')
|
|
65
|
+
@session.switch_to_frame frame
|
|
66
|
+
frame = @session.find(:frame, 'childFrame')
|
|
67
|
+
@session.switch_to_frame frame
|
|
68
|
+
@session.click_link 'Close Window Soon'
|
|
69
|
+
sleep 1
|
|
57
70
|
@session.switch_to_frame :parent # Go back to parentFrame
|
|
58
71
|
expect(@session).to have_selector(:css, 'body#parentBody')
|
|
59
72
|
expect(@session).not_to have_selector(:css, '#childFrame')
|
|
@@ -92,7 +92,18 @@ Capybara::SpecHelper.spec '#within_frame', requires: [:frames] do
|
|
|
92
92
|
it 'works if the frame is closed', requires: %i[frames js] do
|
|
93
93
|
@session.within_frame 'parentFrame' do
|
|
94
94
|
@session.within_frame 'childFrame' do
|
|
95
|
-
@session.click_link 'Close Window'
|
|
95
|
+
@session.click_link 'Close Window Now'
|
|
96
|
+
end
|
|
97
|
+
expect(@session).to have_selector(:css, 'body#parentBody')
|
|
98
|
+
expect(@session).not_to have_selector(:css, '#childFrame')
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
it 'works if the frame is closed with a slight delay', requires: %i[frames js] do
|
|
103
|
+
@session.within_frame 'parentFrame' do
|
|
104
|
+
@session.within_frame 'childFrame' do
|
|
105
|
+
@session.click_link 'Close Window Soon'
|
|
106
|
+
sleep 1
|
|
96
107
|
end
|
|
97
108
|
expect(@session).to have_selector(:css, 'body#parentBody')
|
|
98
109
|
expect(@session).not_to have_selector(:css, '#childFrame')
|
|
@@ -109,12 +109,24 @@ Capybara::SpecHelper.spec 'node' do
|
|
|
109
109
|
expect(@session.first('//input').value).to eq('')
|
|
110
110
|
end
|
|
111
111
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
112
|
+
if ENV['CAPYBARA_THOROUGH']
|
|
113
|
+
it 'should raise if the text field is readonly' do
|
|
114
|
+
expect { @session.first('//input[@readonly]').set('changed') }.to raise_error(Capybara::ReadOnlyElementError)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it 'should raise if the textarea is readonly' do
|
|
118
|
+
expect { @session.first('//textarea[@readonly]').set('changed') }.to raise_error(Capybara::ReadOnlyElementError)
|
|
119
|
+
end
|
|
120
|
+
else
|
|
121
|
+
it 'should not change if the text field is readonly' do
|
|
122
|
+
@session.first('//input[@readonly]').set('changed')
|
|
123
|
+
expect(@session.first('//input[@readonly]').value).to eq 'should not change'
|
|
124
|
+
end
|
|
115
125
|
|
|
116
|
-
|
|
117
|
-
|
|
126
|
+
it 'should not change if the textarea is readonly' do
|
|
127
|
+
@session.first('//textarea[@readonly]').set('changed')
|
|
128
|
+
expect(@session.first('//textarea[@readonly]').value).to eq 'textarea should not change'
|
|
129
|
+
end
|
|
118
130
|
end
|
|
119
131
|
|
|
120
132
|
it 'should use global default options' do
|
|
@@ -183,7 +195,7 @@ Capybara::SpecHelper.spec 'node' do
|
|
|
183
195
|
|
|
184
196
|
it 'should see a disabled fieldset as disabled' do
|
|
185
197
|
@session.visit('/form')
|
|
186
|
-
expect(@session.find(:
|
|
198
|
+
expect(@session.find(:xpath, './/fieldset[@id="form_disabled_fieldset"]')).to be_disabled
|
|
187
199
|
end
|
|
188
200
|
|
|
189
201
|
context 'in a disabled fieldset' do
|
|
@@ -85,11 +85,11 @@ Capybara::SpecHelper.spec '#uncheck' do
|
|
|
85
85
|
end
|
|
86
86
|
|
|
87
87
|
it 'should raise original error when no label available' do
|
|
88
|
-
expect { @session.uncheck('form_cars_porsche') }.to raise_error(Capybara::ElementNotFound,
|
|
88
|
+
expect { @session.uncheck('form_cars_porsche') }.to raise_error(Capybara::ElementNotFound, /Unable to find visible checkbox "form_cars_porsche"/)
|
|
89
89
|
end
|
|
90
90
|
|
|
91
91
|
it 'should raise error if not allowed to click label' do
|
|
92
|
-
expect { @session.uncheck('form_cars_jaguar', allow_label_click: false) }.to raise_error(Capybara::ElementNotFound,
|
|
92
|
+
expect { @session.uncheck('form_cars_jaguar', allow_label_click: false) }.to raise_error(Capybara::ElementNotFound, /Unable to find visible checkbox "form_cars_jaguar"/)
|
|
93
93
|
end
|
|
94
94
|
|
|
95
95
|
it 'should include node filter description in error if necessary' do
|
|
@@ -56,7 +56,7 @@ Capybara::SpecHelper.spec '#unselect' do
|
|
|
56
56
|
|
|
57
57
|
context "with a locator that doesn't exist" do
|
|
58
58
|
it 'should raise an error' do
|
|
59
|
-
msg =
|
|
59
|
+
msg = /Unable to find select box "does not exist"/
|
|
60
60
|
expect do
|
|
61
61
|
@session.unselect('foo', from: 'does not exist')
|
|
62
62
|
end.to raise_error(Capybara::ElementNotFound, msg)
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
</script>
|
|
11
11
|
</head>
|
|
12
12
|
<body id="childBody">
|
|
13
|
-
<a href="javascript:void(0)" onClick="closeWin()">Close Window</a>
|
|
13
|
+
<a href="javascript:void(0)" onClick="closeWin()">Close Window Now</a>
|
|
14
|
+
<a href="javascript:void(0)" onClick="setTimeout(function(){closeWin()}, 10)">Close Window Soon</a>
|
|
14
15
|
<iframe src="/frame_one" id="grandchildFrame1"></iframe>
|
|
15
16
|
<iframe src="/frame_two" id="grandchildFrame2"></iframe>
|
|
16
17
|
</body>
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<script src="https://unpkg.com/react/umd/react.development.js"></script>
|
|
5
|
+
<script src="https://unpkg.com/react-dom/umd/react-dom.development.js"></script>
|
|
6
|
+
</head>
|
|
7
|
+
<body>
|
|
8
|
+
<div id="root"></div>
|
|
9
|
+
<script>
|
|
10
|
+
// https://codepen.io/gaearon/pen/VmmPgp?editors=0010
|
|
11
|
+
class NameForm extends React.Component {
|
|
12
|
+
constructor(props) {
|
|
13
|
+
super(props);
|
|
14
|
+
this.state = { value: '' };
|
|
15
|
+
|
|
16
|
+
this.handleChange = this.handleChange.bind(this);
|
|
17
|
+
this.handleSubmit = this.handleSubmit.bind(this);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
handleChange(event) {
|
|
21
|
+
this.setState({ value: event.target.value });
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
handleSubmit(event) {
|
|
25
|
+
alert('A name was submitted: ' + this.state.value);
|
|
26
|
+
event.preventDefault();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
render() {
|
|
30
|
+
return (
|
|
31
|
+
React.createElement("form", { onSubmit: this.handleSubmit },
|
|
32
|
+
React.createElement("label", null, "Name:",
|
|
33
|
+
|
|
34
|
+
React.createElement("input", { type: "text", value: this.state.value, onChange: this.handleChange })),
|
|
35
|
+
|
|
36
|
+
React.createElement("input", { type: "submit", value: "Submit" })));
|
|
37
|
+
}}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
ReactDOM.render(
|
|
41
|
+
React.createElement(NameForm, null),
|
|
42
|
+
document.getElementById('root'));
|
|
43
|
+
</script>
|
|
44
|
+
</body>
|
|
45
|
+
</html>
|
data/lib/capybara/version.rb
CHANGED
data/lib/capybara/window.rb
CHANGED
|
@@ -49,7 +49,7 @@ module Capybara
|
|
|
49
49
|
# @return [Boolean] whether this window is the window in which commands are being executed
|
|
50
50
|
def current?
|
|
51
51
|
@driver.current_window_handle == @handle
|
|
52
|
-
rescue @driver.no_such_window_error
|
|
52
|
+
rescue @driver.no_such_window_error # rubocop:disable Naming/RescuedExceptionsVariableName
|
|
53
53
|
false
|
|
54
54
|
end
|
|
55
55
|
|
data/lib/capybara.rb
CHANGED
|
@@ -466,42 +466,8 @@ module Capybara
|
|
|
466
466
|
require 'capybara/selenium/driver'
|
|
467
467
|
end
|
|
468
468
|
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
end
|
|
472
|
-
|
|
473
|
-
Capybara.register_server :webrick do |app, port, host, **options|
|
|
474
|
-
require 'rack/handler/webrick'
|
|
475
|
-
options = { Host: host, Port: port, AccessLog: [], Logger: WEBrick::Log.new(nil, 0) }.merge(options)
|
|
476
|
-
Rack::Handler::WEBrick.run(app, options)
|
|
477
|
-
end
|
|
478
|
-
|
|
479
|
-
Capybara.register_server :puma do |app, port, host, **options|
|
|
480
|
-
begin
|
|
481
|
-
require 'rack/handler/puma'
|
|
482
|
-
rescue LoadError
|
|
483
|
-
raise LoadError, 'Capybara is unable to load `puma` for its server, please add `puma` to your project or specify a different server via something like `Capybara.server = :webrick`.'
|
|
484
|
-
else
|
|
485
|
-
unless Rack::Handler::Puma.respond_to?(:config)
|
|
486
|
-
raise LoadError, 'Capybara requires `puma` version 3.8.0 or higher, please upgrade `puma` or register and specify your own server block'
|
|
487
|
-
end
|
|
488
|
-
end
|
|
489
|
-
# If we just run the Puma Rack handler it installs signal handlers which prevent us from being able to interrupt tests.
|
|
490
|
-
# Therefore construct and run the Server instance ourselves.
|
|
491
|
-
# Rack::Handler::Puma.run(app, { Host: host, Port: port, Threads: "0:4", workers: 0, daemon: false }.merge(options))
|
|
492
|
-
options = { Host: host, Port: port, Threads: '0:4', workers: 0, daemon: false }.merge(options)
|
|
493
|
-
conf = Rack::Handler::Puma.config(app, options)
|
|
494
|
-
events = conf.options[:Silent] ? ::Puma::Events.strings : ::Puma::Events.stdio
|
|
495
|
-
|
|
496
|
-
events.log 'Capybara starting Puma...'
|
|
497
|
-
events.log "* Version #{Puma::Const::PUMA_VERSION} , codename: #{Puma::Const::CODE_NAME}"
|
|
498
|
-
events.log "* Min threads: #{conf.options[:min_threads]}, max threads: #{conf.options[:max_threads]}"
|
|
499
|
-
|
|
500
|
-
Puma::Server.new(conf.app, events, conf.options).tap do |s|
|
|
501
|
-
s.binder.parse conf.options[:binds], s.events
|
|
502
|
-
s.min_threads, s.max_threads = conf.options[:min_threads], conf.options[:max_threads]
|
|
503
|
-
end.run.join
|
|
504
|
-
end
|
|
469
|
+
require 'capybara/registrations/servers'
|
|
470
|
+
require 'capybara/registrations/drivers'
|
|
505
471
|
|
|
506
472
|
Capybara.configure do |config|
|
|
507
473
|
config.always_include_port = false
|
|
@@ -527,38 +493,3 @@ Capybara.configure do |config|
|
|
|
527
493
|
config.default_normalize_ws = false
|
|
528
494
|
config.allow_gumbo = false
|
|
529
495
|
end
|
|
530
|
-
|
|
531
|
-
Capybara.register_driver :rack_test do |app|
|
|
532
|
-
Capybara::RackTest::Driver.new(app)
|
|
533
|
-
end
|
|
534
|
-
|
|
535
|
-
Capybara.register_driver :selenium do |app|
|
|
536
|
-
Capybara::Selenium::Driver.new(app)
|
|
537
|
-
end
|
|
538
|
-
|
|
539
|
-
Capybara.register_driver :selenium_headless do |app|
|
|
540
|
-
Capybara::Selenium::Driver.load_selenium
|
|
541
|
-
browser_options = ::Selenium::WebDriver::Firefox::Options.new
|
|
542
|
-
browser_options.args << '-headless'
|
|
543
|
-
Capybara::Selenium::Driver.new(app, browser: :firefox, options: browser_options)
|
|
544
|
-
end
|
|
545
|
-
|
|
546
|
-
Capybara.register_driver :selenium_chrome do |app|
|
|
547
|
-
Capybara::Selenium::Driver.load_selenium
|
|
548
|
-
browser_options = ::Selenium::WebDriver::Chrome::Options.new.tap do |opts|
|
|
549
|
-
# Workaround https://bugs.chromium.org/p/chromedriver/issues/detail?id=2650&q=load&sort=-id&colspec=ID%20Status%20Pri%20Owner%20Summary
|
|
550
|
-
opts.args << '--disable-site-isolation-trials'
|
|
551
|
-
end
|
|
552
|
-
Capybara::Selenium::Driver.new(app, browser: :chrome, options: browser_options)
|
|
553
|
-
end
|
|
554
|
-
|
|
555
|
-
Capybara.register_driver :selenium_chrome_headless do |app|
|
|
556
|
-
Capybara::Selenium::Driver.load_selenium
|
|
557
|
-
browser_options = ::Selenium::WebDriver::Chrome::Options.new.tap do |opts|
|
|
558
|
-
opts.args << '--headless'
|
|
559
|
-
opts.args << '--disable-gpu' if Gem.win_platform?
|
|
560
|
-
# Workaround https://bugs.chromium.org/p/chromedriver/issues/detail?id=2650&q=load&sort=-id&colspec=ID%20Status%20Pri%20Owner%20Summary
|
|
561
|
-
opts.args << '--disable-site-isolation-trials'
|
|
562
|
-
end
|
|
563
|
-
Capybara::Selenium::Driver.new(app, browser: :chrome, options: browser_options)
|
|
564
|
-
end
|
data/spec/minitest_spec_spec.rb
CHANGED
|
@@ -146,6 +146,6 @@ RSpec.describe 'capybara/minitest/spec' do
|
|
|
146
146
|
reporter.report
|
|
147
147
|
expect(output.string).to include('20 runs, 42 assertions, 1 failures, 0 errors, 1 skips')
|
|
148
148
|
# Make sure error messages are displayed
|
|
149
|
-
expect(output.string).to
|
|
149
|
+
expect(output.string).to match(/expected to find select box "non_existing_form_title" .*but there were no matches/)
|
|
150
150
|
end
|
|
151
151
|
end
|