capybara 3.37.1 → 3.39.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +54 -4
  3. data/README.md +23 -11
  4. data/lib/capybara/helpers.rb +5 -1
  5. data/lib/capybara/node/actions.rb +4 -4
  6. data/lib/capybara/node/base.rb +2 -1
  7. data/lib/capybara/node/finders.rb +2 -0
  8. data/lib/capybara/node/whitespace_normalizer.rb +81 -0
  9. data/lib/capybara/queries/base_query.rb +2 -2
  10. data/lib/capybara/queries/selector_query.rb +4 -2
  11. data/lib/capybara/queries/text_query.rb +1 -1
  12. data/lib/capybara/rack_test/browser.rb +8 -2
  13. data/lib/capybara/rack_test/form.rb +29 -7
  14. data/lib/capybara/rack_test/node.rb +18 -15
  15. data/lib/capybara/registrations/drivers.rb +3 -3
  16. data/lib/capybara/registrations/servers.rb +30 -10
  17. data/lib/capybara/rspec/matcher_proxies.rb +3 -3
  18. data/lib/capybara/rspec/matchers/base.rb +8 -6
  19. data/lib/capybara/rspec/matchers/compound.rb +1 -1
  20. data/lib/capybara/selector/definition/link.rb +2 -1
  21. data/lib/capybara/selector/definition.rb +1 -1
  22. data/lib/capybara/selector/filter_set.rb +4 -5
  23. data/lib/capybara/selector/regexp_disassembler.rb +2 -5
  24. data/lib/capybara/selenium/driver.rb +6 -3
  25. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +8 -4
  26. data/lib/capybara/selenium/extensions/html5_drag.rb +5 -4
  27. data/lib/capybara/selenium/logger_suppressor.rb +4 -0
  28. data/lib/capybara/selenium/node.rb +60 -25
  29. data/lib/capybara/selenium/nodes/chrome_node.rb +5 -1
  30. data/lib/capybara/selenium/nodes/edge_node.rb +24 -2
  31. data/lib/capybara/selenium/nodes/firefox_node.rb +2 -2
  32. data/lib/capybara/selenium/nodes/safari_node.rb +2 -2
  33. data/lib/capybara/selenium/patches/action_pauser.rb +3 -3
  34. data/lib/capybara/selenium/patches/atoms.rb +1 -1
  35. data/lib/capybara/selenium/patches/pause_duration_fix.rb +1 -1
  36. data/lib/capybara/server/animation_disabler.rb +21 -22
  37. data/lib/capybara/server/middleware.rb +1 -1
  38. data/lib/capybara/session/config.rb +3 -1
  39. data/lib/capybara/session.rb +11 -9
  40. data/lib/capybara/spec/public/test.js +4 -0
  41. data/lib/capybara/spec/session/all_spec.rb +1 -1
  42. data/lib/capybara/spec/session/attach_file_spec.rb +6 -0
  43. data/lib/capybara/spec/session/check_spec.rb +1 -0
  44. data/lib/capybara/spec/session/click_link_spec.rb +11 -0
  45. data/lib/capybara/spec/session/current_scope_spec.rb +1 -1
  46. data/lib/capybara/spec/session/fill_in_spec.rb +6 -0
  47. data/lib/capybara/spec/session/find_link_spec.rb +10 -0
  48. data/lib/capybara/spec/session/find_spec.rb +2 -2
  49. data/lib/capybara/spec/session/first_spec.rb +1 -1
  50. data/lib/capybara/spec/session/frame/within_frame_spec.rb +2 -0
  51. data/lib/capybara/spec/session/has_all_selectors_spec.rb +5 -5
  52. data/lib/capybara/spec/session/has_ancestor_spec.rb +2 -2
  53. data/lib/capybara/spec/session/has_any_selectors_spec.rb +2 -2
  54. data/lib/capybara/spec/session/has_button_spec.rb +6 -0
  55. data/lib/capybara/spec/session/has_current_path_spec.rb +1 -1
  56. data/lib/capybara/spec/session/has_link_spec.rb +10 -0
  57. data/lib/capybara/spec/session/has_none_selectors_spec.rb +7 -7
  58. data/lib/capybara/spec/session/has_select_spec.rb +6 -0
  59. data/lib/capybara/spec/session/has_text_spec.rb +4 -8
  60. data/lib/capybara/spec/session/matches_style_spec.rb +2 -0
  61. data/lib/capybara/spec/session/node_spec.rb +40 -1
  62. data/lib/capybara/spec/session/reset_session_spec.rb +13 -0
  63. data/lib/capybara/spec/session/scroll_spec.rb +3 -1
  64. data/lib/capybara/spec/session/window/windows_spec.rb +1 -1
  65. data/lib/capybara/spec/session/within_spec.rb +13 -0
  66. data/lib/capybara/spec/spec_helper.rb +8 -2
  67. data/lib/capybara/spec/test_app.rb +25 -6
  68. data/lib/capybara/spec/views/form.erb +17 -0
  69. data/lib/capybara/spec/views/with_html.erb +3 -3
  70. data/lib/capybara/spec/views/with_scope.erb +2 -2
  71. data/lib/capybara/version.rb +1 -1
  72. data/lib/capybara.rb +4 -2
  73. data/spec/capybara_spec.rb +12 -0
  74. data/spec/counter_spec.rb +35 -0
  75. data/spec/css_builder_spec.rb +1 -1
  76. data/spec/css_splitter_spec.rb +1 -1
  77. data/spec/dsl_spec.rb +2 -0
  78. data/spec/minitest_spec.rb +4 -0
  79. data/spec/minitest_spec_spec.rb +4 -0
  80. data/spec/per_session_config_spec.rb +1 -1
  81. data/spec/rack_test_spec.rb +10 -2
  82. data/spec/rspec/scenarios_spec.rb +1 -1
  83. data/spec/rspec/shared_spec_matchers.rb +1 -1
  84. data/spec/rspec_matchers_spec.rb +25 -0
  85. data/spec/rspec_spec.rb +2 -2
  86. data/spec/sauce_spec_chrome.rb +1 -1
  87. data/spec/selector_spec.rb +2 -2
  88. data/spec/selenium_spec_chrome.rb +7 -6
  89. data/spec/selenium_spec_chrome_remote.rb +8 -8
  90. data/spec/selenium_spec_edge.rb +12 -6
  91. data/spec/selenium_spec_firefox.rb +20 -8
  92. data/spec/selenium_spec_firefox_remote.rb +19 -4
  93. data/spec/selenium_spec_ie.rb +4 -2
  94. data/spec/selenium_spec_safari.rb +3 -1
  95. data/spec/server_spec.rb +2 -2
  96. data/spec/shared_selenium_session.rb +5 -5
  97. data/spec/spec_helper.rb +33 -0
  98. data/spec/whitespace_normalizer_spec.rb +54 -0
  99. data/spec/xpath_builder_spec.rb +1 -1
  100. metadata +5 -2
