capybara 2.14.4 → 2.15.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -69,11 +69,11 @@ Capybara::SpecHelper.spec "#uncheck" do
69
69
  end
70
70
 
71
71
  it "should raise original error when no label available" do
72
- expect { @session.uncheck('form_cars_ariel') }.to raise_error(Capybara::ElementNotFound, 'Unable to find checkbox "form_cars_ariel"')
72
+ expect { @session.uncheck('form_cars_ariel') }.to raise_error(Capybara::ElementNotFound, 'Unable to find visible checkbox "form_cars_ariel" that is not disabled')
73
73
  end
74
74
 
75
75
  it "should raise error if not allowed to click label" do
76
- expect{@session.uncheck('form_cars_jaguar', allow_label_click: false)}.to raise_error(Capybara::ElementNotFound, 'Unable to find checkbox "form_cars_jaguar"')
76
+ expect{@session.uncheck('form_cars_jaguar', allow_label_click: false)}.to raise_error(Capybara::ElementNotFound, 'Unable to find visible checkbox "form_cars_jaguar" that is not disabled')
77
77
  end
78
78
  end
79
79
  end
@@ -55,7 +55,7 @@ Capybara::SpecHelper.spec "#unselect" do
55
55
 
56
56
  context "with a locator that doesn't exist" do
57
57
  it "should raise an error" do
58
- msg = "Unable to find select box \"does not exist\""
58
+ msg = "Unable to find visible select box \"does not exist\" that is not disabled"
59
59
  expect do
60
60
  @session.unselect('foo', from: 'does not exist')
61
61
  end.to raise_error(Capybara::ElementNotFound, msg)
@@ -64,7 +64,7 @@ Capybara::SpecHelper.spec "#unselect" do
64
64
 
65
65
  context "with an option that doesn't exist" do
66
66
  it "should raise an error" do
67
- msg = "Unable to find option \"Does not Exist\""
67
+ msg = 'Unable to find visible option "Does not Exist"'
68
68
  expect do
69
69
  @session.unselect('Does not Exist', from: 'form_underwear')
70
70
  end.to raise_error(Capybara::ElementNotFound, msg)
@@ -27,12 +27,12 @@ Capybara::SpecHelper.spec '#become_closed', requires: [:windows, :js] do
27
27
 
28
28
  it 'should raise error if value of :wait is less than timeout' do
29
29
  @session.within_window @other_window do
30
- @session.execute_script('setTimeout(function(){ window.close(); }, 700);')
30
+ @session.execute_script('setTimeout(function(){ window.close(); }, 1000);')
31
31
  end
32
32
  Capybara.using_wait_time 2 do
33
33
  expect do
