capybara 0.4.1.2 → 1.0.0.beta1

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 (69) hide show
  1. data/History.txt +46 -0
  2. data/README.rdoc +211 -64
  3. data/lib/capybara.rb +31 -15
  4. data/lib/capybara/cucumber.rb +12 -16
  5. data/lib/capybara/dsl.rb +65 -28
  6. data/lib/capybara/node/actions.rb +7 -5
  7. data/lib/capybara/node/document.rb +8 -0
  8. data/lib/capybara/node/finders.rb +11 -7
  9. data/lib/capybara/node/matchers.rb +32 -6
  10. data/lib/capybara/node/simple.rb +20 -0
  11. data/lib/capybara/rack_test/browser.rb +115 -0
  12. data/lib/capybara/rack_test/driver.rb +77 -0
  13. data/lib/capybara/rack_test/form.rb +80 -0
  14. data/lib/capybara/rack_test/node.rb +101 -0
  15. data/lib/capybara/rspec.rb +11 -3
  16. data/lib/capybara/rspec/features.rb +22 -0
  17. data/lib/capybara/rspec/matchers.rb +146 -0
  18. data/lib/capybara/selector.rb +27 -8
  19. data/lib/capybara/selenium/driver.rb +148 -0
  20. data/lib/capybara/selenium/node.rb +91 -0
  21. data/lib/capybara/session.rb +42 -15
  22. data/lib/capybara/spec/driver.rb +55 -1
  23. data/lib/capybara/spec/fixtures/capybara.jpg +0 -0
  24. data/lib/capybara/spec/public/test.js +7 -2
  25. data/lib/capybara/spec/session.rb +51 -7
  26. data/lib/capybara/spec/session/attach_file_spec.rb +9 -6
  27. data/lib/capybara/spec/session/click_button_spec.rb +35 -0
  28. data/lib/capybara/spec/session/current_host_spec.rb +62 -0
  29. data/lib/capybara/spec/session/fill_in_spec.rb +6 -0
  30. data/lib/capybara/spec/session/find_spec.rb +23 -1
  31. data/lib/capybara/spec/session/first_spec.rb +39 -6
  32. data/lib/capybara/spec/session/has_css_spec.rb +30 -0
  33. data/lib/capybara/spec/session/has_field_spec.rb +47 -11
  34. data/lib/capybara/spec/session/javascript.rb +0 -1
  35. data/lib/capybara/spec/session/text_spec.rb +19 -0
  36. data/lib/capybara/spec/test_app.rb +9 -0
  37. data/lib/capybara/spec/views/form.erb +8 -3
  38. data/lib/capybara/spec/views/header_links.erb +7 -0
  39. data/lib/capybara/spec/views/host_links.erb +12 -0
  40. data/lib/capybara/spec/views/with_html.erb +6 -2
  41. data/lib/capybara/spec/views/with_html_entities.erb +1 -0
  42. data/lib/capybara/spec/views/with_js.erb +4 -0
  43. data/lib/capybara/util/save_and_open_page.rb +7 -3
  44. data/lib/capybara/util/timeout.rb +2 -2
  45. data/lib/capybara/version.rb +1 -1
  46. data/spec/capybara_spec.rb +1 -1
  47. data/spec/driver/rack_test_driver_spec.rb +24 -2
  48. data/spec/driver/selenium_driver_spec.rb +2 -1
  49. data/spec/dsl_spec.rb +56 -4
  50. data/spec/rspec/features_spec.rb +45 -0
  51. data/spec/rspec/matchers_spec.rb +451 -0
  52. data/spec/rspec_spec.rb +9 -2
  53. data/spec/save_and_open_page_spec.rb +9 -13
  54. data/spec/server_spec.rb +4 -0
  55. data/spec/session/rack_test_session_spec.rb +2 -2
  56. data/spec/session/selenium_session_spec.rb +1 -1
  57. data/spec/spec_helper.rb +0 -14
  58. data/spec/string_spec.rb +1 -1
  59. metadata +60 -69
  60. data/lib/capybara/driver/celerity_driver.rb +0 -164
  61. data/lib/capybara/driver/culerity_driver.rb +0 -26
  62. data/lib/capybara/driver/rack_test_driver.rb +0 -303
  63. data/lib/capybara/driver/selenium_driver.rb +0 -161
  64. data/spec/driver/celerity_driver_spec.rb +0 -13
  65. data/spec/driver/culerity_driver_spec.rb +0 -14
  66. data/spec/driver/remote_culerity_driver_spec.rb +0 -22
  67. data/spec/driver/remote_selenium_driver_spec.rb +0 -16
  68. data/spec/session/celerity_session_spec.rb +0 -24
  69. data/spec/session/culerity_session_spec.rb +0 -26
