capybara 3.31.0 → 3.34.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +93 -13
  3. data/README.md +9 -4
  4. data/lib/capybara.rb +18 -8
  5. data/lib/capybara/config.rb +4 -6
  6. data/lib/capybara/cucumber.rb +1 -1
  7. data/lib/capybara/driver/base.rb +4 -0
  8. data/lib/capybara/helpers.rb +25 -1
  9. data/lib/capybara/minitest.rb +215 -141
  10. data/lib/capybara/minitest/spec.rb +156 -97
  11. data/lib/capybara/node/actions.rb +16 -21
  12. data/lib/capybara/node/element.rb +3 -5
  13. data/lib/capybara/node/finders.rb +7 -6
  14. data/lib/capybara/node/matchers.rb +11 -11
  15. data/lib/capybara/node/simple.rb +5 -1
  16. data/lib/capybara/queries/ancestor_query.rb +1 -1
  17. data/lib/capybara/queries/current_path_query.rb +14 -4
  18. data/lib/capybara/queries/selector_query.rb +16 -10
  19. data/lib/capybara/queries/sibling_query.rb +1 -1
  20. data/lib/capybara/queries/style_query.rb +1 -1
  21. data/lib/capybara/queries/text_query.rb +7 -1
  22. data/lib/capybara/rack_test/browser.rb +9 -3
  23. data/lib/capybara/rack_test/driver.rb +1 -0
  24. data/lib/capybara/rack_test/form.rb +1 -1
  25. data/lib/capybara/rack_test/node.rb +1 -1
  26. data/lib/capybara/registration_container.rb +44 -0
  27. data/lib/capybara/registrations/patches/puma_ssl.rb +3 -1
  28. data/lib/capybara/registrations/servers.rb +2 -1
  29. data/lib/capybara/result.rb +8 -8
  30. data/lib/capybara/rspec.rb +2 -0
  31. data/lib/capybara/rspec/matcher_proxies.rb +5 -5
  32. data/lib/capybara/rspec/matchers.rb +7 -6
  33. data/lib/capybara/rspec/matchers/have_current_path.rb +2 -2
  34. data/lib/capybara/rspec/matchers/have_text.rb +1 -1
  35. data/lib/capybara/rspec/matchers/match_style.rb +5 -0
  36. data/lib/capybara/selector.rb +10 -1
  37. data/lib/capybara/selector/definition.rb +11 -9
  38. data/lib/capybara/selector/definition/button.rb +8 -5
  39. data/lib/capybara/selector/definition/css.rb +1 -1
  40. data/lib/capybara/selector/definition/datalist_input.rb +1 -1
  41. data/lib/capybara/selector/definition/element.rb +2 -1
  42. data/lib/capybara/selector/definition/fillable_field.rb +1 -1
  43. data/lib/capybara/selector/definition/label.rb +1 -1
  44. data/lib/capybara/selector/definition/link.rb +8 -0
  45. data/lib/capybara/selector/definition/select.rb +1 -1
  46. data/lib/capybara/selector/definition/table.rb +1 -1
  47. data/lib/capybara/selector/definition/table_row.rb +1 -1
  48. data/lib/capybara/selector/filter_set.rb +2 -2
  49. data/lib/capybara/selector/selector.rb +9 -1
  50. data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -1
  51. data/lib/capybara/selenium/atoms/src/getAttribute.js +1 -1
  52. data/lib/capybara/selenium/driver.rb +35 -6
  53. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +9 -11
  54. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +9 -11
  55. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +3 -3
  56. data/lib/capybara/selenium/extensions/find.rb +3 -3
  57. data/lib/capybara/selenium/extensions/scroll.rb +8 -10
  58. data/lib/capybara/selenium/node.rb +75 -12
  59. data/lib/capybara/selenium/nodes/chrome_node.rb +20 -11
  60. data/lib/capybara/selenium/nodes/firefox_node.rb +2 -2
  61. data/lib/capybara/selenium/nodes/safari_node.rb +1 -1
  62. data/lib/capybara/selenium/patches/action_pauser.rb +26 -0
  63. data/lib/capybara/selenium/patches/atoms.rb +4 -4
  64. data/lib/capybara/selenium/patches/logs.rb +7 -9
  65. data/lib/capybara/server/animation_disabler.rb +3 -2
  66. data/lib/capybara/server/middleware.rb +4 -2
  67. data/lib/capybara/session.rb +23 -14
  68. data/lib/capybara/session/config.rb +3 -1
  69. data/lib/capybara/session/matchers.rb +11 -11
  70. data/lib/capybara/spec/public/test.js +24 -1
  71. data/lib/capybara/spec/session/accept_alert_spec.rb +1 -1
  72. data/lib/capybara/spec/session/check_spec.rb +6 -0
  73. data/lib/capybara/spec/session/click_button_spec.rb +11 -0
  74. data/lib/capybara/spec/session/current_url_spec.rb +11 -1
  75. data/lib/capybara/spec/session/fill_in_spec.rb +9 -0
  76. data/lib/capybara/spec/session/find_spec.rb +11 -8
  77. data/lib/capybara/spec/session/has_button_spec.rb +18 -0
  78. data/lib/capybara/spec/session/has_css_spec.rb +11 -7
  79. data/lib/capybara/spec/session/has_current_path_spec.rb +15 -2
  80. data/lib/capybara/spec/session/has_field_spec.rb +16 -0
  81. data/lib/capybara/spec/session/has_select_spec.rb +4 -4
  82. data/lib/capybara/spec/session/has_selector_spec.rb +4 -4
  83. data/lib/capybara/spec/session/has_text_spec.rb +0 -11
  84. data/lib/capybara/spec/session/matches_style_spec.rb +2 -2
  85. data/lib/capybara/spec/session/node_spec.rb +76 -29
  86. data/lib/capybara/spec/session/refresh_spec.rb +1 -0
  87. data/lib/capybara/spec/session/save_page_spec.rb +4 -4
  88. data/lib/capybara/spec/session/window/window_spec.rb +7 -7
  89. data/lib/capybara/spec/spec_helper.rb +13 -14
  90. data/lib/capybara/spec/test_app.rb +22 -21
  91. data/lib/capybara/spec/views/form.erb +25 -1
  92. data/lib/capybara/spec/views/with_animation.erb +8 -0
  93. data/lib/capybara/spec/views/with_dragula.erb +3 -1
  94. data/lib/capybara/spec/views/with_html.erb +2 -2
  95. data/lib/capybara/spec/views/with_js.erb +2 -0
  96. data/lib/capybara/spec/views/with_sortable_js.erb +1 -1
  97. data/lib/capybara/version.rb +1 -1
  98. data/lib/capybara/window.rb +3 -7
  99. data/spec/basic_node_spec.rb +9 -8
  100. data/spec/capybara_spec.rb +1 -1
  101. data/spec/dsl_spec.rb +14 -1
  102. data/spec/fixtures/selenium_driver_rspec_success.rb +1 -1
  103. data/spec/minitest_spec.rb +3 -2
  104. data/spec/rack_test_spec.rb +28 -5
  105. data/spec/regexp_dissassembler_spec.rb +0 -4
  106. data/spec/result_spec.rb +38 -31
  107. data/spec/rspec/features_spec.rb +3 -1
  108. data/spec/rspec/scenarios_spec.rb +4 -0
  109. data/spec/rspec/shared_spec_matchers.rb +63 -51
  110. data/spec/rspec_spec.rb +4 -0
  111. data/spec/selector_spec.rb +2 -1
  112. data/spec/selenium_spec_chrome.rb +4 -2
  113. data/spec/selenium_spec_chrome_remote.rb +2 -0
  114. data/spec/server_spec.rb +56 -49
  115. data/spec/shared_selenium_node.rb +18 -0
  116. data/spec/shared_selenium_session.rb +84 -7
  117. data/spec/spec_helper.rb +1 -1
  118. metadata +25 -24
  119. data/lib/capybara/spec/session/source_spec.rb +0 -0
