capybara 3.23.0 → 3.35.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (183) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +264 -11
  3. data/README.md +10 -6
  4. data/lib/capybara.rb +20 -8
  5. data/lib/capybara/config.rb +10 -8
  6. data/lib/capybara/cucumber.rb +1 -1
  7. data/lib/capybara/driver/base.rb +4 -0
  8. data/lib/capybara/driver/node.rb +4 -0
  9. data/lib/capybara/dsl.rb +10 -2
  10. data/lib/capybara/helpers.rb +28 -2
  11. data/lib/capybara/minitest.rb +232 -144
  12. data/lib/capybara/minitest/spec.rb +156 -97
  13. data/lib/capybara/node/actions.rb +36 -36
  14. data/lib/capybara/node/base.rb +6 -6
  15. data/lib/capybara/node/document.rb +2 -2
  16. data/lib/capybara/node/document_matchers.rb +3 -3
  17. data/lib/capybara/node/element.rb +77 -33
  18. data/lib/capybara/node/finders.rb +24 -17
  19. data/lib/capybara/node/matchers.rb +79 -64
  20. data/lib/capybara/node/simple.rb +11 -4
  21. data/lib/capybara/queries/ancestor_query.rb +6 -10
  22. data/lib/capybara/queries/base_query.rb +2 -1
  23. data/lib/capybara/queries/current_path_query.rb +14 -4
  24. data/lib/capybara/queries/selector_query.rb +259 -23
  25. data/lib/capybara/queries/sibling_query.rb +5 -11
  26. data/lib/capybara/queries/style_query.rb +1 -1
  27. data/lib/capybara/queries/text_query.rb +13 -1
  28. data/lib/capybara/rack_test/browser.rb +13 -4
  29. data/lib/capybara/rack_test/driver.rb +2 -1
  30. data/lib/capybara/rack_test/form.rb +2 -2
  31. data/lib/capybara/rack_test/node.rb +42 -6
  32. data/lib/capybara/registration_container.rb +44 -0
  33. data/lib/capybara/registrations/drivers.rb +18 -12
  34. data/lib/capybara/registrations/patches/puma_ssl.rb +29 -0
  35. data/lib/capybara/registrations/servers.rb +9 -2
  36. data/lib/capybara/result.rb +39 -19
  37. data/lib/capybara/rspec.rb +2 -0
  38. data/lib/capybara/rspec/matcher_proxies.rb +5 -5
  39. data/lib/capybara/rspec/matchers.rb +97 -74
  40. data/lib/capybara/rspec/matchers/base.rb +19 -6
  41. data/lib/capybara/rspec/matchers/count_sugar.rb +2 -1
  42. data/lib/capybara/rspec/matchers/have_ancestor.rb +5 -7
  43. data/lib/capybara/rspec/matchers/have_current_path.rb +2 -2
  44. data/lib/capybara/rspec/matchers/have_selector.rb +15 -10
  45. data/lib/capybara/rspec/matchers/have_sibling.rb +4 -7
  46. data/lib/capybara/rspec/matchers/have_text.rb +4 -7
  47. data/lib/capybara/rspec/matchers/have_title.rb +2 -2
  48. data/lib/capybara/rspec/matchers/match_selector.rb +3 -3
  49. data/lib/capybara/rspec/matchers/match_style.rb +7 -2
  50. data/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
  51. data/lib/capybara/selector.rb +46 -19
  52. data/lib/capybara/selector/builders/css_builder.rb +10 -6
  53. data/lib/capybara/selector/builders/xpath_builder.rb +4 -2
  54. data/lib/capybara/selector/css.rb +1 -1
  55. data/lib/capybara/selector/definition.rb +13 -11
  56. data/lib/capybara/selector/definition/button.rb +32 -15
  57. data/lib/capybara/selector/definition/checkbox.rb +2 -2
  58. data/lib/capybara/selector/definition/css.rb +3 -1
  59. data/lib/capybara/selector/definition/datalist_input.rb +2 -2
  60. data/lib/capybara/selector/definition/datalist_option.rb +1 -1
  61. data/lib/capybara/selector/definition/element.rb +3 -2
  62. data/lib/capybara/selector/definition/field.rb +1 -1
  63. data/lib/capybara/selector/definition/file_field.rb +1 -1
  64. data/lib/capybara/selector/definition/fillable_field.rb +2 -2
  65. data/lib/capybara/selector/definition/label.rb +5 -3
  66. data/lib/capybara/selector/definition/link.rb +8 -0
  67. data/lib/capybara/selector/definition/option.rb +1 -1
  68. data/lib/capybara/selector/definition/radio_button.rb +2 -2
  69. data/lib/capybara/selector/definition/select.rb +33 -14
  70. data/lib/capybara/selector/definition/table.rb +6 -3
  71. data/lib/capybara/selector/definition/table_row.rb +2 -2
  72. data/lib/capybara/selector/filter_set.rb +13 -11
  73. data/lib/capybara/selector/filters/base.rb +6 -1
  74. data/lib/capybara/selector/filters/locator_filter.rb +1 -1
  75. data/lib/capybara/selector/regexp_disassembler.rb +7 -0
  76. data/lib/capybara/selector/selector.rb +13 -3
  77. data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -1
  78. data/lib/capybara/selenium/atoms/isDisplayed.min.js +1 -1
  79. data/lib/capybara/selenium/atoms/src/getAttribute.js +1 -1
  80. data/lib/capybara/selenium/atoms/src/isDisplayed.js +10 -10
  81. data/lib/capybara/selenium/driver.rb +86 -24
  82. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +24 -21
  83. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +21 -19
  84. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +17 -1
  85. data/lib/capybara/selenium/driver_specializations/safari_driver.rb +0 -4
  86. data/lib/capybara/selenium/extensions/file_input_click_emulation.rb +34 -0
  87. data/lib/capybara/selenium/extensions/find.rb +37 -26
  88. data/lib/capybara/selenium/extensions/html5_drag.rb +55 -11
  89. data/lib/capybara/selenium/extensions/modifier_keys_stack.rb +28 -0
  90. data/lib/capybara/selenium/extensions/scroll.rb +8 -10
  91. data/lib/capybara/selenium/logger_suppressor.rb +8 -2
  92. data/lib/capybara/selenium/node.rb +160 -40
  93. data/lib/capybara/selenium/nodes/chrome_node.rb +72 -12
  94. data/lib/capybara/selenium/nodes/edge_node.rb +32 -14
  95. data/lib/capybara/selenium/nodes/firefox_node.rb +28 -32
  96. data/lib/capybara/selenium/nodes/safari_node.rb +5 -29
  97. data/lib/capybara/selenium/patches/action_pauser.rb +26 -0
  98. data/lib/capybara/selenium/patches/atoms.rb +4 -4
  99. data/lib/capybara/selenium/patches/is_displayed.rb +16 -0
  100. data/lib/capybara/selenium/patches/logs.rb +32 -7
  101. data/lib/capybara/server.rb +19 -3
  102. data/lib/capybara/server/animation_disabler.rb +8 -3
  103. data/lib/capybara/server/checker.rb +1 -1
  104. data/lib/capybara/server/middleware.rb +22 -10
  105. data/lib/capybara/session.rb +66 -40
  106. data/lib/capybara/session/config.rb +11 -3
  107. data/lib/capybara/session/matchers.rb +11 -11
  108. data/lib/capybara/spec/public/offset.js +6 -0
  109. data/lib/capybara/spec/public/test.js +75 -7
  110. data/lib/capybara/spec/session/accept_alert_spec.rb +1 -1
  111. data/lib/capybara/spec/session/all_spec.rb +60 -5
  112. data/lib/capybara/spec/session/ancestor_spec.rb +5 -0
  113. data/lib/capybara/spec/session/assert_text_spec.rb +9 -5
  114. data/lib/capybara/spec/session/check_spec.rb +6 -0
  115. data/lib/capybara/spec/session/click_button_spec.rb +16 -0
  116. data/lib/capybara/spec/session/click_link_or_button_spec.rb +9 -0
  117. data/lib/capybara/spec/session/current_url_spec.rb +11 -1
  118. data/lib/capybara/spec/session/fill_in_spec.rb +29 -0
  119. data/lib/capybara/spec/session/find_spec.rb +55 -0
  120. data/lib/capybara/spec/session/has_ancestor_spec.rb +2 -0
  121. data/lib/capybara/spec/session/has_button_spec.rb +51 -0
  122. data/lib/capybara/spec/session/has_css_spec.rb +26 -4
  123. data/lib/capybara/spec/session/has_current_path_spec.rb +15 -2
  124. data/lib/capybara/spec/session/has_field_spec.rb +34 -0
  125. data/lib/capybara/spec/session/has_select_spec.rb +32 -4
  126. data/lib/capybara/spec/session/has_selector_spec.rb +4 -4
  127. data/lib/capybara/spec/session/has_table_spec.rb +51 -5
  128. data/lib/capybara/spec/session/has_text_spec.rb +30 -0
  129. data/lib/capybara/spec/session/html_spec.rb +1 -1
  130. data/lib/capybara/spec/session/matches_style_spec.rb +2 -2
  131. data/lib/capybara/spec/session/node_spec.rb +394 -9
  132. data/lib/capybara/spec/session/refresh_spec.rb +2 -1
  133. data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +2 -2
  134. data/lib/capybara/spec/session/save_page_spec.rb +4 -4
  135. data/lib/capybara/spec/session/save_screenshot_spec.rb +4 -15
  136. data/lib/capybara/spec/session/selectors_spec.rb +16 -3
  137. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +1 -1
  138. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +1 -1
  139. data/lib/capybara/spec/session/window/window_spec.rb +8 -8
  140. data/lib/capybara/spec/session/window/windows_spec.rb +1 -1
  141. data/lib/capybara/spec/spec_helper.rb +14 -14
  142. data/lib/capybara/spec/test_app.rb +27 -21
  143. data/lib/capybara/spec/views/form.erb +47 -4
  144. data/lib/capybara/spec/views/offset.erb +32 -0
  145. data/lib/capybara/spec/views/spatial.erb +31 -0
  146. data/lib/capybara/spec/views/with_animation.erb +37 -1
  147. data/lib/capybara/spec/views/with_dragula.erb +24 -0
  148. data/lib/capybara/spec/views/with_html.erb +24 -2
  149. data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
  150. data/lib/capybara/spec/views/with_js.erb +4 -1
  151. data/lib/capybara/spec/views/with_jstree.erb +26 -0
  152. data/lib/capybara/spec/views/with_sortable_js.erb +1 -1
  153. data/lib/capybara/version.rb +1 -1
  154. data/lib/capybara/window.rb +3 -7
  155. data/spec/basic_node_spec.rb +15 -14
  156. data/spec/capybara_spec.rb +28 -28
  157. data/spec/dsl_spec.rb +16 -3
  158. data/spec/filter_set_spec.rb +5 -5
  159. data/spec/fixtures/selenium_driver_rspec_failure.rb +1 -1
  160. data/spec/fixtures/selenium_driver_rspec_success.rb +1 -1
  161. data/spec/minitest_spec.rb +3 -2
  162. data/spec/minitest_spec_spec.rb +46 -46
  163. data/spec/rack_test_spec.rb +38 -15
  164. data/spec/regexp_dissassembler_spec.rb +52 -38
  165. data/spec/result_spec.rb +43 -32
  166. data/spec/rspec/features_spec.rb +4 -1
  167. data/spec/rspec/scenarios_spec.rb +4 -0
  168. data/spec/rspec/shared_spec_matchers.rb +68 -56
  169. data/spec/rspec_spec.rb +9 -5
  170. data/spec/selector_spec.rb +32 -17
  171. data/spec/selenium_spec_chrome.rb +78 -11
  172. data/spec/selenium_spec_chrome_remote.rb +23 -6
  173. data/spec/selenium_spec_edge.rb +15 -12
  174. data/spec/selenium_spec_firefox.rb +24 -19
  175. data/spec/selenium_spec_firefox_remote.rb +0 -8
  176. data/spec/selenium_spec_ie.rb +1 -6
  177. data/spec/server_spec.rb +106 -44
  178. data/spec/session_spec.rb +5 -5
  179. data/spec/shared_selenium_node.rb +56 -2
  180. data/spec/shared_selenium_session.rb +122 -15
  181. data/spec/spec_helper.rb +2 -2
  182. metadata +63 -17
  183. data/lib/capybara/spec/session/source_spec.rb +0 -0