@@ -24,6 +24,7 @@ module Capybara
24
24
  Capybara.app_host = nil
25
25
  Capybara.default_selector = :xpath
26
26
  Capybara.default_max_wait_time = 1
27
+ Capybara.default_retry_interval = 0.01
27
28
  Capybara.ignore_hidden_elements = true
28
29
  Capybara.exact = false
29
30
  Capybara.raise_server_errors = true
@@ -37,7 +38,7 @@ module Capybara
37
38
  Capybara.predicates_wait = true
38
39
  Capybara.default_normalize_ws = false
39
40
  Capybara.use_html5_parsing = !ENV['HTML5_PARSING'].nil?
40
- Capybara.w3c_click_offset = false
41
+ Capybara.w3c_click_offset = true
41
42
  reset_threadsafe
42
43
  end
43
44
 
@@ -122,6 +123,11 @@ module Capybara
122
123
  YAML.safe_load results, permitted_classes: perms
123
124
  end
124
125
 
126
+ def extract_content_type(session)
127
+ expect(session).to have_xpath("//pre[@id='content_type']")
128
+ Capybara::HTML(session.body).xpath("//pre[@id='content_type']").first.text
129
+ end
130
+
125
131
  def be_an_invalid_element_error(session)
126
132
  satisfy { |error| session.driver.invalid_element_errors.any? { |e| error.is_a? e } }
127
133
  end
@@ -132,4 +138,4 @@ module Capybara
132
138
  end
133
139
  end
134
140
 
135
- Dir["#{File.dirname(__FILE__)}/session/**/*.rb"].each { |file| require_relative file }
141
+ Dir["#{File.dirname(__FILE__)}/session/**/*.rb"].sort.each { |file| require_relative file }
@@ -177,6 +177,22 @@ class TestApp < Sinatra::Base
177
177
  HTML
178
178
  end
179
179
 
180
+ get '/with_iframe' do
181
+ <<-HTML
182
+ <!DOCTYPE html>
183
+ <html lang="en">
184
+ <head>
185
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
186
+ <title>Test with Iframe</title>
187
+ </head>
188
+
189
+ <body>
190
+ <iframe src="#{params[:url]}" id="#{params[:id]}"></iframe>
191
+ </body>
192
+ </html>
193
+ HTML
194
+ end
195
+
180
196
  get '/base/with_base' do
181
197
  <<-HTML
182
198
  <!DOCTYPE html>
@@ -232,6 +248,10 @@ class TestApp < Sinatra::Base
232
248
  'Thomas, Walpole, was , here'
233
249
  end
234
250
 
251
+ get '/apple-touch-icon-precomposed.png' do
252
+ halt(404)
253
+ end
254
+
235
255
  get '/:view' do |view|
236
256
  view_template = "#{__dir__}/views/#{view}.erb"
