capybara 0.2.0 → 0.3.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 (71) hide show
  1. data/Manifest.txt +39 -0
  2. data/README.rdoc +181 -57
  3. data/Rakefile +7 -16
  4. data/config.ru +6 -0
  5. data/lib/capybara.rb +19 -9
  6. data/lib/capybara/cucumber.rb +4 -0
  7. data/lib/capybara/driver/base.rb +25 -8
  8. data/lib/capybara/driver/celerity_driver.rb +108 -0
  9. data/lib/capybara/driver/culerity_driver.rb +1 -70
  10. data/lib/capybara/driver/rack_test_driver.rb +57 -25
  11. data/lib/capybara/driver/selenium_driver.rb +28 -10
  12. data/lib/capybara/dsl.rb +7 -4
  13. data/lib/capybara/node.rb +50 -29
  14. data/lib/capybara/rails.rb +1 -1
  15. data/lib/capybara/save_and_open_page.rb +1 -1
  16. data/lib/capybara/searchable.rb +45 -0
  17. data/lib/capybara/server.rb +11 -4
  18. data/lib/capybara/session.rb +94 -94
  19. data/lib/capybara/wait_until.rb +23 -0
  20. data/lib/capybara/xpath.rb +55 -41
  21. data/spec/capybara_spec.rb +18 -0
  22. data/spec/driver/celerity_driver_spec.rb +17 -0
  23. data/spec/driver/culerity_driver_spec.rb +3 -0
  24. data/spec/driver/rack_test_driver_spec.rb +3 -0
  25. data/spec/driver/remote_culerity_driver_spec.rb +19 -0
  26. data/spec/driver/remote_selenium_driver_spec.rb +18 -0
  27. data/spec/driver/selenium_driver_spec.rb +2 -0
  28. data/spec/drivers_spec.rb +51 -5
  29. data/spec/dsl/all_spec.rb +38 -0
  30. data/spec/dsl/attach_file_spec.rb +66 -0
  31. data/spec/dsl/check_spec.rb +28 -0
  32. data/spec/dsl/choose_spec.rb +28 -0
  33. data/spec/dsl/click_button_spec.rb +183 -0
  34. data/spec/dsl/click_link_spec.rb +88 -0
  35. data/spec/dsl/click_spec.rb +26 -0
  36. data/spec/dsl/current_url_spec.rb +10 -0
  37. data/spec/dsl/fill_in_spec.rb +83 -0
  38. data/spec/dsl/find_button_spec.rb +18 -0
  39. data/spec/dsl/find_field_spec.rb +24 -0
  40. data/spec/dsl/find_link_spec.rb +19 -0
  41. data/spec/dsl/find_spec.rb +36 -0
  42. data/spec/dsl/has_content_spec.rb +103 -0
  43. data/spec/dsl/has_css_spec.rb +109 -0
  44. data/spec/dsl/has_xpath_spec.rb +115 -0
  45. data/spec/dsl/locate_spec.rb +38 -0
  46. data/spec/dsl/select_spec.rb +27 -0
  47. data/spec/dsl/uncheck_spec.rb +29 -0
  48. data/spec/dsl/within_spec.rb +145 -0
  49. data/spec/fixtures/capybara.jpg +0 -0
  50. data/spec/public/test.js +27 -0
  51. data/spec/searchable_spec.rb +61 -0
  52. data/spec/server_spec.rb +47 -0
  53. data/spec/session/celerity_session_spec.rb +27 -0
  54. data/spec/session/culerity_session_spec.rb +1 -0
  55. data/spec/session/rack_test_session_spec.rb +1 -0
  56. data/spec/session/selenium_session_spec.rb +1 -0
  57. data/spec/session_spec.rb +32 -903
  58. data/spec/session_with_headers_support_spec.rb +13 -0
  59. data/spec/session_with_javascript_support_spec.rb +165 -0
  60. data/spec/session_without_headers_support_spec.rb +15 -0
  61. data/spec/session_without_javascript_support_spec.rb +15 -0
  62. data/spec/spec_helper.rb +12 -0
  63. data/spec/test_app.rb +9 -1
  64. data/spec/views/form.erb +38 -0
  65. data/spec/views/postback.erb +13 -0
  66. data/spec/views/with_html.erb +13 -0
  67. data/spec/views/with_js.erb +9 -24
  68. data/spec/views/with_simple_html.erb +1 -1
  69. data/spec/wait_until_spec.rb +28 -0
  70. data/spec/xpath_spec.rb +34 -3
  71. metadata +54 -5
