capybara 3.29.0 → 3.33.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +91 -1
  3. data/README.md +10 -3
  4. data/lib/capybara.rb +17 -7
  5. data/lib/capybara/config.rb +7 -3
  6. data/lib/capybara/cucumber.rb +1 -1
  7. data/lib/capybara/dsl.rb +10 -2
  8. data/lib/capybara/helpers.rb +3 -1
  9. data/lib/capybara/minitest.rb +232 -144
  10. data/lib/capybara/minitest/spec.rb +153 -97
  11. data/lib/capybara/node/actions.rb +35 -35
  12. data/lib/capybara/node/document.rb +2 -2
  13. data/lib/capybara/node/document_matchers.rb +3 -3
  14. data/lib/capybara/node/element.rb +23 -16
  15. data/lib/capybara/node/finders.rb +17 -11
  16. data/lib/capybara/node/matchers.rb +64 -51
  17. data/lib/capybara/node/simple.rb +4 -2
  18. data/lib/capybara/queries/ancestor_query.rb +1 -1
  19. data/lib/capybara/queries/base_query.rb +2 -1
  20. data/lib/capybara/queries/selector_query.rb +25 -5
  21. data/lib/capybara/queries/sibling_query.rb +1 -1
  22. data/lib/capybara/queries/style_query.rb +1 -1
  23. data/lib/capybara/queries/text_query.rb +6 -0
  24. data/lib/capybara/rack_test/browser.rb +7 -2
  25. data/lib/capybara/rack_test/driver.rb +1 -1
  26. data/lib/capybara/rack_test/form.rb +1 -1
  27. data/lib/capybara/rack_test/node.rb +34 -9
  28. data/lib/capybara/registration_container.rb +44 -0
  29. data/lib/capybara/registrations/servers.rb +1 -1
  30. data/lib/capybara/result.rb +29 -5
  31. data/lib/capybara/rspec/matcher_proxies.rb +4 -4
  32. data/lib/capybara/rspec/matchers.rb +27 -27
  33. data/lib/capybara/rspec/matchers/base.rb +12 -6
  34. data/lib/capybara/rspec/matchers/count_sugar.rb +2 -1
  35. data/lib/capybara/rspec/matchers/have_ancestor.rb +4 -3
  36. data/lib/capybara/rspec/matchers/have_current_path.rb +2 -2
  37. data/lib/capybara/rspec/matchers/have_selector.rb +15 -7
  38. data/lib/capybara/rspec/matchers/have_sibling.rb +3 -3
  39. data/lib/capybara/rspec/matchers/have_text.rb +3 -3
  40. data/lib/capybara/rspec/matchers/have_title.rb +2 -2
  41. data/lib/capybara/rspec/matchers/match_selector.rb +3 -3
  42. data/lib/capybara/rspec/matchers/match_style.rb +2 -2
  43. data/lib/capybara/rspec/matchers/spatial_sugar.rb +2 -1
  44. data/lib/capybara/selector.rb +34 -17
  45. data/lib/capybara/selector/css.rb +1 -1
  46. data/lib/capybara/selector/definition.rb +7 -6
  47. data/lib/capybara/selector/definition/button.rb +8 -2
  48. data/lib/capybara/selector/definition/checkbox.rb +2 -2
  49. data/lib/capybara/selector/definition/css.rb +3 -1
  50. data/lib/capybara/selector/definition/datalist_input.rb +1 -1
  51. data/lib/capybara/selector/definition/datalist_option.rb +1 -1
  52. data/lib/capybara/selector/definition/element.rb +1 -1
  53. data/lib/capybara/selector/definition/field.rb +1 -1
  54. data/lib/capybara/selector/definition/file_field.rb +1 -1
  55. data/lib/capybara/selector/definition/fillable_field.rb +2 -2
  56. data/lib/capybara/selector/definition/label.rb +4 -2
  57. data/lib/capybara/selector/definition/link.rb +8 -0
  58. data/lib/capybara/selector/definition/radio_button.rb +2 -2
  59. data/lib/capybara/selector/definition/select.rb +32 -13
  60. data/lib/capybara/selector/definition/table.rb +6 -3
  61. data/lib/capybara/selector/filter_set.rb +11 -9
  62. data/lib/capybara/selector/filters/base.rb +6 -1
  63. data/lib/capybara/selector/filters/locator_filter.rb +1 -1
  64. data/lib/capybara/selector/selector.rb +8 -2
  65. data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -1
  66. data/lib/capybara/selenium/atoms/src/getAttribute.js +1 -1
  67. data/lib/capybara/selenium/driver.rb +22 -11
  68. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +8 -10
  69. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +7 -9
  70. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +2 -2
  71. data/lib/capybara/selenium/extensions/html5_drag.rb +30 -13
  72. data/lib/capybara/selenium/node.rb +97 -18
  73. data/lib/capybara/selenium/nodes/chrome_node.rb +11 -14
  74. data/lib/capybara/selenium/nodes/edge_node.rb +4 -2
  75. data/lib/capybara/selenium/nodes/firefox_node.rb +4 -4
  76. data/lib/capybara/selenium/patches/action_pauser.rb +26 -0
  77. data/lib/capybara/selenium/patches/logs.rb +3 -5
  78. data/lib/capybara/server.rb +15 -3
  79. data/lib/capybara/server/checker.rb +1 -1
  80. data/lib/capybara/server/middleware.rb +20 -10
  81. data/lib/capybara/session.rb +43 -26
  82. data/lib/capybara/session/config.rb +9 -3
  83. data/lib/capybara/session/matchers.rb +6 -6
  84. data/lib/capybara/spec/public/test.js +69 -6
  85. data/lib/capybara/spec/session/all_spec.rb +60 -5
  86. data/lib/capybara/spec/session/ancestor_spec.rb +5 -0
  87. data/lib/capybara/spec/session/assert_text_spec.rb +9 -5
  88. data/lib/capybara/spec/session/click_button_spec.rb +16 -0
  89. data/lib/capybara/spec/session/fill_in_spec.rb +29 -0
  90. data/lib/capybara/spec/session/find_spec.rb +31 -8
  91. data/lib/capybara/spec/session/has_button_spec.rb +16 -0
  92. data/lib/capybara/spec/session/has_css_spec.rb +12 -9
  93. data/lib/capybara/spec/session/has_current_path_spec.rb +2 -2
  94. data/lib/capybara/spec/session/has_field_spec.rb +16 -0
  95. data/lib/capybara/spec/session/has_select_spec.rb +32 -4
  96. data/lib/capybara/spec/session/has_selector_spec.rb +4 -4
  97. data/lib/capybara/spec/session/has_table_spec.rb +51 -5
  98. data/lib/capybara/spec/session/has_text_spec.rb +35 -0
  99. data/lib/capybara/spec/session/node_spec.rb +160 -29
  100. data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +2 -2
  101. data/lib/capybara/spec/session/save_screenshot_spec.rb +4 -4
  102. data/lib/capybara/spec/session/selectors_spec.rb +15 -2
  103. data/lib/capybara/spec/session/window/window_spec.rb +7 -7
  104. data/lib/capybara/spec/spec_helper.rb +2 -2
  105. data/lib/capybara/spec/test_app.rb +14 -18
  106. data/lib/capybara/spec/views/form.erb +18 -2
  107. data/lib/capybara/spec/views/with_dragula.erb +3 -1
  108. data/lib/capybara/spec/views/with_html.erb +2 -2
  109. data/lib/capybara/spec/views/with_js.erb +1 -0
  110. data/lib/capybara/version.rb +1 -1
  111. data/spec/capybara_spec.rb +1 -1
  112. data/spec/dsl_spec.rb +16 -3
  113. data/spec/minitest_spec.rb +1 -1
  114. data/spec/minitest_spec_spec.rb +46 -46
  115. data/spec/rack_test_spec.rb +13 -1
  116. data/spec/regexp_dissassembler_spec.rb +40 -36
  117. data/spec/result_spec.rb +43 -32
  118. data/spec/rspec/features_spec.rb +1 -0
  119. data/spec/rspec/shared_spec_matchers.rb +68 -56
  120. data/spec/rspec_spec.rb +4 -4
  121. data/spec/selector_spec.rb +1 -1
  122. data/spec/selenium_spec_chrome.rb +9 -6
  123. data/spec/selenium_spec_chrome_remote.rb +2 -0
  124. data/spec/selenium_spec_firefox.rb +7 -2
  125. data/spec/server_spec.rb +65 -31
  126. data/spec/session_spec.rb +1 -1
  127. data/spec/shared_selenium_node.rb +21 -3
  128. data/spec/shared_selenium_session.rb +33 -14
  129. data/spec/spec_helper.rb +1 -1
  130. metadata +6 -4