237
257
  has_layout = File.exist?(view_template) && File.open(view_template) { |f| f.first.downcase.include?('doctype') }
@@ -240,12 +260,15 @@ class TestApp < Sinatra::Base
240
260
 
241
261
  post '/form' do
242
262
  self.class.form_post_count += 1
243
- %(<pre id="results">#{params[:form].merge('post_count' => self.class.form_post_count).to_yaml}</pre>)
263
+ %(
264
+ <pre id="content_type">#{request.content_type}</pre>
265
+ <pre id="results">#{params.fetch(:form, {}).merge('post_count' => self.class.form_post_count).to_yaml}</pre>
266
+ )
244
267
  end
245
268
 
246
269
  post '/upload_empty' do
247
270
  if params[:form][:file].nil?
248
- 'Successfully ignored empty file field.'
271
+ "Successfully ignored empty file field. Content type was #{request.content_type}"
249
272
  else
250
273
  'Something went wrong.'
251
274
  end
@@ -272,10 +295,6 @@ class TestApp < Sinatra::Base
272
295
  'No files uploaded'
273
296
  end
274
297
 
275
- get '/apple-touch-icon-precomposed.png' do
276
- halt(404)
277
- end
278
-
279
298
  class << self
280
299
  attr_accessor :form_post_count
281
300
  end
@@ -586,6 +586,19 @@ New line after and before textarea tag
586
586
  <p>
587
587
  </form>
588
588
 
589
+ <form action="/form" method="post" enctype="multipart/form-data">
590
+ <input type="hidden" name="form[document2]" value="hidden_field"/>
591
+
592
+ <p>
593
+ <label for="form_document">Document with hidden</label>
594
+ <input type="file" name="form[document2]" id="form_document2"/>
595
+ </p>
596
+
597
+ <p>
598
+ <input type="submit" value="Upload Empty With Hidden"/>
599
+ <p>
600
+ </form>
601
+
589
602
  <form action="/upload_multiple" method="post" enctype="multipart/form-data">
590
603
  <p>
591
604
  <label for="form_multiple_file_name">File Name</label>
@@ -682,6 +695,10 @@ New line after and before textarea tag
682
695
  </p>
683
696
  </form>
684
697
 
698
+ <form id="single_input_form" action="/form" method="post">
699
+ <input type="text" name="form[single_input]" id="single_input"/>
700
+ </form>
701
+
685
702
  <label>Confusion
686
703
  <input type="checkbox" id="confusion_checkbox" class="confusion-checkbox confusion"/>
687
704
  </label>
@@ -19,7 +19,7 @@
19
19
 
20
20
  <p class="para" id="first" data-random="abc\def" style="line-height: 25px;">
21
21
  Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
22
- tempor incididunt ut <a href="/with_simple_html" title="awesome title" class="simple" tabindex="1">labore</a>
22
+ tempor incididunt ut <a href="/with_simple_html" title="awesome title" class="simple" tabindex="1" target="_self">labore</a>
23
23
  et dolore magna aliqua. Ut enim ad minim veniam,
24
24
  quis nostrud exercitation <a href="/foo" id="foo" data-test-id="test-foo">ullamco</a> laboris nisi
25
25
  ut aliquip ex ea commodo consequat.
@@ -88,7 +88,7 @@ banana</textarea>
88
88
  </div>
89
89
 
90
90
  <div style="display: none;">
91
- <a id="first_invisble" class="hidden">first hidden link</a>
91
+ <a id="first_invisible" class="hidden">first hidden link</a>
92
92
  </div>
93
93
 
94
94
  <div style="display: none;">
@@ -138,7 +138,7 @@ banana</textarea>
138
138
  Ancestor
139
139
  <div id="child">Child</div>
140
140
  </div>
141
- <div id="ancestor1_sibiling">
141
+ <div id="ancestor1_sibling">
142
142
  ASibling
143
143
  </div>
144
144
  </div>
@@ -35,8 +35,8 @@
35
35
  </ul>
36
36
  </div>
37
37
 
38
- <div id="another_foo">
38
+ <div id="another_foo" onclick="this.innerHTML = 'I was clicked';">
39
39
  <ul>
40
- <li>With Simple HTML: <a href="/">Go</a>
40
+ <li>With Simple HTML: <a href="/">Go</a></li>
41
41
  </ul>
42
42
  </div>
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Capybara
4
- VERSION = '3.37.1'
4
+ VERSION = '3.39.0'
5
5
  end
data/lib/capybara.rb CHANGED
@@ -79,6 +79,7 @@ module Capybara
79
79
  # - **automatic_reload** (Boolean = `true`) - Whether to automatically reload elements as Capybara is waiting.
80
80
  # - **default_max_wait_time** (Numeric = `2`) - The maximum number of seconds to wait for asynchronous processes to finish.
81
81
  # - **default_normalize_ws** (Boolean = `false`) - Whether text predicates and matchers use normalize whitespace behavior.
82
+ # - **default_retry_interval** (Numeric = `0.01`) - The number of seconds to delay the next check in asynchronous processes.
82
83
  # - **default_selector** (`:css`, `:xpath` = `:css`) - Methods which take a selector use the given type by default. See also {Capybara::Selector}.
83
84
  # - **default_set_options** (Hash = `{}`) - The default options passed to {Capybara::Node::Element#set Element#set}.
84
85
  # - **enable_aria_label** (Boolean = `false`) - Whether fields, links, and buttons will match against `aria-label` attribute.
@@ -101,7 +102,7 @@ module Capybara
101
102
  # and {configure raise_server_errors} is `true`.
102
103
  # - **test_id** (Symbol, String, `nil` = `nil`) - Optional attribute to match locator against with built-in selectors along with id.
103
104
  # - **threadsafe** (Boolean = `false`) - Whether sessions can be configured individually.
104
- # - **w3c_click_offset** (Boolean = 'false') - Whether click offsets should be from element center (true) or top left (false)
105
+ # - **w3c_click_offset** (Boolean = 'true') - Whether click offsets should be from element center (true) or top left (false)
105
106
  #
106
107
  # #### DSL Options
107
108
  #
@@ -496,6 +497,7 @@ Capybara.configure do |config|
496
497
  config.server = :default
497
498
  config.default_selector = :css
498
499
  config.default_max_wait_time = 2
500
+ config.default_retry_interval = 0.01
499
501
  config.ignore_hidden_elements = true
500
502
  config.default_host = 'http://www.example.com'
501
503
  config.automatic_reload = true
@@ -514,5 +516,5 @@ Capybara.configure do |config|
514
516
  config.predicates_wait = true
515
517
  config.default_normalize_ws = false
516
518
  config.use_html5_parsing = false
517
- config.w3c_click_offset = false
519
+ config.w3c_click_offset = true
518
520
  end
@@ -15,6 +15,18 @@ RSpec.describe Capybara do
15
15
  end
16
16
  end
17
17
 
18
+ describe 'default_retry_interval' do
19
+ before { @previous_default_interval = described_class.default_retry_interval }
20
+
21
+ after { described_class.default_retry_interval = @previous_default_interval } # rubocop:disable RSpec/InstanceVariable
22
+
23
+ it 'should be changeable' do
24
+ expect(described_class.default_retry_interval).not_to eq(0.1)
25
+ described_class.default_retry_interval = 0.1
26
+ expect(described_class.default_retry_interval).to eq(0.1)
27
+ end
28
+ end
29
+
18
30
  describe '.register_driver' do
19
31
  it 'should add a new driver' do
20
32
  described_class.register_driver :schmoo do |app|
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Capybara::Server::Middleware::Counter do
6
+ let(:counter) { described_class.new }
7
+ let(:uri) { '/example' }
8
+
9
+ describe '#increment' do
10
+ it 'successfully' do
11
+ counter.increment(uri)
12
+ expect(counter).to be_positive
13
+ end
14
+ end
15
+
16
+ describe '#decrement' do
17
+ before do
18
+ counter.increment(uri)
19
+ end
20
+
21
+ context 'successfully' do
22
+ it 'with same uri' do
23
+ expect(counter).to be_positive
24
+ counter.decrement(uri)
25
+ expect(counter).not_to be_positive
26
+ end
27
+
28
+ it 'with changed uri' do
29
+ expect(counter).to be_positive
30
+ counter.decrement('/')
31
+ expect(counter).not_to be_positive
32
+ end
33
+ end
34
+ end
35
+ end
@@ -5,7 +5,7 @@ require 'spec_helper'
5
5
  # rubocop:disable RSpec/InstanceVariable
6
6
  RSpec.describe Capybara::Selector::CSSBuilder do
7
7
  let :builder do
8
- ::Capybara::Selector::CSSBuilder.new(@css)
8
+ described_class.new(@css)
9
9
  end
10
10
 
11
11
  context 'add_attribute_conditions' do
@@ -4,7 +4,7 @@ require 'spec_helper'
4
4
 
5
5
  RSpec.describe Capybara::Selector::CSS::Splitter do
6
6
  let :splitter do
7
- ::Capybara::Selector::CSS::Splitter.new
7
+ described_class.new
8
8
  end
9
9
 
10
10
  context 'split not needed' do
data/spec/dsl_spec.rb CHANGED
@@ -15,6 +15,8 @@ Capybara::SpecHelper.run_specs TestClass.new, 'DSL', capybara_skip: %i[
15
15
  pending "Nokogiri doesn't support case insensitive CSS attribute matchers"
16
16
  when /#click_button should follow permanent redirects that maintain method/
17
17
  pending "Rack < 2 doesn't support 308" if Gem.loaded_specs['rack'].version < Gem::Version.new('2.0.0')
18
+ when /#attach_file with multipart form should send prior hidden field if no file submitted/
19
+ skip 'Rack-test < 2 needs an empty file to detect multipart form' if Gem.loaded_specs['rack-test'].version < Gem::Version.new('2.0.0')
18
20
  end
19
21
  end
20
22
 
@@ -15,6 +15,10 @@ class MinitestTest < Minitest::Test
15
15
  Capybara.reset_sessions!
16
16
  end
17
17
 
18
+ def self.test_order
19
+ :sorted
20
+ end
21
+
18
22
  def test_assert_text
19
23
  assert_text('Form', normalize_ws: false)
20
24
  assert_no_text('Not on the page')
@@ -16,6 +16,10 @@ class MinitestSpecTest < Minitest::Spec
16
16
  Capybara.reset_sessions!
17
17
  end
18
18
 
19
+ def self.test_order
20
+ :sorted
21
+ end
22
+
19
23
  it 'supports text expectations' do
20
24
  _(page).must_have_text('Form', minimum: 1)
21
25
  _(page).wont_have_text('Not a form')
@@ -12,7 +12,7 @@ RSpec.describe Capybara::SessionConfig do
12
12
  default_selector default_max_wait_time ignore_hidden_elements
13
13
  automatic_reload match exact raise_server_errors visible_text_only
14
14
  automatic_label_click enable_aria_label save_path
15
- asset_host].each do |m|
15
+ asset_host default_retry_interval].each do |m|
16
16
  expect(session.config.public_send(m)).to eq Capybara.public_send(m)
