capybara 3.16.0 → 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.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +27 -0
  3. data/README.md +2 -2
  4. data/lib/capybara/config.rb +1 -2
  5. data/lib/capybara/node/actions.rb +5 -5
  6. data/lib/capybara/node/base.rb +4 -4
  7. data/lib/capybara/node/element.rb +5 -5
  8. data/lib/capybara/node/finders.rb +6 -4
  9. data/lib/capybara/node/simple.rb +3 -2
  10. data/lib/capybara/queries/selector_query.rb +5 -5
  11. data/lib/capybara/queries/style_query.rb +1 -1
  12. data/lib/capybara/rack_test/form.rb +1 -1
  13. data/lib/capybara/registrations/drivers.rb +36 -0
  14. data/lib/capybara/registrations/servers.rb +38 -0
  15. data/lib/capybara/result.rb +2 -2
  16. data/lib/capybara/rspec/matcher_proxies.rb +2 -2
  17. data/lib/capybara/rspec/matchers/base.rb +2 -2
  18. data/lib/capybara/selector/css.rb +1 -1
  19. data/lib/capybara/selector/filters/base.rb +1 -1
  20. data/lib/capybara/selector/selector.rb +1 -0
  21. data/lib/capybara/selector.rb +55 -32
  22. data/lib/capybara/selenium/driver.rb +85 -44
  23. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +16 -4
  24. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +23 -0
  25. data/lib/capybara/selenium/driver_specializations/internet_explorer_driver.rb +5 -0
  26. data/lib/capybara/selenium/driver_specializations/safari_driver.rb +14 -1
  27. data/lib/capybara/selenium/extensions/find.rb +48 -37
  28. data/lib/capybara/selenium/logger_suppressor.rb +29 -0
  29. data/lib/capybara/selenium/node.rb +22 -8
  30. data/lib/capybara/selenium/nodes/chrome_node.rb +8 -2
  31. data/lib/capybara/server/animation_disabler.rb +1 -1
  32. data/lib/capybara/server/checker.rb +1 -1
  33. data/lib/capybara/server/middleware.rb +3 -3
  34. data/lib/capybara/session/config.rb +2 -8
  35. data/lib/capybara/session.rb +1 -1
  36. data/lib/capybara/spec/session/attach_file_spec.rb +1 -1
  37. data/lib/capybara/spec/session/check_spec.rb +4 -4
  38. data/lib/capybara/spec/session/choose_spec.rb +2 -2
  39. data/lib/capybara/spec/session/click_button_spec.rb +28 -1
  40. data/lib/capybara/spec/session/fill_in_spec.rb +2 -2
  41. data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +14 -1
  42. data/lib/capybara/spec/session/frame/within_frame_spec.rb +12 -1
  43. data/lib/capybara/spec/session/node_spec.rb +18 -6
  44. data/lib/capybara/spec/session/uncheck_spec.rb +2 -2
  45. data/lib/capybara/spec/session/unselect_spec.rb +1 -1
  46. data/lib/capybara/spec/views/frame_child.erb +2 -1
  47. data/lib/capybara/spec/views/react.erb +45 -0
  48. data/lib/capybara/version.rb +1 -1
  49. data/lib/capybara/window.rb +1 -1
  50. data/lib/capybara.rb +2 -70
  51. data/spec/minitest_spec_spec.rb +1 -1
  52. data/spec/result_spec.rb +10 -6
  53. data/spec/rspec/shared_spec_matchers.rb +8 -4
  54. data/spec/selector_spec.rb +4 -0
  55. data/spec/selenium_spec_safari.rb +2 -3
  56. data/spec/session_spec.rb +7 -0
  57. data/spec/shared_selenium_session.rb +14 -11
  58. data/spec/spec_helper.rb +2 -1
  59. 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
- case tag_name
59
+ tag_name, type = attrs(:tagName, :type)
60
+ case tag_name.downcase
60
61
  when 'input'
