capybara 0.1

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 (43) hide show
  1. data/History.txt +4 -0
  2. data/Manifest.txt +42 -0
  3. data/README.rdoc +208 -0
  4. data/Rakefile +33 -0
  5. data/examples/webcat.rb +36 -0
  6. data/lib/capybara.rb +30 -0
  7. data/lib/capybara/core_ext/tcp_socket.rb +26 -0
  8. data/lib/capybara/cucumber.rb +32 -0
  9. data/lib/capybara/driver/culerity_driver.rb +83 -0
  10. data/lib/capybara/driver/firewatir_driver.rb +66 -0
  11. data/lib/capybara/driver/rack_test_driver.rb +151 -0
  12. data/lib/capybara/driver/safariwatir_driver.rb +67 -0
  13. data/lib/capybara/driver/selenium_driver.rb +93 -0
  14. data/lib/capybara/dsl.rb +58 -0
  15. data/lib/capybara/node.rb +36 -0
  16. data/lib/capybara/rails.rb +11 -0
  17. data/lib/capybara/save_and_open_page.rb +25 -0
  18. data/lib/capybara/server.rb +53 -0
  19. data/lib/capybara/session.rb +190 -0
  20. data/script/console +10 -0
  21. data/script/destroy +14 -0
  22. data/script/generate +14 -0
  23. data/spec/driver/culerity_driver_spec.rb +10 -0
  24. data/spec/driver/firewatir_driver_spec.rb +10 -0
  25. data/spec/driver/rack_test_driver_spec.rb +9 -0
  26. data/spec/driver/safariwarit_driver_spec.rb +10 -0
  27. data/spec/driver/selenium_driver_spec.rb +10 -0
  28. data/spec/drivers_spec.rb +72 -0
  29. data/spec/dsl_spec.rb +139 -0
  30. data/spec/fixtures/test_file.txt +1 -0
  31. data/spec/public/jquery.js +19 -0
  32. data/spec/session/culerity_session_spec.rb +23 -0
  33. data/spec/session/rack_test_session_spec.rb +23 -0
  34. data/spec/session/selenium_session_spec.rb +23 -0
  35. data/spec/session_spec.rb +611 -0
  36. data/spec/spec_helper.rb +10 -0
  37. data/spec/test_app.rb +67 -0
  38. data/spec/views/form.erb +117 -0
  39. data/spec/views/with_html.erb +19 -0
  40. data/spec/views/with_js.erb +20 -0
  41. data/spec/views/with_scope.erb +36 -0
  42. data/spec/views/with_simple_html.erb +1 -0
  43. metadata +164 -0