@@ -10,7 +10,6 @@ shared_examples_for "session with javascript support" do
10
10
 
11
11
  describe 'Node#drag_to' do
12
12
  it "should drag and drop an object" do
13
- pending "drag/drop is currently broken under celerity/culerity" if @session.driver.is_a?(Capybara::Driver::Celerity)
14
13
  @session.visit('/with_js')
15
14
  element = @session.find('//div[@id="drag"]')
16
15
  target = @session.find('//div[@id="drop"]')
@@ -0,0 +1,19 @@
1
+ shared_examples_for "text" do
2
+ describe '#text' do
3
+ before do
4
+ @session.visit('/with_simple_html')
5
+ end
6
+
7
+ it "should print the text of the page" do
8
+ @session.text.should == 'Bar'
9
+ end
10
+
11
+ context "with css as default selector" do
12
+ before { Capybara.default_selector = :css }
13
+ it "should print the text of the page" do
14
+ @session.text.should == 'Bar'
15
+ end
16
+ after { Capybara.default_selector = :xpath }
17
+ end
18
+ end
19
+ end
@@ -22,6 +22,10 @@ class TestApp < Sinatra::Base
22
22
  redirect '/landed'
23
23
  end
24
24
 
25
+ get '/host' do
26
+ "Current host is #{request.scheme}://#{request.host}"
27
+ end
28
+
25
29
  get '/redirect/:times/times' do
26
30
  times = params[:times].to_i
27
31
  if times.zero?
@@ -59,6 +63,11 @@ class TestApp < Sinatra::Base
59
63
  redirect back
60
64
  end
61
65
 
66
+ get '/slow_response' do
67
+ sleep 2
68
+ 'Finally!'
69
+ end
70
+
62
71
  get '/set_cookie' do
63
72
  cookie_value = 'test_cookie'
64
73
  response.set_cookie('capybara', cookie_value)
@@ -109,6 +109,11 @@
109
109
  </select>
110
110
  </p>
111
111
 
112
+ <p>
113
+ <label for="form_zipcode">Zipcode</label>
114
+ <input type="text" maxlength="5" name="form[zipcode]" id="form_zipcode" />
115
+ </p>
116
+
112
117
  <p>
113
118
  <label for="form_tendency">Tendency</label>
114
119
  <select name="form[tendency]" id="form_tendency"></select>
@@ -242,10 +247,10 @@
242
247
 
243
248
  <p>
244
249
  <input type="button" name="form[fresh]" id="fresh_btn" value="i am fresh"/>
245
- <input type="submit" name="form[awesome]" id="awe123" value="awesome"/>
250
+ <input type="submit" name="form[awesome]" id="awe123" title="What an Awesome Button" value="awesome"/>
246
251
  <input type="submit" name="form[crappy]" id="crap321" value="crappy"/>
247
- <input type="image" name="form[okay]" id="okay556" value="okay" alt="oh hai thar"/>
248
- <button type="submit" id="click_me_123" value="click_me">Click me!</button>
252
+ <input type="image" name="form[okay]" id="okay556" title="Okay 556 Image" value="okay" alt="oh hai thar"/>
253
+ <button type="submit" id="click_me_123" title="Click Title button" value="click_me">Click me!</button>
249
254
  <button type="submit" name="form[no_value]">No Value!</button>
250
255
  <button id="no_type">No Type!</button>
251
256
  </p>
@@ -0,0 +1,7 @@
1
+ <p>
2
+ <a href="/get_header">Link</a>
3
+ </p>
4
+
5
+ <form action="/get_header" method="get">
6
+ <p><input type="submit" value="Post"/></p>
7
+ </form>
@@ -0,0 +1,12 @@
1
+ <p>
2
+ <a href="/host">Relative Host</a>
3
+ <a href="http://capybara2.elabs.se/host">Absolute Host</a>
4
+ </p>
5
+
6
+ <form action="/host">
7
+ <p><input type="submit" value="Relative Host"/></p>
8
+ </form>
9
+
10
+ <form action="http://capybara2.elabs.se/host">
11
+ <p><input type="submit" value="Absolute Host"/></p>
12
+ </form>
@@ -56,11 +56,15 @@
56
56
  </div>
