capybara 3.31.0 → 3.33.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +51 -0
  3. data/README.md +10 -3
  4. data/lib/capybara.rb +17 -7
  5. data/lib/capybara/cucumber.rb +1 -1
  6. data/lib/capybara/minitest.rb +215 -141
  7. data/lib/capybara/minitest/spec.rb +153 -97
  8. data/lib/capybara/node/actions.rb +16 -20
  9. data/lib/capybara/node/element.rb +2 -0
  10. data/lib/capybara/node/matchers.rb +4 -6
  11. data/lib/capybara/queries/selector_query.rb +8 -1
  12. data/lib/capybara/queries/style_query.rb +1 -1
  13. data/lib/capybara/queries/text_query.rb +6 -0
  14. data/lib/capybara/rack_test/browser.rb +3 -1
  15. data/lib/capybara/registration_container.rb +44 -0
  16. data/lib/capybara/registrations/servers.rb +1 -1
  17. data/lib/capybara/result.rb +5 -1
  18. data/lib/capybara/rspec/matcher_proxies.rb +4 -4
  19. data/lib/capybara/rspec/matchers/have_text.rb +1 -1
  20. data/lib/capybara/selector.rb +10 -1
  21. data/lib/capybara/selector/definition.rb +5 -4
  22. data/lib/capybara/selector/definition/button.rb +1 -0
  23. data/lib/capybara/selector/definition/fillable_field.rb +1 -1
  24. data/lib/capybara/selector/definition/link.rb +8 -0
  25. data/lib/capybara/selector/definition/table.rb +1 -1
  26. data/lib/capybara/selector/selector.rb +4 -0
  27. data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -1
  28. data/lib/capybara/selenium/atoms/src/getAttribute.js +1 -1
  29. data/lib/capybara/selenium/driver.rb +7 -4
  30. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +7 -9
  31. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +7 -9
  32. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +2 -2
  33. data/lib/capybara/selenium/node.rb +69 -9
  34. data/lib/capybara/selenium/nodes/chrome_node.rb +0 -9
  35. data/lib/capybara/selenium/nodes/firefox_node.rb +2 -2
  36. data/lib/capybara/selenium/patches/action_pauser.rb +26 -0
  37. data/lib/capybara/selenium/patches/logs.rb +3 -5
  38. data/lib/capybara/session.rb +3 -3
  39. data/lib/capybara/session/config.rb +3 -1
  40. data/lib/capybara/spec/public/test.js +18 -0
  41. data/lib/capybara/spec/session/click_button_spec.rb +11 -0
  42. data/lib/capybara/spec/session/fill_in_spec.rb +9 -0
  43. data/lib/capybara/spec/session/find_spec.rb +11 -8
  44. data/lib/capybara/spec/session/has_button_spec.rb +16 -0
  45. data/lib/capybara/spec/session/has_css_spec.rb +9 -6
  46. data/lib/capybara/spec/session/has_current_path_spec.rb +2 -2
  47. data/lib/capybara/spec/session/has_field_spec.rb +16 -0
  48. data/lib/capybara/spec/session/has_select_spec.rb +4 -4
  49. data/lib/capybara/spec/session/has_selector_spec.rb +4 -4
  50. data/lib/capybara/spec/session/node_spec.rb +54 -27
  51. data/lib/capybara/spec/session/window/window_spec.rb +7 -7
  52. data/lib/capybara/spec/spec_helper.rb +2 -2
  53. data/lib/capybara/spec/test_app.rb +14 -18
  54. data/lib/capybara/spec/views/form.erb +7 -1
  55. data/lib/capybara/spec/views/with_dragula.erb +3 -1
  56. data/lib/capybara/spec/views/with_html.erb +2 -2
  57. data/lib/capybara/spec/views/with_js.erb +1 -0
  58. data/lib/capybara/version.rb +1 -1
  59. data/spec/capybara_spec.rb +1 -1
  60. data/spec/dsl_spec.rb +14 -1
  61. data/spec/minitest_spec.rb +1 -1
  62. data/spec/rack_test_spec.rb +13 -0
  63. data/spec/regexp_dissassembler_spec.rb +0 -4
  64. data/spec/result_spec.rb +38 -31
  65. data/spec/rspec/shared_spec_matchers.rb +65 -53
  66. data/spec/selector_spec.rb +1 -1
  67. data/spec/selenium_spec_chrome.rb +4 -2
  68. data/spec/selenium_spec_chrome_remote.rb +2 -0
  69. data/spec/server_spec.rb +41 -49
  70. data/spec/shared_selenium_node.rb +18 -0
  71. data/spec/shared_selenium_session.rb +25 -7
  72. data/spec/spec_helper.rb +1 -1
  73. metadata +5 -3