17
17
  end
18
18
  end
@@ -30,6 +30,8 @@ Capybara::SpecHelper.run_specs TestSessions::RackTest, 'RackTest', capybara_skip
30
30
  skip "Nokogiri doesn't support case insensitive CSS attribute matchers"
31
31
  when /#click_button should follow permanent redirects that maintain method/
32
32
  skip "Rack < 2 doesn't support 308" if Gem.loaded_specs['rack'].version < Gem::Version.new('2.0.0')
33
+ when /#attach_file with multipart form should send prior hidden field if no file submitted/
34
+ skip 'Rack-test < 2 needs an empty file to detect multipart form' if Gem.loaded_specs['rack-test'].version < Gem::Version.new('2.0.0')
33
35
  end
34
36
  end
35
37
 
@@ -93,6 +95,12 @@ RSpec.describe Capybara::Session do # rubocop:disable RSpec/MultipleDescribes
93
95
  session.click_button('Upload Empty')
94
96
  expect(session.html).to include('Successfully ignored empty file field.')
95
97
  end
98
+
99
+ it 'should submit multipart even if no file is submitted' do
100
+ session.visit('/form')
101
+ session.click_button('Upload Empty')
102
+ expect(session.html).to include('Content type was multipart/form-data;')
103
+ end
96
104
  end
