capybara 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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