capybara 3.30.0 → 3.31.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +21 -0
  3. data/README.md +1 -1
  4. data/lib/capybara/dsl.rb +10 -2
  5. data/lib/capybara/minitest.rb +18 -4
  6. data/lib/capybara/node/element.rb +11 -8
  7. data/lib/capybara/node/finders.rb +5 -1
  8. data/lib/capybara/node/matchers.rb +24 -15
  9. data/lib/capybara/node/simple.rb +1 -1
  10. data/lib/capybara/queries/base_query.rb +2 -1
  11. data/lib/capybara/rack_test/node.rb +34 -9
  12. data/lib/capybara/result.rb +24 -4
  13. data/lib/capybara/rspec/matchers.rb +27 -27
  14. data/lib/capybara/rspec/matchers/base.rb +12 -6
  15. data/lib/capybara/rspec/matchers/count_sugar.rb +2 -1
  16. data/lib/capybara/rspec/matchers/have_ancestor.rb +4 -3
  17. data/lib/capybara/rspec/matchers/have_current_path.rb +2 -2
  18. data/lib/capybara/rspec/matchers/have_selector.rb +15 -7
  19. data/lib/capybara/rspec/matchers/have_sibling.rb +3 -3
  20. data/lib/capybara/rspec/matchers/have_text.rb +2 -2
  21. data/lib/capybara/rspec/matchers/have_title.rb +2 -2
  22. data/lib/capybara/rspec/matchers/match_selector.rb +3 -3
  23. data/lib/capybara/rspec/matchers/match_style.rb +2 -2
  24. data/lib/capybara/rspec/matchers/spatial_sugar.rb +2 -1
  25. data/lib/capybara/selector.rb +2 -0
  26. data/lib/capybara/selector/definition/label.rb +1 -1
  27. data/lib/capybara/selector/definition/select.rb +31 -12
  28. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +1 -1
  29. data/lib/capybara/selenium/extensions/html5_drag.rb +24 -8
  30. data/lib/capybara/selenium/node.rb +23 -6
  31. data/lib/capybara/selenium/nodes/chrome_node.rb +4 -2
  32. data/lib/capybara/selenium/nodes/edge_node.rb +1 -1
  33. data/lib/capybara/selenium/nodes/firefox_node.rb +1 -1
  34. data/lib/capybara/session.rb +30 -15
  35. data/lib/capybara/spec/public/test.js +40 -6
  36. data/lib/capybara/spec/session/all_spec.rb +45 -5
  37. data/lib/capybara/spec/session/assert_text_spec.rb +5 -5
  38. data/lib/capybara/spec/session/fill_in_spec.rb +20 -0
  39. data/lib/capybara/spec/session/has_css_spec.rb +3 -3
  40. data/lib/capybara/spec/session/has_select_spec.rb +28 -0
  41. data/lib/capybara/spec/session/has_text_spec.rb +5 -1
  42. data/lib/capybara/spec/session/node_spec.rb +92 -3
  43. data/lib/capybara/spec/views/form.erb +6 -1
  44. data/lib/capybara/version.rb +1 -1
  45. data/spec/rack_test_spec.rb +0 -1
  46. data/spec/result_spec.rb +4 -0
  47. data/spec/selenium_spec_chrome.rb +2 -1
  48. metadata +2 -2
@@ -95,6 +95,26 @@ Capybara::SpecHelper.spec '#fill_in' do
95
95
  expect(extract_results(@session)['html5_color']).to eq('#112233')
96
96
  end
97
97
 
98
+ describe 'with input[type="range"]' do
99
+ it 'should set the range slider correctly' do
100
+ @session.fill_in('form_age', with: 51)
101
+ @session.click_button('awesome')
102
+ expect(extract_results(@session)['age'].to_f).to eq 51
103
+ end
104
+
105
+ it 'should set the range slider to valid values' do
106
+ @session.fill_in('form_age', with: '37.6')
107
+ @session.click_button('awesome')
108
+ expect(extract_results(@session)['age'].to_f).to eq 37.5
109
+ end
110
+
111
+ it 'should respect the range slider limits' do
112
+ @session.fill_in('form_age', with: '3')
113
+ @session.click_button('awesome')
114
+ expect(extract_results(@session)['age'].to_f).to eq 13
115
+ end
116
+ end
117
+
98
118
  it 'should fill in a field with a custom type' do