57
57
 
58
58
  <div style="display: none;">
59
- <a class="visibility">hidden link</a>
59
+ <a id="first_invisble" class="hidden">first hidden link</a>
60
+ </div>
61
+
62
+ <div style="display: none;">
63
+ <a id="invisible" class="visibility hidden">hidden link</a>
60
64
  </div>
61
65
 
62
66
  <div>
63
- <a class="visibility">visible link</a>
67
+ <a id="visible" class="visibility">visible link</a>
64
68
  </div>
65
69
 
66
70
  <ul>
@@ -0,0 +1 @@
1
+ Encoding with &mdash; html entities &raquo;
@@ -34,6 +34,10 @@
34
34
  <p>
35
35
  <input type="checkbox" id="checkbox_with_event"/>
36
36
  </p>
37
+
38
+ <p>
39
+ <input type="submit" id="fire_ajax_request" value="Fire Ajax Request"/>
40
+ </p>
37
41
  </body>
38
42
  </html>
39
43
 
@@ -1,7 +1,8 @@
1
1
  module Capybara
2
2
  class << self
3
- def save_and_open_page(html)
4
- name = File.join(*[Capybara.save_and_open_page_path, "capybara-#{Time.new.strftime("%Y%m%d%H%M%S")}.html"].compact)
3
+ def save_page(html, file_name=nil)
4
+ file_name ||= "capybara-#{Time.new.strftime("%Y%m%d%H%M%S")}#{rand(10**10)}.html"
5
+ name = File.join(*[Capybara.save_and_open_page_path, file_name].compact)
5
6
 
6
7
  unless Capybara.save_and_open_page_path.nil? || File.directory?(Capybara.save_and_open_page_path )
7
8
  FileUtils.mkdir_p(Capybara.save_and_open_page_path)
@@ -11,8 +12,11 @@ module Capybara
11
12
  tempfile = File.new(name,'w')
12
13
  tempfile.write(rewrite_css_and_image_references(html))
13
14
  tempfile.close
15
+ tempfile.path
16
+ end
14
17
 
15
- open_in_browser(tempfile.path)
18
+ def save_and_open_page(html, file_name=nil)
19
+ open_in_browser save_page(html, file_name)
16
20
  end
17
21
 
18
22
  protected
@@ -4,7 +4,7 @@ module Capybara
4
4
  ##
5
5
  # Provides timeout similar to standard library Timeout, but avoids threads
6
6
  #
7
- def timeout(seconds = 1, driver = nil, &block)
7
+ def timeout(seconds = 1, driver = nil, error_message = nil, &block)
8
8
  start_time = Time.now
9
9
 
10
10
  result = nil
@@ -14,7 +14,7 @@ module Capybara
14
14
 
15
15
  delay = seconds - (Time.now - start_time)
16
16
  if delay <= 0
17
- raise TimeoutError
17
+ raise TimeoutError, error_message || "timed out"
18
18
  end
19
19
 
20
20
  driver && driver.wait_until(delay)
@@ -1,3 +1,3 @@
1
1
  module Capybara
2
- VERSION = '0.4.1.2'
2
+ VERSION = '1.0.0.beta1'
3
3
  end
@@ -17,7 +17,7 @@ describe Capybara do
17
17
  describe '.register_driver' do
18
18
  it "should add a new driver" do
19
19
  Capybara.register_driver :schmoo do |app|
20
- Capybara::Driver::RackTest.new(app)
20
+ Capybara::RackTest::Driver.new(app)
21
21
  end
22
22
  session = Capybara::Session.new(:schmoo, TestApp)
23
23
  session.visit('/')
@@ -14,14 +14,14 @@ def capture(*streams)
14
14
  result.string
15
15
  end
16
16
 
17
- describe Capybara::Driver::RackTest do
17
+ describe Capybara::RackTest::Driver do
18
18
  before do
19
19
  @driver = TestSessions::RackTest.driver
20
20
  end
21
21
 
22
22
  it "should throw an error when no rack app is given" do
23
23
  running do
24
- Capybara::Driver::RackTest.new(nil)
24
+ Capybara::RackTest::Driver.new(nil)
25
25
  end.should raise_error(ArgumentError)
26
26
  end
27
27
 
@@ -81,4 +81,26 @@ describe Capybara::Driver::RackTest do
81
81
  lambda { @driver.request }.should raise_error
82
82
  end