@@ -0,0 +1,13 @@
1
+ require File.expand_path('spec_helper', File.dirname(__FILE__))
2
+
3
+
4
+ shared_examples_for "session with headers support" do
5
+
6
+ describe '#response_headers' do
7
+ it "should return response headers" do
8
+ @session.visit('/with_simple_html')
9
+ @session.response_headers['Content-Type'].should == 'text/html'
10
+ end
11
+ end
12
+
13
+ end
@@ -0,0 +1,165 @@
1
+ require File.expand_path('spec_helper', File.dirname(__FILE__))
2
+
3
+ require 'nokogiri'
4
+
5
+ shared_examples_for "session with javascript support" do
6
+ describe '#body' do
7
+ it "should return the current state of the page" do
8
+ @session.visit('/with_js')
9
+ @session.body.should include('I changed it')
10
+ @session.body.should_not include('This is text')
11
+ end
12
+ end
13
+
14
+ describe '#source' do
15
+ it "should return the original, unmodified source of the page" do
16
+ pending "cannot figure out how to do this with selenium" if @session.mode == :selenium
17
+ @session.visit('/with_js')
18
+ @session.source.should include('This is text')
19
+ @session.source.should_not include('I changed it')
20
+ end
21
+ end
22
+
23
+ describe "#evaluate_script" do
24
+ it "should return the evaluated script" do
25
+ @session.visit('/with_js')
26
+ @session.evaluate_script("1+3").should == 4
27
+ end
28
+ end
29
+
30
+ describe '#locate' do
31
+ it "should wait for asynchronous load" do
32
+ @session.visit('/with_js')
33
+ @session.click_link('Click me')
34
+ @session.locate("//a[contains(.,'Has been clicked')]")[:href].should == '#'
35
+ end
36
+ end
37
+
38
+ describe '#wait_until' do
39
+ before do
40
+ @default_timeout = Capybara.default_wait_time
41
+ end
42
+
43
+ after do
44
+ Capybara.default_wait_time = @default_wait_time
45
+ end
46
+
47
+ it "should wait for block to return true" do
48
+ @session.visit('/with_js')
49
+ @session.select('My Waiting Option', :from => 'waiter')
50
+ @session.evaluate_script('activeRequests == 1').should be_true
51
+ @session.wait_until do
52
+ @session.evaluate_script('activeRequests == 0')
53
+ end
54
+ @session.evaluate_script('activeRequests == 0').should be_true
55
+ end
56
+
57
+ it "should raise Capybara::TimeoutError if block doesn't return true within timeout" do
58
+ @session.visit('/with_html')
59
+ Proc.new do
60
+ @session.wait_until(0.1) do
61
+ @session.find('//div[@id="nosuchthing"]')
62
+ end
63
+ end.should raise_error(::Capybara::TimeoutError)
64
+ end
65
+
66
+ it "should accept custom timeout in seconds" do
67
+ start = Time.now
68
+ Capybara.default_wait_time = 5
69
+ begin
70
+ @session.wait_until(0.1) { false }
71
+ rescue Capybara::TimeoutError; end
72
+ (Time.now - start).should be_close(0.1, 0.1)
73
+ end
74
+
75
+ it "should default to Capybara.default_wait_time before timeout" do
76
+ start = Time.now
77
+ Capybara.default_wait_time = 0.2
78
+ begin
79
+ @session.wait_until { false }
80
+ rescue Capybara::TimeoutError; end
81
+ (Time.now - start).should be_close(0.2, 0.1)
82
+ end
83
+ end
84
+
85
+ describe '#click' do
86
+ it "should wait for asynchronous load" do
87
+ @session.visit('/with_js')
88
+ @session.click_link('Click me')
89
+ @session.click('Has been clicked')
90
+ end
91
+ end
92
+
93
+ describe '#click_link' do
94
+ it "should wait for asynchronous load" do
95
+ @session.visit('/with_js')
96
+ @session.click_link('Click me')
97
+ @session.click_link('Has been clicked')
98
+ end
99
+ end
100
+
101
+ describe '#click_button' do
102
+ it "should wait for asynchronous load" do
103
+ @session.visit('/with_js')
104
+ @session.click_link('Click me')
105
+ @session.click_button('New Here')
106
+ end
107
+ end
108
+
109
+ describe '#fill_in' do
110
+ it "should wait for asynchronous load" do
111
+ @session.visit('/with_js')
112
+ @session.click_link('Click me')
113
+ @session.fill_in('new_field', :with => 'Testing...')
114
+ end
115
+ end
116
+
117
+ describe '#has_xpath?' do
118
+ it "should wait for content to appear" do
119
+ @session.visit('/with_js')
120
+ @session.click_link('Click me')
121
+ @session.should have_xpath("//input[@type='submit' and @value='New Here']")
122
+ end
123
+ end
124
+
125
+ describe '#has_no_xpath?' do
126
+ it "should wait for content to disappear" do
127
+ @session.visit('/with_js')
128
+ @session.click_link('Click me')
129
+ @session.should have_no_xpath("//p[@id='change']")
130
+ end
131
+ end
132
+
133
+ describe '#has_css?' do
134
+ it "should wait for content to appear" do
135
+ @session.visit('/with_js')
136
+ @session.click_link('Click me')
137
+ @session.should have_css("input[type='submit'][value='New Here']")
138
+ end
139
+ end
140
+
141
+ describe '#has_no_xpath?' do
142
+ it "should wait for content to disappear" do
143
+ @session.visit('/with_js')
144
+ @session.click_link('Click me')
145
+ @session.should have_no_css("p#change")
146
+ end
147
+ end
148
+
149
+ describe '#has_content?' do
150
+ it "should wait for content to appear" do
151
+ @session.visit('/with_js')
152
+ @session.click_link('Click me')
153
+ @session.should have_content("Has been clicked")
154
+ end
155
+ end
156
+
157
+ describe '#has_no_content?' do
158
+ it "should wait for content to disappear" do
159
+ @session.visit('/with_js')
160
+ @session.click_link('Click me')
161
+ @session.should have_no_content("I changed it")
162
+ end
163
+ end
164
+
165
+ end
@@ -0,0 +1,15 @@
1
+ require File.expand_path('spec_helper', File.dirname(__FILE__))
2
+
3
+ require 'nokogiri'
4
+
5
+ shared_examples_for "session without headers support" do
6
+ describe "#evaluate_script" do
7
+ before{ @session.visit('/with_simple_html') }
8
+ it "should raise an error" do
9
+ running {
10
+ @session.response_headers
11
+ }.should raise_error(Capybara::NotSupportedByDriverError)
12
+ end
13
+ end
14
+ end
15
+
@@ -0,0 +1,15 @@
1
+ require File.expand_path('spec_helper', File.dirname(__FILE__))
2
+
3
+ require 'nokogiri'
4
+
5
+ shared_examples_for "session without javascript support" do
6
+ describe "#evaluate_script" do
7
+ before{ @session.visit('/with_js') }
8
+ it "should raise an error" do
9
+ running {
10
+ @session.evaluate_script("1+5")
11
+ }.should raise_error(Capybara::NotSupportedByDriverError)
12
+ end
13
+ end
14
+
15
+ end
@@ -2,9 +2,21 @@ $:.unshift(File.expand_path('../lib', File.dirname(__FILE__)))
2
2
  $:.unshift(File.dirname(__FILE__))