@@ -92,11 +92,6 @@ private
92
92
  end
93
93
  end
94
94
 
95
- def w3c?
96
- (defined?(Selenium::WebDriver::VERSION) && (Selenium::WebDriver::VERSION.to_f >= 4)) ||
97
- capabilities.is_a?(::Selenium::WebDriver::Remote::W3C::Capabilities)
98
- end
99
-
100
95
  def browser_version(to_float = true)
101
96
  caps = capabilities
102
97
  ver = (caps[:browser_version] || caps[:version])
@@ -116,10 +111,6 @@ private
116
111
  capabilities['chrome']['chromedriverVersion'].split(' ')[0]
117
112
  end
118
113
 
119
- def capabilities
120
- driver.browser.capabilities
121
- end
122
-
123
114
  def native_displayed?
124
115
  (driver.options[:native_displayed] != false) &&
125
116
  (w3c? && chromedriver_supports_displayed_endpoint?) &&
@@ -42,7 +42,7 @@ class Capybara::Selenium::FirefoxNode < Capybara::Selenium::Node
42
42
 
43
43
  def send_keys(*args)
44
44
  # https://github.com/mozilla/geckodriver/issues/846
45
- return super(*args.map { |arg| arg == :space ? ' ' : arg }) if args.none? { |arg| arg.is_a? Array }
45
+ return super(*args.map { |arg| arg == :space ? ' ' : arg }) if args.none?(Array)
46
46
 
47
47
  native.click
48
48
  _send_keys(args).perform
@@ -85,7 +85,7 @@ private
85
85
  (driver.options[:native_displayed] != false) && !ENV['DISABLE_CAPYBARA_SELENIUM_OPTIMIZATIONS']
86
86
  end
87
87
 
88
- def click_with_options(click_options)
88
+ def perform_with_options(click_options)
89
89
  # Firefox/marionette has an issue clicking with offset near viewport edge
90
90
  # scroll element to middle just in case
91
91
  scroll_to_center if click_options.coords?
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionPauser
4
+ def initialize(mouse, keyboard)
5
+ super
6
+ @devices[:pauser] = Pauser.new
7
+ end
8
+
9
+ def pause(duration)
10
+ @actions << [:pauser, :pause, [duration]]
11
+ self
12
+ end
13
+
14
+ class Pauser
15
+ def pause(duration)
16
+ sleep duration
17
+ end
18
+ end
19
+
20
+ private_constant :Pauser
21
+ end
22
+
23
+ if defined?(::Selenium::WebDriver::VERSION) && (::Selenium::WebDriver::VERSION.to_f < 4) &&
24
+ defined?(::Selenium::WebDriver::ActionBuilder)
25
+ ::Selenium::WebDriver::ActionBuilder.prepend(ActionPauser)
26
+ end
@@ -33,11 +33,9 @@ module Capybara
33
33
  end
34
34
 
35
35
  Array(data).map do |l|
36
- begin
37
- ::Selenium::WebDriver::LogEntry.new l.fetch('level', 'UNKNOWN'), l.fetch('timestamp'), l.fetch('message')
38
- rescue KeyError
39
- next
40
- end
36
+ ::Selenium::WebDriver::LogEntry.new l.fetch('level', 'UNKNOWN'), l.fetch('timestamp'), l.fetch('message')
37
+ rescue KeyError
38
+ next
41
39
  end
42
40
  rescue ::Selenium::WebDriver::Error::UnknownCommandError