@@ -0,0 +1,4 @@
1
+ === 0.0.1 2009-11-04
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
@@ -0,0 +1,42 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.rdoc
4
+ Rakefile
5
+ examples/webcat.rb
6
+ lib/capybara.rb
7
+ lib/capybara/core_ext/tcp_socket.rb
8
+ lib/capybara/cucumber.rb
9
+ lib/capybara/driver/culerity_driver.rb
10
+ lib/capybara/driver/firewatir_driver.rb
11
+ lib/capybara/driver/rack_test_driver.rb
12
+ lib/capybara/driver/safariwatir_driver.rb
13
+ lib/capybara/driver/selenium_driver.rb
14
+ lib/capybara/dsl.rb
15
+ lib/capybara/node.rb
16
+ lib/capybara/rails.rb
17
+ lib/capybara/save_and_open_page.rb
18
+ lib/capybara/server.rb
19
+ lib/capybara/session.rb
20
+ script/console
21
+ script/destroy
22
+ script/generate
23
+ spec/driver/culerity_driver_spec.rb
24
+ spec/driver/firewatir_driver_spec.rb
25
+ spec/driver/rack_test_driver_spec.rb
26
+ spec/driver/safariwarit_driver_spec.rb
27
+ spec/driver/selenium_driver_spec.rb
28
+ spec/drivers_spec.rb
29
+ spec/dsl_spec.rb
30
+ spec/fixtures/test_file.txt
31
+ spec/public/jquery.js
32
+ spec/session/culerity_session_spec.rb
33
+ spec/session/rack_test_session_spec.rb
34
+ spec/session/selenium_session_spec.rb
35
+ spec/session_spec.rb
36
+ spec/spec_helper.rb
37
+ spec/test_app.rb
38
+ spec/views/form.erb
39
+ spec/views/with_html.erb
40
+ spec/views/with_js.erb
41
+ spec/views/with_scope.erb
42
+ spec/views/with_simple_html.erb
@@ -0,0 +1,208 @@
1
+ = capybara
2
+
3
+ * http://github.com/jnicklas/capybara
4
+
5
+ == Description:
6
+
7
+ Capybara aims to simplify the process of integration testing Rack applications,
8
+ such as Rails, Sinatra or Merb. It is inspired by and aims to replace Webrat as
9
+ a DSL for interacting with a webapplication. It is agnostic about the driver
10
+ running your tests and currently comes bundled with rack-test, Culerity and
11
+ Selenium support built in.
12
+
13
+ == Disclaimer:
14
+
15
+ Capybara is alpha level software, don't use it unless you're prepared to get
16
+ your hands dirty.
17
+
18
+ == Using Capybara with Cucumber
19
+
20
+ Capybara is built to work nicely with Cucumber. The API is very similar to
21
+ Webrat, so if you know Webrat you should feel right at home. Remove any
22
+ references to Webrat from your <tt>env.rb</tt>, if you're using Rails, make sure to set
23
+
24
+ Cucumber::Rails::World.use_transactional_fixtures = false
25
+
26
+ Capybara uses DatabaseCleaner to truncate the database. Require Capybara in your
27
+ env.rb. For Rails do this:
28
+
29
+ require 'capybara/rails'
30
+ require 'capybara/cucumber'
31
+
32
+ For other frameworks, you'll need to set the Rack app manually:
33
+
34
+ require 'capybara/cucumber'
35
+ Capybara.app = MyRackApp
36
+
37
+ Now you can use it in your steps:
38
+
39
+ When /I sign in/ do
40
+ within("//form[@id='session']") do
41
+ fill_in 'Login', :with => 'user@example.com'
42
+ fill_in 'Password', :with => 'password'
43
+ end
44
+ click_link 'Sign in'
45
+ end
46
+
47
+ == Default and current driver
48
+
49
+ You can set up a default driver for your features. For example if you'd prefer
50
+ to run Selenium, you could do:
51
+
52
+ require 'capybara/rails'
53
+ require 'capybara/cucumber'
54
+ Capybara.default_driver = :selenium
55
+
56
+ You can change the driver temporarily:
57
+
58
+ Capybara.current_driver = :culerity
59
+ Capybara.use_default_driver
60
+
61
+ == Cucumber and Tags
62
+
63
+ Capybara sets up some [tags](http://wiki.github.com/aslakhellesoy/cucumber/tags)
64
+ for you to use in Cucumber. Often you'll want to use run only some scenarios
65
+ with a driver that supports JavaScript, Capybara makes this easy: simply tag the
66
+ scenario (or feature) with <tt>@javascript</tt>:
67
+
68
+ @javascript
69
+ Scenario: do something AJAXy
70
+ When I click the AJAX link
71
+ ...
72
+
73
+ You can change which driver Capybara uses for JavaScript:
74
+
75
+ Capybara.javascript_driver = :culerity
76
+
77
+ There are also explicit <tt>@selenium</tt>, <tt>@culerity</tt> and <tt>@rack_test</tt> tags set up
78
+ for you.
79
+
80
+ == The API
81
+
82
+ Navigation:
83
+
84
+ visit – The only way to get to anywhere.
85
+
86
+ Scoping:
87
+
88
+ within – Takes a block which executes in the given scope
89
+
90
+ Interaction:
91
+
92
+ click_link
93
+ click_button
94
+ fill_in – Currently broken with password fields under Culerity
95
+ choose
96
+ check
97
+ uncheck – Currently broken under Culerity
98
+ attach_file
99
+ select
100
+
101
+ Querying:
102
+
103
+ body
104
+ has_xpath? – Checks if given XPath exists, takes text and count options
105
+ has_css? – Checks if given CSS exists, takes text and count options
106
+ has_content? – Checks if the given content is on the page
107
+ find_field
108
+ find_link
109
+ find_button
110
+ field_labeled
111
+
112
+ Debugging:
113
+
114
+ save_and_open_page
115
+
116
+ == Using the DSL outside cucumber
117
+
118
+ You can mix the DSL into any context, for example you could use it in RSpec
119
+ examples. Just load the dsl and include it anywhere:
120
+
121
+ require 'capybara'
122
+ require 'capybara/dsl'
123
+
124
+ include Capybara
125
+ Capybara.default_driver = :culerity
126
+
127
+ within("//form[@id='session']") do
128
+ fill_in 'Login', :with => 'user@example.com'
129
+ fill_in 'Password', :with => 'password'
130
+ end
131
+ click_link 'Sign in'
132
+
133
+ == Using the sessions manually
134
+
135
+ For ultimate control, you can instantiate and use a session manually.
136
+
137
+ require 'capybara'
138
+
139
+ session = Capybara::Session.new(:culerity, my_rack_app)
140
+ session.within("//form[@id='session']") do
141
+ session.fill_in 'Login', :with => 'user@example.com'
142
+ session.fill_in 'Password', :with => 'password'
143
+ end
144
+ session.click_link 'Sign in'
145
+
146
+ == Install:
147
+
148
+ Capybara is hosted on Gemcutter, install it with:
149
+
150
+ sudo gem install capybara
151
+
152
+ == Gotchas:
153
+
154
+ * Everything is *case sensitive*. Capybara heavily relies on XPath, which
155
+ doesn't support case insensitive searches.
156
+
157
+ * The <tt>have_tag</tt> and <tt>have_text</tt> matchers in RSpec-Rails are not
158
+ supported. You should use <tt>page.should have_css('#header p')</tt>,
159
+ <tt>page.should have_xpath('//ul/li')</tt> and <tt>page.should
160
+ have_content('Monkey')</tt> instead.
161
+
162
+ * Unchecking checkboxes and filling in password fields is currently broken under
163
+ Culerity.
164
+
165
+ * Domain names (including subdomains) don't work under rack-test. Since it's a
166
+ pain to set up subdomains for the other drivers anyway, you should consider an
167
+ alternate solution. You might use
168
+ [default_url_options](https://gist.github.com/643a758320a2926bd2ed) in Rails
169
+ for example.
170
+
171
+ * The <tt>set_hidden_field</tt> method from Webrat is not implemented, since it doesn't
172
+ work in any of the browser based drivers (Culerity, Selenium)
173
+
174
+ * Access to session, request and response from the test is not possible. Maybe
175
+ we'll do response headers at some point in the future, but the others really
176
+ shouldn't be touched in an integration test anyway.
177
+
178
+ * Access to Rails specific stuff (such as <tt>controller</tt>) is unavailable,
179
+ since we're not using Rails' integration testing.
180
+
181
+ * <tt><a href="#"></tt> Will cause problems under rack-test, please do
182
+ <tt><a href="/same/url#"></tt> instead. You can achieve this in Rails with
183
+ <tt>link_to('foo', :anchor => '')</tt>
184
+
185
+ == License:
186
+
187
+ (The MIT License)
188
+
189
+ Copyright (c) 2009 Jonas Nicklas
190
+
191
+ Permission is hereby granted, free of charge, to any person obtaining
192
+ a copy of this software and associated documentation files (the
193
+ 'Software'), to deal in the Software without restriction, including
194
+ without limitation the rights to use, copy, modify, merge, publish,
195
+ distribute, sublicense, and/or sell copies of the Software, and to
196
+ permit persons to whom the Software is furnished to do so, subject to
197
+ the following conditions:
198
+
199
+ The above copyright notice and this permission notice shall be
200
+ included in all copies or substantial portions of the Software.
201
+
202
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
203
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
204
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
205
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
206
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
207
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
208
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,33 @@
1
+ require 'rubygems'
2
+ gem 'hoe', '>= 2.1.0'
3
+ require 'hoe'
4
+ require 'fileutils'
5
+ require './lib/capybara'
6
+
7
+ Hoe.plugin :newgem
8
+ # Hoe.plugin :website
9
+ # Hoe.plugin :cucumberfeatures
10
+
11
+ # Generate all the Rake tasks
12
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
13
+ $hoe = Hoe.spec 'capybara' do
14
+ self.developer 'Jonas Nicklas', 'jonas.nicklas@gmail.com'
15
+ self.rubyforge_name = self.name # TODO this is default value
16
+ self.readme_file = 'README.rdoc'
17
+ self.extra_rdoc_files = ['README.rdoc']
18
+
19
+ self.extra_deps = [
20
+ ['nokogiri', '>= 1.3.3'],
21
+ ['culerity', '>= 0.2.3'],
22
+ ['selenium-webdriver', '>= 0.0.3'],
23
+ ['rack', '>= 1.0.0'],
24
+ ['database_cleaner', '>= 0.2.3']
25
+ ]
26
+ end
27
+
28
+ require 'newgem/tasks'
29
+ Dir['tasks/**/*.rake'].each { |t| load t }
30
+
31
+ # TODO - want other tests/tasks run by default? Add them to the list
32
+ # remove_task :default
33
+ # task :default => [:spec, :features]
@@ -0,0 +1,36 @@
1
+ session = Capybara::Session.new('http://localhost:3000')
2
+
3
+ session.visit '/'
4
+
5
+ session.driver.trigger :click, '//div[@id=foo]//a'
6
+ session.driver.trigger :mouseover, '#foo a.bar' # will be ignored by drivers who do not support it
7
+
8
+ nodelist = session.find 'li#foo a'
9
+ nodelist.empty?
10
+ nodelist.first.tag_name # => 'a'
11
+ nodelist.first.text # => 'a cute link'
12
+ nodelist.first.html # => 'a <em>cute</em> link'
13
+ nodelist.first.attributes # => { :href => '/blah' }
14
+ nodelist.first.trigger :click
15
+
16
+ session.request.url # => '/blah'
17
+ session.response.ok? # => true
18
+
19
+ # fancy stuff, just builds on the stuff above!
20
+
21
+ session.click_link 'a cute link'
22
+ session.click_button 'an awesome button'
23
+ session.within '#foo' do
24
+ click_link 'a cute link'
25
+ end
26
+ session.fill_in 'foo', :with => 'bar'
27
+ session.choose 'Monkey'
28
+ session.check 'I am awesome'
29
+ session.wait_for '#fooo"
30
+
31
+ # In cuke:
32
+
33
+ When 'I am awesome' do
34
+ page.check 'I am awesome'
35
+ page.click_button 'FooBar'
36
+ end
@@ -0,0 +1,30 @@
1
+ require 'nokogiri'
2
+
3
+ module Capybara
4
+ VERSION = '0.1'
5
+
6
+ class CapybaraError < StandardError; end
7
+ class DriverNotFoundError < CapybaraError; end
8
+ class ElementNotFound < CapybaraError; end
9
+
10
+ class << self
11
+ attr_accessor :debug, :asset_root
12
+
13
+ def log(message)
14
+ puts "[capybara] #{message}" if debug
15
+ true
16
+ end
17
+ end
18
+
19
+ autoload :Server, 'capybara/server'
20
+ autoload :Session, 'capybara/session'
21
+ autoload :Node, 'capybara/node'
22
+
23
+ module Driver
24
+ autoload :RackTest, 'capybara/driver/rack_test_driver'
25
+ autoload :Culerity, 'capybara/driver/culerity_driver'
26
+ autoload :SafariWatir, 'capybara/driver/safariwatir_driver'
27
+ autoload :FireWatir, 'capybara/driver/firewatir_driver'
28
+ autoload :Selenium, 'capybara/driver/selenium_driver'
29
+ end
30
+ end
@@ -0,0 +1,26 @@
1
+ class TCPSocket
2
+ def self.wait_for_service_with_timeout(options)
3
+ start_time = Time.now
4
+
5
+ until listening_service?(options)
6
+ verbose_wait
7
+
8
+ if options[:timeout] && (Time.now > start_time + options[:timeout])
9
+ raise SocketError.new("Socket did not open within #{options[:timeout]} seconds")
10
+ end
11
+ end
12
+ end
13
+
14
+ def self.wait_for_service_termination_with_timeout(options)
15
+ start_time = Time.now
16
+
17
+ while listening_service?(options)
18
+ verbose_wait
19
+
20
+ if options[:timeout] && (Time.now > start_time + options[:timeout])
21
+ raise SocketError.new("Socket did not terminate within #{options[:timeout]} seconds")
22
+ end
23
+ end
24
+ end
25
+ end
26
+
@@ -0,0 +1,32 @@
1
+ require 'capybara'
2
+ require 'capybara/dsl'
3
+
4
+ World(Capybara)
5
+
6
+ After do
7
+ Capybara.reset_sessions!
8
+ end
9
+
10
+ require 'database_cleaner'
11
+ require 'database_cleaner/cucumber'
12
+ DatabaseCleaner.strategy = :truncation
13
+
14
+ Before('@javascript') do
15
+ Capybara.current_driver = Capybara.javascript_driver
16
+ end
17
+
18
+ Before('@selenium') do
19
+ Capybara.current_driver = :selenium
20
+ end
21
+
22
+ Before('@culerity') do
23
+ Capybara.current_driver = :culerity
24
+ end
25
+
26
+ Before('@rack_test') do
27
+ Capybara.current_driver = :rack_test
28
+ end
29
+
30
+ After do
31
+ Capybara.use_default_driver
32
+ end
@@ -0,0 +1,83 @@
1
+ require 'culerity'
2
+
3
+ class Capybara::Driver::Culerity
4
+ class Node < Capybara::Node
5
+ def text
6
+ node.text
7
+ end
8
+
9
+ def [](name)
10
+ value = if name.to_sym == :class
11
+ node.class_name
12
+ else
13
+ node.send(name.to_sym)
14
+ end
15
+ return value if value and not value.empty?
16
+ end
17
+
18
+ def set(value)
19
+ node.set(value.to_s)
20
+ end
21
+
22
+ def select(option)
23
+ node.select(option)
24
+ end
25
+
26
+ def click
27
+ node.click
28
+ end
29
+
30
+ def tag_name
31
+ # FIXME: this might be the dumbest way ever of getting the tag name
32
+ # there has to be something better...
33
+ node.to_xml[/^\s*<([a-z0-9\-\:]+)/, 1]
34
+ end
35
+ end
36
+
37
+ attr_reader :app, :rack_server
38
+
39
+ def self.server
40
+ unless @_server
41
+ @_server = ::Culerity::run_server
42
+ at_exit do
43
+ @_server.close
44
+ end
45
+ end
46
+ @_server
47
+ end
48
+
49
+ def initialize(app)
50
+ @app = app
51
+ @rack_server = Capybara::Server.new(@app)
52
+ @rack_server.boot
53
+ end
54
+
55
+ def visit(path)
56
+ browser.goto(url(path))
57
+ end
58
+
59
+ def body
60
+ browser.html
61
+ end
62
+
63
+ def find(selector)
64
+ browser.elements_by_xpath(selector).map { |node| Node.new(self, node) }
65
+ end
66
+
67
+ private
68
+
69
+ def url(path)
70
+ rack_server.url(path)
71
+ end
72
+
73
+ def browser
74
+ unless @_browser
75
+ @_browser = ::Culerity::RemoteBrowserProxy.new self.class.server, {:browser => :firefox, :log_level => :off}
76
+ at_exit do
77
+ @_browser.exit
78
+ end
79
+ end
80
+ @_browser
81
+ end
82
+
83
+ end