@@ -14,8 +14,9 @@ Capybara::SpecHelper.spec '#has_css?' do
14
14
  # This was never a specifically accepted format but it has worked for a
15
15
  # lot of versions.
16
16
  # TODO: Remove in 4.0
17
- expect_any_instance_of(Kernel).to receive(:warn) # rubocop:disable RSpec/AnyInstance
17
+ allow(Capybara::Helpers).to receive(:warn).and_return(nil)
18
18
  expect(@session).to have_css(:p)
19
+ expect(Capybara::Helpers).to have_received(:warn)
19
20
  end
20
21
 
21
22
  it 'should be false if the given selector is not on the page' do
@@ -234,18 +235,21 @@ Capybara::SpecHelper.spec '#has_css?' do
234
235
  context 'with spatial requirements', requires: [:spatial] do
235
236
  before do
236
237
  @session.visit('/spatial')
237
- @center = @session.find(:css, '.center')
238
+ end
239
+
240
+ let :center do
241
+ @session.find(:css, '.center')
238
242
  end
239
243
 
240
244
  it 'accepts spatial options' do
241
- expect(@session).to have_css('div', above: @center).thrice
242
- expect(@session).to have_css('div', above: @center, right_of: @center).once
245
+ expect(@session).to have_css('div', above: center).thrice
246
+ expect(@session).to have_css('div', above: center, right_of: center).once
243
247
  end