@@ -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)
@@ -428,6 +448,41 @@ Capybara::SpecHelper.spec '#find' do
428
448
  expect(@session.find(:css, 'input', &:disabled?)[:name]).to eq('disabled_text')
429
449
  end
430
450
 
451
+ context 'with spatial filters', requires: [:spatial] do
452
+ before do
453
+ @session.visit('/spatial')
454
+ end
455
+
456
+ let :center do
457
+ @session.find(:css, 'div.center')
458
+ end
459
+
460
+ it 'should find an element above another element' do
461
+ expect(@session.find(:css, 'div:not(.corner)', above: center).text).to eq('2')
462
+ end
463
+
464
+ it 'should find an element below another element' do
465
+ expect(@session.find(:css, 'div:not(.corner):not(.footer)', below: center).text).to eq('8')
466
+ end
467
+
468
+ it 'should find an element left of another element' do
469
+ expect(@session.find(:css, 'div:not(.corner)', left_of: center).text).to eq('4')
470
+ end
471
+
472
+ it 'should find an element right of another element' do
473
+ expect(@session.find(:css, 'div:not(.corner)', right_of: center).text).to eq('6')
474
+ end
475
+
476
+ it 'should combine spatial filters' do
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')
479
+ end
480
+
481
+ it 'should find an element "near" another element' do
482
+ expect(@session.find(:css, 'div.distance', near: center).text).to eq('2')
483
+ end
484
+ end
485
+
431
486
  context 'within a scope' do