3
3
 
4
4
  require 'rubygems'
5
+ require 'spec'
6
+ require 'spec/autorun'
5
7
  require 'capybara'
6
8
  require 'test_app'
7
9
  require 'drivers_spec'
8
10
  require 'session_spec'
11
+ Dir[File.dirname(__FILE__)+'/dsl/*'].each { |group|
12
+ require group
13
+ include Object.const_get(group.match(/.*[\/]{1}([\w]*)[.rb]./).captures.first.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase })
14
+ }
15
+ require 'session_with_javascript_support_spec'
16
+ require 'session_without_javascript_support_spec'
17
+ require 'session_with_headers_support_spec'
18
+ require 'session_without_headers_support_spec'
9
19
 
10
20
  alias :running :lambda
21
+
22
+ Capybara.default_wait_time = 1 # less timeout so tests run faster
@@ -1,5 +1,6 @@
1
1
  require 'sinatra/base'
2
2
  require 'rack'
3
+ require 'yaml'
3
4
 
4
5
  class TestApp < Sinatra::Base
5
6
  set :root, File.dirname(__FILE__)
@@ -50,7 +51,14 @@ class TestApp < Sinatra::Base
50
51
  end
51
52
 
52
53
  post '/upload' do
53
- params[:form][:document][:tempfile].read rescue 'No file uploaded'
54
+ begin
55
+ buffer = []
56
+ buffer << "Content-type: #{params[:form][:document][:type]}"
57
+ buffer << "File content: #{params[:form][:document][:tempfile].read}"
58
+ buffer.join(' | ')
59
+ rescue
60
+ 'No file uploaded'
61
+ end
54
62
  end