244
248
 
245
249
  it 'supports spatial sugar' do
246
- expect(@session).to have_css('div').left_of(@center).thrice
247
- expect(@session).to have_css('div').below(@center).right_of(@center).once
248
- expect(@session).to have_css('div').near(@center).exactly(8).times
250
+ expect(@session).to have_css('div').left_of(center).thrice
251
+ expect(@session).to have_css('div').below(center).right_of(center).once
252
+ expect(@session).to have_css('div').near(center).exactly(8).times
249
253
  end
250
254
  end
251
255
 
@@ -94,6 +94,13 @@ Capybara::SpecHelper.spec '#has_current_path?' do
94
94
  expect(@session).to have_current_path(nil, ignore_query: true)
95
95
  end.not_to raise_exception
96
96
  end
97
+
98
+ it 'should accept a filter block that receives Addressable::URL' do
99
+ @session.visit('/with_js?a=3&b=defgh')
100
+ expect(@session).to have_current_path('/with_js', ignore_query: true) { |url|
101
+ url.query_values.keys == %w[a b]
102
+ }
103
+ end
97
104
  end
98
105
 
99
106
  Capybara::SpecHelper.spec '#has_no_current_path?' do
@@ -128,11 +135,17 @@ Capybara::SpecHelper.spec '#has_no_current_path?' do
128
135
  # Without ignore_query option
129
136
  expect do
130
137
  expect(@session).not_to have_current_path('/with_js')
131
- end. not_to raise_exception
138
+ end.not_to raise_exception
132
139
 
133
140
  # With ignore_query option
134
141
  expect do
135
142
  expect(@session).not_to have_current_path('/with_js', ignore_query: true)
136
- end. not_to raise_exception
143
+ end.not_to raise_exception
144
+ end
145
+
146
+ it 'should accept a filter block that receives Addressable::URL' do
147
+ expect(@session).to have_no_current_path('/with_js', ignore_query: true) { |url|
148
+ !url.query.nil?
149
+ }
137
150
  end
138
151
  end
@@ -60,6 +60,22 @@ Capybara::SpecHelper.spec '#has_field' do
60
60
  end
61
61
  end
62
62
 