43
41
  raise NotImplementedError, LOG_MSG
@@ -97,8 +97,8 @@ module Capybara
97
97
 
98
98
  def driver
99
99
  @driver ||= begin
100
- unless Capybara.drivers.key?(mode)
101
- other_drivers = Capybara.drivers.keys.map(&:inspect)
100
+ unless Capybara.drivers[mode]
101
+ other_drivers = Capybara.drivers.names.map(&:inspect)
102
102
  raise Capybara::DriverNotFoundError, "no driver called #{mode.inspect} was found, available drivers: #{other_drivers.join(', ')}"
103
103
  end
104
104
  driver = Capybara.drivers[mode].call(app)
@@ -192,7 +192,7 @@ module Capybara
192
192
  # @return [String] A snapshot of the DOM of the current document, as it looks right now (potentially modified by JavaScript).
193
193
  #
194
194
  def html
195
- driver.html
195
+ driver.html || ''
196
196
  end
197
197
  alias_method :body, :html
198
198
  alias_method :source, :html
@@ -8,7 +8,7 @@ module Capybara
8
8
  automatic_reload match exact exact_text raise_server_errors visible_text_only
9
9
  automatic_label_click enable_aria_label save_path asset_host default_host app_host
10
10
  server_host server_port server_errors default_set_options disable_animation test_id
11
- predicates_wait default_normalize_ws w3c_click_offset].freeze
11
+ predicates_wait default_normalize_ws w3c_click_offset enable_aria_role].freeze
12
12
 
13
13
  attr_accessor(*OPTIONS)
14
14
 
@@ -37,6 +37,8 @@ module Capybara
37
37
  # See {Capybara.configure}
38
38
  # @!method enable_aria_label
39
39
  # See {Capybara.configure}
40
+ # @!method enable_aria_role
41
+ # See {Capybara.configure}
40
42
  # @!method save_path
41
43
  # See {Capybara.configure}
42
44
  # @!method asset_host
@@ -108,6 +108,13 @@ $(function() {
108
108
  }, 4000);
109
109
  return false;
110
110
  });
