capybara 2.14.4 → 2.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +17 -0
  3. data/README.md +14 -22
  4. data/lib/capybara.rb +16 -4
  5. data/lib/capybara/config.rb +12 -2
  6. data/lib/capybara/driver/base.rb +4 -0
  7. data/lib/capybara/node/finders.rb +79 -16
  8. data/lib/capybara/queries/ancestor_query.rb +25 -0
  9. data/lib/capybara/queries/selector_query.rb +4 -1
  10. data/lib/capybara/queries/sibling_query.rb +25 -0
  11. data/lib/capybara/rack_test/browser.rb +5 -0
  12. data/lib/capybara/rack_test/driver.rb +5 -1
  13. data/lib/capybara/rack_test/form.rb +1 -3
  14. data/lib/capybara/rack_test/node.rb +1 -1
  15. data/lib/capybara/rspec/compound.rb +95 -0
  16. data/lib/capybara/rspec/matchers.rb +4 -1
  17. data/lib/capybara/selector.rb +1 -0
  18. data/lib/capybara/selector/filter.rb +13 -41
  19. data/lib/capybara/selector/filter_set.rb +12 -5
  20. data/lib/capybara/selector/filters/base.rb +33 -0
  21. data/lib/capybara/selector/filters/expression_filter.rb +40 -0
  22. data/lib/capybara/selector/filters/node_filter.rb +27 -0
  23. data/lib/capybara/selector/selector.rb +4 -4
  24. data/lib/capybara/selenium/driver.rb +12 -2
  25. data/lib/capybara/selenium/node.rb +70 -55
  26. data/lib/capybara/session.rb +65 -41
  27. data/lib/capybara/spec/session/ancestor_spec.rb +85 -0
  28. data/lib/capybara/spec/session/attach_file_spec.rb +1 -1
  29. data/lib/capybara/spec/session/check_spec.rb +4 -4
  30. data/lib/capybara/spec/session/choose_spec.rb +2 -2
  31. data/lib/capybara/spec/session/click_button_spec.rb +1 -1
  32. data/lib/capybara/spec/session/click_link_or_button_spec.rb +3 -3
  33. data/lib/capybara/spec/session/click_link_spec.rb +1 -1
  34. data/lib/capybara/spec/session/fill_in_spec.rb +2 -2
  35. data/lib/capybara/spec/session/find_spec.rb +1 -1
  36. data/lib/capybara/spec/session/refresh_spec.rb +28 -0
  37. data/lib/capybara/spec/session/select_spec.rb +2 -2
  38. data/lib/capybara/spec/session/sibling_spec.rb +52 -0
  39. data/lib/capybara/spec/session/uncheck_spec.rb +2 -2
  40. data/lib/capybara/spec/session/unselect_spec.rb +2 -2
  41. data/lib/capybara/spec/session/window/become_closed_spec.rb +3 -3
  42. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +11 -9
  43. data/lib/capybara/spec/session/window/within_window_spec.rb +27 -2
  44. data/lib/capybara/spec/test_app.rb +3 -1
  45. data/lib/capybara/spec/views/with_html.erb +27 -1
  46. data/lib/capybara/spec/views/with_windows.erb +4 -0
  47. data/lib/capybara/version.rb +1 -1
  48. data/spec/capybara_spec.rb +9 -1
  49. data/spec/minitest_spec_spec.rb +1 -1
  50. data/spec/rspec/shared_spec_matchers.rb +146 -42
  51. data/spec/selenium_spec_chrome.rb +12 -16
  52. data/spec/selenium_spec_marionette.rb +2 -0
  53. data/spec/shared_selenium_session.rb +2 -0
  54. metadata +14 -6
  55. data/lib/capybara/selector/expression_filter.rb +0 -40
@@ -58,7 +58,7 @@ module Capybara
58
58
  ]