63
+ context 'with validation message', requires: [:html_validation] do
64
+ it 'should accept a regexp' do
65
+ @session.fill_in('form_zipcode', with: '1234')
66
+ expect(@session).to have_field('form_zipcode', validation_message: /match the requested format/)
67
+ expect(@session).not_to have_field('form_zipcode', validation_message: /random/)
68
+ end
69
+
70
+ it 'should accept a string' do
71
+ @session.fill_in('form_zipcode', with: '1234')
72
+ expect(@session).to have_field('form_zipcode', validation_message: 'Please match the requested format.')
73
+ expect(@session).not_to have_field('form_zipcode', validation_message: 'match the requested format.')
74
+ @session.fill_in('form_zipcode', with: '12345')
75
+ expect(@session).to have_field('form_zipcode', validation_message: '')
76
+ end
77
+ end
78
+
63
79
  context 'with type' do
64
80
  it 'should be true if a field with the given type is on the page' do
65
81
  expect(@session).to have_field('First Name', type: 'text')
@@ -63,7 +63,7 @@ Capybara::SpecHelper.spec '#has_select?' do
63
63
  end
64
64
 
65
65
  it "should be true even when the selected option invisible, regardless of the select's visibility" do
66
- expect(@session).to have_select('Icecream', visible: false, selected: 'Chocolate')
66
+ expect(@session).to have_select('Icecream', visible: :hidden, selected: 'Chocolate')
67
67
  expect(@session).to have_select('Sorbet', selected: 'Vanilla')
68
68
  end
69
69
  end
@@ -88,7 +88,7 @@ Capybara::SpecHelper.spec '#has_select?' do
88
88
  end
89
89
 
90
90
  it "should be true even when the selected values are invisible, regardless of the select's visibility" do
91
- expect(@session).to have_select('Dessert', visible: false, with_options: %w[Pudding Tiramisu])
91
+ expect(@session).to have_select('Dessert', visible: :hidden, with_options: %w[Pudding Tiramisu])
92
92
  expect(@session).to have_select('Cake', with_selected: ['Chocolate Cake', 'Sponge Cake'])
93
93
  end
94
94
 
@@ -113,7 +113,7 @@ Capybara::SpecHelper.spec '#has_select?' do
113
113
  end
114
114
 
115
115
  it 'should be true even when the options are invisible, if the select itself is invisible' do
116
- expect(@session).to have_select('Icecream', visible: false, options: %w[Chocolate Vanilla Strawberry])
116
+ expect(@session).to have_select('Icecream', visible: :hidden, options: %w[Chocolate Vanilla Strawberry])
117
117
  end
118
118
  end
119
119
 
@@ -158,7 +158,7 @@ Capybara::SpecHelper.spec '#has_select?' do
158
158
  end
159
159
 
160
160
  it 'should be true even when the options are invisible, if the select itself is invisible' do
161
- expect(@session).to have_select('Icecream', visible: false, with_options: %w[Vanilla Strawberry])
161
+ expect(@session).to have_select('Icecream', visible: :hidden, with_options: %w[Vanilla Strawberry])
162
162
  end
163
163
  end
164
164
 
@@ -61,12 +61,12 @@ Capybara::SpecHelper.spec '#has_selector?' do
61
61
  end
62
62
 
63
63
  it 'should respect visibility setting' do
64
- expect(@session).to have_selector(:id, 'hidden-text', text: 'Some of this text is hidden!', visible: false)
65
- expect(@session).not_to have_selector(:id, 'hidden-text', text: 'Some of this text is hidden!', visible: true)
64
+ expect(@session).to have_selector(:id, 'hidden-text', text: 'Some of this text is hidden!', visible: :all)
65
+ expect(@session).not_to have_selector(:id, 'hidden-text', text: 'Some of this text is hidden!', visible: :visible)
66
66
  Capybara.ignore_hidden_elements = false