99
119
  @session.fill_in('Schmooo', with: 'Schmooo is the game')
100
120
  @session.click_button('awesome')
@@ -185,10 +185,10 @@ Capybara::SpecHelper.spec '#has_css?' do
185
185
  end
186
186
 
187
187
  it 'should be false when content occurs more times than given' do
188
- expect(@session).not_to have_css('h2.head', maximum: 4) # edge case
189
- expect(@session).not_to have_css('h2', maximum: 3)
188
+ # expect(@session).not_to have_css('h2.head', maximum: 4) # edge case
189
+ # expect(@session).not_to have_css('h2', maximum: 3)
190
190
  expect(@session).not_to have_css('h2').at_most(3).times
191
- expect(@session).not_to have_css('p', maximum: 1)
191
+ # expect(@session).not_to have_css('p', maximum: 1)
192
192
  end
193
193
 
194
194
  it 'should coerce maximum to an integer' do
@@ -117,6 +117,34 @@ Capybara::SpecHelper.spec '#has_select?' do
117
117
  end
118
118
  end
119
119
 
120
+ context 'with enabled options' do
121
+ it 'should be true if the listed options exist and are enabled' do
122
+ expect(@session).to have_select('form_title', enabled_options: %w[Mr Mrs Miss])
123
+ end
124
+
125
+ it 'should be false if the listed options do not exist' do
126
+ expect(@session).not_to have_select('form_title', enabled_options: ['Not there'])
127
+ end
128
+
129
+ it 'should be false if the listed option exists but is not enabled' do
130
+ expect(@session).not_to have_select('form_title', enabled_options: %w[Mr Mrs Miss Other])
131
+ end
132
+ end
133
+
134
+ context 'with disabled options' do
135
+ it 'should be true if the listed options exist and are disabled' do
136
+ expect(@session).to have_select('form_title', disabled_options: ['Other'])
137
+ end
138
+
139
+ it 'should be false if the listed options do not exist' do
140
+ expect(@session).not_to have_select('form_title', disabled_options: ['Not there'])
141
+ end
142
+
143
+ it 'should be false if the listed option exists but is not disabled' do
144
+ expect(@session).not_to have_select('form_title', disabled_options: %w[Other Mrs])
145
+ end
146
+ end
147
+
120
148
  context 'with partial options' do
121
149
  it 'should be true if a field with the given partial options is on the page' do
122
150
  expect(@session).to have_select('Region', with_options: %w[Norway Sweden])
@@ -127,7 +127,11 @@ Capybara::SpecHelper.spec '#has_text?' do
127
127
  def to_hash; { value: 'Other hash' } end
128
128
  end.new
129
129
  @session.visit('/with_html')
130
- expect(@session).to have_text(:visible, with_to_hash, {})
130
+ if RUBY_VERSION >= '2.7'
131
+ expect(@session).to have_text(:visible, with_to_hash, **{})
132
+ else
133
+ expect(@session).to have_text(:visible, with_to_hash, {})
134
+ end
131
135
  end
132
136
 
133
137
  it 'should fail if passed without empty options' do
@@ -270,11 +270,11 @@ Capybara::SpecHelper.spec 'node' do
270
270
  end
271
271
 
272
272
  it 'works when details is toggled open and closed' do
273
- @session.find(:css, '#closed_details').click
273
+ @session.find(:css, '#closed_details > summary').click
274
274
  expect(@session).to have_css('#closed_details *', visible: true, count: 5)
275
275
  .and(have_no_css('#closed_details *', visible: :hidden))
276
276
 
277
- @session.find(:css, '#closed_details').click
277
+ @session.find(:css, '#closed_details > summary').click
278
278
  descendants_css = '#closed_details > *:not(summary), #closed_details > *:not(summary) *'
279
279
  expect(@session).to have_no_css(descendants_css, visible: true)
280
280
  .and(have_css(descendants_css, visible: :hidden, count: 3))
@@ -468,6 +468,50 @@ Capybara::SpecHelper.spec 'node' do
468
468
  end