111
+ $('#aria-button').click(function() {
112
+ var span = $(this);
113
+ setTimeout(function() {
114
+ $(span).after('<span role="button">ARIA button has been clicked</span>')
115
+ }, 1000);
116
+ return false;
117
+ });
111
118
  $('#waiter').change(function() {
112
119
  activeRequests = 1;
113
120
  setTimeout(function() {
@@ -153,6 +160,7 @@ $(function() {
153
160
  });
154
161
  $('#click-test').on({
155
162
  click: function(e) {
163
+ window.click_delay = ((new Date().getTime()) - window.mouse_down_time)/1000.0;
156
164
  var desc = "";
157
165
  if (e.altKey) desc += 'alt ';
158
166
  if (e.ctrlKey) desc += 'control ';
@@ -179,6 +187,16 @@ $(function() {
179
187
  if (e.shiftKey) desc += 'shift ';
180
188
  var pos = this.getBoundingClientRect();
181
189
  $(this).after('<a id="has-been-right-clicked" href="#">Has been ' + desc + 'right clicked at ' + (e.clientX - pos.left) + ',' + (e.clientY - pos.top) + '</a>');
190
+ },
191
+ mousedown: function(e) {
192
+ window.click_delay = undefined;
193
+ window.right_click_delay = undefined;
194
+ window.mouse_down_time = new Date().getTime();
195
+ },
196
+ mouseup: function(e) {
197
+ if (e.button == 2){
198
+ window.right_click_delay = ((new Date().getTime()) - window.mouse_down_time)/1000.0;
199
+ }
182
200
  }
183
201
  });
184
202
  $('#open-alert').click(function() {
@@ -193,6 +193,17 @@ Capybara::SpecHelper.spec '#click_button' do
193
193
  end
194
194
  end
195
195
 
196
+ context 'when Capybara.enable_aria_role = true' do
197
+ it 'should click on a button role', requires: [:js] do
198
+ Capybara.enable_aria_role = true
199
+ @session.using_wait_time(1.5) do
200
+ @session.visit('/with_js')
201
+ @session.click_button('ARIA button')
202
+ expect(@session).to have_button('ARIA button has been clicked')
203
+ end
204
+ end
205
+ end
206
+
196
207
  context 'with fields associated with the form using the form attribute', requires: [:form_attribute] do
197
208
  let(:results) { extract_results(@session) }
198
209
 
@@ -47,6 +47,15 @@ Capybara::SpecHelper.spec '#fill_in' do
47
47
  expect(extract_results(@session)['description']).to eq('Texty text')
48
48
  end
49
49
 
50
+ it 'should fill in a textarea in a reasonable time by default' do
51
+ textarea = @session.find(:fillable_field, 'form[description]')
52
+ value = 'a' * 4000
53
+ start = Time.now
54
+ textarea.fill_in(with: value)
55
+ expect(Time.now.to_f).to be_within(0.25).of start.to_f
56
+ expect(textarea.value).to eq value
57
+ end
58
+
50
59
  it 'should fill in a password field by id' do
51
60
  @session.fill_in('form_password', with: 'supasikrit')
52
61
  @session.click_button('awesome')
@@ -451,32 +451,35 @@ Capybara::SpecHelper.spec '#find' do
451
451
  context 'with spatial filters', requires: [:spatial] do
452
452
  before do
453
453
  @session.visit('/spatial')
454
- @center = @session.find(:css, 'div.center')
454
+ end
455
+
456
+ let :center do
457
+ @session.find(:css, 'div.center')
455
458
  end
456
459
 
457
460
  it 'should find an element above another element' do
458
- expect(@session.find(:css, 'div:not(.corner)', above: @center).text).to eq('2')
461
+ expect(@session.find(:css, 'div:not(.corner)', above: center).text).to eq('2')
459
462
  end
460
463
 
461
464
  it 'should find an element below another element' do
462
- expect(@session.find(:css, 'div:not(.corner):not(.footer)', below: @center).text).to eq('8')
465
+ expect(@session.find(:css, 'div:not(.corner):not(.footer)', below: center).text).to eq('8')
463
466
  end
464
467
 
465
468
  it 'should find an element left of another element' do
466
- expect(@session.find(:css, 'div:not(.corner)', left_of: @center).text).to eq('4')
469
+ expect(@session.find(:css, 'div:not(.corner)', left_of: center).text).to eq('4')
467
470
  end
468
471
 
469
472
  it 'should find an element right of another element' do
470
- expect(@session.find(:css, 'div:not(.corner)', right_of: @center).text).to eq('6')
473
+ expect(@session.find(:css, 'div:not(.corner)', right_of: center).text).to eq('6')
471
474
  end
472
475
 
473
476
  it 'should combine spatial filters' do
474
- expect(@session.find(:css, 'div', left_of: @center, above: @center).text).to eq('1')
475
- expect(@session.find(:css, 'div', right_of: @center, below: @center).text).to eq('9')
477
+ expect(@session.find(:css, 'div', left_of: center, above: center).text).to eq('1')
478
+ expect(@session.find(:css, 'div', right_of: center, below: center).text).to eq('9')
476
479
  end
477
480
 
478
481
  it 'should find an element "near" another element' do
479
- expect(@session.find(:css, 'div.distance', near: @center).text).to eq('2')
482
+ expect(@session.find(:css, 'div.distance', near: center).text).to eq('2')
480
483
  end
481
484
  end
482
485
 
@@ -39,6 +39,14 @@ Capybara::SpecHelper.spec '#has_button?' do
39
39
  expect(@session).to have_button('awe123', type: 'submit')
40
40
  expect(@session).not_to have_button('awe123', type: 'reset')
41
41
  end
42
+
43
+ it 'should be true for role=button when enable_aria_role: true' do
44
+ expect(@session).to have_button('ARIA button', enable_aria_role: true)
45
+ end
46
+
47
+ it 'should be false for role=button when enable_aria_role: false' do
48
+ expect(@session).not_to have_button('ARIA button', enable_aria_role: false)
49
+ end
42
50
  end
43
51
 
44
52
  Capybara::SpecHelper.spec '#has_no_button?' do
@@ -66,4 +74,12 @@ Capybara::SpecHelper.spec '#has_no_button?' do
66
74
  it 'should be false for disabled buttons if disabled: false' do
67
75
  expect(@session).to have_no_button('Disabled button', disabled: false)
68
76
  end
77
+
78
+ it 'should be true for role=button when enable_aria_role: false' do
79
+ expect(@session).to have_no_button('ARIA button', enable_aria_role: false)
80
+ end
81
+
82
+ it 'should be false for role=button when enable_aria_role: true' do
83
+ expect(@session).not_to have_no_button('ARIA button', enable_aria_role: true)
84
+ end
69
85
  end
@@ -234,18 +234,21 @@ Capybara::SpecHelper.spec '#has_css?' do
234
234
  context 'with spatial requirements', requires: [:spatial] do
235
235
  before do
236
236
  @session.visit('/spatial')
237
- @center = @session.find(:css, '.center')
237
+ end
238
+
239
+ let :center do
240
+ @session.find(:css, '.center')
238
241
  end
239
242
 
240
243
  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
244
+ expect(@session).to have_css('div', above: center).thrice
245
+ expect(@session).to have_css('div', above: center, right_of: center).once
243
246
  end
244
247
 
245
248
  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
249
+ expect(@session).to have_css('div').left_of(center).thrice
250
+ expect(@session).to have_css('div').below(center).right_of(center).once
251
+ expect(@session).to have_css('div').near(center).exactly(8).times
249
252
  end
250
253
  end
251
254
 
@@ -128,11 +128,11 @@ Capybara::SpecHelper.spec '#has_no_current_path?' do
128
128
  # Without ignore_query option
129
129
  expect do
130
130
  expect(@session).not_to have_current_path('/with_js')
131
- end. not_to raise_exception
131
+ end.not_to raise_exception
132
132
 
133
133
  # With ignore_query option
134
134
  expect do
135
135
  expect(@session).not_to have_current_path('/with_js', ignore_query: true)
136
- end. not_to raise_exception
136
+ end.not_to raise_exception
137
137
  end
138
138
  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
@@ -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
@@ -446,7 +446,7 @@ Capybara::SpecHelper.spec 'node' do
446
446
 
447
447
  it 'should work with Dragula' do
448
448
  @session.visit('/with_dragula')
449
- @session.within(:css, '#sortable') do
449
+ @session.within(:css, '#sortable.ready') do
450
450
  src = @session.find('div', text: 'Item 1')
451
451
  target = @session.find('div', text: 'Item 3')
452
452
  src.drag_to target
@@ -758,7 +758,7 @@ Capybara::SpecHelper.spec 'node' do
758
758
  @session.visit('with_js')
759
759
  @session.find(:css, '#click-test').click(x: 5, y: 5)
760
760
  link = @session.find(:link, 'has-been-clicked')
761
- locations = link.text.match(/^Has been clicked at (?<x>[\d\.-]+),(?<y>[\d\.-]+)$/)
761
+ locations = link.text.match(/^Has been clicked at (?<x>[\d.-]+),(?<y>[\d.-]+)$/)
762
762
  # 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
763
  # integer/float conversions and rounding.
764
764
  expect(locations[:x].to_f).to be_within(1).of(5)
@@ -808,7 +808,10 @@ Capybara::SpecHelper.spec 'node' do
808
808
  context 'offset', requires: [:js] do
809
809
  before do
810
810
  @session.visit('/offset')
811
- @clicker = @session.find(:id, 'clicker')
811
+ end
812
+
813
+ let :clicker do
814
+ @session.find(:id, 'clicker')
812
815
  end
813
816
 
814
817
  context 'when w3c_click_offset is false' do
@@ -817,17 +820,17 @@ Capybara::SpecHelper.spec 'node' do
817
820
  end
818
821
 
819
822
  it 'should offset from top left of element' do
820
- @clicker.click(x: 10, y: 5)
823
+ clicker.click(x: 10, y: 5)
821
824
  expect(@session).to have_text(/clicked at 110,105/)
822
825
  end
823
826
 
824
827
  it 'should offset outside the element' do
825
- @clicker.click(x: -15, y: -10)
828
+ clicker.click(x: -15, y: -10)
826
829
  expect(@session).to have_text(/clicked at 85,90/)
827
830
  end
828
831
 
829
832
  it 'should default to click the middle' do
830
- @clicker.click
833
+ clicker.click
831
834
  expect(@session).to have_text(/clicked at 150,150/)
832
835
  end
833
836
  end
@@ -838,21 +841,30 @@ Capybara::SpecHelper.spec 'node' do
838
841
  end
839
842
 
840
843
  it 'should offset from center of element' do
841
- @clicker.click(x: 10, y: 5)
844
+ clicker.click(x: 10, y: 5)
842
845
  expect(@session).to have_text(/clicked at 160,155/)
843
846
  end
844
847
 
845
848
  it 'should offset outside from center of element' do
846
- @clicker.click(x: -65, y: -60)
849
+ clicker.click(x: -65, y: -60)
847
850
  expect(@session).to have_text(/clicked at 85,90/)
848
851
  end
849
852
 
850
853
  it 'should default to click the middle' do
851
- @clicker.click
854
+ clicker.click
852
855
  expect(@session).to have_text(/clicked at 150,150/)
853
856
  end
854
857
  end
855
858
  end
859
+
860
+ context 'delay', requires: [:js] do
861
+ it 'should delay the mouse up' do
862
+ @session.visit('with_js')
863
+ @session.find(:css, '#click-test').click(delay: 2)
864
+ delay = @session.evaluate_script('window.click_delay')
865
+ expect(delay).to be >= 2
866
+ end
867
+ end
856
868
  end
857
869
 
858
870
  describe '#double_click', requires: [:js] do
@@ -872,7 +884,7 @@ Capybara::SpecHelper.spec 'node' do
872
884
  @session.visit('with_js')
873
885
  @session.find(:css, '#click-test').double_click(x: 10, y: 5)
874
886
  link = @session.find(:link, 'has-been-double-clicked')
875
- locations = link.text.match(/^Has been double clicked at (?<x>[\d\.-]+),(?<y>[\d\.-]+)$/)
887
+ locations = link.text.match(/^Has been double clicked at (?<x>[\d.-]+),(?<y>[\d.-]+)$/)
876
888
  # 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
889
  # to integer/float conversions and rounding.
878
890
  expect(locations[:x].to_f).to be_within(1).of(10)
@@ -891,7 +903,10 @@ Capybara::SpecHelper.spec 'node' do
891
903
  context 'offset', requires: [:js] do
892
904
  before do
893
905
  @session.visit('/offset')
894
- @clicker = @session.find(:id, 'clicker')
906
+ end
907
+
908
+ let :clicker do
909
+ @session.find(:id, 'clicker')
895
910
  end
896
911
 
897
912
  context 'when w3c_click_offset is false' do
@@ -900,17 +915,17 @@ Capybara::SpecHelper.spec 'node' do
900
915
  end
901
916
 
902
917
  it 'should offset from top left of element' do
903
- @clicker.double_click(x: 10, y: 5)
918
+ clicker.double_click(x: 10, y: 5)
904
919
  expect(@session).to have_text(/clicked at 110,105/)
905
920
  end
906
921
 
907
922
  it 'should offset outside the element' do
908
- @clicker.double_click(x: -15, y: -10)
923
+ clicker.double_click(x: -15, y: -10)
909
924
  expect(@session).to have_text(/clicked at 85,90/)
910
925
  end
911
926
 
912
927
  it 'should default to click the middle' do
913
- @clicker.double_click
928
+ clicker.double_click
914
929
  expect(@session).to have_text(/clicked at 150,150/)
915
930
  end
916
931
  end
@@ -921,17 +936,17 @@ Capybara::SpecHelper.spec 'node' do
921
936
  end
922
937
 
923
938
  it 'should offset from center of element' do
924
- @clicker.double_click(x: 10, y: 5)
939
+ clicker.double_click(x: 10, y: 5)
925
940
  expect(@session).to have_text(/clicked at 160,155/)
926
941
  end
927
942
 
928
943
  it 'should offset outside from center of element' do
929
- @clicker.double_click(x: -65, y: -60)
944
+ clicker.double_click(x: -65, y: -60)
930
945
  expect(@session).to have_text(/clicked at 85,90/)
931
946
  end
932
947
 
933
948
  it 'should default to click the middle' do
934
- @clicker.double_click
949
+ clicker.double_click
935
950
  expect(@session).to have_text(/clicked at 150,150/)
936
951
  end
937
952
  end
@@ -955,7 +970,7 @@ Capybara::SpecHelper.spec 'node' do
955
970
  @session.visit('with_js')
956
971
  @session.find(:css, '#click-test').right_click(x: 10, y: 10)
957
972
  link = @session.find(:link, 'has-been-right-clicked')
958
- locations = link.text.match(/^Has been right clicked at (?<x>[\d\.-]+),(?<y>[\d\.-]+)$/)
973
+ locations = link.text.match(/^Has been right clicked at (?<x>[\d.-]+),(?<y>[\d.-]+)$/)
959
974
  # 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
975
  # to integer/float conversions and rounding
961
976
  expect(locations[:x].to_f).to be_within(1).of(10)
@@ -974,7 +989,10 @@ Capybara::SpecHelper.spec 'node' do
974
989
  context 'offset', requires: [:js] do
975
990
  before do
976
991
  @session.visit('/offset')
977
- @clicker = @session.find(:id, 'clicker')
992
+ end
993
+
994
+ let :clicker do
995
+ @session.find(:id, 'clicker')
978
996
  end
979
997
 
980
998
  context 'when w3c_click_offset is false' do
@@ -983,17 +1001,17 @@ Capybara::SpecHelper.spec 'node' do
983
1001
  end
984
1002
 
985
1003
  it 'should offset from top left of element' do
986
- @clicker.right_click(x: 10, y: 5)
1004
+ clicker.right_click(x: 10, y: 5)
987
1005
  expect(@session).to have_text(/clicked at 110,105/)
988
1006
  end
989
1007
 
990
1008
  it 'should offset outside the element' do
991
- @clicker.right_click(x: -15, y: -10)
1009
+ clicker.right_click(x: -15, y: -10)
992
1010
  expect(@session).to have_text(/clicked at 85,90/)
993
1011
  end
994
1012
 
995
1013
  it 'should default to click the middle' do
996
- @clicker.right_click
1014
+ clicker.right_click
997
1015
  expect(@session).to have_text(/clicked at 150,150/)
998
1016
  end
999
1017
  end
@@ -1004,21 +1022,30 @@ Capybara::SpecHelper.spec 'node' do
1004
1022
  end
1005
1023
 
1006
1024
  it 'should offset from center of element' do
1007
- @clicker.right_click(x: 10, y: 5)
1025
+ clicker.right_click(x: 10, y: 5)
1008
1026
  expect(@session).to have_text(/clicked at 160,155/)
1009
1027
  end
1010
1028
 
1011
1029
  it 'should offset outside from center of element' do
1012
- @clicker.right_click(x: -65, y: -60)
1030
+ clicker.right_click(x: -65, y: -60)
1013
1031
  expect(@session).to have_text(/clicked at 85,90/)
1014
1032
  end
1015
1033
 
1016
1034
  it 'should default to click the middle' do
1017
- @clicker.right_click
1035
+ clicker.right_click
1018
1036
  expect(@session).to have_text(/clicked at 150,150/)
1019
1037
  end
1020
1038
  end
1021
1039
  end
1040
+
1041
+ context 'delay', requires: [:js] do
1042
+ it 'should delay the mouse up' do
1043
+ @session.visit('with_js')
1044
+ @session.find(:css, '#click-test').right_click(delay: 2)
1045
+ delay = @session.evaluate_script('window.right_click_delay')
1046
+ expect(delay).to be >= 2
1047
+ end
1048
+ end
1022
1049
  end
1023
1050
 
1024
1051
  describe '#send_keys', requires: [:send_keys] do