67
- expect(@session).to have_selector(:id, 'hidden-text', text: 'Some of this text is hidden!', visible: false)
67
+ expect(@session).to have_selector(:id, 'hidden-text', text: 'Some of this text is hidden!', visible: :all)
68
68
  Capybara.visible_text_only = true
69
- expect(@session).not_to have_selector(:id, 'hidden-text', text: 'Some of this text is hidden!', visible: true)
69
+ expect(@session).not_to have_selector(:id, 'hidden-text', text: 'Some of this text is hidden!', visible: :visible)
70
70
  end
71
71
 
72
72
  it 'should discard all matches where the given regexp is not matched' do
@@ -133,17 +133,6 @@ Capybara::SpecHelper.spec '#has_text?' do
133
133
  expect(@session).to have_text(:visible, with_to_hash, {})
134
134
  end
135
135
  end
136
-
137
- it 'should fail if passed without empty options' do
138
- with_to_hash = Class.new do
139
- def to_s; '42' end
140
- def to_hash; { blah: 'Other hash' } end
141
- end.new
142
- @session.visit('/with_html')
143
- expect do
144
- expect(@session).to have_text(:visible, with_to_hash)
145
- end.to raise_error(ArgumentError)
146
- end
147
136
  end
148
137
 
149
138
  context 'with exact: true option' do
@@ -28,8 +28,8 @@ Capybara::SpecHelper.spec '#matches_style?', requires: [:css] do
28
28
  output(/have_style is deprecated/).to_stderr
29
29
 
30
30
  el = @session.find(:css, '#first')
31
- allow(el).to receive(:warn).and_return(nil)
31
+ allow(Capybara::Helpers).to receive(:warn).and_return(nil)
32
32
  el.has_style?('display' => /^bl/)
33
- expect(el).to have_received(:warn)
33
+ expect(Capybara::Helpers).to have_received(:warn)
34
34
  end
35
35
  end
@@ -271,12 +271,12 @@ Capybara::SpecHelper.spec 'node' do
271
271
 
272
272
  it 'works when details is toggled open and closed' do
273
273
  @session.find(:css, '#closed_details > summary').click
274
- expect(@session).to have_css('#closed_details *', visible: true, count: 5)
274
+ expect(@session).to have_css('#closed_details *', visible: :visible, count: 5)
275
275
  .and(have_no_css('#closed_details *', visible: :hidden))
276
276
 
277
277
  @session.find(:css, '#closed_details > summary').click
278
278
  descendants_css = '#closed_details > *:not(summary), #closed_details > *:not(summary) *'
279
- expect(@session).to have_no_css(descendants_css, visible: true)
279
+ expect(@session).to have_no_css(descendants_css, visible: :visible)
280
280
  .and(have_css(descendants_css, visible: :hidden, count: 3))
281
281
  end
282
282
  end
@@ -388,8 +388,8 @@ Capybara::SpecHelper.spec 'node' do
388
388
 
389
389
  describe '#==' do
390
390
  it 'preserve object identity' do
391
- expect(@session.find('//h1') == @session.find('//h1')).to be true # rubocop:disable Lint/UselessComparison
392
- expect(@session.find('//h1') === @session.find('//h1')).to be true # rubocop:disable Style/CaseEquality, Lint/UselessComparison
391
+ expect(@session.find('//h1') == @session.find('//h1')).to be true # rubocop:disable Lint/BinaryOperatorWithIdenticalOperands
392
+ expect(@session.find('//h1') === @session.find('//h1')).to be true # rubocop:disable Style/CaseEquality, Lint/BinaryOperatorWithIdenticalOperands
393
393
  expect(@session.find('//h1').eql?(@session.find('//h1'))).to be false
394
394
  end
395
395
 
@@ -409,6 +409,17 @@ Capybara::SpecHelper.spec 'node' do
409
409
  element = @session.find(:link, 'Second Link')
410
410
  expect(@session.find(:xpath, element.path)).to eq(element)
411
411
  end