469
469
  end
470
470
 
471
+ it 'should simulate a single held down modifier key' do
472
+ %I[
473
+ alt
474
+ ctrl
475
+ meta
476
+ shift
477
+ ].each do |modifier_key|
478
+ @session.visit('/with_js')
479
+
480
+ element = @session.find('//div[@id="drag"]')
481
+ target = @session.find('//div[@id="drop"]')
482
+
483
+ element.drag_to(target, drop_modifiers: modifier_key)
484
+ expect(@session).to have_css('div.drag_start', exact_text: 'Dragged!')
485
+ expect(@session).to have_xpath("//div[contains(., 'Dropped!-#{modifier_key}')]")
486
+ end
487
+ end
488
+
489
+ it 'should simulate multiple held down modifier keys' do
490
+ @session.visit('/with_js')
491
+
492
+ element = @session.find('//div[@id="drag"]')
493
+ target = @session.find('//div[@id="drop"]')
494
+
495
+ modifier_keys = %I[alt ctrl meta shift]
496
+
497
+ element.drag_to(target, drop_modifiers: modifier_keys)
498
+ expect(@session).to have_xpath("//div[contains(., 'Dropped!-#{modifier_keys.join('-')}')]")
499
+ end
500
+
501
+ it 'should support key aliases' do
502
+ { control: :ctrl,
503
+ command: :meta,
504
+ cmd: :meta }.each do |(key_alias, key)|
505
+ @session.visit('/with_js')
506
+
507
+ element = @session.find('//div[@id="drag"]')
508
+ target = @session.find('//div[@id="drop"]')
509
+
510
+ element.drag_to(target, drop_modifiers: [key_alias])
511
+ expect(target).to have_text("Dropped!-#{key}", exact: true)
512
+ end
513
+ end
514
+
471
515
  context 'HTML5', requires: %i[js html5_drag] do
472
516
  it 'should HTML5 drag and drop an object' do
473
517
  @session.visit('/with_js')
@@ -499,8 +543,13 @@ Capybara::SpecHelper.spec 'node' do
499
543
  target = @session.find('//div[@id="drop_html5"]')
500
544
  element.drag_to(target)
501
545
 
546
+ conditions = %w[DragLeave Drop DragEnd].map do |text|
547
+ have_css('div.log', text: text)
548
+ end
549
+ expect(@session).to(conditions.reduce { |memo, cond| memo.and(cond) })
550
+
502
551
  # The first "DragOver" div is inserted by the last dragover event dispatched
503
- drag_over_div = @session.find('//div[@class="log" and starts-with(text(), "DragOver")]', match: :first)
552
+ drag_over_div = @session.first('//div[@class="log" and starts-with(text(), "DragOver")]')
504
553
  position = drag_over_div.text.sub('DragOver ', '')
505
554
 