@@ -20,7 +20,7 @@ module Capybara
20
20
  # @return [true]
21
21
  #
22
22
  def assert_current_path(path, **options)
23
- _verify_current_path(path, options) do |query|
23
+ _verify_current_path(path, **options) do |query|
24
24
  raise Capybara::ExpectationNotMet, query.failure_message unless query.resolves_for?(self)
25
25
  end
26
26
  end
@@ -36,7 +36,7 @@ module Capybara
36
36
  # @return [true]
37
37
  #
38
38
  def assert_no_current_path(path, **options)
39
- _verify_current_path(path, options) do |query|
39
+ _verify_current_path(path, **options) do |query|
40
40
  raise Capybara::ExpectationNotMet, query.negative_failure_message if query.resolves_for?(self)
41
41
  end
42
42
  end
@@ -51,7 +51,7 @@ module Capybara
51
51
  # @return [Boolean]
52
52
  #
53
53
  def has_current_path?(path, **options)
54
- make_predicate(options) { assert_current_path(path, options) }
54
+ make_predicate(options) { assert_current_path(path, **options) }
55
55
  end
56
56
 
57
57
  ##
@@ -64,13 +64,13 @@ module Capybara
64
64
  # @return [Boolean]
65
65
  #
66
66
  def has_no_current_path?(path, **options)