412
+
413
+ it 'reports when element in shadow dom', requires: [:shadow_dom] do
414
+ @session.visit('/with_js')
415
+ shadow = @session.find(:css, '#shadow')
416
+ element = @session.evaluate_script(<<~JS, shadow)
417
+ (function(root){
418
+ return root.shadowRoot.querySelector('span');
419
+ })(arguments[0])
420
+ JS
421
+ expect(element.path).to eq '(: Shadow DOM element - no XPath :)'
422
+ end
412
423
  end
413
424
 
414
425
  describe '#trigger', requires: %i[js trigger] do
@@ -446,7 +457,7 @@ Capybara::SpecHelper.spec 'node' do
446
457
 
447
458
  it 'should work with Dragula' do
448
459
  @session.visit('/with_dragula')
449
- @session.within(:css, '#sortable') do
460
+ @session.within(:css, '#sortable.ready') do
450
461
  src = @session.find('div', text: 'Item 1')
451
462
  target = @session.find('div', text: 'Item 3')
452
463
  src.drag_to target
@@ -671,6 +682,15 @@ Capybara::SpecHelper.spec 'node' do
671
682
  expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped string: text/plain Some dropped text")]')
672
683
  end
673
684
 
685
+ it 'can drop a pathname' do
686
+ @session.visit('/with_js')
687
+ target = @session.find('//div[@id="drop_html5"]')
688
+ target.drop(
689
+ Pathname.new(with_os_path_separators(File.expand_path('../fixtures/capybara.jpg', File.dirname(__FILE__))))
690
+ )
691
+ expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped file: capybara.jpg")]')
692
+ end
693
+
674
694
  it 'can drop multiple strings' do
675
695
  @session.visit('/with_js')
676
696
  target = @session.find('//div[@id="drop_html5"]')
@@ -758,7 +778,7 @@ Capybara::SpecHelper.spec 'node' do
758
778
  @session.visit('with_js')
759
779
  @session.find(:css, '#click-test').click(x: 5, y: 5)
760
780
  link = @session.find(:link, 'has-been-clicked')
761
- locations = link.text.match(/^Has been clicked at (?<x>[\d\.-]+),(?<y>[\d\.-]+)$/)
781
+ locations = link.text.match(/^Has been clicked at (?<x>[\d.-]+),(?<y>[\d.-]+)$/)
762
782
  # Resulting click location should be very close to 0, 0 relative to top left corner of the element, but may not be exact due to
763
783
  # integer/float conversions and rounding.
764
784
  expect(locations[:x].to_f).to be_within(1).of(5)
@@ -808,7 +828,10 @@ Capybara::SpecHelper.spec 'node' do
808
828
  context 'offset', requires: [:js] do
809
829
  before do
810
830
  @session.visit('/offset')
811
- @clicker = @session.find(:id, 'clicker')
831
+ end
832
+
833
+ let :clicker do
834
+ @session.find(:id, 'clicker')
812
835
  end
813
836
 
814
837
  context 'when w3c_click_offset is false' do
@@ -817,17 +840,17 @@ Capybara::SpecHelper.spec 'node' do
817
840
  end
818
841
 
819
842
  it 'should offset from top left of element' do
820
- @clicker.click(x: 10, y: 5)
843
+ clicker.click(x: 10, y: 5)
821
844
  expect(@session).to have_text(/clicked at 110,105/)
822
845
  end
823
846
 
824
847
  it 'should offset outside the element' do
825
- @clicker.click(x: -15, y: -10)
848
+ clicker.click(x: -15, y: -10)
826
849
  expect(@session).to have_text(/clicked at 85,90/)
827
850
  end
828
851
 
829
852
  it 'should default to click the middle' do
830
- @clicker.click
853
+ clicker.click
831
854
  expect(@session).to have_text(/clicked at 150,150/)
832
855
  end
833
856
  end
@@ -838,21 +861,30 @@ Capybara::SpecHelper.spec 'node' do
838
861
  end