55
63
  end
56
64
 
@@ -17,6 +17,12 @@
17
17
  <label for="form_name">Name</label>
18
18
  <input type="text" name="form[name]" value="John Smith" id="form_name"/>
19
19
  </p>
20
+
21
+ <p>
22
+ <label>Street<br/>
23
+ <input type="text" name="form[street]" value="Sesame street 66"/>
24
+ </label>
25
+ </p>
20
26
 
21
27
  <p>
22
28
  <label for="form_phone">Phone</label>
@@ -139,3 +145,35 @@
139
145
  <input type="submit" value="Go FAR"/>
140
146
  </p>
141
147
  </form>
148
+
149
+ <form action="/form" method="post">
150
+ <p>
151
+ <label for="html5_email">Html5 Email</label>
152
+ <input type="email" name="form[html5_email]" value="person@email.com" id="html5_email"/>
153
+ </p>
154
+ <p>
155
+ <label for="html5_url">Html5 Url</label>
156
+ <input type="url" name="form[html5_url]" value="http://www.example.com" id="html5_url"/>
157
+ </p>
158
+ <p>
159
+ <label for="html5_search">Html5 Search</label>
160
+ <input type="search" name="form[html5_search]" value="what are you looking for" id="html5_search"/>
161
+ </p>
162
+ <p>
163
+ <label for="html5_tel">Html5 Tel</label>
164
+ <input type="tel" name="form[html5_tel]" value="911" id="html5_tel"/>
165
+ </p>
166
+ <p>
167
+ <label for="html5_color">Html5 Color</label>
168
+ <input type="color" name="form[html5_color]" value="#FFF" id="html5_color"/>
169
+ </p>
170
+ </form>
171
+
172
+ <form action="/form" method="post">
173
+ <p>
174
+ <button type="submit" name="form[button]" value="button_first">Just an input that came first</button>
175
+ <button type="submit" name="form[button]" value="button_second">Just an input</button>
176
+ <input type="submit" name="form[button]" value="Just a button that came first"/>
177
+ <input type="submit" name="form[button]" value="Just a button"/>
178
+ </p>
179
+ </form>
@@ -0,0 +1,13 @@
1
+ <h1>Postback</h1>
2
+
3
+ <form method="get">
4
+ <p>
5
+ <input type="submit" value="With no action">
6
+ </p>
7
+ </form>
8
+
9
+ <form action="" method="get">
10
+ <p>
11
+ <input type="submit" value="With blank action">
12
+ </p>
13
+ </form>
@@ -16,4 +16,17 @@
16
16
 
17
17
  <p>
18
18
  <input type="text" id="test_field" value="monkey"/>
19
+ <a title="twas a fine link" href="/redirect">A link came first</a>
20
+ <a title="a fine link" href="/with_simple_html">A link</a>
21
+ <a>No Href</a>
22
+ <a href="">Blank Href</a>
23
+ <a href="#">Blank Anchor</a>
24
+ <a href="#anchor">Anchor</a>
25
+ <a href="/with_simple_html#anchor">Anchor on different page</a>
26
+ <a href="/with_html#anchor">Anchor on same page</a>
27
+ <input type="text" value="" id="test_field">
19
28
  </p>
29
+
30
+ <div id="hidden" style="display:none;">
31
+ <div id="hidden_via_ancestor">Inside element with hidden ancestor</div>
32
+ </div>
@@ -4,29 +4,7 @@
4
4
  <title>with_js</title>
5
5
  <script src="/jquery.js" type="text/javascript" charset="utf-8"></script>
6
6
  <script src="/jquery-ui.js" type="text/javascript" charset="utf-8"></script>
7
- <script type="text/javascript" charset="utf-8">
8
- //<![CDATA[
9
- $(function() {
10
- $('#change').text('I changed it');
11
- $('#drag').draggable();
12
- $('#drop').droppable({
13
- drop: function(event, ui) {
14
- ui.draggable.remove();
15
- $(this).html('Dropped!');
16
- }
17
- });
18
- $('#clickable').click(function() {
19
- var link = $(this);
20
- setTimeout(function() {
21
- $(link).after('<a href="#">Has been clicked</a>');
22
- $(link).after('<input type="submit" value="New Here">');
23
- $(link).after('<input type="text" id="new_field">');
24
- }, 500);
25
- return false;
26
- });
27
- });
28
- //]]>
29
- </script>
7
+ <script src="/test.js" type="text/javascript" charset="utf-8"></script>
30
8
  </head>