432
487
  before do
433
488
  @session.visit('/with_scope')
@@ -39,6 +39,8 @@ Capybara::SpecHelper.spec '#have_no_ancestor' do
39
39
  it 'should assert no matching ancestor' do
40
40
  el = @session.find(:css, '#ancestor1')
41
41
  expect(el).to have_no_ancestor(:css, '#child')
42
+ expect(el).to have_no_ancestor(:css, '#ancestor1_sibiling')
42
43
  expect(el).not_to have_ancestor(:css, '#child')
44
+ expect(el).not_to have_ancestor(:css, '#ancestor1_sibiling')
43
45
  end
44
46
  end
@@ -9,6 +9,8 @@ Capybara::SpecHelper.spec '#has_button?' do
9
9
  expect(@session).to have_button('med')
10
10
  expect(@session).to have_button('crap321')
11
11
  expect(@session).to have_button(:crap321)
12
+ expect(@session).to have_button('button with label element')
13
+ expect(@session).to have_button('button within label element')
12
14
  end
13
15
 
14
16
  it 'should be true for disabled buttons if disabled: true' do
@@ -39,6 +41,30 @@ Capybara::SpecHelper.spec '#has_button?' do
39
41
  expect(@session).to have_button('awe123', type: 'submit')
40
42
  expect(@session).not_to have_button('awe123', type: 'reset')