34
- expect(@other_window).to become_closed(wait: 0.4)
35
- end.to raise_error(RSpec::Expectations::ExpectationNotMetError, /\Aexpected #<Window @handle=".+"> to become closed after 0.4 seconds\Z/)
34
+ expect(@other_window).to become_closed(wait: 0.2)
35
+ end.to raise_error(RSpec::Expectations::ExpectationNotMetError, /\Aexpected #<Window @handle=".+"> to become closed after 0.2 seconds\Z/)
36
36
  end
37
37
  end
38
38
  end
@@ -79,7 +79,7 @@ Capybara::SpecHelper.spec '#switch_to_window', requires: [:windows] do
79
79
  @session.within(:css, '#doesNotOpenWindows') do
80
80
  @session.switch_to_window { @session.title == 'With Windows' }
81
81
  end
82
- end.to raise_error(Capybara::ScopeError, "`switch_to_window` is not supposed to be invoked from `within`'s, `within_frame`'s' or `within_window`'s' block.")
82
+ end.to raise_error(Capybara::ScopeError, /`switch_to_window` is not supposed to be invoked/)
83
83
  end
84
84
 
85
85
  it "should raise error when invoked inside `within_frame` as it's nonsense" do
@@ -87,16 +87,18 @@ Capybara::SpecHelper.spec '#switch_to_window', requires: [:windows] do
87
87
  @session.within_frame('frameOne') do
88
88
  @session.switch_to_window { @session.title == 'With Windows' }
89
89
  end
90
- end.to raise_error(Capybara::ScopeError, "`switch_to_window` is not supposed to be invoked from `within`'s, `within_frame`'s' or `within_window`'s' block.")
90
+ end.to raise_error(Capybara::ScopeError, /`switch_to_window` is not supposed to be invoked from/)
91
91
  end
92
92
 
93
- it "should raise error when invoked inside `within_window` as it's nonsense" do
94
- window = (@session.windows - [@window]).first
95
- expect do
96
- @session.within_window window do
97
- @session.switch_to_window { @session.title == 'With Windows' }
98
- end
99
- end.to raise_error(Capybara::ScopeError, "`switch_to_window` is not supposed to be invoked from `within`'s, `within_frame`'s' or `within_window`'s' block.")
93
+ it "should allow to be called inside within_window and within_window will still return to original" do
94
+ other_windows = (@session.windows - [@window])
95
+ expect(@session.current_window).to eq(@window)
96
+ @session.within_window other_windows[0] do
97
+ expect(@session.current_window).to eq(other_windows[0])
98
+ @session.switch_to_window other_windows[1]
99
+ expect(@session.current_window).to eq(other_windows[1])
100
+ end
101
+ expect(@session.current_window).to eq(@window)
100
102
  end
101
103
 
102
104
  it "should raise error if window matching block wasn't found" do
@@ -57,10 +57,10 @@ Capybara::SpecHelper.spec '#within_window', requires: [:windows] do
57
57
  expect(@session.send(:scopes)).to eq([nil])
58
58
  end
59
59
 
60
- it "should leave correct scopes after execution in case of error" do
60
+ it "should leave correct scopes after execution in case of error", requires: [:windows, :frames] do
61
61
  window = (@session.windows - [@window]).first
62
62
  expect do
63
- @session.within 'html' do
63
+ @session.within_frame 'frameOne' do
64
64
  @session.within_window(window) {}
65
65
  end
66
66
  end.to raise_error(Capybara::ScopeError)
@@ -102,6 +102,31 @@ Capybara::SpecHelper.spec '#within_window', requires: [:windows] do
102
102
  expect(@session.title).to eq('With Windows')
103
103
  end
104
104
 
105
+ it "should be able to nest within_window" do
106
+ @session.within_window(->{ @session.title == 'Title of popup two'}) do
107
+ expect(@session).to have_css('#divInPopupTwo')
108
+ @session.within_window(->{ @session.title == 'Title of the first popup'}) do
109
+ expect(@session).to have_css('#divInPopupOne')
110
+ end
111
+ expect(@session).to have_css('#divInPopupTwo')
112
+ expect(@session).not_to have_css('divInPopupOne')
113
+ end
114
+ expect(@session).not_to have_css('#divInPopupTwo')
115
+ expect(@session).not_to have_css('divInPopupOne')
116
+ expect(@session.title).to eq('With Windows')
117
+ end
118
+
119
+ it "should work inside a normal scope" do
120
+ expect(@session).to have_css('#openWindow')
121
+ @session.within(:css, '#scope') do
122
+ @session.within_window(->{ @session.title == 'Title of the first popup'}) do
123
+ expect(@session).to have_css('#divInPopupOne')
124
+ end
125
+ expect(@session).to have_content('My scoped content')
126
+ expect(@session).not_to have_css('#openWindow')
127
+ end
128
+ end
129
+
105
130
  it "should raise error if window wasn't found" do
106
131
  expect do
107
132
  @session.within_window(->{ @session.title == 'Invalid title'}) do
@@ -17,6 +17,7 @@ class TestApp < Sinatra::Base
17
17
  set :raise_errors, true
18
18
  set :show_exceptions, false
19
19
 
20
+ @@form_post_count = 0
20
21
  # Also check lib/capybara/spec/views/*.erb for pages not listed here
21
22
 
22
23
  get '/' do
@@ -147,7 +148,8 @@ class TestApp < Sinatra::Base
147
148
  end
148
149
 
149
150
  post '/form' do
150
- '<pre id="results">' + params[:form].to_yaml + '</pre>'
151
+ @@form_post_count += 1
152
+ '<pre id="results">' + params[:form].merge({"post_count" => @@form_post_count}).to_yaml + '</pre>'
151
153
  end
152
154
 
153
155
  post '/upload_empty' do
@@ -19,7 +19,7 @@
19
19
  et dolore magna aliqua. Ut enim ad minim veniam,
20
20
  quis nostrud exercitation <a href="/foo" id="foo">ullamco</a> laboris nisi
21
21
  ut aliquip ex ea commodo consequat.
22
- <a href="/with_simple_html" aria-label="Go to simple"><img width="20" height="20" alt="awesome image" /></a>
22
+ <a href="/with_simple_html" aria-label="Go to simple"><img id="first_image" width="20" height="20" alt="awesome image" /></a>
23
23
  </p>
24
24
 
25
25
  <p class="para" id="second">
@@ -121,3 +121,29 @@ banana</textarea>
121
121
  <a id="link_placeholder">No href</a>
122
122
  <a id="link_blank_href" href="">Blank href</a>
123
123
  </div>
124
+
125
+ <div id="ancestor3">
126
+ Ancestor
127
+ <div id="ancestor2">
128
+ Ancestor
129
+ <div id="ancestor1">
130
+ Ancestor
131
+ <div id="child">Child</div>
132
+ </div>
133
+ </div>
134
+ <button id="ancestor_button" type="submit" disabled>
135
+ <img id="button_img" width="20" height="20" alt="button img"/>
136
+ </button>
137
+ </div>
138
+
139
+ <div id="sibling_test">
140
+ <div id="sibling_wrapper" data-pre=true>
141
+ <div id="pre_sibling" data-pre=true>Pre Sibling</div>
142
+ <div id="mid_sibling">Mid Sibling</div>
143
+ <div id="post_sibling" data-post=true>Post Sibling</div>
144
+ </div>
145
+ <div id="other_sibling_wrapper" data-post=true>
146
+ <div data-pre=true>Pre Sibling</div>
147
+ <div data-post=true>Post Sibling</div>
148
+ </div>
149
+ </div>
@@ -46,5 +46,9 @@
46
46
  <button id="doesNotOpenWindows">Does not open windows</button>
47
47
 
48
48
  <iframe src="/frame_one" id="frameOne"></iframe>
49
+
50
+ <div id="scope">
51
+ <span>My scoped content</span>
52
+ </div>
49
53
  </body>
50
54
  </html>
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Capybara
3
- VERSION = '2.14.4'
3
+ VERSION = '2.15.0'
4
4
  end
@@ -92,9 +92,17 @@ RSpec.describe Capybara do
92
92
  require 'rack/handler/puma'
93
93
  mock_app = double('app')
94
94
  Capybara.server = :puma
95
- expect(Rack::Handler::Puma).to receive(:run)
95
+ expect(Rack::Handler::Puma).to receive(:run).with(mock_app, hash_including(Host: nil, Port: 8000))
96
96
  Capybara.server.call(mock_app, 8000)
97
97
  end
98
+
99
+ it "should pass options to server" do
100
+ require 'rack/handler/puma'
101
+ mock_app = double('app')
102
+ Capybara.server = :puma, { Silent: true }
103
+ expect(Rack::Handler::Puma).to receive(:run).with(mock_app, hash_including(Host: nil, Port: 9000, Silent: true))
104
+ Capybara.server.call(mock_app, 9000)
105
+ end
98
106
  end
99
107
 
100
108
  describe 'app_host' do
@@ -122,6 +122,6 @@ RSpec.describe 'capybara/minitest/spec' do
122
122
  reporter.report
123
123
  expect(output.string).to include("16 runs, 39 assertions, 1 failures, 0 errors, 0 skips")
124
124
  #Make sure error messages are displayed
125
- expect(output.string).to include('expected to find select box "non_existing_form_title" but there were no matches')
125
+ expect(output.string).to include('expected to find visible select box "non_existing_form_title" that is not disabled but there were no matches')
126
126
  end
127
127
  end
@@ -2,6 +2,7 @@
2
2
  require 'spec_helper'
3
3
  require 'capybara/dsl'
4
4
  require 'capybara/rspec/matchers'
5
+ require 'benchmark'
5
6
 
6
7
  RSpec.shared_examples Capybara::RSpecMatchers do |session, mode|
7
8
 
@@ -10,7 +11,7 @@ RSpec.shared_examples Capybara::RSpecMatchers do |session, mode|
10
11
 
11
12
  describe "have_css matcher" do
12
13
  it "gives proper description" do
13
- expect(have_css('h1').description).to eq("have css \"h1\"")
14
+ expect(have_css('h1').description).to eq("have visible css \"h1\"")
14
15
  end
15
16
 
16
17
  context "on a string" do
@@ -22,7 +23,7 @@ RSpec.shared_examples Capybara::RSpecMatchers do |session, mode|
22
23
  it "fails if has_css? returns false" do
23
24
  expect do
24
25
  expect("<h1>Text</h1>").to have_css('h2')
25
- end.to raise_error(/expected to find css "h2" but there were no matches/)
26
+ end.to raise_error(/expected to find visible css "h2" but there were no matches/)
26
27
  end
27
28
 
28
29
  it "passes if matched node count equals expected count" do
@@ -32,25 +33,25 @@ RSpec.shared_examples Capybara::RSpecMatchers do |session, mode|
32
33
  it "fails if matched node count does not equal expected count" do
33
34
  expect do
34
35
  expect("<h1>Text</h1>").to have_css('h1', count: 2)
35
- end.to raise_error("expected to find css \"h1\" 2 times, found 1 match: \"Text\"")
36
+ end.to raise_error("expected to find visible css \"h1\" 2 times, found 1 match: \"Text\"")
36
37
  end
37
38
 
38
39
  it "fails if matched node count is less than expected minimum count" do
39
40
  expect do
40
41
  expect("<h1>Text</h1>").to have_css('p', minimum: 1)
41
- end.to raise_error("expected to find css \"p\" at least 1 time but there were no matches")
42
+ end.to raise_error("expected to find visible css \"p\" at least 1 time but there were no matches")
42
43
  end
43
44
 
44
45
  it "fails if matched node count is more than expected maximum count" do
45
46
  expect do
46
47
  expect("<h1>Text</h1><h1>Text</h1><h1>Text</h1>").to have_css('h1', maximum: 2)
47
- end.to raise_error('expected to find css "h1" at most 2 times, found 3 matches: "Text", "Text", "Text"')
48
+ end.to raise_error('expected to find visible css "h1" at most 2 times, found 3 matches: "Text", "Text", "Text"')
48
49
  end
49
50
 
50
51
  it "fails if matched node count does not belong to expected range" do
51
52
  expect do
52
53
  expect("<h1>Text</h1>").to have_css('h1', between: 2..3)
53
- end.to raise_error("expected to find css \"h1\" between 2 and 3 times, found 1 match: \"Text\"")
54
+ end.to raise_error("expected to find visible css \"h1\" between 2 and 3 times, found 1 match: \"Text\"")
54
55
  end
55
56
 
56
57
  end
@@ -63,7 +64,7 @@ RSpec.shared_examples Capybara::RSpecMatchers do |session, mode|
63
64
  it "fails if has_no_css? returns false" do
64
65
  expect do
65
66
  expect("<h1>Text</h1>").not_to have_css('h1')
66
- end.to raise_error(/expected not to find css "h1"/)
67
+ end.to raise_error(/expected not to find visible css "h1"/)
67
68
  end
68
69
 
69
70
  it "passes if matched node count does not equal expected count" do
@@ -73,7 +74,7 @@ RSpec.shared_examples Capybara::RSpecMatchers do |session, mode|
73
74
  it "fails if matched node count equals expected count" do
74
75
  expect do
75
76
  expect("<h1>Text</h1>").not_to have_css('h1', count: 1)
76
- end.to raise_error(/expected not to find css "h1"/)
77
+ end.to raise_error(/expected not to find visible css "h1"/)
77
78
  end
78
79
  end
79
80
 
@@ -96,7 +97,7 @@ RSpec.shared_examples Capybara::RSpecMatchers do |session, mode|
96
97
  it "fails if has_css? returns false" do
97
98
  expect do
98
99
  expect(page).to have_css('h1#doesnotexist')
99
- end.to raise_error(/expected to find css "h1#doesnotexist" but there were no matches/)
100
+ end.to raise_error(/expected to find visible css "h1#doesnotexist" but there were no matches/)
100
101
  end
101
102
  end
102
103
 
@@ -108,7 +109,7 @@ RSpec.shared_examples Capybara::RSpecMatchers do |session, mode|
108
109
  it "fails if has_no_css? returns false" do
109
110
  expect do
110
111
  expect(page).not_to have_css('h1')
111
- end.to raise_error(/expected not to find css "h1"/)
112
+ end.to raise_error(/expected not to find visible css "h1"/)
112
113
  end
113
114
  end
114
115
  end
@@ -116,7 +117,7 @@ RSpec.shared_examples Capybara::RSpecMatchers do |session, mode|
116
117
 
117
118
  describe "have_xpath matcher" do
118
119
  it "gives proper description" do
119
- expect(have_xpath('//h1').description).to eq("have xpath \"\/\/h1\"")
120
+ expect(have_xpath('//h1').description).to eq("have visible xpath \"\/\/h1\"")
120
121
  end
121
122
 
122
123
  context "on a string" do
@@ -128,7 +129,7 @@ RSpec.shared_examples Capybara::RSpecMatchers do |session, mode|
128
129
  it "fails if has_xpath? returns false" do
129
130
  expect do
130
131
  expect("<h1>Text</h1>").to have_xpath('//h2')
131
- end.to raise_error(%r(expected to find xpath "//h2" but there were no matches))
132
+ end.to raise_error(%r(expected to find visible xpath "//h2" but there were no matches))
132
133
  end
133
134
  end
134
135
 
@@ -140,7 +141,7 @@ RSpec.shared_examples Capybara::RSpecMatchers do |session, mode|
140
141
  it "fails if has_no_xpath? returns false" do
141
142
  expect do
142
143
  expect("<h1>Text</h1>").not_to have_xpath('//h1')
143
- end.to raise_error(%r(expected not to find xpath "//h1"))
144
+ end.to raise_error(%r(expected not to find visible xpath "//h1"))
144
145
  end
145
146
  end
146
147
 
@@ -163,7 +164,7 @@ RSpec.shared_examples Capybara::RSpecMatchers do |session, mode|
163
164
  it "fails if has_xpath? returns false" do
164
165
  expect do
165
166
  expect(page).to have_xpath("//h1[@id='doesnotexist']")
166
- end.to raise_error(%r(expected to find xpath "//h1\[@id='doesnotexist'\]" but there were no matches))
167
+ end.to raise_error(%r(expected to find visible xpath "//h1\[@id='doesnotexist'\]" but there were no matches))
167
168
  end
168
169
  end
169
170
 
@@ -175,7 +176,7 @@ RSpec.shared_examples Capybara::RSpecMatchers do |session, mode|
175
176
  it "fails if has_no_xpath? returns false" do
176
177
  expect do
177
178
  expect(page).not_to have_xpath('//h1')
178
- end.to raise_error(%r(expected not to find xpath "//h1"))
179
+ end.to raise_error(%r(expected not to find visible xpath "//h1"))
179
180
  end
180
181
  end
181
182
  end
@@ -185,7 +186,7 @@ RSpec.shared_examples Capybara::RSpecMatchers do |session, mode|
185
186
  it "gives proper description" do
186
187
  matcher = have_selector('//h1')
187
188
  expect("<h1>Text</h1>").to matcher
188
- expect(matcher.description).to eq("have xpath \"//h1\"")
189
+ expect(matcher.description).to eq("have visible xpath \"//h1\"")
189
190
  end
190
191
 
191
192
  context "on a string" do
@@ -197,7 +198,7 @@ RSpec.shared_examples Capybara::RSpecMatchers do |session, mode|
197
198
  it "fails if has_selector? returns false" do
198
199
  expect do
199
200
  expect("<h1>Text</h1>").to have_selector('//h2')
200
- end.to raise_error(%r(expected to find xpath "//h2" but there were no matches))
201
+ end.to raise_error(%r(expected to find visible xpath "//h2" but there were no matches))
201
202
  end
202
203
  end
203
204
 
@@ -209,7 +210,7 @@ RSpec.shared_examples Capybara::RSpecMatchers do |session, mode|
209
210
  it "fails if has_no_selector? returns false" do
210
211
  expect do
211
212
  expect("<h1>Text</h1>").not_to have_selector(:css, 'h1')
212
- end.to raise_error(%r(expected not to find css "h1"))
213
+ end.to raise_error(%r(expected not to find visible css "h1"))
213
214
  end
214
215
  end
215
216
  end
@@ -227,13 +228,13 @@ RSpec.shared_examples Capybara::RSpecMatchers do |session, mode|
227
228
  it "fails if has_selector? returns false" do
228
229
  expect do
229
230
  expect(page).to have_selector("//h1[@id='doesnotexist']")
230
- end.to raise_error(%r(expected to find xpath "//h1\[@id='doesnotexist'\]" but there were no matches))
231
+ end.to raise_error(%r(expected to find visible xpath "//h1\[@id='doesnotexist'\]" but there were no matches))
231
232
  end
232
233
 
233
234
  it "includes text in error message" do
234
235
  expect do
235
236
  expect(page).to have_selector("//h1", text: 'wrong text')
236
- end.to raise_error(%r(expected to find xpath "//h1" with text "wrong text" but there were no matches))
237
+ end.to raise_error(%r(expected to find visible xpath "//h1" with text "wrong text" but there were no matches))
237
238
  end
238
239
  end
239
240
 
@@ -245,7 +246,7 @@ RSpec.shared_examples Capybara::RSpecMatchers do |session, mode|
245
246
  it "fails if has_no_selector? returns false" do
246
247
  expect do
247
248
  expect(page).not_to have_selector(:css, 'h1', text: 'test')
248
- end.to raise_error(%r(expected not to find css "h1" with text "test"))
249
+ end.to raise_error(%r(expected not to find visible css "h1" with text "test"))
249
250
  end
250
251
  end
251
252
  end
@@ -483,7 +484,7 @@ RSpec.shared_examples Capybara::RSpecMatchers do |session, mode|
483
484
  let(:html) { '<a href="#">Just a link</a><a href="#">Another link</a>' }
484
485
 
485
486
  it "gives proper description" do
486
- expect(have_link('Just a link').description).to eq("have link \"Just a link\"")
487
+ expect(have_link('Just a link').description).to eq("have visible link \"Just a link\"")
487
488
  end
488
489
 
489
490
  it "passes if there is such a button" do
@@ -493,7 +494,7 @@ RSpec.shared_examples Capybara::RSpecMatchers do |session, mode|
493
494
  it "fails if there is no such button" do
494
495
  expect do
495
496
  expect(html).to have_link('No such Link')
496
- end.to raise_error(/expected to find link "No such Link"/)
497
+ end.to raise_error(/expected to find visible link "No such Link"/)
497
498
  end
498
499
 
499
500
  it "supports compounding" do
@@ -617,7 +618,7 @@ RSpec.shared_examples Capybara::RSpecMatchers do |session, mode|
617
618
  let(:html) { '<button>A button</button><input type="submit" value="Another button"/>' }
618
619
 
619
620
  it "gives proper description" do
620
- expect(have_button('A button').description).to eq("have button \"A button\"")
621
+ expect(have_button('A button').description).to eq("have visible button \"A button\"")
621
622
  end
622
623
 
623
624
  it "passes if there is such a button" do
@@ -627,7 +628,7 @@ RSpec.shared_examples Capybara::RSpecMatchers do |session, mode|
627
628
  it "fails if there is no such button" do
628
629
  expect do
629
630
  expect(html).to have_button('No such Button')
630
- end.to raise_error(/expected to find button "No such Button"/)
631
+ end.to raise_error(/expected to find visible button "No such Button"/)
631
632
  end
632
633
 
633
634
  it "supports compounding" do
@@ -639,11 +640,11 @@ RSpec.shared_examples Capybara::RSpecMatchers do |session, mode|
639
640
  let(:html) { '<p><label>Text field<input type="text" value="some value"/></label></p>' }
640
641
 
641
642
  it "gives proper description" do
642
- expect(have_field('Text field').description).to eq("have field \"Text field\"")
643
+ expect(have_field('Text field').description).to eq("have visible field \"Text field\" that is not disabled")
643
644
  end
644
645
 
645
646
  it "gives proper description for a given value" do
646
- expect(have_field('Text field', with: 'some value').description).to eq("have field \"Text field\" with value \"some value\"")
647
+ expect(have_field('Text field', with: 'some value').description).to eq("have visible field \"Text field\" that is not disabled with value \"some value\"")
647
648
  end
648
649
 
649
650
  it "passes if there is such a field" do
@@ -657,13 +658,13 @@ RSpec.shared_examples Capybara::RSpecMatchers do |session, mode|
657
658
  it "fails if there is no such field" do
658
659
  expect do
659
660
  expect(html).to have_field('No such Field')
660
- end.to raise_error(/expected to find field "No such Field"/)
661
+ end.to raise_error(/expected to find visible field "No such Field"/)
661
662
  end
662
663
 
663
664
  it "fails if there is such field but with false value" do
664
665
  expect do
665
666
  expect(html).to have_field('Text field', with: 'false value')
666
- end.to raise_error(/expected to find field "Text field"/)
667
+ end.to raise_error(/expected to find visible field "Text field"/)
667
668
  end
668
669
 
669
670
  it "treats a given value as a string" do
@@ -687,7 +688,7 @@ RSpec.shared_examples Capybara::RSpecMatchers do |session, mode|
687
688
  end
688
689
 
689
690
  it "gives proper description" do
690
- expect(have_checked_field('it is checked').description).to eq("have field \"it is checked\" that is checked")
691
+ expect(have_checked_field('it is checked').description).to eq("have visible field \"it is checked\" that is checked and not disabled")
691
692
  end
692
693
 
693
694
  context "with should" do
@@ -698,13 +699,13 @@ RSpec.shared_examples Capybara::RSpecMatchers do |session, mode|
698
699
  it "fails if there is such a field but it is not checked" do
699
700
  expect do
700
701
  expect(html).to have_checked_field('unchecked field')
701
- end.to raise_error(/expected to find field "unchecked field"/)
702
+ end.to raise_error(/expected to find visible field "unchecked field"/)
702
703
  end
703
704
 
704
705
  it "fails if there is no such field" do
705
706
  expect do
706
707
  expect(html).to have_checked_field('no such field')
707
- end.to raise_error(/expected to find field "no such field"/)
708
+ end.to raise_error(/expected to find visible field "no such field"/)
708
709
  end
709
710
  end
710
711
 
@@ -712,7 +713,7 @@ RSpec.shared_examples Capybara::RSpecMatchers do |session, mode|
712
713
  it "fails if there is such a field and it is checked" do
713
714
  expect do
714
715
  expect(html).not_to have_checked_field('it is checked')
715
- end.to raise_error(/expected not to find field "it is checked"/)
716
+ end.to raise_error(/expected not to find visible field "it is checked"/)
716
717
  end
717
718
 
718
719
  it "passes if there is such a field but it is not checked" do
@@ -736,7 +737,7 @@ RSpec.shared_examples Capybara::RSpecMatchers do |session, mode|
736
737
  end
737
738
 
738
739
  it "gives proper description" do
739
- expect(have_unchecked_field('unchecked field').description).to eq("have field \"unchecked field\" that is not checked")
740
+ expect(have_unchecked_field('unchecked field').description).to eq("have visible field \"unchecked field\" that is not checked and not disabled")
740
741
  end
741
742
 
742
743
  context "with should" do
@@ -747,13 +748,13 @@ RSpec.shared_examples Capybara::RSpecMatchers do |session, mode|
747
748
  it "fails if there is such a field but it is checked" do
748
749
  expect do
749
750
  expect(html).to have_unchecked_field('it is checked')
750
- end.to raise_error(/expected to find field "it is checked"/)
751
+ end.to raise_error(/expected to find visible field "it is checked"/)
751
752
  end
752
753
 
753
754
  it "fails if there is no such field" do
754
755
  expect do
755
756
  expect(html).to have_unchecked_field('no such field')
756
- end.to raise_error(/expected to find field "no such field"/)
757
+ end.to raise_error(/expected to find visible field "no such field"/)
757
758
  end
758
759
  end
759
760
 
@@ -761,7 +762,7 @@ RSpec.shared_examples Capybara::RSpecMatchers do |session, mode|
761
762
  it "fails if there is such a field and it is not checked" do
762
763
  expect do
763
764
  expect(html).not_to have_unchecked_field('unchecked field')
764
- end.to raise_error(/expected not to find field "unchecked field"/)
765
+ end.to raise_error(/expected not to find visible field "unchecked field"/)
765
766
  end
766
767
 
767
768
  it "passes if there is such a field but it is checked" do
@@ -782,11 +783,11 @@ RSpec.shared_examples Capybara::RSpecMatchers do |session, mode|
782
783
  let(:html) { '<label>Select Box<select></select></label>' }
783
784
 
784
785
  it "gives proper description" do
785
- expect(have_select('Select Box').description).to eq("have select box \"Select Box\"")
786
+ expect(have_select('Select Box').description).to eq("have visible select box \"Select Box\" that is not disabled")
786
787
  end
787
788
 
788
789
  it "gives proper description for a given selected value" do
789
- expect(have_select('Select Box', selected: 'some value').description).to eq("have select box \"Select Box\" with \"some value\" selected")
790
+ expect(have_select('Select Box', selected: 'some value').description).to eq('have visible select box "Select Box" that is not disabled with "some value" selected')
790
791
  end
791
792
 
792
793
  it "passes if there is such a select" do
@@ -796,7 +797,7 @@ RSpec.shared_examples Capybara::RSpecMatchers do |session, mode|
796
797
  it "fails if there is no such select" do
797
798
  expect do
798
799
  expect(html).to have_select('No such Select box')
799
- end.to raise_error(/expected to find select box "No such Select box"/)
800
+ end.to raise_error(/expected to find visible select box "No such Select box"/)
800
801
  end
801
802
 
802
803
  it "supports compounding" do
@@ -808,7 +809,14 @@ RSpec.shared_examples Capybara::RSpecMatchers do |session, mode|
808
809
  let(:html) { '<table><caption>Lovely table</caption></table>' }
809
810
 
810
811
  it "gives proper description" do
811
- expect(have_table('Lovely table').description).to eq("have table \"Lovely table\"")
812
+ expect(have_table('Lovely table').description).to eq("have visible table \"Lovely table\"")
813
+ end
814
+
815
+ it "gives proper description when :visible option passed" do
816
+ expect(have_table('Lovely table', visible: true).description).to eq("have visible table \"Lovely table\"")
817
+ expect(have_table('Lovely table', visible: :hidden).description).to eq("have non-visible table \"Lovely table\"")
818
+ expect(have_table('Lovely table', visible: :all).description).to eq("have table \"Lovely table\"")
819
+ expect(have_table('Lovely table', visible: false).description).to eq("have table \"Lovely table\"")
812
820
  end
813
821
 
814
822
  it "passes if there is such a select" do
@@ -818,11 +826,107 @@ RSpec.shared_examples Capybara::RSpecMatchers do |session, mode|
818
826
  it "fails if there is no such select" do
819
827
  expect do
820
828
  expect(html).to have_table('No such Table')
821
- end.to raise_error(/expected to find table "No such Table"/)
829
+ end.to raise_error(/expected to find visible table "No such Table"/)
822
830
  end
823
831
 
824
832
  it "supports compounding" do
825
833
  expect(html).to have_table('nope').or have_table('Lovely table')
826
834
  end if RSpec::Version::STRING.to_f >= 3.0
827
835
  end
836
+
837
+ if RSpec::Version::STRING.to_f >= 3.0
838
+ context "compounding", requires: [:js] do
839
+ before(:each) do
840
+ @session = session
841
+ @session.visit('/with_js')
842
+ @el = @session.find(:css, '#reload-me')
843
+ end
844
+
845
+ context "#and" do
846
+ it "should run 'concurrently'" do
847
+ Capybara.using_wait_time(2) do
848
+ matcher = have_text('this is not there').and have_text('neither is this')
849
+ expect(Benchmark.realtime do
850
+ expect {
851
+ expect(@el).to matcher
852
+ }.to raise_error RSpec::Expectations::ExpectationNotMetError
853
+ end).to be_between(2,3)
854
+ end
855
+ end
856
+
857
+ it "should run 'concurrently' and retry" do
858
+ @session.click_link('reload-link')
859
+ @session.using_wait_time(2) do
860
+ expect(Benchmark.realtime do
861
+ expect {
862
+ expect(@el).to have_text('waiting to be reloaded').and(have_text('has been reloaded'))
863
+ }.to raise_error RSpec::Expectations::ExpectationNotMetError, /expected to find text "waiting to be reloaded" in "has been reloaded"/
864
+ end).to be_between(2,3)
865
+ end
866
+ end
867
+
868
+ it "should ignore :wait options" do
869
+ @session.using_wait_time(2) do
870
+ matcher = have_text('this is not there', wait: 5).and have_text('neither is this', wait: 6)
871
+ expect(Benchmark.realtime do
872
+ expect {
873
+ expect(@el).to matcher
874
+ }.to raise_error RSpec::Expectations::ExpectationNotMetError
875
+ end).to be_between(2,3)
876
+ end
877
+ end
878
+
879
+ it "should work on the session" do
880
+ @session.using_wait_time(2) do
881
+ @session.click_link('reload-link')
882
+ expect(@session).to have_selector(:css, 'h1', text: 'FooBar').and have_text('has been reloaded')
883
+ end
884
+ end
885
+ end
886
+
887
+ context "#and_then" do
888
+ it "should run sequentially" do
889
+ @session.click_link('reload-link')
890
+ expect(@el).to have_text('waiting to be reloaded').and_then have_text('has been reloaded')
891
+ end
892
+ end
893
+
894
+ context "#or" do
895
+ it "should run 'concurrently'" do
896
+ @session.using_wait_time(3) do
897
+ expect(Benchmark.realtime do
898
+ expect(@el).to have_text('has been reloaded').or have_text('waiting to be reloaded')
899
+ end).to be < 1
900
+ end
901
+ end
902
+
903
+ it "should retry" do
904
+ @session.using_wait_time(3) do
905
+ expect(Benchmark.realtime do
906
+ expect {
907
+ expect(@el).to have_text('has been reloaded').or have_text('random stuff')
908
+ }.to raise_error RSpec::Expectations::ExpectationNotMetError
909
+ end).to be > 3
910
+ end
911
+ end
912
+
913
+ it "should ignore :wait options" do
914
+ @session.using_wait_time(2) do
915
+ expect(Benchmark.realtime do
916
+ expect {
917
+ expect(@el).to have_text('this is not there', wait: 10).or have_text('neither is this', wait: 15)
918
+ }.to raise_error RSpec::Expectations::ExpectationNotMetError
919
+ end).to be_between(2,3)
920
+ end
921
+ end
922
+
923
+ it "should work on the session" do
924
+ @session.using_wait_time(2) do
925
+ @session.click_link('reload-link')
926
+ expect(@session).to have_selector(:css, 'h1', text: 'Not on the page').or have_text('has been reloaded')
927
+ end
928
+ end
929
+ end
930
+ end
931
+ end
828
932
  end