67
- make_predicate(options) { assert_no_current_path(path, options) }
67
+ make_predicate(options) { assert_no_current_path(path, **options) }
68
68
  end
69
69
 
70
70
  private
71
71
 
72
- def _verify_current_path(path, options)
73
- query = Capybara::Queries::CurrentPathQuery.new(path, options)
72
+ def _verify_current_path(path, **options)
73
+ query = Capybara::Queries::CurrentPathQuery.new(path, **options)
74
74
  document.synchronize(query.wait) do
75
75
  yield(query)
76
76
  end
@@ -1,21 +1,57 @@
1
1
  var activeRequests = 0;
2
2
  $(function() {
3
3
  $('#change').text('I changed it');
4
- $('#drag, #drag_scroll, #drag_link').draggable();
4
+ $('#drag, #drag_scroll, #drag_link').draggable({
5
+ start: function(event, ui){
6
+ $(document.body).append(
7
+ "<div class='drag_start'>Dragged!" +
8
+ (event.altKey ? "-alt" : "") +
9
+ (event.ctrlKey ? "-ctrl" : "") +
10
+ (event.metaKey ? "-meta" : "") +
11
+ (event.shiftKey ? "-shift" : "") +
12
+ "</div>"
13
+ );
14
+ }
15
+ });
5
16
  $('#drop, #drop_scroll').droppable({
6
17
  tolerance: 'touch',
7
18
  drop: function(event, ui) {
8
19
  ui.draggable.remove();
9
- $(this).html('Dropped!');
20
+ $(this).html(
21
+ "Dropped!" +
22
+ (event.altKey ? "-alt" : "") +
23
+ (event.ctrlKey ? "-ctrl" : "") +
24
+ (event.metaKey ? "-meta" : "") +
25
+ (event.shiftKey ? "-shift" : "")
26
+ );
10
27
  }
11
28
  });
12
29
  $('#drag_html5, #drag_html5_scroll').on('dragstart', function(ev){
30
+ $(document.body).append(
31
+ "<div class='drag_start'>HTML5 Dragged!" +
32
+ (event.altKey ? "-alt" : "") +
33
+ (event.ctrlKey ? "-ctrl" : "") +
34
+ (event.metaKey ? "-meta" : "") +
35
+ (event.shiftKey ? "-shift" : "") +
36
+ "</div>"
37
+ );
13
38
  ev.originalEvent.dataTransfer.setData("text", ev.target.id);
14
39
  });
40
+ $('#drag_html5, #drag_html5_scroll').on('dragend', function(ev){
41
+ $(this).after('<div class="log">DragEnd with client position: ' + ev.clientX + ',' + ev.clientY)
42
+ });
15
43
  $('#drop_html5, #drop_html5_scroll').on('dragover', function(ev){
16
44
  $(this).after('<div class="log">DragOver with client position: ' + ev.clientX + ',' + ev.clientY)
17
45
  if ($(this).hasClass('drop')) { ev.preventDefault(); }
18
46
  });
47
+ $('#drop_html5, #drop_html5_scroll').on('dragleave', function(ev){
48
+ $(this).after('<div class="log">DragLeave with client position: ' + ev.clientX + ',' + ev.clientY)
49
+ if ($(this).hasClass('drop')) { ev.preventDefault(); }
50
+ });
51
+ $('#drop_html5, #drop_html5_scroll').on('drop', function(ev){
52
+ $(this).after('<div class="log">Drop with client position: ' + ev.clientX + ',' + ev.clientY)
53
+ if ($(this).hasClass('drop')) { ev.preventDefault(); }
54
+ });
19
55
  $('#drop_html5, #drop_html5_scroll').on('drop', function(ev){
20
56
  ev.preventDefault();
21
57
  var oev = ev.originalEvent;
@@ -27,10 +63,19 @@ $(function() {
27
63
  $(this).append('HTML5 Dropped file: ' + file.name);
28
64
  } else {
29
65
  var _this = this;
30
- var callback = (function(type){
31
- return function(s){
32
- $(_this).append('HTML5 Dropped string: ' + type + ' ' + s)
33
- }
66
+ var callback = (function(type) {
67
+ return function(s) {
68
+ $(_this).append(
69
+ "HTML5 Dropped string: " +
70
+ type +
71
+ " " +
72
+ s +
73
+ (ev.altKey ? "-alt" : "") +
74
+ (ev.ctrlKey ? "-ctrl" : "") +
75
+ (ev.metaKey ? "-meta" : "") +
76
+ (ev.shiftKey ? "-shift" : "")
77
+ );
78
+ };
34
79
  })(item.type);
35
80
  item.getAsString(callback);
36
81
  }
@@ -63,6 +108,13 @@ $(function() {
63
108
  }, 4000);
64
109
  return false;
65
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
+ });
66
118
  $('#waiter').change(function() {
67
119
  activeRequests = 1;
68
120
  setTimeout(function() {
@@ -108,6 +160,7 @@ $(function() {
108
160
  });
109
161
  $('#click-test').on({
110
162
  click: function(e) {
163
+ window.click_delay = ((new Date().getTime()) - window.mouse_down_time)/1000.0;
111
164
  var desc = "";
112
165
  if (e.altKey) desc += 'alt ';
113
166
  if (e.ctrlKey) desc += 'control ';
@@ -134,6 +187,16 @@ $(function() {
134
187
  if (e.shiftKey) desc += 'shift ';
135
188
  var pos = this.getBoundingClientRect();
136
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
+ }
137
200
  }
138
201
  });
139
202
  $('#open-alert').click(function() {
@@ -36,10 +36,50 @@ Capybara::SpecHelper.spec '#all' do
36
36
  expect(@result).to include('Smith', 'John', 'John Smith')
37
37
  end
38
38
 
39
+ it 'should allow reversing the order' do
40
+ @session.visit('/form')
41
+ fields = @session.all(:fillable_field, 'Name', exact: false).to_a
42
+ reverse_fields = @session.all(:fillable_field, 'Name', order: :reverse, exact: false).to_a
43
+ expect(fields).to eq(reverse_fields.reverse)
44
+ end
45
+
39
46
  it 'should raise an error when given invalid options' do
40
47
  expect { @session.all('//p', schmoo: 'foo') }.to raise_error(ArgumentError)
41
48
  end
42
49
 
50
+ it 'should not reload by default', requires: [:driver] do
51
+ paras = @session.all(:css, 'p', minimum: 3)
52
+ expect { paras[0].text }.not_to raise_error
53
+ @session.refresh
54
+ expect { paras[0].text }.to raise_error do |err|
55
+ expect(err).to be_an_invalid_element_error(@session)
56
+ end
57
+ end
58
+
59
+ context 'with allow_reload' do
60
+ it 'should reload if true' do
61
+ paras = @session.all(:css, 'p', allow_reload: true, minimum: 3)
62
+ expect { paras[0].text }.not_to raise_error
63
+ @session.refresh
64
+ sleep 1 # Ensure page has started to reload
65
+ expect(paras[0]).to have_text('Lorem ipsum dolor')
66
+ expect(paras[1]).to have_text('Duis aute irure dolor')
67
+ end
68
+
69
+ it 'should not reload if false', requires: [:driver] do
70
+ paras = @session.all(:css, 'p', allow_reload: false, minimum: 3)
71
+ expect { paras[0].text }.not_to raise_error
72
+ @session.refresh
73
+ sleep 1 # Ensure page has started to reload
74
+ expect { paras[0].text }.to raise_error do |err|
75
+ expect(err).to be_an_invalid_element_error(@session)
76
+ end
77
+ expect { paras[2].text }.to raise_error do |err|
78
+ expect(err).to be_an_invalid_element_error(@session)
79
+ end
80
+ end
81
+ end
82
+
43
83
  context 'with css selectors' do
44
84
  it 'should find all elements using the given selector' do
45
85
  expect(@session.all(:css, 'h1').first.text).to eq('This is a test')
@@ -128,6 +168,7 @@ Capybara::SpecHelper.spec '#all' do
128
168
  it 'should succeed when the number of elements founds matches the expectation' do
129
169
  expect { @session.all(:css, 'h1, p', count: 4) }.not_to raise_error
130
170
  end
171
+
131
172
  it 'should raise ExpectationNotMet when the number of elements founds does not match the expectation' do
132
173
  expect { @session.all(:css, 'h1, p', count: 5) }.to raise_error(Capybara::ExpectationNotMet)
133
174
  end
@@ -137,6 +178,7 @@ Capybara::SpecHelper.spec '#all' do
137
178
  it 'should succeed when the number of elements founds matches the expectation' do
138
179
  expect { @session.all(:css, 'h1, p', minimum: 0) }.not_to raise_error
139
180
  end
181
+
140
182
  it 'should raise ExpectationNotMet when the number of elements founds does not match the expectation' do
141
183
  expect { @session.all(:css, 'h1, p', minimum: 5) }.to raise_error(Capybara::ExpectationNotMet)
142
184
  end
@@ -146,6 +188,7 @@ Capybara::SpecHelper.spec '#all' do
146
188
  it 'should succeed when the number of elements founds matches the expectation' do
147
189
  expect { @session.all(:css, 'h1, p', maximum: 4) }.not_to raise_error
148
190
  end
191
+
149
192
  it 'should raise ExpectationNotMet when the number of elements founds does not match the expectation' do
150
193
  expect { @session.all(:css, 'h1, p', maximum: 0) }.to raise_error(Capybara::ExpectationNotMet)
151
194
  end
@@ -155,6 +198,7 @@ Capybara::SpecHelper.spec '#all' do
155
198
  it 'should succeed when the number of elements founds matches the expectation' do
156
199
  expect { @session.all(:css, 'h1, p', between: 2..7) }.not_to raise_error
157
200
  end
201
+
158
202
  it 'should raise ExpectationNotMet when the number of elements founds does not match the expectation' do
159
203
  expect { @session.all(:css, 'h1, p', between: 0..3) }.to raise_error(Capybara::ExpectationNotMet)
160
204
  end
@@ -165,6 +209,13 @@ Capybara::SpecHelper.spec '#all' do
165
209
  expect { @session.all(:css, 'h1, p', between: 5..) }.to raise_error(Capybara::ExpectationNotMet)
166
210
  end
167
211
  TEST
212
+
213
+ eval <<~TEST, binding, __FILE__, __LINE__ + 1 if RUBY_VERSION.to_f > 2.6
214
+ it'treats a beginless range as maximum' do
215
+ expect { @session.all(:css, 'h1, p', between: ..7) }.not_to raise_error
216
+ expect { @session.all(:css, 'h1, p', between: ..3) }.to raise_error(Capybara::ExpectationNotMet)
217
+ end
218
+ TEST
168
219
  end
169
220
 
170
221
  context 'with multiple count filters' do
@@ -173,32 +224,36 @@ Capybara::SpecHelper.spec '#all' do
173
224
  minimum: 5,
174
225
  maximum: 0,
175
226
  between: 0..3 }
176
- expect { @session.all(:css, 'h1, p', o) }.not_to raise_error
227
+ expect { @session.all(:css, 'h1, p', **o) }.not_to raise_error
177
228
  end
229
+
178
230
  context 'with no :count expectation' do
179
231
  it 'fails if :minimum is not met' do
180
232
  o = { minimum: 5,
181
233
  maximum: 4,
182
234
  between: 2..7 }
183
- expect { @session.all(:css, 'h1, p', o) }.to raise_error(Capybara::ExpectationNotMet)
235
+ expect { @session.all(:css, 'h1, p', **o) }.to raise_error(Capybara::ExpectationNotMet)
184
236
  end
237
+
185
238
  it 'fails if :maximum is not met' do
186
239
  o = { minimum: 0,
187
240
  maximum: 0,
188
241
  between: 2..7 }
189
- expect { @session.all(:css, 'h1, p', o) }.to raise_error(Capybara::ExpectationNotMet)
242
+ expect { @session.all(:css, 'h1, p', **o) }.to raise_error(Capybara::ExpectationNotMet)
190
243
  end
244
+
191
245
  it 'fails if :between is not met' do
192
246
  o = { minimum: 0,
193
247
  maximum: 4,
194
248
  between: 0..3 }
195
- expect { @session.all(:css, 'h1, p', o) }.to raise_error(Capybara::ExpectationNotMet)
249
+ expect { @session.all(:css, 'h1, p', **o) }.to raise_error(Capybara::ExpectationNotMet)
196
250
  end
251
+
197
252
  it 'succeeds if all combineable expectations are met' do
198
253
  o = { minimum: 0,
199
254
  maximum: 4,
200
255
  between: 2..7 }
201
- expect { @session.all(:css, 'h1, p', o) }.not_to raise_error
256
+ expect { @session.all(:css, 'h1, p', **o) }.not_to raise_error
202
257
  end
203
258
  end
204
259
  end
@@ -20,6 +20,11 @@ Capybara::SpecHelper.spec '#ancestor' do
20
20
  expect(el.ancestor('//div', text: "Ancestor\nAncestor\nAncestor")[:id]).to eq('ancestor3')
21
21
  end
22
22
 
23
+ it 'should find the closest ancestor' do
24
+ el = @session.find(:css, '#child')
25
+ expect(el.ancestor('.//div', order: :reverse, match: :first)[:id]).to eq('ancestor1')
26
+ end
27
+
23
28
  it 'should raise an error if there are multiple matches' do
24
29
  el = @session.find(:css, '#child')
25
30
  expect { el.ancestor('//div') }.to raise_error(Capybara::Ambiguous)
@@ -157,32 +157,36 @@ Capybara::SpecHelper.spec '#assert_text' do
157
157
  minimum: 6,
158
158
  maximum: 0,
159
159
  between: 0..4 }
160
- expect { @session.assert_text('Header', o) }.not_to raise_error
160
+ expect { @session.assert_text('Header', **o) }.not_to raise_error
161
161
  end
162
+
162
163
  context 'with no :count expectation' do
163
164
  it 'fails if :minimum is not met' do
164
165
  o = { minimum: 6,
165
166
  maximum: 5,
166
167
  between: 2..7 }
167
- expect { @session.assert_text('Header', o) }.to raise_error(Capybara::ExpectationNotMet)
168
+ expect { @session.assert_text('Header', **o) }.to raise_error(Capybara::ExpectationNotMet)
168
169
  end
170
+
169
171
  it 'fails if :maximum is not met' do
170
172
  o = { minimum: 0,
171
173
  maximum: 0,
172
174
  between: 2..7 }
173
- expect { @session.assert_text('Header', o) }.to raise_error(Capybara::ExpectationNotMet)
175
+ expect { @session.assert_text('Header', **o) }.to raise_error(Capybara::ExpectationNotMet)
174
176
  end
177
+
175
178
  it 'fails if :between is not met' do
176
179
  o = { minimum: 0,
177
180
  maximum: 5,
178
181
  between: 0..4 }
179
- expect { @session.assert_text('Header', o) }.to raise_error(Capybara::ExpectationNotMet)
182
+ expect { @session.assert_text('Header', **o) }.to raise_error(Capybara::ExpectationNotMet)
180
183
  end
184
+
181
185
  it 'succeeds if all combineable expectations are met' do
182
186
  o = { minimum: 0,
183
187
  maximum: 5,
184
188
  between: 2..7 }
185
- expect { @session.assert_text('Header', o) }.not_to raise_error
189
+ expect { @session.assert_text('Header', **o) }.not_to raise_error
186
190
  end
187
191
  end
188
192
  end
@@ -186,6 +186,22 @@ Capybara::SpecHelper.spec '#click_button' do
186
186
  @session.click_button(name: 'form[awesome]')
187
187
  expect(extract_results(@session)['first_name']).to eq('John')
188
188
  end
189
+
190
+ it 'should submit by specific button name regex' do
191
+ @session.click_button(name: /form\[awes.*\]/)
192
+ expect(extract_results(@session)['first_name']).to eq('John')
193
+ end
194
+ end
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
189
205
  end
190
206
 
191
207
  context 'with fields associated with the form using the form attribute', requires: [:form_attribute] do
@@ -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')
@@ -95,6 +104,26 @@ Capybara::SpecHelper.spec '#fill_in' do
95
104
  expect(extract_results(@session)['html5_color']).to eq('#112233')
96
105
  end
97
106
 
107
+ describe 'with input[type="range"]' do
108
+ it 'should set the range slider correctly' do
109
+ @session.fill_in('form_age', with: 51)
110
+ @session.click_button('awesome')
111
+ expect(extract_results(@session)['age'].to_f).to eq 51
112
+ end
113
+
114
+ it 'should set the range slider to valid values' do
115
+ @session.fill_in('form_age', with: '37.6')
116
+ @session.click_button('awesome')
117
+ expect(extract_results(@session)['age'].to_f).to eq 37.5
118
+ end
119
+
120
+ it 'should respect the range slider limits' do
121
+ @session.fill_in('form_age', with: '3')
122
+ @session.click_button('awesome')
123
+ expect(extract_results(@session)['age'].to_f).to eq 13
124
+ end
125
+ end
126
+
98
127
  it 'should fill in a field with a custom type' do
99
128
  @session.fill_in('Schmooo', with: 'Schmooo is the game')
100
129
  @session.click_button('awesome')
@@ -275,14 +275,17 @@ Capybara::SpecHelper.spec '#find' do
275
275
  @session.find(:css, '.multiple', match: :one)
276
276
  end.to raise_error(Capybara::Ambiguous)
277
277
  end
278
+
278
279
  it 'raises an error even if there the match is exact and the others are inexact' do
279
280
  expect do
280
281
  @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singular')], exact: false, match: :one)
281
282
  end.to raise_error(Capybara::Ambiguous)
282
283
  end
284
+
283
285
  it 'returns the element if there is only one' do
284
286
  expect(@session.find(:css, '.singular', match: :one).text).to eq('singular')
285
287
  end
288
+
286
289
  it 'raises an error if there is no match' do
287
290
  expect do
288
291
  @session.find(:css, '.does-not-exist', match: :one)
@@ -294,6 +297,7 @@ Capybara::SpecHelper.spec '#find' do
294
297
  it 'returns the first matched element' do
295
298
  expect(@session.find(:css, '.multiple', match: :first).text).to eq('multiple one')
296
299
  end
300
+
297
301
  it 'raises an error if there is no match' do
298
302
  expect do
299
303
  @session.find(:css, '.does-not-exist', match: :first)
@@ -308,19 +312,23 @@ Capybara::SpecHelper.spec '#find' do
308
312
  @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('multiple')], match: :smart, exact: false)
309
313
  end.to raise_error(Capybara::Ambiguous)
310
314
  end
315
+
311
316
  it 'finds a single exact match when there also are inexact matches' do
312
317
  result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singular')], match: :smart, exact: false)
313
318
  expect(result.text).to eq('almost singular')
314
319
  end
320
+
315
321
  it 'raises an error when there are multiple inexact matches' do
316
322
  expect do
317
323
  @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singul')], match: :smart, exact: false)
318
324
  end.to raise_error(Capybara::Ambiguous)
319
325
  end
326
+
320
327
  it 'finds a single inexact match' do
321
328
  result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singular but')], match: :smart, exact: false)
322
329
  expect(result.text).to eq('almost singular but not quite')
323
330
  end
331
+
324
332
  it 'raises an error if there is no match' do
325
333
  expect do
326
334
  @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('does-not-exist')], match: :smart, exact: false)
@@ -334,20 +342,24 @@ Capybara::SpecHelper.spec '#find' do
334
342
  @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('multiple')], match: :smart, exact: true)
335
343
  end.to raise_error(Capybara::Ambiguous)
336
344
  end
345
+
337
346
  it 'finds a single exact match when there also are inexact matches' do
338
347
  result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singular')], match: :smart, exact: true)
339
348
  expect(result.text).to eq('almost singular')
340
349
  end
350
+
341
351
  it 'raises an error when there are multiple inexact matches' do
342
352
  expect do
343
353
  @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singul')], match: :smart, exact: true)
344
354
  end.to raise_error(Capybara::ElementNotFound)
345
355
  end
356
+
346
357
  it 'raises an error when there is a single inexact matches' do
347
358
  expect do
348
359
  @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singular but')], match: :smart, exact: true)
349
360
  end.to raise_error(Capybara::ElementNotFound)
350
361
  end
362
+
351
363
  it 'raises an error if there is no match' do
352
364
  expect do
353
365
  @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('does-not-exist')], match: :smart, exact: true)
@@ -362,18 +374,22 @@ Capybara::SpecHelper.spec '#find' do
362
374
  result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('multiple')], match: :prefer_exact, exact: false)
