david-capybara 0.3.8 → 0.3.9.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. data/History.txt +21 -0
  2. data/README.rdoc +33 -2
  3. data/lib/capybara.rb +5 -4
  4. data/lib/capybara/driver/base.rb +12 -0
  5. data/lib/capybara/driver/celerity_driver.rb +15 -2
  6. data/lib/capybara/driver/rack_test_driver.rb +29 -22
  7. data/lib/capybara/driver/selenium_driver.rb +8 -7
  8. data/lib/capybara/rails.rb +0 -1
  9. data/lib/capybara/save_and_open_page.rb +4 -1
  10. data/lib/capybara/session.rb +16 -2
  11. data/lib/capybara/spec/driver.rb +62 -6
  12. data/lib/capybara/spec/session.rb +46 -0
  13. data/lib/capybara/spec/session/click_button_spec.rb +7 -0
  14. data/lib/capybara/spec/session/fill_in_spec.rb +12 -1
  15. data/lib/capybara/spec/session/javascript.rb +9 -1
  16. data/lib/capybara/spec/session/locate_spec.rb +6 -0
  17. data/lib/capybara/spec/session/response_code.rb +19 -0
  18. data/lib/capybara/spec/session/select_spec.rb +9 -1
  19. data/lib/capybara/spec/test_app.rb +21 -2
  20. data/lib/capybara/spec/views/form.erb +11 -1
  21. data/lib/capybara/spec/views/with_html.erb +1 -0
  22. data/lib/capybara/version.rb +1 -1
  23. data/lib/capybara/xpath.rb +1 -1
  24. data/spec/driver/celerity_driver_spec.rb +2 -1
  25. data/spec/driver/culerity_driver_spec.rb +3 -2
  26. data/spec/driver/rack_test_driver_spec.rb +4 -2
  27. data/spec/driver/remote_culerity_driver_spec.rb +3 -2
  28. data/spec/driver/remote_selenium_driver_spec.rb +1 -0
  29. data/spec/driver/selenium_driver_spec.rb +2 -0
  30. data/spec/save_and_open_page_spec.rb +53 -13
  31. data/spec/session/celerity_session_spec.rb +2 -1
  32. data/spec/session/culerity_session_spec.rb +2 -1
  33. data/spec/session/rack_test_session_spec.rb +1 -0
  34. data/spec/session/selenium_session_spec.rb +1 -0
  35. metadata +45 -6
@@ -1,3 +1,24 @@
1
+ # Version 0.3.9
2
+
3
+ Release data: 2010-07-03
4
+
5
+ ### Added
6
+
7
+ * status_code which returns the HTTP status code of the last response (no Selenium!)
8
+ * Capybara.save_and_open_page to store tempfiles
9
+ * RackTest and Culerity drivers now clean up after themselves properly
10
+
11
+ ### Fixed
12
+
13
+ * When no rack app is set and the app is called, a more descriptive error is raised
14
+ * select now works with optgroups
15
+ * Don't submit image buttons unless they were clicked under rack-test
16
+ * Support custom field types under Selenium
17
+ * Support input fields without a type, treat them as though they were text fields
18
+ * Redirect now throws an error after 5 redirects, as per RFC
19
+ * Selenium now properly raises an error when Node#trigger is called
20
+ * Node#value now returns the correct value for textareas under rack-test
21
+
1
22
  # Version 0.3.8
2
23
 
3
24
  Release date: 2010-05-12
@@ -8,7 +8,8 @@ Capybara aims to simplify the process of integration testing Rack applications,
8
8
  such as Rails, Sinatra or Merb. It is inspired by and aims to replace Webrat as
9
9
  a DSL for interacting with a webapplication. It is agnostic about the driver
10
10
  running your tests and currently comes bundled with rack-test, Culerity,