506
555
  expect(@session).to have_css('div.log', text: /DragLeave #{position}/, count: 1)
@@ -551,6 +600,46 @@ Capybara::SpecHelper.spec 'node' do
551
600
  source.drag_to target
552
601
  expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped")]')
553
602
  end
603
+
604
+ it 'should simulate a single held down modifier key' do
605
+ %I[alt ctrl meta shift].each do |modifier_key|
606
+ @session.visit('/with_js')
607
+
608
+ element = @session.find('//div[@id="drag_html5"]')
609
+ target = @session.find('//div[@id="drop_html5"]')
610
+
611
+ element.drag_to(target, drop_modifiers: modifier_key)
612
+
613
+ expect(@session).to have_css('div.drag_start', exact_text: 'HTML5 Dragged!')
614
+ expect(@session).to have_xpath("//div[contains(., 'HTML5 Dropped string: text/plain drag_html5-#{modifier_key}')]")
615
+ end
616
+ end
617
+
618
+ it 'should simulate multiple held down modifier keys' do
619
+ @session.visit('/with_js')
620
+
621
+ element = @session.find('//div[@id="drag_html5"]')
622
+ target = @session.find('//div[@id="drop_html5"]')
623
+
624
+ modifier_keys = %I[alt ctrl meta shift]
625
+
626
+ element.drag_to(target, drop_modifiers: modifier_keys)
627
+ expect(@session).to have_xpath("//div[contains(., 'HTML5 Dropped string: text/plain drag_html5-#{modifier_keys.join('-')}')]")
628
+ end
629
+
630
+ it 'should support key aliases' do
631
+ { control: :ctrl,
632
+ command: :meta,
633
+ cmd: :meta }.each do |(key_alias, key)|
634
+ @session.visit('/with_js')
635
+
636
+ element = @session.find('//div[@id="drag_html5"]')
637
+ target = @session.find('//div[@id="drop_html5"]')
638
+
639
+ element.drag_to(target, drop_modifiers: [key_alias])
640
+ expect(target).to have_text(%r{^HTML5 Dropped string: text/plain drag_html5-#{key}$}m, exact: true)
641
+ end
642
+ end
554
643
  end
555
644
  end
556
645
 
@@ -11,7 +11,7 @@
11
11
  <option>Miss</option>
12
12
  <option disabled="disabled">Other</option>
13
13
  </select>
14
- </p>
14
+ </p>
15
15
 
16
16
  <p>
17
17
  <label for="customer_name">Customer Name
@@ -62,6 +62,11 @@
62
62
  <input type="text" name="form[name]" value="John Smith" id="form_name"/>
63
63
  </p>
64
64
 
65
+ <p>
66
+ <label for="form_age">Age</label>
67
+ <input type="range" name="form[age]" value="18" min="13" max="100" step="0.5" id="form_age"/>
68
+ </p>
69
+
65
70
  <p>
66
71
  <label for="form_schmooo">Schmooo</label>
67
72
  <input type="schmooo" name="form[schmooo]" value="This is Schmooo!" id="form_schmooo"/>
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Capybara
4
- VERSION = '3.30.0'
4
+ VERSION = '3.31.0'
5
5
  end
@@ -82,7 +82,6 @@ RSpec.describe Capybara::Session do # rubocop:disable RSpec/MultipleDescribes
82
82
  describe '#fill_in' do
83
83
  it 'should warn that :fill_options are not supported' do
84
84
  session.visit '/with_html'
85
-
86
85
  expect { session.fill_in 'test_field', with: 'not_monkey', fill_options: { random: true } }.to \
87
86
  output(/^Options passed to Node#set but the RackTest driver doesn't support any - ignoring/).to_stderr
88
87
  expect(session).to have_field('test_field', with: 'not_monkey')
@@ -78,6 +78,10 @@ RSpec.describe Capybara::Result do
78
78
  eval <<~TEST, binding, __FILE__, __LINE__ + 1 if RUBY_VERSION.to_f > 2.5
79
79
  expect(result[2..].map(&:text)).to eq %w[Gamma Delta]
80
80
  TEST
81
+ eval <<~TEST, binding, __FILE__, __LINE__ + 1 if RUBY_VERSION.to_f > 2.6
82
+ expect(result[..2].map(&:text)).to eq %w[Alpha Beta Gamma]
83
+ expect(result[...2].map(&:text)).to eq %w[Alpha Beta]
84
+ TEST
81
85
  end
82
86
 
83
87
  it 'works with filter blocks' do
@@ -14,7 +14,8 @@ browser_options = ::Selenium::WebDriver::Chrome::Options.new
14
14
  browser_options.headless! if ENV['HEADLESS']
15
15
  browser_options.add_option(:w3c, ENV['W3C'] != 'false')
16
16
  # Chromedriver 77 requires setting this for headless mode on linux
17
- # browser_options.add_preference('download.default_directory', Capybara.save_path)
17
+ # Different versions of Chrome/selenium-webdriver require setting differently - jus set them all
18
+ browser_options.add_preference('download.default_directory', Capybara.save_path)
18
19
  browser_options.add_preference(:download, default_directory: Capybara.save_path)
19
20
 
20
21
  Capybara.register_driver :selenium_chrome do |app|
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capybara
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.30.0
4
+ version: 3.31.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Walpole
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain:
12
12
  - gem-public_cert.pem
13
- date: 2019-12-25 00:00:00.000000000 Z
13
+ date: 2020-01-26 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: addressable