61
- case self[:type]
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 => err
100
- if err.is_a?(::Selenium::WebDriver::Error::ElementClickInterceptedError) ||
101
- err.message =~ /Other element would receive the click/
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 err
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
- tag_name == 'fieldset' && find_xpath('ancestor-or-self::fieldset[@disabled]').any?
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 ::Selenium::WebDriver::Error::ExpectedError => err
18
- raise ArgumentError, "Selenium < 3.14 with remote Chrome doesn't support multiple file upload" if err.message.match?(/File not found : .+\n.+/m)
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
@@ -36,7 +36,7 @@ module Capybara
36
36
  attr_reader :disable_markup
37
37
 
38
38
  def html_content?
39
- !!(@headers['Content-Type'] =~ /html/)
39
+ /html/.match?(@headers['Content-Type'])
40
40
  end
41
41
 
42
42
  def insert_disable(html)
@@ -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
@@ -46,9 +46,9 @@ module Capybara
46
46
  @counter.increment
47
47
  begin
48
48
  @extended_app.call(env)
49
- rescue *@server_errors => err
50
- @error ||= err
51
- raise err
49
+ rescue *@server_errors => e
50
+ @error ||= e
51
+ raise e
52
52
  ensure
53
53
  @counter.decrement
54
54
  end
@@ -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}." if url && url !~ URI::DEFAULT_PARSER.make_regexp
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}." if url && url !~ URI::DEFAULT_PARSER.make_regexp
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
  #
@@ -141,7 +141,7 @@ module Capybara
141
141
  #
142
142
  def quit
143
143
  @driver.quit if @driver.respond_to? :quit
144
- @driver = nil
144
+ @document = @driver = nil
145
145
  @touched = false
146
146
  @server&.reset_error!
147
147
  end
@@ -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 = 'Unable to find file field "does not exist"'
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 = 'Unable to find checkbox "does not exist"'
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, 'Unable to find visible checkbox "form_cars_ariel"')
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, 'Unable to find visible checkbox "form_cars_mclaren"')
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, 'Unable to find visible checkbox "form_cars_mclaren"')
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 = 'Unable to find radio button "does not exist"'
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, 'Unable to find visible radio button "party_democrat"')
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 = 'Unable to find button "does not exist"'
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 = 'Unable to find visible field "Super Secret"'
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 = 'Unable to find field "does not exist"'
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
- it 'should raise if the text field is readonly' do
113
- expect { @session.first('//input[@readonly]').set('changed') }.to raise_error(Capybara::ReadOnlyElementError)
114
- end
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
- it 'should raise if the textarea is readonly' do
117
- expect { @session.first('//textarea[@readonly]').set('changed') }.to raise_error(Capybara::ReadOnlyElementError)
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(:css, '#form_disabled_fieldset')).to be_disabled
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, 'Unable to find visible checkbox "form_cars_porsche"')
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, 'Unable to find visible checkbox "form_cars_jaguar"')
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 = 'Unable to find select box "does not exist"'
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>
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Capybara
4
- VERSION = '3.16.0'
4
+ VERSION = '3.17.0'
5
5
  end
@@ -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
- Capybara.register_server :default do |app, port, _host|
470
- Capybara.run_default_server(app, port)
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,37 +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
- browser_options = ::Selenium::WebDriver::Chrome::Options.new.tap do |opts|
548
- # Workaround https://bugs.chromium.org/p/chromedriver/issues/detail?id=2650&q=load&sort=-id&colspec=ID%20Status%20Pri%20Owner%20Summary
549
- opts.args << '--disable-site-isolation-trials'
550
- end
551
- Capybara::Selenium::Driver.new(app, browser: :chrome, options: browser_options)
552
- end
553
-
554
- Capybara.register_driver :selenium_chrome_headless do |app|
555
- Capybara::Selenium::Driver.load_selenium
556
- browser_options = ::Selenium::WebDriver::Chrome::Options.new.tap do |opts|
557
- opts.args << '--headless'
558
- opts.args << '--disable-gpu' if Gem.win_platform?
559
- # Workaround https://bugs.chromium.org/p/chromedriver/issues/detail?id=2650&q=load&sort=-id&colspec=ID%20Status%20Pri%20Owner%20Summary
560
- opts.args << '--disable-site-isolation-trials'
561
- end
562
- Capybara::Selenium::Driver.new(app, browser: :chrome, options: browser_options)
563
- end
@@ -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 include('expected to find select box "non_existing_form_title" but there were no matches')
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