41
43
  end
44
+
45
+ it 'should be true for role=button when enable_aria_role: true' do
46
+ expect(@session).to have_button('ARIA button', enable_aria_role: true)
47
+ end
48
+
49
+ it 'should be false for a role=button within a label when enable_aria_role: true' do
50
+ expect(@session).not_to have_button('role=button within label', enable_aria_role: true)
51
+ end
52
+
53
+ it 'should be false for role=button when enable_aria_role: false' do
54
+ expect(@session).not_to have_button('ARIA button', enable_aria_role: false)
55
+ end
56
+
57
+ it 'should be false for a role=button within a label when enable_aria_role: false' do
58
+ expect(@session).not_to have_button('role=button within label', enable_aria_role: false)
59
+ end
60
+
61
+ it 'should not affect other selectors when enable_aria_role: true' do
62
+ expect(@session).to have_button('Click me!', enable_aria_role: true)
63
+ end
64
+
65
+ it 'should not affect other selectors when enable_aria_role: false' do
66
+ expect(@session).to have_button('Click me!', enable_aria_role: false)
67
+ end
42
68
  end
43
69
 
44
70
  Capybara::SpecHelper.spec '#has_no_button?' do
@@ -66,4 +92,29 @@ Capybara::SpecHelper.spec '#has_no_button?' do
66
92
  it 'should be false for disabled buttons if disabled: false' do
67
93
  expect(@session).to have_no_button('Disabled button', disabled: false)