363
375
  expect(result.text).to eq('multiple one')
364
376
  end
377
+
365
378
  it 'finds a single exact match when there also are inexact matches' do
366
379
  result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singular')], match: :prefer_exact, exact: false)
367
380
  expect(result.text).to eq('almost singular')
368
381
  end
382
+
369
383
  it 'picks the first one when there are multiple inexact matches' do
370
384
  result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singul')], match: :prefer_exact, exact: false)
371
385
  expect(result.text).to eq('almost singular but not quite')
372
386
  end
387
+
373
388
  it 'finds a single inexact match' do
374
389
  result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singular but')], match: :prefer_exact, exact: false)
375
390
  expect(result.text).to eq('almost singular but not quite')
376
391
  end
392
+
377
393
  it 'raises an error if there is no match' do
378
394
  expect do
379
395
  @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('does-not-exist')], match: :prefer_exact, exact: false)
@@ -386,20 +402,24 @@ Capybara::SpecHelper.spec '#find' do
386
402
  result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('multiple')], match: :prefer_exact, exact: true)
387
403
  expect(result.text).to eq('multiple one')
388
404
  end
405
+
389
406
  it 'finds a single exact match when there also are inexact matches' do
390
407
  result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singular')], match: :prefer_exact, exact: true)
391
408
  expect(result.text).to eq('almost singular')