97
105
 
98
106
  it 'should not submit an obsolete mime type' do
@@ -212,7 +220,7 @@ RSpec.describe Capybara::RackTest::Driver do
212
220
  driver = described_class.new(TestApp)
213
221
 
214
222
  driver.visit('/redirect')
215
- expect(driver.response.header['Location']).to be_nil
223
+ expect(driver.response.headers['Location']).to be_nil
216
224
  expect(driver.current_url).to match %r{/landed$}
217
225
  end
218
226
 
@@ -226,7 +234,7 @@ RSpec.describe Capybara::RackTest::Driver do
226
234
  driver = described_class.new(TestApp, follow_redirects: false)
227
235
 
228
236
  driver.visit('/redirect')
229
- expect(driver.response.header['Location']).to match %r{/redirect_again$}
237
+ expect(driver.response.headers['Location']).to match %r{/redirect_again$}
230
238
  expect(driver.current_url).to match %r{/redirect$}
231
239
  end
232
240
  end
@@ -16,7 +16,7 @@ feature 'if fscenario aliases focused tag then' do
16
16
  end
17
17
 
18
18
  feature 'if xscenario aliases to pending then' do
19
- xscenario "this test should be 'temporarily disabled with xscenario'" do
19
+ xscenario "this test should be 'temporarily disabled with xscenario'" do # rubocop:disable RSpec/PendingWithoutReason
20
20
  end
21
21
  end
22
22
 
@@ -120,7 +120,7 @@ RSpec.shared_examples Capybara::RSpecMatchers do |session, _mode|
120
120
 
121
121
  describe 'have_xpath matcher' do
122
122
  it 'gives proper description' do
123
- expect(have_xpath('//h1').description).to eq("have visible xpath \"\/\/h1\"")
123
+ expect(have_xpath('//h1').description).to eq('have visible xpath "//h1"')
124
124
  end
125
125
 
126
126
  context 'on a string' do
@@ -56,6 +56,31 @@ RSpec.describe 'Capybara RSpec Matchers', type: :feature do
56
56
  end
57
57
  end
58
58
 