11
- Celerity and Selenium support built in.
11
+ Celerity and Selenium support built in. env.js support is available as the
12
+ {capybara-envjs gem}[http://github.com/smparkes/capybara-envjs].
12
13
 
13
14
  == Install:
14
15
 
@@ -123,6 +124,16 @@ being.
123
124
  Install celerity as noted above, make sure JRuby is in your path. Note that
124
125
  Culerity doesn't seem to be working under Ruby 1.9 at the moment.
125
126
 
127
+ == env.js
128
+
129
+ The {capybara-envjs driver}[http://github.com/smparkes/capybara-envjs]
130
+ uses the envjs gem ({GitHub}[http://github.com/smparkes/env-js],
131
+ {rubygems.org}[http://rubygems.org/gems/envjs]) to interpret
132
+ JavaScript outside the browser. The driver is installed by installing the capybara-envjs gem:
133
+ gem install capybara-envjs
134
+ More info about the driver and env.js are available through the links above. The envjs gem only supports
135
+ Ruby 1.8.7 at this time.
136
+
126
137
  == The DSL
127
138
 
128
139
  Capybara's DSL is inspired by Webrat. While backwards compatibility is retained
@@ -141,6 +152,10 @@ You can use the <tt>visit</tt> method to navigate to other pages:
141
152
  The visit method only takes a single parameter, the request method is *always*
142
153
  GET.
143
154
 
155
+ You can get the current path of the browsing session for test assertions:
156
+
157
+ current_path.should == post_comments_path(post)
158
+
144
159
  === Clicking links and buttons
145
160
 
146
161
  You can interact with the webapp by following links and buttons. Capybara
@@ -196,6 +211,17 @@ specific table, identified by either id or text of the table's caption tag.
196
211
  fill_in 'Name', :with => 'Jimmy'
197
212
  end
198
213
 
214
+ You can also specify a scope to be used for future searches with the <tt>scope_to</tt>.
215
+ It returns a handle to the session scoped to the provided selector.
216
+
217
+ scope = page.scope_to("//div[@id='foo']")
218
+ scope.has_xpath("//a[@class='bar']")
219
+
220
+ You can also chain scopes by calling <tt>scope_to</tt> on an existing scope.
221
+
222
+ more_scope = scope.scope_to("//p")
223
+ more_scope.has_xpath("//a[@class='baz']")
224
+
199
225
  === Querying
200
226
 
201
227
  Capybara has a rich set of options for querying the page for the existence of
@@ -228,7 +254,12 @@ You can also find specific elements, in order to manipulate them:
228
254
 
229
255
  === Scripting
230
256
 
231
- In drivers which support it, you can easily evaluate JavaScript:
257
+ In drivers which support it, you can easily execute JavaScript:
258
+
259
+ page.execute_script("$('body').empty()")
260
+
261
+ For simple expressions, you can return the result of the script. Note
262
+ that this may break with more complicated expressions:
232
263
 
233
264
  result = page.evaluate_script('4 + 4');
234
265
 
@@ -11,15 +11,16 @@ module Capybara
11
11
  class TimeoutError < CapybaraError; end
12
12
  class LocateHiddenElementError < CapybaraError; end
13
13
  class InfiniteRedirectError < TimeoutError; end
14
-
14
+
15
15
  class << self
16
16
  attr_accessor :debug, :asset_root, :app_host, :run_server, :default_host
17
17
  attr_accessor :default_selector, :default_wait_time, :ignore_hidden_elements
18
+ attr_accessor :save_and_open_page_path
18
19
 
19
20
  def default_selector
20
21
  @default_selector ||= :xpath
21
22
  end
22
-
23
+
23
24
  def default_wait_time
24
25
  @default_wait_time ||= 2
25
26
  end
@@ -29,14 +30,14 @@ module Capybara
29
30
  true
30
31
  end
31
32
  end
32
-
33
+
33
34
  autoload :Server, 'capybara/server'
34
35
  autoload :Session, 'capybara/session'
35
36
  autoload :Node, 'capybara/node'
36
37
  autoload :XPath, 'capybara/xpath'
37
38
  autoload :Searchable, 'capybara/searchable'
38
39
  autoload :VERSION, 'capybara/version'
39
-
40
+
40
41
  module Driver
41
42
  autoload :Base, 'capybara/driver/base'
42
43
  autoload :RackTest, 'capybara/driver/rack_test_driver'
@@ -3,6 +3,10 @@ class Capybara::Driver::Base
3
3
  raise NotImplementedError
4
4
  end
5
5
 
6
+ def current_path
7
+ URI.parse(current_url).path
8
+ end
9
+
6
10
  def visit(path)
7
11
  raise NotImplementedError
8
12
  end
@@ -11,6 +15,10 @@ class Capybara::Driver::Base
11
15
  raise NotImplementedError
12
16
  end
13
17
 
18
+ def execute_script(script)
19
+ raise Capybara::NotSupportedByDriverError
20
+ end
21
+
14
22
  def evaluate_script(script)
15
23
  raise Capybara::NotSupportedByDriverError
16
24
  end
@@ -25,6 +33,10 @@ class Capybara::Driver::Base
25
33
  def response_headers
26
34
  raise Capybara::NotSupportedByDriverError
27
35
  end
36
+
37
+ def status_code
38
+ raise Capybara::NotSupportedByDriverError
39
+ end
28
40
 
29
41
  def body
30
42
  raise NotImplementedError
@@ -72,7 +72,7 @@ class Capybara::Driver::Celerity < Capybara::Driver::Base
72
72
  def path
73
73
  node.xpath
74
74
  end
75
-
75
+
76
76
  def trigger(event)
77
77
  node.fire_event(event.to_s)
78
78
  end
@@ -102,7 +102,7 @@ class Capybara::Driver::Celerity < Capybara::Driver::Base
102
102
  def current_url
103
103
  browser.url
104
104
  end
105
-
105
+
106
106
  def source
107
107
  browser.html
108
108
  end
@@ -115,12 +115,21 @@ class Capybara::Driver::Celerity < Capybara::Driver::Base
115
115
  browser.response_headers
116
116
  end
117
117
 
118
+ def status_code
119
+ browser.status_code
120
+ end
121
+
118
122
  def find(selector)
119
123
  browser.elements_by_xpath(selector).map { |node| Node.new(self, node) }
120
124
  end
121
125
 
122
126
  def wait?; true; end
123
127
 
128
+ def execute_script(script)
129
+ browser.execute_script script
130
+ nil
131
+ end
132
+
124
133
  def evaluate_script(script)
125
134
  browser.execute_script "#{script}"
126
135
  end
@@ -134,6 +143,10 @@ class Capybara::Driver::Celerity < Capybara::Driver::Base
134
143
  @_browser
135
144
  end
136
145
 
146
+ def cleanup!
147
+ browser.clear_cookies
148
+ end
149
+
137
150
  private
138
151
 
139
152
  def url(path)
@@ -26,6 +26,13 @@ class Capybara::Driver::RackTest < Capybara::Driver::Base
26
26
  end
27
27
  end
28
28
 
29
+ def value
30
+ if tag_name == 'textarea'
31
+ node.content
32
+ else
33
+ super
34
+ end
35
+ end
29
36
 
30
37
  def set(value)
31
38
  if tag_name == 'input' and type == 'radio'
@@ -112,7 +119,7 @@ class Capybara::Driver::RackTest < Capybara::Driver::Base
112
119
  def params(button)
113
120
  params = {}
114
121
 
115
- node.xpath(".//input[@type!='radio' and @type!='checkbox' and @type!='submit']").map do |input|
122
+ node.xpath(".//input[not(@type) or (@type!='radio' and @type!='checkbox' and @type!='submit' and @type!='image')]").map do |input|
116
123
  merge_param!(params, input['name'].to_s, input['value'].to_s)
117
124
  end
118
125
  node.xpath(".//textarea").map do |textarea|
@@ -192,7 +199,7 @@ class Capybara::Driver::RackTest < Capybara::Driver::Base
192
199
  end
193
200
 
194
201
  def process(method, path, attributes = {})
195
- return if path.gsub(/^#{current_path}/, '') =~ /^#/
202
+ return if path.gsub(/^#{request_path}/, '') =~ /^#/
196
203
  send(method, path, attributes, env)
197
204
  follow_redirects!
198
205
  end
@@ -205,8 +212,12 @@ class Capybara::Driver::RackTest < Capybara::Driver::Base
205
212
  response.headers
206
213
  end
207
214
 
215
+ def status_code
216
+ response.status
217
+ end
218
+
208
219
  def submit(method, path, attributes)
209
- path = current_path if not path or path.empty?
220
+ path = request_path if not path or path.empty?
210
221
  send(method, path, attributes, env)
211
222
  follow_redirects!
212
223
  end
@@ -214,21 +225,32 @@ class Capybara::Driver::RackTest < Capybara::Driver::Base
214
225
  def find(selector)
215
226
  html.xpath(selector).map { |node| Node.new(self, node) }
216
227
  end
217
-
228
+
218
229
  def body
219
230
  @body ||= response.body
220
231
  end
221
-
232
+
222
233
  def html
223
234
  @html ||= Nokogiri::HTML(body)
224
235
  end
225
236
  alias_method :source, :body
226
237
 
238
+ def cleanup!
239
+ clear_cookies
240
+ end
241
+
227
242
  def get(*args, &block); reset_cache; super; end
228
243
  def post(*args, &block); reset_cache; super; end
229
244
  def put(*args, &block); reset_cache; super; end
230
245
  def delete(*args, &block); reset_cache; super; end
231
-
246
+
247
+ def follow_redirects!
248
+ 5.times do
249
+ follow_redirect! if response.redirect?
250
+ end
251
+ raise Capybara::InfiniteRedirectError, "redirected more than 5 times, check for infinite redirects." if response.redirect?
252
+ end
253
+
232
254
  private
233
255
 
234
256
  def reset_cache
@@ -240,20 +262,10 @@ private
240
262
  Rack::MockSession.new(app, Capybara.default_host || "www.example.com")
241
263
  end
242
264
 
243
- def current_path
265
+ def request_path
244
266
  request.path rescue ""
245
267
  end
246
268
 
247
- def follow_redirects!
248
- Capybara::WaitUntil.timeout(4) do
249
- redirect = response.redirect?
250
- follow_redirect! if redirect
251
- not redirect
252
- end
253
- rescue Capybara::TimeoutError
254
- raise Capybara::InfiniteRedirectError, "infinite redirect detected!"
255
- end
256
-
257
269
  def env
258
270
  env = {}
259
271
  begin
@@ -264,9 +276,4 @@ private
264
276
  env
265
277
  end
266
278
 
267
- def reset_cache
268
- @body = nil
269
- @html = nil
270
- end
271
-
272
279
  end
@@ -25,13 +25,13 @@ class Capybara::Driver::Selenium < Capybara::Driver::Base
25
25
  end
26
26
 
27
27
  def set(value)
28
- if tag_name == 'textarea' or (tag_name == 'input' and %w(text password hidden file).include?(type))
29
- node.clear
30
- node.send_keys(value.to_s)
31
- elsif tag_name == 'input' and type == 'radio'
28
+ if tag_name == 'input' and type == 'radio'
32
29
  node.click
33
30
  elsif tag_name == 'input' and type == 'checkbox'
34
31
  node.click if node.attribute('checked') != value
32
+ elsif tag_name == 'textarea' or tag_name == 'input'
33
+ node.clear
34
+ node.send_keys(value.to_s)
35
35
  end
36
36
  end
37
37
 
@@ -73,9 +73,6 @@ class Capybara::Driver::Selenium < Capybara::Driver::Base
73
73
  node.displayed? and node.displayed? != "false"
74
74
  end
75
75
 
76
- def trigger(event)
77
- end
78
-
79
76
  private
80
77
 
81
78
  def all_unfiltered(locator)
@@ -128,6 +125,10 @@ class Capybara::Driver::Selenium < Capybara::Driver::Base
128
125
 
129
126
  def wait?; true; end
130
127
 
128
+ def execute_script(script)
129
+ browser.execute_script script
130
+ end
131
+
131
132
  def evaluate_script(script)
132
133
  browser.execute_script "return #{script}"
133
134
  end
@@ -4,7 +4,6 @@ require 'capybara/dsl'
4
4
  Capybara.app = Rack::Builder.new do
5
5
  map "/" do
6
6
  if Rails.version.to_f >= 3.0
7
- ActionDispatch::Static
8
7
  run Rails.application
9
8
  else # Rails 2
10
9
  use Rails::Rack::Static
@@ -3,8 +3,11 @@ module Capybara
3
3
  extend(self)
4
4
 
5
5
  def save_and_open_page(html)
6
- name="capybara-#{Time.new.strftime("%Y%m%d%H%M%S")}.html"
6
+ name = File.join(*[Capybara.save_and_open_page_path, "capybara-#{Time.new.strftime("%Y%m%d%H%M%S")}.html"].compact)
7
7
 
8
+ unless Capybara.save_and_open_page_path.nil? || File.directory?(Capybara.save_and_open_page_path )
9
+ FileUtils.mkdir_p(Capybara.save_and_open_page_path)
10
+ end
8
11
  FileUtils.touch(name) unless File.exist?(name)
9
12
 
10
13
  tempfile = File.new(name,'w')
@@ -12,7 +12,7 @@ module Capybara
12
12
  :has_no_content?, :has_no_css?, :has_no_xpath?, :has_xpath?, :locate, :save_and_open_page, :select, :source, :uncheck,
13
13
  :visit, :wait_until, :within, :within_fieldset, :within_table, :within_frame, :has_link?, :has_no_link?, :has_button?,
14
14
  :has_no_button?, :has_field?, :has_no_field?, :has_checked_field?, :has_unchecked_field?, :has_no_table?, :has_table?,
15
- :unselect, :has_select?, :has_no_select?
15
+ :unselect, :has_select?, :has_no_select?, :current_path, :scope_to
16
16
  ]
17
17
 
18
18
  attr_reader :mode, :app
@@ -34,7 +34,9 @@ module Capybara
34
34
 
35
35
  def_delegator :driver, :cleanup!
36
36
  def_delegator :driver, :current_url
37
+ def_delegator :driver, :current_path
37
38
  def_delegator :driver, :response_headers
39
+ def_delegator :driver, :status_code
38
40
  def_delegator :driver, :visit
39
41
  def_delegator :driver, :body
40
42
  def_delegator :driver, :source
@@ -126,6 +128,14 @@ module Capybara
126
128
  end
127
129
  end
128
130
 
131
+ def scope_to(*locator)
132
+ scoped_session = self.clone
133
+ scoped_session.instance_eval do
134
+ @scopes = scopes + locator
135
+ end
136
+ scoped_session
137
+ end
138
+
129
139
  def has_xpath?(path, options={})
130
140
  wait_conditionally_until do
131
141
  results = all(:xpath, path, options)
@@ -227,7 +237,7 @@ module Capybara
227
237
  def locate(kind_or_locator, locator=nil, fail_msg = nil)
228
238
  node = wait_conditionally_until { find(kind_or_locator, locator) }
229
239
  ensure
230
- raise Capybara::ElementNotFound, fail_msg || "Unable to locate '#{kind_or_locator}'" unless node
240
+ raise Capybara::ElementNotFound, fail_msg || "Unable to locate '#{locator || kind_or_locator}'" unless node
231
241
  return node
232
242
  end
233
243
 
@@ -235,6 +245,10 @@ module Capybara
235
245
  WaitUntil.timeout(timeout,driver) { yield }
236
246
  end
237
247
 
248
+ def execute_script(script)
249
+ driver.execute_script(script)
250
+ end
251
+
238
252
  def evaluate_script(script)
239
253
  driver.evaluate_script(script)
240
254
  end
@@ -1,6 +1,6 @@
1
1
  require 'capybara/spec/test_app'
2
2
 
3
- Dir[File.dirname(__FILE__)+'/driver/*'].each { |group|
3
+ Dir[File.dirname(__FILE__)+'/driver/*'].each { |group|
4
4
  require group
5
5
  }
6
6
 
@@ -13,11 +13,16 @@ shared_examples_for 'driver' do
13
13
  @driver.visit('/foo')
14
14
  @driver.body.should include('Another World')
15
15
  end
16
-
16
+
17
17
  it "should show the correct URL" do
18
18
  @driver.visit('/foo')
19
19
  @driver.current_url.should include('/foo')
20
20
  end
21
+
22
+ it 'should show the correct location' do
23
+ @driver.visit('/foo')
24
+ @driver.current_path.should == '/foo'
25
+ end
21
26
  end
22
27
 
23
28
  describe '#body' do
@@ -55,6 +60,10 @@ shared_examples_for 'driver' do
55
60
  @driver.find('//input[@id="checked_field"]')[0][:checked].should be_true
56
61
  end
57
62
 
63
+ it "should allow retrieval of the value" do
64
+ @driver.find('//textarea').first.value.should == 'banana'
65
+ end
66
+
58
67
  it "should allow assignment of field value" do
59
68
  @driver.find('//input').first.value.should == 'monkey'
60
69
  @driver.find('//input').first.set('gorilla')
@@ -66,10 +75,10 @@ shared_examples_for 'driver' do
66
75
  @driver.find('//a')[1].tag_name.should == 'a'
67
76
  @driver.find('//p')[1].tag_name.should == 'p'
68
77
  end
69
-
78
+
70
79
  it "should extract node visibility" do
71
80
  @driver.find('//a')[0].should be_visible
72
-
81
+
73
82
  @driver.find('//div[@id="hidden"]')[0].should_not be_visible
74
83
  @driver.find('//div[@id="hidden_via_ancestor"]')[0].should_not be_visible
75
84
  end
@@ -81,7 +90,7 @@ shared_examples_for 'driver' do
81
90
  @driver.visit('/tables')
82
91
  @node = @driver.find('//body').first
83
92
  end
84
-
93
+
85
94
  it "should be able to navigate/search child node" do
86
95
  @node.all('//table').size.should == 5
87
96
  @node.find('//form').all('.//table').size.should == 1
@@ -95,7 +104,6 @@ shared_examples_for 'driver' do
95
104
  end
96
105
  end
97
106
  end
98
-
99
107
  end
100
108
 
101
109
  shared_examples_for "driver with javascript support" do
@@ -130,6 +138,22 @@ shared_examples_for "driver with header support" do
130
138
  end
131
139
  end
132
140
 
141
+ shared_examples_for "driver with status code support" do
142
+ it "should make the status code available through status_code" do
143
+ @driver.visit('/with_simple_html')
144
+ @driver.status_code.should == 200
145
+ end
146
+ end
147
+
148
+ shared_examples_for "driver without status code support" do
149
+ it "should raise when trying to access the status code available through status_code" do
150
+ @driver.visit('/with_simple_html')
151
+ lambda {
152
+ @driver.status_code
153
+ }.should raise_error(Capybara::NotSupportedByDriverError)
154
+ end
155
+ end
156
+
133
157
  shared_examples_for "driver with frame support" do
134
158
  describe '#within_frame' do
135
159
  before(:each) do
@@ -160,3 +184,35 @@ shared_examples_for "driver with frame support" do
160
184
  end
161
185
  end
162
186
  end
187
+
188
+ shared_examples_for "driver with cookies support" do
189
+ describe "#cleanup" do
190
+ it "should set and clean cookies" do
191
+ @driver.visit('/get_cookie')
192
+ @driver.body.should_not include('test_cookie')
193
+
194
+ @driver.visit('/set_cookie')
195
+ @driver.body.should include('Cookie set to test_cookie')
196
+
197
+ @driver.visit('/get_cookie')
198
+ @driver.body.should include('test_cookie')
199
+
200
+ @driver.cleanup!
201
+ @driver.visit('/get_cookie')
202
+ @driver.body.should_not include('test_cookie')
203
+ end
204
+ end
205
+ end
206
+
207
+ shared_examples_for "driver with infinite redirect detection" do
208
+ it "should follow 5 redirects" do
209
+ @driver.visit('/redirect/5/times')
210
+ @driver.body.should include('redirection complete')
211
+ end
212
+
213
+ it "should not follow more than 5 redirects" do
214
+ running do
215
+ @driver.visit('/redirect/6/times')
216
+ end.should raise_error(Capybara::InfiniteRedirectError)
217
+ end
218
+ end
@@ -39,6 +39,52 @@ shared_examples_for "session" do
39
39
  end
40
40
  end
41
41
 
42
+ describe '#scope_to' do
43
+ let(:scope) { @session.scope_to("//p[@id='first']") }
44
+ let(:more_scope) { scope.scope_to("//a[@id='foo']") }
45
+
46
+ before do
47
+ @session.visit('/with_html')
48
+ end
49
+
50
+ it 'has a simple link' do
51
+ scope.should have_xpath("//a[@class='simple']")
52
+ end
53
+
54
+ it 'does not have a redirect link' do
55
+ scope.should have_no_xpath("//a[@id='red']")
56
+ end
57
+
58
+ it 'does have a redirect link' do
59
+ @session.should have_xpath("//a[@id='red']")
60
+ end
61
+
62
+ it 'does not share scopes' do
63
+ @session.should have_xpath("//a[@id='red']")
64
+ scope.should have_no_xpath("//a[@id='red']")
65
+ @session.should have_xpath("//a[@id='red']")
66
+ end
67
+
68
+ context 'more_scope' do
69
+ it 'has the text for foo' do
70
+ more_scope.should have_content('ullamco')
71
+ end
72
+
73
+ it 'does not have a simple link' do
74
+ more_scope.should have_no_xpath("//a[@class='simple']")
75
+ end
76
+
77
+ it 'has not overridden scope' do
78
+ scope.should have_xpath("//a[@class='simple']")
79
+ end
80
+
81
+ it 'has not overridden session' do
82
+ @session.should have_xpath("//p[@id='second']")
83
+ end
84
+ end
85
+
86
+ end
87
+
42
88
  it_should_behave_like "all"
43
89
  it_should_behave_like "attach_file"
44
90
  it_should_behave_like "check"
@@ -207,6 +207,12 @@ shared_examples_for "click_button" do
207
207
  @results = extract_results(@session)
208
208
  @results['no_value'].should_not be_nil
209
209
  end
210
+
211
+ it "should not send image buttons that were not clicked" do
212
+ @session.click_button('Click me!')
213
+ @results = extract_results(@session)
214
+ @results['okay'].should be_nil
215
+ end
210
216
 
211
217
  it "should serialize and send GET forms" do
212
218
  @session.visit('/form')
@@ -218,6 +224,7 @@ shared_examples_for "click_button" do
218
224
 
219
225
  it "should follow redirects" do
220
226
  @session.click_button('Go FAR')
227
+ @session.current_url.should match(%r{/landed$})
221
228
  @session.body.should include('You landed')
222
229
  end
223
230
 
@@ -22,6 +22,12 @@ shared_examples_for "fill_in" do
22
22
  extract_results(@session)['street'].should == 'Avenue Q'
23
23
  end
24
24
 
25
+ it "should fill in a url field by label without for" do
26
+ @session.fill_in('Html5 Url', :with => 'http://www.avenueq.com')
27
+ @session.click_button('html5_submit')
28
+ extract_results(@session)['html5_url'].should == 'http://www.avenueq.com'
29
+ end
30
+
25
31
  it "should favour exact label matches over partial matches" do
26
32
  @session.fill_in('Name', :with => 'Harry Jones')
27
33
  @session.click_button('awesome')
@@ -53,12 +59,17 @@ shared_examples_for "fill_in" do
53
59
  end
54
60
 
55
61
  it "should fill in a field with a custom type" do
56
- pending "selenium doesn't seem to find custom fields" if @session.mode == :selenium
57
62
  @session.fill_in('Schmooo', :with => 'Schmooo is the game')
58
63
  @session.click_button('awesome')
59
64
  extract_results(@session)['schmooo'].should == 'Schmooo is the game'
60
65
  end
61
66
 
67
+ it "should fill in a field without a type" do
68
+ @session.fill_in('Phone', :with => '+1 555 7022')
69
+ @session.click_button('awesome')
70
+ extract_results(@session)['phone'].should == '+1 555 7022'
71
+ end
72
+
62
73
  it "should fill in a password field by name" do
63
74
  @session.fill_in('form[password]', :with => 'supasikrit')
64
75
  @session.click_button('awesome')
@@ -35,12 +35,20 @@ shared_examples_for "session with javascript support" do
35
35
  end
36
36
 
37
37
  describe "#evaluate_script" do
38
- it "should return the evaluated script" do
38
+ it "should evaluate the given script and return whatever it produces" do
39
39
  @session.visit('/with_js')
40
40
  @session.evaluate_script("1+3").should == 4
41
41
  end
42
42
  end
43
43
 
44
+ describe "#execute_script" do
45
+ it "should execute the given script and return nothing" do
46
+ @session.visit('/with_js')
47
+ @session.execute_script("$('#change').text('Funky Doodle')").should be_nil
48
+ @session.should have_css('#change', :text => 'Funky Doodle')
49
+ end
50
+ end
51
+
44
52
  describe '#locate' do
45
53
  it "should wait for asynchronous load" do
46
54
  @session.visit('/with_js')
@@ -38,6 +38,12 @@ shared_examples_for "locate" do
38
38
  end.should raise_error(Capybara::ElementNotFound, "arghh")
39
39
  end
40
40
 
41
+ it "should raise ElementNotFound with a useful default message if nothing was found" do
42
+ running do
43
+ @session.locate(:xpath, '//div[@id="nosuchthing"]').should be_nil
44
+ end.should raise_error(Capybara::ElementNotFound, "Unable to locate '//div[@id=\"nosuchthing\"]'")
45
+ end
46
+
41
47
  it "should accept an XPath instance and respect the order of paths" do
42
48
  @session.visit('/form')
43
49
  @xpath = Capybara::XPath.text_field('Name')
@@ -0,0 +1,19 @@
1
+ shared_examples_for "session with status code support" do
2
+ describe '#status_code' do
3
+ it "should return response codes" do
4
+ @session.visit('/with_simple_html')
5
+ @session.status_code.should == 200
6
+ end
7
+ end
8
+ end
9
+
10
+ shared_examples_for "session without status code support" do
11
+ describe "#status_code" do
12
+ before{ @session.visit('/with_simple_html') }
13
+ it "should raise an error" do
14
+ running {
15
+ @session.status_code
16
+ }.should raise_error(Capybara::NotSupportedByDriverError)
17
+ end
18
+ end
19
+ end
@@ -37,7 +37,15 @@ shared_examples_for "select" do
37
37
  extract_results(@session)['locale'].should == 'jo'
38
38
  end
39
39
 
40
- it "match labels with preceding or trailing whitespace" do
40
+ it "should obey from" do
41
+ @session.select("Miss", :from => "Other title")
42
+ @session.click_button('awesome')
43
+ results = extract_results(@session)
44
+ results['other_title'].should == "Miss"
45
+ results['title'].should_not == "Miss"
46
+ end
47
+
48
+ it "show match labels with preceding or trailing whitespace" do
41
49
  @session.select("Lojban", :from => 'Locale')
42
50
  @session.click_button('awesome')
43
51
  extract_results(@session)['locale'].should == 'jbo'
@@ -13,7 +13,7 @@ class TestApp < Sinatra::Base
13
13
  get '/foo' do
14
14
  'Another World'
15
15
  end
16
-
16
+
17
17
  get '/redirect' do
18
18
  redirect '/redirect_again'
19
19
  end
@@ -22,6 +22,15 @@ class TestApp < Sinatra::Base
22
22
  redirect '/landed'
23
23
  end
24
24
 
25
+ get '/redirect/:times/times' do
26
+ times = params[:times].to_i
27
+ if times.zero?
28
+ "redirection complete"
29
+ else
30
+ redirect "/redirect/#{times - 1}/times"
31
+ end
32
+ end
33
+
25
34
  get '/landed' do
26
35
  "You landed"
27
36
  end
@@ -33,7 +42,7 @@ class TestApp < Sinatra::Base
33
42
  get '/form/get' do
34
43
  '<pre id="results">' + params[:form].to_yaml + '</pre>'
35
44
  end
36
-
45
+
37
46
  get '/favicon.ico' do
38
47
  nil
39
48
  end
@@ -50,6 +59,16 @@ class TestApp < Sinatra::Base
50
59
  redirect back
51
60
  end
52
61
 
62
+ get '/set_cookie' do
63
+ cookie_value = 'test_cookie'
64
+ response.set_cookie('capybara', cookie_value)
65
+ "Cookie set to #{cookie_value}"
66
+ end
67
+
68
+ get '/get_cookie' do
69
+ request.cookies['capybara']
70
+ end
71
+
53
72
  get '/:view' do |view|
54
73
  erb view.to_sym
55
74
  end
@@ -11,6 +11,16 @@
11
11
  </select>
12
12
  </p>
13
13
 
14
+
15
+ <p>
16
+ <label for="form_other_title">Other title</label>
17
+ <select name="form[other_title]" id="form_other_title">
18
+ <option>Mrs</option>
19
+ <option>Mr</option>
20
+ <option>Miss</option>
21
+ </select>
22
+ </p>
23
+
14
24
  <p>
15
25
  <label for="form_first_name">
16
26
  First Name
@@ -46,7 +56,7 @@
46
56
 
47
57
  <p>
48
58
  <label for="form_phone">Phone</label>
49
- <input type="text" name="form[phone]" value="+1 555 7021" id="form_phone"/>
59
+ <input name="form[phone]" value="+1 555 7021" id="form_phone"/>
50
60
  </p>
51
61
 
52
62
  <p>
@@ -20,6 +20,7 @@
20
20
 
21
21
  <p>
22
22
  <input type="text" id="test_field" value="monkey"/>
23
+ <textarea>banana</textarea>
23
24
  <a href="/redirect_back">BackToMyself</a>
24
25
  <a title="twas a fine link" href="/redirect">A link came first</a>
25
26
  <a title="a fine link" href="/with_simple_html">A link</a>
@@ -1,3 +1,3 @@
1
1
  module Capybara
2
- VERSION = '0.3.8'
2
+ VERSION = '0.3.9'
3
3
  end
@@ -112,7 +112,7 @@ module Capybara
112
112
 
113
113
  def text_field(locator, options={})
114
114
  options = options.merge(:value => options[:with]) if options.has_key?(:with)
115
- add_field(locator, "//input[@type!='radio' and @type!='checkbox' and @type!='hidden']", options)
115
+ add_field(locator, "//input[not(@type) or (@type!='radio' and @type!='checkbox' and @type!='hidden')]", options)
116
116
  end
117
117
 
118
118
  def text_area(locator, options={})
@@ -9,7 +9,8 @@ if RUBY_PLATFORM =~ /java/
9
9
  it_should_behave_like "driver"
10
10
  it_should_behave_like "driver with javascript support"
11
11
  it_should_behave_like "driver with header support"
12
-
12
+ it_should_behave_like "driver with status code support"
13
+ it_should_behave_like "driver with cookies support"
13
14
  end
14
15
  else
15
16
  puts "#{File.basename(__FILE__)} requires JRuby; skipping.."
@@ -4,9 +4,10 @@ describe Capybara::Driver::Culerity do
4
4
  before(:all) do
5
5
  @driver = Capybara::Driver::Culerity.new(TestApp)
6
6
  end
7
-
7
+
8
8
  it_should_behave_like "driver"
9
9
  it_should_behave_like "driver with javascript support"
10
10
  it_should_behave_like "driver with header support"
11
-
11
+ it_should_behave_like "driver with status code support"
12
+ it_should_behave_like "driver with cookies support"
12
13
  end
@@ -10,8 +10,10 @@ describe Capybara::Driver::RackTest do
10
10
  Capybara::Driver::RackTest.new(nil)
11
11
  end.should raise_error(ArgumentError)
12
12
  end
13
-
13
+
14
14
  it_should_behave_like "driver"
15
15
  it_should_behave_like "driver with header support"
16
-
16
+ it_should_behave_like "driver with status code support"
17
+ it_should_behave_like "driver with cookies support"
18
+ it_should_behave_like "driver with infinite redirect detection"
17
19
  end
@@ -13,11 +13,12 @@ describe Capybara::Driver::Culerity do
13
13
  end
14
14
 
15
15
  it "should navigate to a fully qualified remote page" do
16
- @driver.visit('http://elabs.se/contact')
17
- @driver.body.should include('Edithouse eLabs AB')
16
+ @driver.visit('http://capybara-testapp.heroku.com/foo')
17
+ @driver.body.should include('Another World')
18
18
  end
19
19
 
20
20
  it_should_behave_like "driver"
21
21
  it_should_behave_like "driver with javascript support"
22
22
  it_should_behave_like "driver with header support"
23
+ it_should_behave_like "driver with status code support"
23
24
  end
@@ -15,4 +15,5 @@ describe Capybara::Driver::Selenium do
15
15
 
16
16
  it_should_behave_like "driver"
17
17
  it_should_behave_like "driver with javascript support"
18
+ it_should_behave_like "driver without status code support"
18
19
  end
@@ -8,4 +8,6 @@ describe Capybara::Driver::Selenium do
8
8
  it_should_behave_like "driver"
9
9
  it_should_behave_like "driver with javascript support"
10
10
  it_should_behave_like "driver with frame support"
11
+ it_should_behave_like "driver without status code support"
12
+ it_should_behave_like "driver with cookies support"
11
13
  end
@@ -5,18 +5,12 @@ require 'launchy'
5
5
  describe Capybara::SaveAndOpenPage do
6
6
  describe "#save_save_and_open_page" do
7
7
  before do
8
-
9
8
  @time = Time.new.strftime("%Y%m%d%H%M%S")
10
- @name = "capybara-#{@time}.html"
11
9
 
12
10
  @temp_file = mock("FILE")
13
11
  @temp_file.stub!(:write)
14
12
  @temp_file.stub!(:close)
15
- @temp_file.stub!(:path).and_return(@name)
16
-
17
- File.should_receive(:exist?).and_return true
18
- File.should_receive(:new).and_return @temp_file
19
-
13
+
20
14
  @html = <<-HTML
21
15
  <html>
22
16
  <head>
@@ -30,14 +24,60 @@ describe Capybara::SaveAndOpenPage do
30
24
  Launchy::Browser.stub(:run)
31
25
  end
32
26
 
33
- it "should create a new temporary file" do
34
- @temp_file.should_receive(:write).with @html
35
- Capybara::SaveAndOpenPage.save_and_open_page @html
27
+ describe "defaults" do
28
+ before do
29
+ @name = "capybara-#{@time}.html"
30
+
31
+ @temp_file.stub!(:path).and_return(@name)
32
+
33
+ File.should_receive(:exist?).and_return true
34
+ File.should_receive(:new).and_return @temp_file
35
+ end
36
+
37
+ it "should create a new temporary file" do
38
+ @temp_file.should_receive(:write).with @html
39
+ Capybara::SaveAndOpenPage.save_and_open_page @html
40
+ end
41
+
42
+ it "should open the file in the browser" do
43
+ Capybara::SaveAndOpenPage.should_receive(:open_in_browser).with(@name)
44
+ Capybara::SaveAndOpenPage.save_and_open_page @html
45
+ end
36
46
  end
47
+
48
+ describe "custom output path" do
49
+ before do
50
+ @custom_path = File.join('tmp', 'capybara')
51
+ @custom_name = File.join(@custom_path, "capybara-#{@time}.html")
37
52
 
38
- it "should open the file in the browser" do
39
- Capybara::SaveAndOpenPage.should_receive(:open_in_browser).with(@name)
40
- Capybara::SaveAndOpenPage.save_and_open_page @html
53
+ @temp_file.stub!(:path).and_return(@custom_name)
54
+
55
+ Capybara.should_receive(:save_and_open_page_path).at_least(:once).and_return(@custom_path)
56
+ end
57
+
58
+ it "should create a new temporary file in the custom path" do
59
+ File.should_receive(:directory?).and_return true
60
+ File.should_receive(:exist?).and_return true
61
+ File.should_receive(:new).and_return @temp_file
62
+
63
+ @temp_file.should_receive(:write).with @html
64
+ Capybara::SaveAndOpenPage.save_and_open_page @html
65
+ end
66
+
67
+ it "should open the file - in the custom path - in the browser" do
68
+ Capybara::SaveAndOpenPage.should_receive(:open_in_browser).with(@custom_name)
69
+ Capybara::SaveAndOpenPage.save_and_open_page @html
70
+ end
71
+
72
+ it "should be possible to configure output path" do
73
+ Capybara.should respond_to(:save_and_open_page_path)
74
+ default_setting = Capybara.save_and_open_page_path
75
+ lambda {
76
+ Capybara.save_and_open_page_path = File.join('tmp', 'capybara')
77
+ Capybara.save_and_open_page_path.should == File.join('tmp', 'capybara')
78
+ }.should_not raise_error
79
+ Capybara.save_and_open_page_path = default_setting
80
+ end
41
81
  end
42
82
  end
43
83
  end
@@ -7,7 +7,7 @@ if RUBY_PLATFORM =~ /java/
7
7
  end
8
8
 
9
9
  describe '#driver' do
10
- it "should be a rack test driver" do
10
+ it "should be a celerity driver" do
11
11
  @session.driver.should be_an_instance_of(Capybara::Driver::Celerity)
12
12
  end
13
13
  end
@@ -21,6 +21,7 @@ if RUBY_PLATFORM =~ /java/
21
21
  it_should_behave_like "session"
22
22
  it_should_behave_like "session with javascript support"
23
23
  it_should_behave_like "session with headers support"
24
+ it_should_behave_like "session with status code support"
24
25
  end
25
26
  else
26
27
  puts "#{File.basename(__FILE__)} requires JRuby; skipping.."
@@ -7,7 +7,7 @@ describe Capybara::Session do
7
7
  end
8
8
 
9
9
  describe '#driver' do
10
- it "should be a rack test driver" do
10
+ it "should be a culerity driver" do
11
11
  @session.driver.should be_an_instance_of(Capybara::Driver::Culerity)
12
12
  end
13
13
  end
@@ -21,5 +21,6 @@ describe Capybara::Session do
21
21
  it_should_behave_like "session"
22
22
  it_should_behave_like "session with javascript support"
23
23
  it_should_behave_like "session with headers support"
24
+ it_should_behave_like "session with status code support"
24
25
  end
25
26
  end
@@ -29,5 +29,6 @@ describe Capybara::Session do
29
29
  it_should_behave_like "session"
30
30
  it_should_behave_like "session without javascript support"
31
31
  it_should_behave_like "session with headers support"
32
+ it_should_behave_like "session with status code support"
32
33
  end
33
34
  end
@@ -21,5 +21,6 @@ describe Capybara::Session do
21
21
  it_should_behave_like "session"
22
22
  it_should_behave_like "session with javascript support"
23
23
  it_should_behave_like "session without headers support"
24
+ it_should_behave_like "session without status code support"
24
25
  end
25
26
  end
metadata CHANGED
@@ -1,12 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: david-capybara
3
3
  version: !ruby/object:Gem::Version
4
+ hash: 113
4
5
  prerelease: false
5
6
  segments:
6
7
  - 0
7
8
  - 3
8
- - 8
9
- version: 0.3.8
9
+ - 9
10
+ - 1
11
+ version: 0.3.9.1
10
12
  platform: ruby
11
13
  authors:
12
14
  - Jonas Nicklas
@@ -14,16 +16,18 @@ autorequire:
14
16
  bindir: bin
15
17
  cert_chain: []
16
18
 
17
- date: 2010-06-18 00:00:00 +01:00
19
+ date: 2010-07-20 00:00:00 +01:00
18
20
  default_executable:
19
21
  dependencies:
20
22
  - !ruby/object:Gem::Dependency
21
23
  name: nokogiri
22
24
  prerelease: false
23
25
  requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
24
27
  requirements:
25
28
  - - ">="
26
29
  - !ruby/object:Gem::Version
30
+ hash: 29
27
31
  segments:
28
32
  - 1
29
33
  - 3
@@ -35,9 +39,11 @@ dependencies:
35
39
  name: mime-types
36
40
  prerelease: false
37
41
  requirement: &id002 !ruby/object:Gem::Requirement
42
+ none: false
38
43
  requirements:
39
44
  - - ">="
40
45
  - !ruby/object:Gem::Version
46
+ hash: 47
41
47
  segments:
42
48
  - 1
43
49
  - 16
@@ -48,9 +54,11 @@ dependencies:
48
54
  name: culerity
49
55
  prerelease: false
50
56
  requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
51
58
  requirements:
52
59
  - - ">="
53
60
  - !ruby/object:Gem::Version
61
+ hash: 31
54
62
  segments:
55
63
  - 0
56
64
  - 2
@@ -62,9 +70,11 @@ dependencies:
62
70
  name: selenium-webdriver
63
71
  prerelease: false
64
72
  requirement: &id004 !ruby/object:Gem::Requirement
73
+ none: false
65
74
  requirements:
66
75
  - - ">="
67
76
  - !ruby/object:Gem::Version
77
+ hash: 25
68
78
  segments:
69
79
  - 0
70
80
  - 0
@@ -76,9 +86,11 @@ dependencies:
76
86
  name: rack
77
87
  prerelease: false
78
88
  requirement: &id005 !ruby/object:Gem::Requirement
89
+ none: false
79
90
  requirements:
80
91
  - - ">="
81
92
  - !ruby/object:Gem::Version
93
+ hash: 23
82
94
  segments:
83
95
  - 1
84
96
  - 0
@@ -90,23 +102,27 @@ dependencies:
90
102
  name: rack-test
91
103
  prerelease: false
92
104
  requirement: &id006 !ruby/object:Gem::Requirement
105
+ none: false
93
106
  requirements:
94
107
  - - ">="
95
108
  - !ruby/object:Gem::Version
109
+ hash: 3
96
110
  segments:
97
111
  - 0
98
112
  - 5
99
- - 2
100
- version: 0.5.2
113
+ - 4
114
+ version: 0.5.4
101
115
  type: :runtime
102
116
  version_requirements: *id006
103
117
  - !ruby/object:Gem::Dependency
104
118
  name: sinatra
105
119
  prerelease: false
106
120
  requirement: &id007 !ruby/object:Gem::Requirement
121
+ none: false
107
122
  requirements:
108
123
  - - ">="
109
124
  - !ruby/object:Gem::Version
125
+ hash: 51
110
126
  segments:
111
127
  - 0
112
128
  - 9
@@ -118,9 +134,11 @@ dependencies:
118
134
  name: rspec
119
135
  prerelease: false
120
136
  requirement: &id008 !ruby/object:Gem::Requirement
137
+ none: false
121
138
  requirements:
122
139
  - - ">="
123
140
  - !ruby/object:Gem::Version
141
+ hash: 13
124
142
  segments:
125
143
  - 1
126
144
  - 2
@@ -128,6 +146,22 @@ dependencies:
128
146
  version: 1.2.9
129
147
  type: :development
130
148
  version_requirements: *id008
149
+ - !ruby/object:Gem::Dependency
150
+ name: launchy
151
+ prerelease: false
152
+ requirement: &id009 !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ">="
156
+ - !ruby/object:Gem::Version
157
+ hash: 25
158
+ segments:
159
+ - 0
160
+ - 3
161
+ - 5
162
+ version: 0.3.5
163
+ type: :development
164
+ version_requirements: *id009
131
165
  description: Capybara is an integration testing tool for rack based web applications. It simulates how a user would interact with a website
132
166
  email:
133
167
  - jonas.nicklas@gmail.com
@@ -158,6 +192,7 @@ files:
158
192
  - lib/capybara/spec/session/click_button_spec.rb
159
193
  - lib/capybara/spec/session/click_link_spec.rb
160
194
  - lib/capybara/spec/session/all_spec.rb
195
+ - lib/capybara/spec/session/response_code.rb
161
196
  - lib/capybara/spec/session/fill_in_spec.rb
162
197
  - lib/capybara/spec/session/uncheck_spec.rb
163
198
  - lib/capybara/spec/session/find_field_spec.rb
@@ -236,23 +271,27 @@ rdoc_options:
236
271
  require_paths:
237
272
  - lib
238
273
  required_ruby_version: !ruby/object:Gem::Requirement
274
+ none: false
239
275
  requirements:
240
276
  - - ">="
241
277
  - !ruby/object:Gem::Version
278
+ hash: 3
242
279
  segments:
243
280
  - 0
244
281
  version: "0"
245
282
  required_rubygems_version: !ruby/object:Gem::Requirement
283
+ none: false
246
284
  requirements:
247
285
  - - ">="
248
286
  - !ruby/object:Gem::Version
287
+ hash: 3
249
288
  segments:
250
289
  - 0
251
290
  version: "0"
252
291
  requirements: []
253
292
 
254
293
  rubyforge_project: capybara
255
- rubygems_version: 1.3.6
294
+ rubygems_version: 1.3.7
256
295
  signing_key:
257
296
  specification_version: 3
258
297
  summary: Capybara aims to simplify the process of integration testing Rack applications, such as Rails, Sinatra or Merb