392
409
  end
410
+
393
411
  it 'raises an error if there are multiple inexact matches' do
394
412
  expect do
395
413
  @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singul')], match: :prefer_exact, exact: true)
396
414
  end.to raise_error(Capybara::ElementNotFound)
397
415
  end
416
+
398
417
  it 'raises an error if there is a single inexact match' do
399
418
  expect do
400
419
  @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singular but')], match: :prefer_exact, exact: true)
401
420
  end.to raise_error(Capybara::ElementNotFound)
402
421
  end
422
+
403
423
  it 'raises an error if there is no match' do
404
424
  expect do
405
425
  @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('does-not-exist')], match: :prefer_exact, exact: true)
@@ -431,32 +451,35 @@ Capybara::SpecHelper.spec '#find' do
431
451
  context 'with spatial filters', requires: [:spatial] do
432
452
  before do
433
453
  @session.visit('/spatial')
434
- @center = @session.find(:css, 'div.center')
454
+ end
455
+
456
+ let :center do
457
+ @session.find(:css, 'div.center')
435
458
  end
436
459
 
437
460
  it 'should find an element above another element' do
438
- 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')
439
462
  end
440
463
 
441
464
  it 'should find an element below another element' do
442
- 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')
443
466
  end
444
467
 
445
468
  it 'should find an element left of another element' do
446
- 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')
447
470
  end
448
471
 
449
472
  it 'should find an element right of another element' do
450
- 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')
451
474
  end
452
475
 
453
476
  it 'should combine spatial filters' do
454
- expect(@session.find(:css, 'div', left_of: @center, above: @center).text).to eq('1')
455
- 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')
456
479
  end
457
480
 
458
481
  it 'should find an element "near" another element' do
459
- 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')
460
483
  end
461
484
  end
462
485