83
83
  end
84
+
85
+ describe ':headers option' do
86
+ it 'should always set headers' do
87
+ @driver = Capybara::RackTest::Driver.new(TestApp, :headers => {'HTTP_FOO' => 'foobar'})
88
+ @driver.visit('/get_header')
89
+ @driver.body.should include('foobar')
90
+ end
91
+
92
+ it 'should keep headers on link clicks' do
93
+ @driver = Capybara::RackTest::Driver.new(TestApp, :headers => {'HTTP_FOO' => 'foobar'})
94
+ @driver.visit('/header_links')
95
+ @driver.find('.//a').first.click
96
+ @driver.body.should include('foobar')
97
+ end
98
+
99
+ it 'should keep headers on form submit' do
100
+ @driver = Capybara::RackTest::Driver.new(TestApp, :headers => {'HTTP_FOO' => 'foobar'})
101
+ @driver.visit('/header_links')
102
+ @driver.find('.//input').first.click
103
+ @driver.body.should include('foobar')
104
+ end
105
+ end
84
106
  end
@@ -1,12 +1,13 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Capybara::Driver::Selenium do
3
+ describe Capybara::Selenium::Driver do
4
4
  before do
5
5
  @driver = TestSessions::Selenium.driver
6
6
  end
7
7
 
8
8
  it_should_behave_like "driver"
9
9
  it_should_behave_like "driver with javascript support"
10
+ it_should_behave_like "driver with resynchronization support"
10
11
  it_should_behave_like "driver with frame support"
11
12
  it_should_behave_like "driver with support for window switching"
12
13
  it_should_behave_like "driver without status code support"
@@ -2,13 +2,14 @@ require 'spec_helper'
2
2
 
3
3
  require 'capybara/dsl'
4
4
 
5
- describe Capybara do
5
+ describe Capybara::DSL do
6
6
 
7
7
  before do
8
8
  Capybara.app = TestApp
9
9
  end
10
10
 
11
11
  after do
12
+ Capybara.session_name = nil
12
13
  Capybara.default_driver = nil
13
14
  Capybara.use_default_driver
14
15
  end
@@ -123,11 +124,53 @@ describe Capybara do
123
124
  Capybara.current_session.object_id.should_not == object_id
124
125
  Capybara.current_session.app.should == Capybara.app
125
126
  end
127
+
128
+ it "should change when the session name changes" do
129
+ object_id = Capybara.current_session.object_id
130
+ Capybara.session_name = :administrator
131
+ Capybara.session_name.should == :administrator
132
+ Capybara.current_session.object_id.should_not == object_id
133
+ Capybara.session_name = :default
134
+ Capybara.session_name.should == :default
135
+ Capybara.current_session.object_id.should == object_id
136
+ end
137
+ end
138
+
139
+ describe "#using_session" do
140
+ it "should change the session name for the duration of the block" do
141
+ Capybara.session_name.should == :default
142
+ Capybara.using_session(:administrator) do
143
+ Capybara.session_name.should == :administrator
144
+ end
145
+ Capybara.session_name.should == :default
146
+ end
147
+
148
+ it "should reset the session to the default, even if an exception occurs" do
149
+ begin
150
+ Capybara.using_session(:raise) do
151
+ raise
152
+ end
153
+ rescue Exception
154
+ end
155
+ Capybara.session_name.should == :default
156
+ end
157
+
158
+ it "should yield the passed block" do
159
+ called = false
160
+ Capybara.using_session(:administrator) { called = true }
161
+ called.should == true
162
+ end
163
+ end
164
+
165
+ describe "#session_name" do
166
+ it "should default to :default" do
167
+ Capybara.session_name.should == :default
168
+ end
126
169
  end
127
170
 
128
171
  describe 'the DSL' do
129
172
  before do
130
- @session = Capybara
173
+ @session = Class.new { include Capybara::DSL }.new
131
174
  end
132
175
 
133
176
  it_should_behave_like "session"
@@ -135,7 +178,7 @@ describe Capybara do
135
178
 
136
179
  it "should be possible to include it in another class" do
137
180
  klass = Class.new do
138
- include Capybara
181
+ include Capybara::DSL
139
182
  end
140
183
  foo = klass.new
141
184
  foo.visit('/with_html')
@@ -145,13 +188,22 @@ describe Capybara do
145
188
 
146
189
  it "should provide a 'page' shortcut for more expressive tests" do
147
190
  klass = Class.new do