59
59
  SESSION_METHODS = [
60
60
  :body, :html, :source, :current_url, :current_host, :current_path,
61
- :execute_script, :evaluate_script, :visit, :go_back, :go_forward,
61
+ :execute_script, :evaluate_script, :visit, :refresh, :go_back, :go_forward,
62
62
  :within, :within_element, :within_fieldset, :within_table, :within_frame, :switch_to_frame,
63
63
  :current_window, :windows, :open_new_window, :switch_to_window, :within_window, :window_opened_by,
64
64
  :save_page, :save_and_open_page, :save_screenshot,
@@ -269,6 +269,15 @@ module Capybara
269
269
  driver.visit(visit_uri.to_s)
270
270
  end
271
271
 
272
+ ##
273
+ #
274
+ # Refresh the page
275
+ #
276
+ def refresh
277
+ raise_server_error!
278
+ driver.refresh
279
+ end
280
+
272
281
  ##
273
282
  #
274
283
  # Move back a single entry in the browser's history.
@@ -472,14 +481,14 @@ module Capybara
472
481
  # @raise [Capybara::WindowError] if no window matches given block
473
482
  # @overload switch_to_window(window)
474
483
  # @param window [Capybara::Window] window that should be switched to
475
- # @raise [Capybara::Driver::Base#no_such_window_error] if unexistent (e.g. closed) window was passed
484
+ # @raise [Capybara::Driver::Base#no_such_window_error] if non-existent (e.g. closed) window was passed
476
485
  #
477
486
  # @return [Capybara::Window] window that has been switched to
478
- # @raise [Capybara::ScopeError] if this method is invoked inside `within`,
479
- # `within_frame` or `within_window` methods
487
+ # @raise [Capybara::ScopeError] if this method is invoked inside `within` or
488
+ # `within_frame` methods
480
489
  # @raise [ArgumentError] if both or neither arguments were provided
481
490
  #
482
- def switch_to_window(window = nil, options= {})
491
+ def switch_to_window(window = nil, options= {}, &window_locator)
483
492
  options, window = window, nil if window.is_a? Hash
484
493
 
485
494
  block_given = block_given?
@@ -487,34 +496,12 @@ module Capybara
487
496
  raise ArgumentError, "`switch_to_window` can take either a block or a window, not both"
488
497
  elsif !window && !block_given
489
498
  raise ArgumentError, "`switch_to_window`: either window or block should be provided"
490
- elsif scopes.size > 1
499
+ elsif !scopes.last.nil?
491
500
  raise Capybara::ScopeError, "`switch_to_window` is not supposed to be invoked from "\
492
- "`within`'s, `within_frame`'s' or `within_window`'s' block."
501
+ "`within` or `within_frame` blocks."
493
502
  end
494
503
 
495
- if window
496
- driver.switch_to_window(window.handle)
497
- window
498
- else
499
- wait_time = Capybara::Queries::BaseQuery.wait(options, config.default_max_wait_time)
500
- document.synchronize(wait_time, errors: [Capybara::WindowError]) do
501
- original_window_handle = driver.current_window_handle
502
- begin
503
- driver.window_handles.each do |handle|
504
- driver.switch_to_window handle
505
- if yield
506
- return Window.new(self, handle)
507
- end
508
- end
509
- rescue => e
510
- driver.switch_to_window(original_window_handle)
511
- raise e
512
- else
513
- driver.switch_to_window(original_window_handle)
514
- raise Capybara::WindowError, "Could not find a window matching block/lambda"
515
- end
516
- end
517
- end
504
+ _switch_to_window(window, options, &window_locator)
518
505
  end
519
506
 
520
507
  ##
@@ -538,30 +525,35 @@ module Capybara
538
525
  # @deprecated Pass window or lambda instead
539
526
  # @param [String] handle, name, url or title of the window
540
527
  #
541
- # @raise [Capybara::ScopeError] if this method is invoked inside `within`,
542
- # `within_frame` or `within_window` methods
528
+ # @raise [Capybara::ScopeError] if this method is invoked inside `within_frame` method
543
529
  # @return value returned by the block
544
530
  #
545
531
  def within_window(window_or_handle)
546
532
  if window_or_handle.instance_of?(Capybara::Window)
547
533
  original = current_window
548
- switch_to_window(window_or_handle) unless original == window_or_handle
549
534
  scopes << nil
550
535
  begin
551
- yield
536
+ _switch_to_window(window_or_handle) unless original == window_or_handle
537
+ begin
538
+ yield
539
+ ensure
540
+ _switch_to_window(original) unless original == window_or_handle
541
+ end
552
542
  ensure
553
- @scopes.pop
554
- switch_to_window(original) unless original == window_or_handle
543
+ scopes.pop
555
544
  end
556
545
  elsif window_or_handle.is_a?(Proc)
557
546
  original = current_window
558
- switch_to_window { window_or_handle.call }
559
547
  scopes << nil
560
548
  begin
561
- yield
549
+ _switch_to_window { window_or_handle.call }
550
+ begin
551
+ yield
552
+ ensure
553
+ _switch_to_window(original)
554
+ end
562
555
  ensure
563
- @scopes.pop
564
- switch_to_window(original)
556
+ scopes.pop
565
557
  end
566
558
  else
567
559
  offending_line = caller.first
@@ -572,7 +564,7 @@ module Capybara
572
564
  scopes << nil
573
565
  driver.within_window(window_or_handle) { yield }
574
566
  ensure
575
- @scopes.pop
567
+ scopes.pop
576
568
  end
577
569
  end
578
570
  end
@@ -919,5 +911,37 @@ module Capybara
919
911
  end
920
912
  end
921
913
  end
914
+
915
+ def _switch_to_window(window = nil, options= {})
916
+ options, window = window, nil if window.is_a? Hash
917
+
918
+ raise Capybara::ScopeError, "Window cannot be switched inside a `within_frame` block" if scopes.include?(:frame)
919
+ raise Capybara::ScopeError, "Window cannot be switch inside a `within` block" unless scopes.last.nil?
920
+
921
+ if window
922
+ driver.switch_to_window(window.handle)
923
+ window
924
+ else
925
+ wait_time = Capybara::Queries::BaseQuery.wait(options, config.default_max_wait_time)
926
+ document.synchronize(wait_time, errors: [Capybara::WindowError]) do
927
+ original_window_handle = driver.current_window_handle
928
+ begin
929
+ driver.window_handles.each do |handle|
930
+ driver.switch_to_window handle
931
+ if yield
932
+ return Window.new(self, handle)
933
+ end
934
+ end
935
+ rescue => e
936
+ driver.switch_to_window(original_window_handle)
937
+ raise e
938
+ else
939
+ driver.switch_to_window(original_window_handle)
940
+ raise Capybara::WindowError, "Could not find a window matching block/lambda"
941
+ end
942
+ end
943
+ end
944
+ end
945
+
922
946
  end
923
947
  end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+ Capybara::SpecHelper.spec '#ancestor' do
3
+ before do
4
+ @session.visit('/with_html')
5
+ end
6
+
7
+ after do
8
+ Capybara::Selector.remove(:monkey)
9
+ end
10
+
11
+ it "should find the ancestor element using the given locator" do
12
+ el = @session.find(:css, '#first_image')
13
+ expect(el.ancestor('//p')).to have_text('Lorem ipsum dolor')
14
+ expect(el.ancestor("//a")[:'aria-label']).to eq('Go to simple')
15
+ end
16
+
17
+ it "should find the ancestor element using the given locator and options" do
18
+ el = @session.find(:css, '#child')
19
+ expect(el.ancestor('//div', text: 'Ancestor Ancestor Ancestor')[:id]).to eq('ancestor3')
20
+ end
21
+
22
+ it "should raise an error if there are multiple matches" do
23
+ el = @session.find(:css, '#child')
24
+ expect { el.ancestor('//div') }.to raise_error(Capybara::Ambiguous)
25
+ expect { el.ancestor('//div', text: 'Ancestor') }.to raise_error(Capybara::Ambiguous)
26
+ end
27
+
28
+ context "with css selectors" do
29
+ it "should find the first element using the given locator" do
30
+ el = @session.find(:css, '#first_image')
31
+ expect(el.ancestor(:css, 'p')).to have_text('Lorem ipsum dolor')
32
+ expect(el.ancestor(:css, 'a')[:'aria-label']).to eq('Go to simple')
33
+ end
34
+
35
+ it "should support pseudo selectors" do
36
+ el = @session.find(:css, '#button_img')
37
+ expect(el.ancestor(:css, 'button:disabled')[:id]).to eq('ancestor_button')
38
+ end
39
+ end
40
+
41
+ context "with xpath selectors" do
42
+ it "should find the first element using the given locator" do
43
+ el = @session.find(:css, '#first_image')
44
+ expect(el.ancestor(:xpath, '//p')).to have_text('Lorem ipsum dolor')
45
+ expect(el.ancestor(:xpath, "//a")[:'aria-label']).to eq('Go to simple')
46
+ end
47
+ end
48
+
49
+ context "with custom selector" do
50
+ it "should use the custom selector" do
51
+ Capybara.add_selector(:level) do
52
+ xpath { |num| ".//*[@id='ancestor#{num}']" }
53
+ end
54
+ el = @session.find(:css, '#child')
55
+ expect(el.ancestor(:level, 1).text).to eq('Ancestor Child')
56
+ expect(el.ancestor(:level, 3).text).to eq('Ancestor Ancestor Ancestor Child')
57
+ end
58
+ end
59
+
60
+
61
+ it "should raise ElementNotFound with a useful default message if nothing was found" do
62
+ el = @session.find(:css, '#child')
63
+ expect do
64
+ el.ancestor(:xpath, '//div[@id="nosuchthing"]')
65
+ end.to raise_error(Capybara::ElementNotFound, "Unable to find xpath \"//div[@id=\\\"nosuchthing\\\"]\" that is an ancestor of visible css \"#child\"")
66
+ end
67
+
68
+
69
+
70
+ context "within a scope" do
71
+ it "should limit the ancestors to inside the scope" do
72
+ @session.within(:css, '#ancestor2') do
73
+ el = @session.find(:css, '#child')
74
+ expect(el.ancestor(:css,'div', text: 'Ancestor')[:id]).to eq('ancestor1')
75
+ end
76
+ end
77
+ end
78
+
79
+ it "should raise if selector type is unknown" do
80
+ el = @session.find(:css, '#child')
81
+ expect do
82
+ el.ancestor(:unknown, '//h1')
83
+ end.to raise_error(ArgumentError)
84
+ end
85
+ end
@@ -81,7 +81,7 @@ Capybara::SpecHelper.spec "#attach_file" do
81
81
 
82
82
  context "with a locator that doesn't exist" do
83
83
  it "should raise an error" do
84
- msg = "Unable to find file field \"does not exist\""
84
+ msg = "Unable to find visible file field \"does not exist\" that is not disabled"
85
85
  expect do
86
86
  @session.attach_file('does not exist', @test_file_path)
87
87
  end.to raise_error(Capybara::ElementNotFound, msg)
@@ -69,7 +69,7 @@ Capybara::SpecHelper.spec "#check" do
69
69
 
70
70
  context "with a locator that doesn't exist" do
71
71
  it "should raise an error" do
72
- msg = "Unable to find checkbox \"does not exist\""
72
+ msg = "Unable to find visible checkbox \"does not exist\" that is not disabled"
73
73
  expect do
74
74
  @session.check('does not exist')
75
75
  end.to raise_error(Capybara::ElementNotFound, msg)
@@ -142,11 +142,11 @@ Capybara::SpecHelper.spec "#check" do
142
142
  end
143
143
 
144
144
  it "should raise original error when no label available" do
145
- expect { @session.check('form_cars_ariel') }.to raise_error(Capybara::ElementNotFound, 'Unable to find checkbox "form_cars_ariel"')
145
+ expect { @session.check('form_cars_ariel') }.to raise_error(Capybara::ElementNotFound, 'Unable to find visible checkbox "form_cars_ariel" that is not disabled')
146
146
  end
147
147
 
148
148
  it "should raise error if not allowed to click label" do
149
- expect{@session.check('form_cars_mclaren', allow_label_click: false)}.to raise_error(Capybara::ElementNotFound, 'Unable to find checkbox "form_cars_mclaren"')
149
+ expect{@session.check('form_cars_mclaren', allow_label_click: false)}.to raise_error(Capybara::ElementNotFound, 'Unable to find visible checkbox "form_cars_mclaren" that is not disabled')
150
150
  end
151
151
  end
152
152
 
@@ -158,7 +158,7 @@ Capybara::SpecHelper.spec "#check" do
158
158
  end
159
159
 
160
160
  it "should raise error if checkbox not visible" do
161
- expect{@session.check('form_cars_mclaren')}.to raise_error(Capybara::ElementNotFound, 'Unable to find checkbox "form_cars_mclaren"')
161
+ expect{@session.check('form_cars_mclaren')}.to raise_error(Capybara::ElementNotFound, 'Unable to find visible checkbox "form_cars_mclaren" that is not disabled')
162
162
  end
163
163
 
164
164
  context "with allow_label_click == true" do
@@ -24,7 +24,7 @@ Capybara::SpecHelper.spec "#choose" do
24
24
 
25
25
  context "with a locator that doesn't exist" do
26
26
  it "should raise an error" do
27
- msg = "Unable to find radio button \"does not exist\""
27
+ msg = "Unable to find visible radio button \"does not exist\" that is not disabled"
28
28
  expect do
29
29
  @session.choose('does not exist')
30
30
  end.to raise_error(Capybara::ElementNotFound, msg)
@@ -82,7 +82,7 @@ Capybara::SpecHelper.spec "#choose" do
82
82
  end
83
83
 
84
84
  it "should raise error if not allowed to click label" do
85
- expect{@session.choose("party_democrat", allow_label_click: false)}.to raise_error(Capybara::ElementNotFound, 'Unable to find radio button "party_democrat"')
85
+ expect{@session.choose("party_democrat", allow_label_click: false)}.to raise_error(Capybara::ElementNotFound, 'Unable to find visible radio button "party_democrat" that is not disabled')
86
86
  end
87
87
  end
88
88
  end
@@ -353,7 +353,7 @@ Capybara::SpecHelper.spec '#click_button' do
353
353
 
354
354
  context "with a locator that doesn't exist" do
355
355
  it "should raise an error" do
356
- msg = "Unable to find button \"does not exist\""
356
+ msg = "Unable to find visible button \"does not exist\""
357
357
  expect do
358
358
  @session.click_button('does not exist')
359
359
  end.to raise_error(Capybara::ElementNotFound, msg)
@@ -54,7 +54,7 @@ Capybara::SpecHelper.spec '#click_link_or_button' do
54
54
  context "when `false`" do
55
55
  it "does not click on link which matches approximately" do
56
56
  @session.visit('/with_html')
57
- msg = "Unable to find link or button \"abore\""
57
+ msg = "Unable to find visible link or button \"abore\""
58
58
  expect do
59
59
  @session.click_link_or_button('abore', exact: true)
60
60
  end.to raise_error(Capybara::ElementNotFound, msg)
@@ -62,7 +62,7 @@ Capybara::SpecHelper.spec '#click_link_or_button' do
62
62
 
63
63
  it "does not click on approximately matching button" do
64
64
  @session.visit('/form')
65
- msg = "Unable to find link or button \"awe\""
65
+ msg = "Unable to find visible link or button \"awe\""
66
66
 
67
67
  expect do
68
68
  @session.click_link_or_button('awe', exact: true)
@@ -74,7 +74,7 @@ Capybara::SpecHelper.spec '#click_link_or_button' do
74
74
  context "with a locator that doesn't exist" do
75
75
  it "should raise an error" do
76
76
  @session.visit('/with_html')
77
- msg = "Unable to find link or button \"does not exist\""
77
+ msg = "Unable to find visible link or button \"does not exist\""
78
78
  expect do
79
79
  @session.click_link_or_button('does not exist')
80
80
  end.to raise_error(Capybara::ElementNotFound, msg)
@@ -67,7 +67,7 @@ Capybara::SpecHelper.spec '#click_link' do
67
67
 
68
68
  context "with a locator that doesn't exist" do
69
69
  it "should raise an error" do
70
- msg = "Unable to find link \"does not exist\""
70
+ msg = "Unable to find visible link \"does not exist\""
71
71
  expect do
72
72
  @session.click_link('does not exist')
73
73
  end.to raise_error(Capybara::ElementNotFound, msg)
@@ -156,7 +156,7 @@ Capybara::SpecHelper.spec "#fill_in" do
156
156
  before { Capybara.ignore_hidden_elements = true }
157
157
  after { Capybara.ignore_hidden_elements = false }
158
158
  it "should not find a hidden field" do
159
- msg = "Unable to find field \"Super Secret\""
159
+ msg = "Unable to find visible field \"Super Secret\" that is not disabled"
160
160
  expect do
161
161
  @session.fill_in('Super Secret', with: '777')
162
162
  end.to raise_error(Capybara::ElementNotFound, msg)
@@ -165,7 +165,7 @@ Capybara::SpecHelper.spec "#fill_in" do
165
165
 
166
166
  context "with a locator that doesn't exist" do
167
167
  it "should raise an error" do
168
- msg = "Unable to find field \"does not exist\""
168
+ msg = "Unable to find visible field \"does not exist\" that is not disabled"
169
169
  expect do
170
170
  @session.fill_in('does not exist', with: 'Blah blah')
171
171
  end.to raise_error(Capybara::ElementNotFound, msg)
@@ -205,7 +205,7 @@ Capybara::SpecHelper.spec '#find' do
205
205
  it "should raise ElementNotFound with a useful default message if nothing was found" do
206
206
  expect do
207
207
  @session.find(:xpath, '//div[@id="nosuchthing"]').to be_nil
208
- end.to raise_error(Capybara::ElementNotFound, "Unable to find xpath \"//div[@id=\\\"nosuchthing\\\"]\"")
208
+ end.to raise_error(Capybara::ElementNotFound, "Unable to find visible xpath \"//div[@id=\\\"nosuchthing\\\"]\"")
209
209
  end
210
210
 
211
211
  it "should accept an XPath instance" do
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+ Capybara::SpecHelper.spec '#refresh' do
3
+ it "reload the page" do
4
+ @session.visit('/form')
5
+ expect(@session).to have_select('form_locale', selected: 'English')
6
+ @session.select('Swedish', from: 'form_locale')
7
+ expect(@session).to have_select('form_locale', selected: 'Swedish')
8
+ @session.refresh
9
+ expect(@session).to have_select('form_locale', selected: 'English')
10
+ end
11
+
12
+ it "raises any errors caught inside the server", requires: [:server] do
13
+ quietly { @session.visit("/error") }
14
+ expect do
15
+ @session.refresh
16
+ end.to raise_error(TestApp::TestAppError)
17
+ end
18
+
19
+ it "it reposts" do
20
+ @session.visit('/form')
21
+ @session.select('Sweden', from: 'form_region')
22
+ @session.click_button('awesome')
23
+ expect {
24
+ @session.refresh
25
+ sleep 2
26
+ }.to change{ extract_results(@session)['post_count'] }.by(1)
27
+ end
28
+ end
@@ -85,7 +85,7 @@ Capybara::SpecHelper.spec "#select" do
85
85
 
86
86
  context "with a locator that doesn't exist" do
87
87
  it "should raise an error" do
88
- msg = "Unable to find select box \"does not exist\""
88
+ msg = "Unable to find visible select box \"does not exist\" that is not disabled"
89
89
  expect do
90
90
  @session.select('foo', from: 'does not exist')
91
91
  end.to raise_error(Capybara::ElementNotFound, msg)
@@ -94,7 +94,7 @@ Capybara::SpecHelper.spec "#select" do
94
94
 
95
95
  context "with an option that doesn't exist" do
96
96
  it "should raise an error" do
97
- msg = "Unable to find option \"Does not Exist\""
97
+ msg = "Unable to find visible option \"Does not Exist\""
98
98
  expect do
99
99
  @session.select('Does not Exist', from: 'form_locale')
100
100
  end.to raise_error(Capybara::ElementNotFound, msg)
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+ Capybara::SpecHelper.spec '#sibling' do
3
+ before do
4
+ @session.visit('/with_html')
5
+ end
6
+
7
+ after do
8
+ Capybara::Selector.remove(:monkey)
9
+ end
10
+
11
+ it "should find a prior sibling element using the given locator" do
12
+ el = @session.find(:css, '#mid_sibling')
13
+ expect(el.sibling('//div[@data-pre]')[:id]).to eq('pre_sibling')
14
+ end
15
+
16
+ it "should find a following sibling element using the given locator" do
17
+ el = @session.find(:css, '#mid_sibling')
18
+ expect(el.sibling('//div[@data-post]')[:id]).to eq('post_sibling')
19
+ end
20
+
21
+ it "should raise an error if there are multiple matches" do
22
+ el = @session.find(:css, '#mid_sibling')
23
+ expect { el.sibling('//div') }.to raise_error(Capybara::Ambiguous)
24
+ end
25
+
26
+ context "with css selectors" do
27
+ it "should find the first element using the given locator" do
28
+ el = @session.find(:css, '#mid_sibling')
29
+ expect(el.sibling(:css, '#pre_sibling')).to have_text('Pre Sibling')
30
+ expect(el.sibling(:css, '#post_sibling')).to have_text('Post Sibling')
31
+ end
32
+ end
33
+
34
+ context "with custom selector" do
35
+ it "should use the custom selector" do
36
+ Capybara.add_selector(:data_attribute) do
37
+ xpath { |attr| ".//*[@data-#{attr}]" }
38
+ end
39
+ el = @session.find(:css, '#mid_sibling')
40
+ expect(el.sibling(:data_attribute, 'pre').text).to eq('Pre Sibling')
41
+ expect(el.sibling(:data_attribute, 'post').text).to eq('Post Sibling')
42
+ end
43
+ end
44
+
45
+
46
+ it "should raise ElementNotFound with a useful default message if nothing was found" do
47
+ el = @session.find(:css, '#child')
48
+ expect do
49
+ el.sibling(:xpath, '//div[@id="nosuchthing"]')
50
+ end.to raise_error(Capybara::ElementNotFound, "Unable to find xpath \"//div[@id=\\\"nosuchthing\\\"]\" that is a sibling of visible css \"#child\"")
51
+ end
52
+ end