31
9
 
32
10
  <body id="with_js">
@@ -41,5 +19,12 @@
41
19
  </div>
42
20
 
43
21
  <p><a href="#" id="clickable">Click me</a></p>
22
+
23
+ <p>
24
+ <select id="waiter">
25
+ <option>Foo</option>
26
+ <option>My Waiting Option</option>
27
+ </select>
28
+ </p>
44
29
  </body>
45
- </html>
30
+ </html>
@@ -1 +1 @@
1
- <h1>Bar</h1>
1
+ Bar
@@ -0,0 +1,28 @@
1
+ require File.expand_path('spec_helper', File.dirname(__FILE__))
2
+
3
+ require 'capybara'
4
+ require 'capybara/wait_until'
5
+
6
+ module Capybara
7
+
8
+ describe WaitUntil do
9
+
10
+ it "should return result of yield if it returns true value within timeout" do
11
+ WaitUntil.timeout { "hello" }.should == "hello"
12
+ end
13
+
14
+ it "should keep trying within timeout" do
15
+ count = 0
16
+ WaitUntil.timeout { count += 1; count == 5 ? count : nil }.should == 5
17
+ end
18
+
19
+ it "should raise Capybara::TimeoutError if block fails to return true within timeout" do
20
+ running do
21
+ WaitUntil.timeout(0.1) { false }
22
+ end.should raise_error(::Capybara::TimeoutError)
23
+ end
24
+
25
+ end
26
+
27
+ end
28
+
@@ -83,9 +83,9 @@ describe Capybara::XPath do
83
83
  end
84
84
 
85
85
  it "should be chainable" do
86
- @query = @xpath.field('First Name').password_field('First Name').to_s
86
+ @query = @xpath.field('First Name').input_field(:password, 'First Name').to_s
87
87
  @driver.find(@query).first.value.should == 'John'
88
- @query = @xpath.field('Password').password_field('Password').to_s
88
+ @query = @xpath.field('Password').input_field(:password, 'Password').to_s
89
89
  @driver.find(@query).first.value.should == 'seeekrit'
90
90
  end
91
91
  end
@@ -99,7 +99,7 @@ describe Capybara::XPath do
99
99
  @query = @xpath.fillable_field('Description').to_s
100
100
  @driver.find(@query).first.text.should == 'Descriptive text goes here'
101
101
  end
102
-
102
+
103
103
  it "should be chainable" do
104
104
  @query = @xpath.fillable_field('First Name').password_field('First Name').to_s
105
105
  @driver.find(@query).first.value.should == 'John'
@@ -220,4 +220,35 @@ describe Capybara::XPath do
220
220
  end
221
221
  end
222
222
 
223
+ [ [:email_field, 'html5_email', 'Html5 Email', 'person@email.com'],
224
+ [:url_field, 'html5_url', 'Html5 Url', 'http://www.example.com'],
225
+ [:search_field, 'html5_search', 'Html5 Search', 'what are you looking for'],
226
+ [:tel_field, 'html5_tel', 'Html5 Tel', '911'],
227
+ [:color_field, 'html5_color', 'Html5 Color', '#FFF']].each do |method, id, label, output|
228
+ describe "##{method}" do
229
+ it "should find a file field by label" do
230
+ @query = @xpath.send(method, label).to_s
231
+ @driver.find(@query).first.value.should == output
232
+ end
233
+
234
+ it "should find a file field by id" do
235
+ @query = @xpath.send(method, id).to_s
236
+ @driver.find(@query).first.value.should == output
237
+ end
238
+
239
+ it "should be chainable" do
240
+ @query = @xpath.send(method, label).password_field(label).to_s
241
+ @driver.find(@query).first.value.should == output
242
+ @query = @xpath.send(method, 'Password').password_field('Password').to_s
243
+ @driver.find(@query).first.value.should == 'seeekrit'
244
+ end
245
+
246
+ it "should be a #fillable_field" do
247
+ @query = @xpath.fillable_field(label).to_s
248
+ @driver.find(@query).first.value.should == output
249
+ end
250
+ end
251
+
252
+ end
253
+
223
254
  end