68
94
  end
95
+
96
+ it 'should be true for role=button when enable_aria_role: false' do
97
+ expect(@session).to have_no_button('ARIA button', enable_aria_role: false)
98
+ end
99
+
100
+ it 'should be true for role=button within a label when enable_aria_role: false' do
101
+ expect(@session).to have_no_button('role=button within label', enable_aria_role: false)
102
+ end
103
+
104
+ it 'should be false for role=button when enable_aria_role: true' do
105
+ expect(@session).not_to have_no_button('ARIA button', enable_aria_role: true)
106
+ end
107
+
108
+ it 'should be true for a role=button within a label when enable_aria_role: true' do
109
+ # label element does not associate with aria button
110
+ expect(@session).to have_no_button('role=button within label', enable_aria_role: true)
111
+ end
112
+
113
+ it 'should not affect other selectors when enable_aria_role: true' do
114
+ expect(@session).to have_no_button('Junk button that does not exist', enable_aria_role: true)
115
+ end
116
+
117
+ it 'should not affect other selectors when enable_aria_role: false' do
118
+ expect(@session).to have_no_button('Junk button that does not exist', enable_aria_role: false)
119
+ end
69
120
  end
@@ -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
@@ -185,10 +186,10 @@ Capybara::SpecHelper.spec '#has_css?' do
185
186
  end
186
187
 
187
188
  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)
189
+ # expect(@session).not_to have_css('h2.head', maximum: 4) # edge case
190
+ # expect(@session).not_to have_css('h2', maximum: 3)
190
191
  expect(@session).not_to have_css('h2').at_most(3).times
191
- expect(@session).not_to have_css('p', maximum: 1)
192
+ # expect(@session).not_to have_css('p', maximum: 1)
192
193
  end
193
194
 
194
195
  it 'should coerce maximum to an integer' do
@@ -231,6 +232,27 @@ Capybara::SpecHelper.spec '#has_css?' do
231
232
  end
232
233
  end
233
234
 
235
+ context 'with spatial requirements', requires: [:spatial] do
236
+ before do
237
+ @session.visit('/spatial')
238
+ end
239
+
240
+ let :center do
241
+ @session.find(:css, '.center')
242
+ end
243
+
244
+ it 'accepts spatial options' do
245
+ expect(@session).to have_css('div', above: center).thrice
246
+ expect(@session).to have_css('div', above: center, right_of: center).once
247
+ end
248
+
249
+ it 'supports spatial sugar' do
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
253
+ end
254
+ end
255
+
234
256
  it 'should allow escapes in the CSS selector' do
235
257
  expect(@session).to have_css('p[data-random="abc\\\\def"]')
236
258
  expect(@session).to have_css("p[data-random='#{Capybara::Selector::CSS.escape('abc\def')}']")
@@ -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')
@@ -93,6 +109,24 @@ Capybara::SpecHelper.spec '#has_field' do
93
109
  expect(@session).not_to have_field('Html5 Multiple Email', multiple: false)
94
110
  end
95
111
  end
112
+
113
+ context 'with valid', requires: [:js] do
114
+ it 'should be true if field is valid' do
115
+ @session.fill_in 'required', with: 'something'
116
+ @session.fill_in 'length', with: 'abcd'
117
+
118
+ expect(@session).to have_field('required', valid: true)
119
+ expect(@session).to have_field('length', valid: true)
120
+ end
121
+
122
+ it 'should be false if field is invalid' do
123
+ expect(@session).not_to have_field('required', valid: true)
124
+ expect(@session).to have_field('required', valid: false)
125
+
126
+ @session.fill_in 'length', with: 'abc'
127
+ expect(@session).not_to have_field('length', valid: true)
128
+ end
129
+ end
96
130
  end
97
131
 
98
132
  Capybara::SpecHelper.spec '#has_no_field' do
@@ -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,35 @@ 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
+ end
118
+ end
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])
117
145
  end
118
146
  end
119
147
 
@@ -130,7 +158,7 @@ Capybara::SpecHelper.spec '#has_select?' do
130
158
  end
131
159
 
132
160
  it 'should be true even when the options are invisible, if the select itself is invisible' do
133
- 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])
134
162
  end
135
163
  end
136
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