59
+ context 'with a filter block' do
60
+ it 'applies the filter' do
61
+ visit('/with_html')
62
+ expect(page).to have_selector(:css, 'input#test_field')
63
+
64
+ expect(page).to have_selector(:css, 'input', count: 1) { |input| input.value == 'monkey' }
65
+ expect(page).to have_selector(:css, 'input', count: 1) do |input|
66
+ input.value == 'monkey'
67
+ end
68
+ expect(page).to have_no_selector(:css, 'input#test_field') { |input| input.value == 'not a monkey' }
69
+ expect(page).to have_no_selector(:css, 'input#test_field') do |input|
70
+ input.value == 'not a monkey'
71
+ end
72
+
73
+ expect(page).not_to have_selector(:css, 'input#test_field') { |input| input.value == 'not a monkey' }
74
+ expect(page).not_to have_selector(:css, 'input#test_field') do |input|
75
+ input.value == 'not a monkey'
76
+ end
77
+ expect(page).not_to have_no_selector(:css, 'input', count: 1) { |input| input.value == 'monkey' }
78
+ expect(page).not_to have_no_selector(:css, 'input#test_field', count: 1) do |input|
79
+ input.value == 'monkey'
80
+ end
81
+ end
82
+ end
83
+
59
84
  def error_msg_for(&block)
60
85
  expect(&block).to(raise_error { |e| return e.message })
61
86
  end
data/spec/rspec_spec.rb CHANGED
@@ -15,7 +15,7 @@ RSpec.describe 'capybara/rspec' do
15
15
  expect(self.class.ancestors).to include Capybara::RSpecMatcherProxies
16
16
  end
17
17
 
18
- context 'resetting session' do
18
+ context 'resetting session', order: :defined do
19
19
  it 'sets a cookie in one example...' do
20
20
  visit('/set_cookie')
21
21
  expect(page.body).to include('Cookie set to test_cookie')
@@ -27,7 +27,7 @@ RSpec.describe 'capybara/rspec' do
27
27
  end
28
28
  end
29
29
 
30
- context 'setting the current driver' do
30
+ context 'setting the current driver', order: :defined do
31
31
  it 'sets the current driver in one example...' do
32
32
  Capybara.current_driver = :selenium
33
33
  end
@@ -27,7 +27,7 @@ Capybara.register_driver :sauce_chrome do |app|
27
27
 
28
28
  Capybara::Selenium::Driver.new(app,
29
29
  browser: :remote, url: url,
30
- desired_capabilities: capabilities,
30
+ capabilities: capabilities,
31
31
  options: Selenium::WebDriver::Chrome::Options.new(args: ['']))
32
32
  end
33
33
 
@@ -111,13 +111,13 @@ RSpec.describe Capybara do
111
111
  end
112
112
 
113
113
  describe 'adding a selector' do
114
- it 'can set default visiblity' do
114
+ it 'can set default visibility' do
115
115
  described_class.add_selector :hidden_field do
116
116
  visible :hidden
117
117
  css { |_sel| 'input[type="hidden"]' }
118
118
  end
119
119
 
120
- expect(string).to have_no_css('input[type="hidden"]')
120
+ expect(string).to have_no_css('input[type="hidden"]') # rubocop:disable RSpec/Capybara/SpecificMatcher
121
121
  expect(string).to have_selector(:hidden_field)
122
122
  end
123
123
  end
@@ -10,8 +10,8 @@ CHROME_DRIVER = :selenium_chrome
10
10
 
11
11
  Selenium::WebDriver::Chrome.path = '/usr/bin/google-chrome-beta' if ENV.fetch('CI', nil) && ENV.fetch('CHROME_BETA', nil)
12
12
 
13
- browser_options = ::Selenium::WebDriver::Chrome::Options.new
14
- browser_options.headless! if ENV['HEADLESS']
13
+ browser_options = Selenium::WebDriver::Chrome::Options.new
14
+ browser_options.add_argument('--headless') if ENV['HEADLESS']
15
15
 
16
16
  # Chromedriver 77 requires setting this for headless mode on linux
17
17
  # Different versions of Chrome/selenium-webdriver require setting differently - jus set them all
@@ -85,6 +85,11 @@ Capybara::SpecHelper.run_specs TestSessions::Chrome, CHROME_DRIVER.to_s, capybar
85
85
  skip 'Need to figure out testing of file downloading on windows platform' if Gem.win_platform?
86
86
  when /Capybara::Session selenium_chrome Capybara::Window#maximize/
87
87
  pending "Chrome headless doesn't support maximize" if ENV['HEADLESS']
88
+ when /Capybara::Session selenium_chrome node #shadow_root should get visible text/
89
+ pending "Selenium doesn't currently support getting visible text for shadow root elements"
90
+ when /Capybara::Session selenium_chrome node #shadow_root/
91
+ skip 'Not supported with this Selenium version' if selenium_lt?('4.1', @session)
92
+ skip 'Not supported with this chromedriver version' if chromedriver_lt?('96.0', @session)
88
93
  end