148
- include Capybara
191
+ include Capybara::DSL
149
192
  end
150
193
  foo = klass.new
151
194
  foo.page.visit('/with_html')
152
195
  foo.page.click_link('ullamco')
153
196
  foo.page.body.should include('Another World')
154
197
  end
198
+
199
+ it "should provide an 'using_session' shortcut" do
200
+ klass = Class.new do
201
+ include Capybara::DSL
202
+ end
203
+ Capybara.should_receive(:using_session).with(:name)
204
+ foo = klass.new
205
+ foo.using_session(:name)
206
+ end
155
207
  end
156
208
 
157
209
  end
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+ require 'capybara/rspec'
3
+
4
+ Capybara.app = TestApp
5
+
6
+ RSpec.configuration.before(:each, :example_group => {:file_path => __FILE__}) do
7
+ @in_filtered_hook = true
8
+ end
9
+
10
+ feature "Capybara's feature DSL" do
11
+ background do
12
+ @in_background = true
13
+ end
14
+
15
+ scenario "includes Capybara" do
16
+ visit('/')
17
+ page.should have_content('Hello world!')
18
+ end
19
+
20
+ scenario "preserves description" do
21
+ example.metadata[:full_description].should == "Capybara's feature DSL preserves description"
22
+ end
23
+
24
+ scenario "allows driver switching", :driver => :selenium do
25
+ Capybara.current_driver.should == :selenium
26
+ end
27
+
28
+ scenario "runs background" do
29
+ @in_background.should be_true
30
+ end
31
+
32
+ scenario "runs hooks filtered by file path" do
33
+ @in_filtered_hook.should be_true
34
+ end
35
+
36
+ scenario "doesn't pollute the Object namespace" do
37
+ Object.new.respond_to?(:feature, true).should be_false
38
+ end
39
+ end
40
+
41
+ feature "Capybara's feature DSL with driver", :driver => :culerity do
42
+ scenario "switches driver" do
43
+ Capybara.current_driver.should == :culerity
44
+ end
45
+ end
@@ -0,0 +1,451 @@
1
+ require 'spec_helper'
2
+ require 'capybara/dsl'
3
+ require 'capybara/rspec/matchers'
4
+
5
+ Capybara.app = TestApp
6
+
7
+ describe Capybara::RSpecMatchers do
8
+ include Capybara::DSL
9
+ include Capybara::RSpecMatchers
10
+
11
+ describe "have_css matcher" do
12
+ context "on a string" do
13
+ context "with should" do
14
+ it "passes if has_css? returns true" do
15
+ "<h1>Text</h1>".should have_css('h1')
16
+ end
17
+
18
+ it "fails if has_css? returns false" do
19
+ expect do
20
+ "<h1>Text</h1>".should have_css('h2')
21
+ end.to raise_error(/expected css "h2" to return something/)
22
+ end
23
+
24
+ it "passes if matched node count equals expected count" do
25
+ "<h1>Text</h1>".should have_css('h1', :count => 1)
26
+ end
27
+
28
+ it "fails if matched node count does not equal expected count" do
29
+ expect do
30
+ "<h1>Text</h1>".should have_css('h1', :count => 2)
31
+ end.to raise_error(/expected css "h1" to return something/)
32
+ end
33
+ end
34
+
35
+ context "with should_not" do
36
+ it "passes if has_no_css? returns true" do
37
+ "<h1>Text</h1>".should_not have_css('h2')
38
+ end
39
+
40
+ it "fails if has_no_css? returns false" do
41
+ expect do
42
+ "<h1>Text</h1>".should_not have_css('h1')
43
+ end.to raise_error(/expected css "h1" not to return anything/)
44
+ end
45
+
46
+ it "passes if matched node count does not equal expected count" do
47
+ "<h1>Text</h1>".should_not have_css('h1', :count => 2)
48
+ end
49
+
50
+ it "fails if matched node count equals expected count" do
51
+ expect do
52
+ "<h1>Text</h1>".should_not have_css('h1', :count => 1)
53
+ end.to raise_error(/expected css "h1" not to return anything/)
54
+ end
55
+ end
56
+ end
57
+
58
+ context "on a page or node" do
59
+ before do
60
+ visit('/with_html')
61
+ end
62
+
63
+ context "with should" do
64
+ it "passes if has_css? returns true" do
65
+ page.should have_css('h1')
66
+ end
67
+
68
+ it "fails if has_css? returns false" do
69
+ expect do
70
+ page.should have_css('h1#doesnotexist')
71
+ end.to raise_error(/expected css "h1#doesnotexist" to return something/)
72
+ end
73
+ end
74
+
75
+ context "with should_not" do
76
+ it "passes if has_no_css? returns true" do
77
+ page.should_not have_css('h1#doesnotexist')
78
+ end
79
+
80
+ it "fails if has_no_css? returns false" do
81
+ expect do
82
+ page.should_not have_css('h1')
83
+ end.to raise_error(/expected css "h1" not to return anything/)
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ describe "have_xpath matcher" do
90
+ context "on a string" do
91
+ context "with should" do
92
+ it "passes if has_css? returns true" do
93
+ "<h1>Text</h1>".should have_xpath('//h1')
94
+ end
95
+
96
+ it "fails if has_css? returns false" do
97
+ expect do
98
+ "<h1>Text</h1>".should have_xpath('//h2')
99
+ end.to raise_error(%r(expected xpath "//h2" to return something))
100
+ end
101
+ end
102
+
103
+ context "with should_not" do
104
+ it "passes if has_no_css? returns true" do
105
+ "<h1>Text</h1>".should_not have_xpath('//h2')
106
+ end
107
+
108
+ it "fails if has_no_css? returns false" do
109
+ expect do
110
+ "<h1>Text</h1>".should_not have_xpath('//h1')
111
+ end.to raise_error(%r(expected xpath "//h1" not to return anything))
112
+ end
113
+ end
114
+ end
115
+
116
+ context "on a page or node" do
117
+ before do
118
+ visit('/with_html')
119
+ end
120
+
121
+ context "with should" do
122
+ it "passes if has_css? returns true" do
123
+ page.should have_xpath('//h1')
124
+ end
125
+
126
+ it "fails if has_css? returns false" do
127
+ expect do
128
+ page.should have_xpath("//h1[@id='doesnotexist']")
129
+ end.to raise_error(%r(expected xpath "//h1\[@id='doesnotexist'\]" to return something))
130
+ end
131
+ end
132
+
133
+ context "with should_not" do
134
+ it "passes if has_no_css? returns true" do
135
+ page.should_not have_xpath('//h1[@id="doesnotexist"]')
136
+ end
137
+
138
+ it "fails if has_no_css? returns false" do
139
+ expect do
140
+ page.should_not have_xpath('//h1')
141
+ end.to raise_error(%r(expected xpath "//h1" not to return anything))
142
+ end
143
+ end
144
+ end
145
+ end
146
+
147
+ describe "have_selector matcher" do
148
+ context "on a string" do
149
+ context "with should" do
150
+ it "passes if has_css? returns true" do
151
+ "<h1>Text</h1>".should have_selector('//h1')
152
+ end
153
+
154
+ it "fails if has_css? returns false" do
155
+ expect do
156
+ "<h1>Text</h1>".should have_selector('//h2')
157
+ end.to raise_error(%r(expected xpath "//h2" to return something))
158
+ end
159
+
160
+ it "fails with the selector's failure_message if set" do
161
+ Capybara.add_selector(:monkey) do
162
+ xpath { |num| ".//*[contains(@id, 'monkey')][#{num}]" }
163
+ failure_message { |node, selector| node.all(".//*[contains(@id, 'monkey')]").map { |node| node.text }.sort.join(', ') }
164
+ end
165
+ expect do
166
+ '<h1 id="monkey_paul">Monkey John</h1>'.should have_selector(:monkey, 14)
167
+ end.to raise_error("Monkey John")
168
+ end
169
+ end
170
+
171
+ context "with should_not" do
172
+ it "passes if has_no_css? returns true" do
173
+ "<h1>Text</h1>".should_not have_selector(:css, 'h2')
174
+ end
175
+
176
+ it "fails if has_no_css? returns false" do
177
+ expect do
178
+ "<h1>Text</h1>".should_not have_selector(:css, 'h1')
179
+ end.to raise_error(%r(expected css "h1" not to return anything))
180
+ end
181
+ end
182
+ end
183
+
184
+ context "on a page or node" do
185
+ before do
186
+ visit('/with_html')
187
+ end
188
+
189
+ context "with should" do
190
+ it "passes if has_css? returns true" do
191
+ page.should have_selector('//h1', :text => 'test')
192
+ end
193
+
194
+ it "fails if has_css? returns false" do
195
+ expect do
196
+ page.should have_selector("//h1[@id='doesnotexist']")
197
+ end.to raise_error(%r(expected xpath "//h1\[@id='doesnotexist'\]" to return something))
198
+ end
199
+
200
+ it "includes text in error message" do
201
+ expect do
202
+ page.should have_selector("//h1", :text => 'wrong text')
203
+ end.to raise_error(%r(expected xpath "//h1" with text "wrong text" to return something))
204
+ end
205
+
206
+ it "fails with the selector's failure_message if set" do
207
+ Capybara.add_selector(:monkey) do
208
+ xpath { |num| ".//*[contains(@id, 'monkey')][#{num}]" }
209
+ failure_message { |node, selector| node.all(".//*[contains(@id, 'monkey')]").map { |node| node.text }.sort.join(', ') }
210
+ end
211
+ expect do
212
+ page.should have_selector(:monkey, 14)
213
+ end.to raise_error("Monkey John, Monkey Paul")
214
+ end
215
+ end
216
+
217
+ context "with should_not" do
218
+ it "passes if has_no_css? returns true" do
219
+ page.should_not have_selector(:css, 'h1#doesnotexist')
220
+ end
221
+
222
+ it "fails if has_no_css? returns false" do
223
+ expect do
224
+ page.should_not have_selector(:css, 'h1', :text => 'test')
225
+ end.to raise_error(%r(expected css "h1" with text "test" not to return anything))
226
+ end
227
+ end
228
+ end
229
+ end
230
+
231
+ describe "have_content matcher" do
232
+ context "on a string" do
233
+ context "with should" do
234
+ it "passes if has_css? returns true" do
235
+ "<h1>Text</h1>".should have_content('Text')
236
+ end
237
+
238
+ it "fails if has_css? returns false" do
239
+ expect do
240
+ "<h1>Text</h1>".should have_content('No such Text')
241
+ end.to raise_error(/expected there to be content "No such Text" in "Text"/)
242
+ end
243
+ end
244
+
245
+ context "with should_not" do
246
+ it "passes if has_no_css? returns true" do
247
+ "<h1>Text</h1>".should_not have_content('No such Text')
248
+ end
249
+
250
+ it "fails if has_no_css? returns false" do
251
+ expect do
252
+ "<h1>Text</h1>".should_not have_content('Text')
253
+ end.to raise_error(/expected content "Text" not to return anything/)
254
+ end
255
+ end
256
+ end
257
+
258
+ context "on a page or node" do
259
+ before do
260
+ visit('/with_html')
261
+ end
262
+
263
+ context "with should" do
264
+ it "passes if has_css? returns true" do
265
+ page.should have_content('This is a test')
266
+ end
267
+
268
+ it "fails if has_css? returns false" do
269
+ expect do
270
+ page.should have_content('No such Text')
271
+ end.to raise_error(/expected there to be content "No such Text" in "(.*)This is a test(.*)"/)
272
+ end
273
+
274
+ context "with default selector CSS" do
275
+ before { Capybara.default_selector = :css }
276
+ it "fails if has_css? returns false" do
277
+ expect do
278
+ page.should have_content('No such Text')
279
+ end.to raise_error(/expected there to be content "No such Text" in "(.*)This is a test(.*)"/)
280
+ end
281
+ after { Capybara.default_selector = :xpath }
282
+ end
283
+ end
284
+
285
+ context "with should_not" do
286
+ it "passes if has_no_css? returns true" do
287
+ page.should_not have_content('No such Text')
288
+ end
289
+
290
+ it "fails if has_no_css? returns false" do
291
+ expect do
292
+ page.should_not have_content('This is a test')
293
+ end.to raise_error(/expected content "This is a test" not to return anything/)
294
+ end
295
+ end
296
+ end
297
+ end
298
+
299
+ describe "have_link matcher" do
300
+ let(:html) { '<a href="#">Just a link</a>' }
301
+
302
+ it "passes if there is such a button" do
303
+ html.should have_link('Just a link')
304
+ end
305
+
306
+ it "fails if there is no such button" do
307
+ expect do
308
+ html.should have_link('No such Link')
309
+ end.to raise_error(/expected link "No such Link"/)
310
+ end
311
+ end
312
+
313
+ describe "have_button matcher" do
314
+ let(:html) { '<button>A button</button><input type="submit" value="Another button"/>' }
315
+
316
+ it "passes if there is such a button" do
317
+ html.should have_button('A button')
318
+ end
319
+
320
+ it "fails if there is no such button" do
321
+ expect do
322
+ html.should have_button('No such Button')
323
+ end.to raise_error(/expected button "No such Button"/)
324
+ end
325
+ end
326
+
327
+ describe "have_field matcher" do
328
+ let(:html) { '<p><label>Text field<input type="text"/></label></p>' }
329
+
330
+ it "passes if there is such a field" do
331
+ html.should have_field('Text field')
332
+ end
333
+
334
+ it "fails if there is no such field" do
335
+ expect do
336
+ html.should have_field('No such Field')
337
+ end.to raise_error(/expected field "No such Field"/)
338
+ end
339
+ end
340
+
341
+ describe "have_checked_field matcher" do
342
+ let(:html) do
343
+ '<label>it is checked<input type="checkbox" checked="checked"/></label>
344
+ <label>unchecked field<input type="checkbox"/></label>'
345
+ end
346
+
347
+ context "with should" do
348
+ it "passes if there is such a field and it is checked" do
349
+ html.should have_checked_field('it is checked')
350
+ end
351
+
352
+ it "fails if there is such a field but it is not checked" do
353
+ expect do
354
+ html.should have_checked_field('unchecked field')
355
+ end.to raise_error(/expected checked_field "unchecked field"/)
356
+ end
357
+
358
+ it "fails if there is no such field" do
359
+ expect do
360
+ html.should have_checked_field('no such field')
361
+ end.to raise_error(/expected checked_field "no such field"/)
362
+ end
363
+ end
364
+
365
+ context "with should not" do
366
+ it "fails if there is such a field and it is checked" do
367
+ expect do
368
+ html.should_not have_checked_field('it is checked')
369
+ end.to raise_error(/expected checked_field "it is checked" not to return anything/)
370
+ end
371
+
372
+ it "passes if there is such a field but it is not checked" do
373
+ html.should_not have_checked_field('unchecked field')
374
+ end
375
+
376
+ it "passes if there is no such field" do
377
+ html.should_not have_checked_field('no such field')
378
+ end
379
+ end
380
+ end
381
+
382
+ describe "have_unchecked_field matcher" do
383
+ let(:html) do
384
+ '<label>it is checked<input type="checkbox" checked="checked"/></label>
385
+ <label>unchecked field<input type="checkbox"/></label>'
386
+ end
387
+
388
+ context "with should" do
389
+ it "passes if there is such a field and it is not checked" do
390
+ html.should have_unchecked_field('unchecked field')
391
+ end
392
+
393
+ it "fails if there is such a field but it is checked" do
394
+ expect do
395
+ html.should have_unchecked_field('it is checked')
396
+ end.to raise_error(/expected unchecked_field "it is checked"/)
397
+ end
398
+
399
+ it "fails if there is no such field" do
400
+ expect do
401
+ html.should have_unchecked_field('no such field')
402
+ end.to raise_error(/expected unchecked_field "no such field"/)
403
+ end
404
+ end
405
+
406
+ context "with should not" do
407
+ it "fails if there is such a field and it is not checked" do
408
+ expect do
409
+ html.should_not have_unchecked_field('unchecked field')
410
+ end.to raise_error(/expected unchecked_field "unchecked field" not to return anything/)
411
+ end
412
+
413
+ it "passes if there is such a field but it is checked" do
414
+ html.should_not have_unchecked_field('it is checked')
415
+ end
416
+
417
+ it "passes if there is no such field" do
418
+ html.should_not have_unchecked_field('no such field')
419
+ end
420
+ end
421
+ end
422
+
423
+ describe "have_select matcher" do
424
+ let(:html) { '<label>Select Box<select></select></label>' }
425
+
426
+ it "passes if there is such a select" do
427
+ html.should have_select('Select Box')
428
+ end
429
+
430
+ it "fails if there is no such select" do
431
+ expect do
432
+ html.should have_select('No such Select box')
433
+ end.to raise_error(/expected select "No such Select box"/)
434
+ end
435
+ end
436
+
437
+ describe "have_table matcher" do
438
+ let(:html) { '<table><caption>Lovely table</caption></table>' }
439
+
440
+ it "passes if there is such a select" do
441
+ html.should have_table('Lovely table')
442
+ end
443
+
444
+ it "fails if there is no such select" do
445
+ expect do
446
+ html.should have_table('No such Table')
447
+ end.to raise_error(/expected table "No such Table"/)
448
+ end
449
+ end
450
+ end
451
+