839
862
 
840
863
  it 'should offset from center of element' do
841
- @clicker.click(x: 10, y: 5)
864
+ clicker.click(x: 10, y: 5)
842
865
  expect(@session).to have_text(/clicked at 160,155/)
843
866
  end
844
867
 
845
868
  it 'should offset outside from center of element' do
846
- @clicker.click(x: -65, y: -60)
869
+ clicker.click(x: -65, y: -60)
847
870
  expect(@session).to have_text(/clicked at 85,90/)
848
871
  end
849
872
 
850
873
  it 'should default to click the middle' do
851
- @clicker.click
874
+ clicker.click
852
875
  expect(@session).to have_text(/clicked at 150,150/)
853
876
  end
854
877
  end
855
878
  end
879
+
880
+ context 'delay', requires: [:js] do
881
+ it 'should delay the mouse up' do
882
+ @session.visit('with_js')
883
+ @session.find(:css, '#click-test').click(delay: 2)
884
+ delay = @session.evaluate_script('window.click_delay')
885
+ expect(delay).to be >= 2
886
+ end
887
+ end
856
888
  end
857
889
 
858
890
  describe '#double_click', requires: [:js] do
@@ -872,7 +904,7 @@ Capybara::SpecHelper.spec 'node' do
872
904
  @session.visit('with_js')
873
905
  @session.find(:css, '#click-test').double_click(x: 10, y: 5)
874
906
  link = @session.find(:link, 'has-been-double-clicked')
875
- locations = link.text.match(/^Has been double clicked at (?<x>[\d\.-]+),(?<y>[\d\.-]+)$/)
907
+ locations = link.text.match(/^Has been double clicked at (?<x>[\d.-]+),(?<y>[\d.-]+)$/)
876
908
  # Resulting click location should be very close to 10, 5 relative to top left corner of the element, but may not be exact due
877
909
  # to integer/float conversions and rounding.
878
910
  expect(locations[:x].to_f).to be_within(1).of(10)
@@ -891,7 +923,10 @@ Capybara::SpecHelper.spec 'node' do
891
923
  context 'offset', requires: [:js] do
892
924
  before do
893
925
  @session.visit('/offset')
894
- @clicker = @session.find(:id, 'clicker')
926
+ end
927
+
928
+ let :clicker do
929
+ @session.find(:id, 'clicker')
895
930
  end
896
931
 
897
932
  context 'when w3c_click_offset is false' do
@@ -900,17 +935,17 @@ Capybara::SpecHelper.spec 'node' do
900
935
  end
901
936
 
902
937
  it 'should offset from top left of element' do
903
- @clicker.double_click(x: 10, y: 5)
938
+ clicker.double_click(x: 10, y: 5)
904
939
  expect(@session).to have_text(/clicked at 110,105/)
905
940
  end
906
941
 
907
942
  it 'should offset outside the element' do
908
- @clicker.double_click(x: -15, y: -10)
943
+ clicker.double_click(x: -15, y: -10)
909
944
  expect(@session).to have_text(/clicked at 85,90/)
910
945
  end
911
946
 
912
947
  it 'should default to click the middle' do
913
- @clicker.double_click
948
+ clicker.double_click
914
949
  expect(@session).to have_text(/clicked at 150,150/)
915
950
  end
916
951
  end
@@ -921,17 +956,17 @@ Capybara::SpecHelper.spec 'node' do
921
956
  end
922
957
 
923
958
  it 'should offset from center of element' do
924
- @clicker.double_click(x: 10, y: 5)
959
+ clicker.double_click(x: 10, y: 5)
925
960
  expect(@session).to have_text(/clicked at 160,155/)
926
961
  end
927
962
 
928
963
  it 'should offset outside from center of element' do
929
- @clicker.double_click(x: -65, y: -60)
964
+ clicker.double_click(x: -65, y: -60)
930
965
  expect(@session).to have_text(/clicked at 85,90/)