89
94
  end
90
95
 
@@ -199,8 +204,4 @@ RSpec.describe 'Capybara::Session with chrome' do
199
204
  end.not_to raise_error
200
205
  end
201
206
  end
202
-
203
- def chromedriver_version
204
- Gem::Version.new(session.driver.browser.capabilities['chrome']['chromedriverVersion'].split[0])
205
- end
206
207
  end
@@ -21,8 +21,8 @@ def ensure_selenium_running!
21
21
  rescue StandardError
22
22
  if timer.expired?
23
23
  raise 'Selenium is not running. ' \
24
- "You can run a selenium server easily with: \n" \
25
- ' $ docker-compose up -d selenium_chrome'
24
+ "You can run a selenium server easily with: \n " \
25
+ '$ docker-compose up -d selenium_chrome'
26
26
  else
27
27
  puts 'Waiting for Selenium docker instance...'
28
28
  sleep 1
@@ -39,11 +39,10 @@ Capybara.register_driver :selenium_chrome_remote do |app|
39
39
  ensure_selenium_running!
40
40
 
41
41
  url = "http://#{selenium_host}:#{selenium_port}/wd/hub"
42
- browser_options = ::Selenium::WebDriver::Chrome::Options.new
42
+ browser_options = Selenium::WebDriver::Chrome::Options.new
43
43
 
44
44
  Capybara::Selenium::Driver.new app,
45
45
  browser: :remote,
46
- desired_capabilities: :chrome,
47
46
  options: browser_options,
48
47
  url: url
49
48
  end
@@ -62,6 +61,11 @@ Capybara::SpecHelper.run_specs TestSessions::Chrome, CHROME_REMOTE_DRIVER.to_s,
62
61
  'Capybara::Session selenium_chrome_remote #attach_file with multipart form should fire change once for each set of files uploaded',
63
62
  'Capybara::Session selenium_chrome_remote #attach_file with multipart form should fire change once when uploading multiple files from empty'
64
63
  pending "Selenium with Remote Chrome doesn't support multiple file upload" unless selenium_gte?(3.14)
64
+ when /Capybara::Session selenium_chrome_remote node #shadow_root should get visible text/
65
+ pending "Selenium doesn't currently support getting visible text for shadow root elements"
66
+ when /Capybara::Session selenium_chrome_remote node #shadow_root/
67
+ skip 'Not supported with this Selenium version' if selenium_lt?('4.1', @session)
68
+ skip 'Not supported with this chromedriver version' if chromedriver_lt?('96.0', @session)
65
69
  end
66
70
  end
67
71
 
@@ -94,8 +98,4 @@ RSpec.describe 'Capybara::Session with remote Chrome' do
94
98
  end.not_to raise_error
95
99
  end
96
100
  end
97
-
98
- def chromedriver_version
99
- Gem::Version.new(session.driver.browser.capabilities['chrome']['chromedriverVersion'].split[0])
100
- end
101
101
  end
@@ -10,15 +10,17 @@ require 'rspec/shared_spec_matchers'
10
10
  # Selenium::WebDriver::Edge::Service.driver_path = '/usr/local/bin/msedgedriver'
11
11
  # end
12
12
 
13
- if ::Selenium::WebDriver::Platform.mac?
14
- Selenium::WebDriver::EdgeChrome.path = '/Applications/Microsoft Edge Dev.app/Contents/MacOS/Microsoft Edge Dev'
13
+ if Selenium::WebDriver::Platform.mac?
14
+ Selenium::WebDriver::Edge.path = '/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge'
15
15
  end
16
16
 
17
17
  Capybara.register_driver :selenium_edge do |app|
18
18
  # ::Selenium::WebDriver.logger.level = "debug"
19
19
  # If we don't create an options object the path set above won't be used
20
- browser_options = ::Selenium::WebDriver::EdgeChrome::Options.new
21
- Capybara::Selenium::Driver.new(app, browser: :edge_chrome, options: browser_options).tap do |driver|
20
+ browser_options = Selenium::WebDriver::Edge::Options.new
21
+ browser_options.add_argument('--headless') if ENV['HEADLESS']
22
+
23
+ Capybara::Selenium::Driver.new(app, browser: :edge, options: browser_options).tap do |driver|
22
24
  driver.browser
23
25
  driver.download_path = Capybara.save_path
24
26
  end
@@ -30,12 +32,16 @@ end
30
32
 
31
33
  skipped_tests = %i[response_headers status_code trigger]
32
34
 
33
- Capybara::SpecHelper.log_selenium_driver_version(Selenium::WebDriver::EdgeChrome) if ENV['CI']
35
+ Capybara::SpecHelper.log_selenium_driver_version(Selenium::WebDriver::Edge) if ENV['CI']
34
36
 
35
37
  Capybara::SpecHelper.run_specs TestSessions::SeleniumEdge, 'selenium', capybara_skip: skipped_tests do |example|
36
38
  case example.metadata[:full_description]
37
39
  when 'Capybara::Session selenium #attach_file with a block can upload by clicking the file input'
38
- pending "EdgeChrome doesn't allow clicking on file inputs"
40
+ pending "Edge doesn't allow clicking on file inputs"
41
+ when /Capybara::Session selenium node #shadow_root should get visible text/
42
+ pending "Selenium doesn't currently support getting visible text for shadow root elements"
43
+ when /Capybara::Session selenium Capybara::Window#maximize/
44
+ pending "Edge headless doesn't support maximize" if ENV['HEADLESS']
39
45
  end
40
46
  end
41
47
 
@@ -6,7 +6,7 @@ require 'shared_selenium_session'
6
6
  require 'shared_selenium_node'
7
7
  require 'rspec/shared_spec_matchers'
8
8
 
9
- browser_options = ::Selenium::WebDriver::Firefox::Options.new
9
+ browser_options = Selenium::WebDriver::Firefox::Options.new
10
10
  browser_options.headless! if ENV['HEADLESS']
11
11
  # browser_options.add_option("log", {"level": "trace"})
12
12
 
@@ -62,20 +62,32 @@ Capybara::SpecHelper.run_specs TestSessions::SeleniumFirefox, 'selenium', capyba
62
62
  when 'Capybara::Session selenium #accept_confirm should work with nested modals'
63
63
  skip 'Broken in 63 <= FF < 69 - https://bugzilla.mozilla.org/show_bug.cgi?id=1487358' if firefox_gte?(63, @session) && firefox_lt?(69, @session)
64
64
  skip 'Hangs in 69 <= FF < 71 - Dont know what issue for this - previous issue was closed as fixed but it is not' if firefox_gte?(69, @session) && firefox_lt?(71, @session)
65
- skip 'Broken again intermittently in FF 71 - jus skip it'
65
+ skip 'Broken again intermittently in FF 71 - jus skip it' if firefox_lt?(109, @session) # don't really know when it was fixed
66
66
  when 'Capybara::Session selenium #click_link can download a file'
67
67
  skip 'Need to figure out testing of file downloading on windows platform' if Gem.win_platform?
68
68
  when 'Capybara::Session selenium #reset_session! removes ALL cookies'
69
69
  pending "Geckodriver doesn't provide a way to remove cookies outside the current domain"
70
70
  when /drag_to.*HTML5/
71
- pending "Firefox < 62 doesn't support a DataTransfer constuctor" if firefox_lt?(62.0, @session)
71
+ pending "Firefox < 62 doesn't support a DataTransfer constructor" if firefox_lt?(62.0, @session)
72
72
  when 'Capybara::Session selenium #accept_alert should handle the alert if the page changes',
73
73
  'Capybara::Session selenium #accept_alert with an asynchronous alert should accept the alert'
74
- skip 'No clue what Firefox is doing here - works fine on MacOS locally'
75
- when 'Capybara::Session selenium node #shadow_root should get the shadow root',
76
- 'Capybara::Session selenium node #shadow_root should find elements inside the shadow dom using CSS',
77
- 'Capybara::Session selenium node #shadow_root should find nested shadow roots'
78
- pending "Firefox doesn't yet have W3C shadow root support"
74
+ skip 'No clue what Firefox is doing here - works fine on MacOS locally' if firefox_lt?(109, @session) # don't really know when it was fixed
75
+ when 'Capybara::Session selenium node #shadow_root should find elements inside the shadow dom using CSS',
76
+ 'Capybara::Session selenium node #shadow_root should find nested shadow roots',
77
+ 'Capybara::Session selenium node #shadow_root should click on elements',
78
+ 'Capybara::Session selenium node #shadow_root should use convenience methods once moved to a descendant of the shadow root',
79
+ 'Capybara::Session selenium node #shadow_root should produce error messages when failing',
80
+ 'Capybara::Session with firefox with selenium driver #evaluate_script returns a shadow root'
81
+ pending "Firefox doesn't yet have full W3C shadow root support"
82
+ when 'Capybara::Session selenium #fill_in should handle carriage returns with line feeds in a textarea correctly'
83
+ pending 'Not sure what firefox is doing here'
84
+ when /Capybara::Session selenium node #shadow_root should get visible text/
85
+ pending "Selenium doesn't currently support getting visible text for shadow root elements"
86
+ when /Capybara::Session selenium node #shadow_root/
87
+ skip 'Not supported with this Selenium version' if selenium_lt?('4.1', @session)
88
+ skip 'Not supported with this geckodriver version' if geckodriver_lt?('0.31.0', @session)
89
+ when /Capybara::Session selenium node #set should submit single text input forms if ended with \\n/
90
+ pending 'Firefox/geckodriver doesn\'t submit with values ending in \n'
79
91
  end
80
92
  end
81
93