931
966
  end
932
967
 
933
968
  it 'should default to click the middle' do
934
- @clicker.double_click
969
+ clicker.double_click
935
970
  expect(@session).to have_text(/clicked at 150,150/)
936
971
  end
937
972
  end
@@ -955,7 +990,7 @@ Capybara::SpecHelper.spec 'node' do
955
990
  @session.visit('with_js')
956
991
  @session.find(:css, '#click-test').right_click(x: 10, y: 10)
957
992
  link = @session.find(:link, 'has-been-right-clicked')
958
- locations = link.text.match(/^Has been right clicked at (?<x>[\d\.-]+),(?<y>[\d\.-]+)$/)
993
+ locations = link.text.match(/^Has been right clicked at (?<x>[\d.-]+),(?<y>[\d.-]+)$/)
959
994
  # Resulting click location should be very close to 10, 10 relative to top left corner of the element, but may not be exact due
960
995
  # to integer/float conversions and rounding
961
996
  expect(locations[:x].to_f).to be_within(1).of(10)
@@ -974,7 +1009,10 @@ Capybara::SpecHelper.spec 'node' do
974
1009
  context 'offset', requires: [:js] do
975
1010
  before do
976
1011
  @session.visit('/offset')
977
- @clicker = @session.find(:id, 'clicker')
1012
+ end
1013
+
1014
+ let :clicker do
1015
+ @session.find(:id, 'clicker')
978
1016
  end
979
1017
 
980
1018
  context 'when w3c_click_offset is false' do
@@ -983,17 +1021,17 @@ Capybara::SpecHelper.spec 'node' do
983
1021
  end
984
1022
 
985
1023
  it 'should offset from top left of element' do
986
- @clicker.right_click(x: 10, y: 5)
1024
+ clicker.right_click(x: 10, y: 5)
987
1025
  expect(@session).to have_text(/clicked at 110,105/)
988
1026
  end
989
1027
 
990
1028
  it 'should offset outside the element' do
991
- @clicker.right_click(x: -15, y: -10)
1029
+ clicker.right_click(x: -15, y: -10)
992
1030
  expect(@session).to have_text(/clicked at 85,90/)
993
1031
  end
994
1032
 
995
1033
  it 'should default to click the middle' do
996
- @clicker.right_click
1034
+ clicker.right_click
997
1035
  expect(@session).to have_text(/clicked at 150,150/)
998
1036
  end
999
1037
  end
@@ -1004,21 +1042,30 @@ Capybara::SpecHelper.spec 'node' do
1004
1042
  end
1005
1043
 
1006
1044
  it 'should offset from center of element' do
1007
- @clicker.right_click(x: 10, y: 5)
1045
+ clicker.right_click(x: 10, y: 5)
1008
1046
  expect(@session).to have_text(/clicked at 160,155/)
1009
1047
  end
1010
1048
 
1011
1049
  it 'should offset outside from center of element' do
1012
- @clicker.right_click(x: -65, y: -60)
1050
+ clicker.right_click(x: -65, y: -60)
1013
1051
  expect(@session).to have_text(/clicked at 85,90/)
1014
1052
  end
1015
1053
 
1016
1054
  it 'should default to click the middle' do
1017
- @clicker.right_click
1055
+ clicker.right_click
1018
1056
  expect(@session).to have_text(/clicked at 150,150/)
1019
1057
  end
1020
1058
  end
1021
1059
  end
1060
+
1061
+ context 'delay', requires: [:js] do
1062
+ it 'should delay the mouse up' do
1063
+ @session.visit('with_js')
1064
+ @session.find(:css, '#click-test').right_click(delay: 2)
1065
+ delay = @session.evaluate_script('window.right_click_delay')
1066
+ expect(delay).to be >= 2
1067
+ end
1068
+ end
1022
1069
  end
1023
1070
 
1024
1071
  describe '#send_keys', requires: [:send_keys] do