bbq 0.0.4 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,7 @@
1
1
  script: bundle exec rake test
2
2
  rvm:
3
+ - 1.9.3
3
4
  - 1.9.2
4
5
  - 1.8.7
5
6
  - ree
7
+ - rbx-19mode
data/CHANGELOG CHANGED
@@ -1,12 +1,35 @@
1
- 0.0.3
1
+ 0.1.0 / 2013-01-06
2
+ ==================
2
3
 
3
- * Added support and tests for Sinatra
4
- * Added Bbq.app and Bbq.app=
4
+ * Extracted Rails' URL helpers inclusion to separate module
5
+ * Include only Capybara::Session::DSL_METHODS in TestUser, not the whole Capybara::DSL
6
+ * Added Capybara sessions pool
7
+ * Moved Test::User default options to separate method
8
+ * Added Test::Client for testing REST APIs
9
+ * Renamed bbq/test.rb to bbq/test_unit.rb. You may want to fix your test_helper.
10
+ * Moved require bbq/test_user to generated test_user.rb. You may want to update your existing test_user.rb.
11
+ * Fixed Capybara 'within' scope for RSpec flavour
5
12
 
6
- 0.0.2
13
+ 0.0.4 / 2011-10-19
14
+ ==================
7
15
 
8
- * ...
16
+ * Make bbq work with capybara 1.0 and 1.1
17
+ * rails is development dependency
9
18
 
10
- 0.0.1
19
+ 0.0.3 / 2011-07-14
20
+ ==================
11
21
 
12
- * ...
22
+ * Added support and tests for Sinatra
23
+ * Added Bbq.app and Bbq.app=
24
+
25
+ 0.0.2 / 2011-07-01
26
+ ==================
27
+
28
+ * Extracted Bbq::TestUser::Eyes module
29
+ * Added :within option to TestUser methods
30
+ * Fix tests for ree and ruby187
31
+
32
+ 0.0.1 / 2011-04-20
33
+ ==================
34
+
35
+ * BBQ introduced to the wild world!
data/README.md CHANGED
@@ -3,7 +3,7 @@ Warning & disclaimer
3
3
 
4
4
  This gem is currently under development. We're targeting most popular use cases - Rails & Rack applications (ex. Sinatra). However the philosophy behind it is not limited to Rails nor web applications in general. There is even example usage with EventMachine. Feel free to modify it for your own needs.
5
5
 
6
- [![Build Status](https://secure.travis-ci.org/drugpl/bbq.png)](http://travis-ci.org/drugpl/bbq)
6
+ [![Build Status](https://secure.travis-ci.org/drugpl/bbq.png)](http://travis-ci.org/drugpl/bbq) [![Dependency Status](https://gemnasium.com/drugpl/bbq.png)](https://gemnasium.com/drugpl/bbq)
7
7
 
8
8
  BBQ
9
9
  ===
@@ -42,7 +42,7 @@ First, add BBQ to your apps Gemfile:
42
42
 
43
43
  ```ruby
44
44
  # Gemfile
45
- gem "bbq", "~> 0.0.2"
45
+ gem "bbq", :git => "git://github.com/drugpl/bbq"
46
46
  ```
47
47
 
48
48
  Run install generator:
@@ -54,7 +54,7 @@ rails generate bbq:install
54
54
  Require BBQ in test/test_helper.rb (in case of Test::Unit):
55
55
 
56
56
  ```ruby
57
- require "bbq/test"
57
+ require "bbq/test_unit"
58
58
  ```
59
59
 
60
60
  Require BBQ in spec/spec_helper.rb (in case of RSpec):
@@ -99,9 +99,14 @@ module Roundtrip
99
99
  click_on "Add update"
100
100
  end
101
101
 
102
+ def open_application
103
+ visit '/'
104
+ end
105
+
102
106
  module TicketReporter
103
107
  def open_tickets_listing
104
- visit tickets_path
108
+ open_application
109
+ click_link 'Tickets'
105
110
  end
106
111
 
107
112
  def open_ticket(summary, description)
@@ -119,8 +124,13 @@ module Roundtrip
119
124
  end
120
125
 
121
126
  module TicketManager
127
+ def open_administration
128
+ visit '/admin'
129
+ end
130
+
122
131
  def open_tickets_listing
123
- visit admin_tickets_path
132
+ open_administration
133
+ click_link 'Tickets'
124
134
  end
125
135
 
126
136
  def close_ticket(summary, comment = nil)
@@ -174,6 +184,67 @@ class AdminTicketsTest < Bbq::TestCase
174
184
  end
175
185
  ```
176
186
 
187
+ Testing REST APIs
188
+ ================
189
+
190
+ Bbq provides `Bbq::TestClient`, similar to `Bbq::TestUser`, but intended for testing APIs.
191
+ It's a thin wrapper around `Rack::Test` which allows you to send requests and run assertions
192
+ against responses.
193
+
194
+ ```ruby
195
+ class ApiTest < Bbq::TestCase
196
+ background do
197
+ headers = {'HTTP_ACCEPT' => 'application/json'}
198
+ @client = TestClient.new(:headers => headers)
199
+ end
200
+
201
+ scenario "admin can browse all user tickets" do
202
+ @client.get "/unicorn" do |response|
203
+ assert_equal 200, response.status
204
+ assert_equal "pink", response.body["unicorn"]["color"]
205
+ end
206
+ @client.post "/ponies", { :name => "Miracle" } do |response|
207
+ assert_equal 200, response.status
208
+ end
209
+ end
210
+ end
211
+ ```
212
+
213
+ Rails' URL Helpers
214
+ ================
215
+
216
+ Using url helpers from Rails in integration tests is not recommended.
217
+ Testing routes is part of integration test, so you should actually use only
218
+
219
+ ```ruby
220
+ visit '/'
221
+ ```
222
+
223
+ in your integration test. Use links and buttons in order to get to other pages in your app.
224
+
225
+ If you really need url helpers in your test user, just include them in your TestUser class:
226
+
227
+ ```ruby
228
+ require 'bbq/rails/routes'
229
+
230
+ module Roundtrip
231
+ class TestUser < Bbq::TestUser
232
+ include Bbq::Rails::Routes
233
+ end
234
+ end
235
+ ```
236
+ or just
237
+
238
+ ```ruby
239
+ module Roundtrip
240
+ class TestUser < Bbq::TestUser
241
+ include ::ActionDispatch::Routing::UrlFor
242
+ include ::Rails.application.routes.url_helpers
243
+ include ::ActionDispatch::Routing::RouteSet::MountedHelpers unless ::Rails.version < "3.1"
244
+ end
245
+ end
246
+ ```
247
+
177
248
  Deal with Devise
178
249
  ================
179
250
 
@@ -202,28 +273,18 @@ Caveats
202
273
  <h2>Timeout::Error</h2>
203
274
 
204
275
  If you simulate multiple users in your tests and spawn multiple browsers with selenium it might
205
- be a good idea to use `Mongrel` instead of `Webrick` to create application server.
206
- We have experienced some problems with `Webrick` that lead to `Timeout::Error` exception
276
+ be a good idea to use Thin instead of Webrick to create application server.
277
+ We have experienced some problems with Webrick that lead to `Timeout::Error` exception
207
278
  when user/browser that was inactive for some time (due to other users/browsers
208
279
  activities) was requested to execute an action.
209
280
 
210
- Put this code into a file loaded before running any acceptance scenario like:
211
- `test/test_helper.rb` or `spec/spec_helper.rb`:
212
-
213
- ```ruby
214
- Capybara.server do |app, port|
215
- require 'rack/handler/mongrel'
216
- Rack::Handler::Mongrel.run(app, :Port => port)
217
- end
218
- ```
219
-
220
- Add `mongrel` to your `Gemfile`:
281
+ Capybara will use Thin instead of Webrick when it's available, so you only need to add Thin to you Gemfile:
221
282
 
222
283
  ```ruby
223
284
  # In test group if you want it to
224
285
  # be used only in tests and not in your development mode
225
286
  # ex. when running 'rails s'
226
- gem 'mongrel', "1.2.0.pre2", :require => false
287
+ gem 'thin', :require => false
227
288
  ```
228
289
 
229
290
  Development environment
@@ -20,6 +20,7 @@ Gem::Specification.new do |s|
20
20
  s.require_paths = ["lib"]
21
21
 
22
22
  s.add_dependency "capybara", "~> 1.0"
23
+ s.add_dependency "activesupport", ">= 2.0"
23
24
 
24
25
  s.add_development_dependency "sqlite3", "~> 1.3.3"
25
26
  s.add_development_dependency "rake", "~> 0.8.7"
data/lib/bbq.rb CHANGED
@@ -1,21 +1,17 @@
1
1
  require 'pathname'
2
2
 
3
3
  module Bbq
4
- def self.root
5
- @root ||= Pathname.new(File.expand_path(File.join(File.dirname(__FILE__), '..')))
6
- end
7
-
8
- def self.rails?
9
- defined?(::Rails)
10
- end
4
+ class << self
5
+ def root
6
+ @root ||= Pathname.new(File.expand_path(File.join(File.dirname(__FILE__), '..')))
7
+ end
11
8
 
12
- def self.app
13
- Capybara.app
14
- end
9
+ def rails?
10
+ defined?(::Rails)
11
+ end
15
12
 
16
- def self.app=(new_app)
17
- Capybara.app=(new_app)
13
+ attr_accessor :app
18
14
  end
19
15
  end
20
16
 
21
- require 'bbq/railtie' if Bbq.rails?
17
+ require 'bbq/railtie' if Bbq.rails?
@@ -5,6 +5,11 @@ if defined?(Devise)
5
5
  module Devise
6
6
  attr_accessor :devise_authentication_key, :email, :password, :scope
7
7
 
8
+ def self.included(klass)
9
+ require 'bbq/rails/routes'
10
+ klass.send(:include, Bbq::Rails::Routes)
11
+ end
12
+
8
13
  def initialize_devise
9
14
  @devise_initialized ||= begin
10
15
  self.devise_authentication_key = ::Devise.authentication_keys.first
@@ -0,0 +1,13 @@
1
+ module Bbq
2
+ module Rails
3
+ module Routes
4
+ def self.included(klass)
5
+ klass.send(:include, ::ActionDispatch::Routing::UrlFor)
6
+ klass.send(:include, ::Rails.application.routes.url_helpers)
7
+ unless ::Rails.version < "3.1"
8
+ klass.send(:include, ::ActionDispatch::Routing::RouteSet::MountedHelpers)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -2,6 +2,10 @@ require 'rails/generators'
2
2
 
3
3
  module Bbq
4
4
  class Railtie < Rails::Railtie
5
+ initializer "bqq.set_app" do
6
+ Bbq.app = Rails.application
7
+ end
8
+
5
9
  rake_tasks do
6
10
  load Bbq.root.join("lib/tasks/bbq.rake")
7
11
  end
@@ -0,0 +1,12 @@
1
+ require 'bbq/util'
2
+
3
+ module Bbq
4
+ module Roles
5
+ def roles(*names)
6
+ names.each do |name|
7
+ module_obj = Bbq::Util.find_module(name, self)
8
+ self.extend(module_obj)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -1,5 +1,6 @@
1
+ require 'bbq'
2
+ require 'bbq/session'
1
3
  require 'rspec/core'
2
- require 'bbq/test_user'
3
4
  require 'capybara/rspec/matchers'
4
5
 
5
6
  module Bbq
@@ -13,45 +14,51 @@ module Bbq
13
14
  end
14
15
 
15
16
  module RSpecMatchers
16
- class TestUserEyes
17
- def initialize(negative, *args)
18
- @args, @negative = args, negative
19
- end
20
-
21
- def matches?(actual)
22
- @negative ? actual.not_see?(*@args) : actual.see?(*@args)
23
- end
17
+ extend RSpec::Matchers::DSL
24
18
 
25
- def failure_message_for_should
26
- "expected to #{@negative ? negative_description : positive_description}"
19
+ matcher :see do |text|
20
+ chain :within do |locator|
21
+ @locator = locator
27
22
  end
28
23
 
29
- def failure_message_for_should_not
30
- "expected to #{@negative ? positive_description : negative_description}"
24
+ match_for_should do |page|
25
+ if @locator
26
+ page.within(@locator) do
27
+ page.see? text
28
+ end
29
+ else
30
+ page.see? text
31
+ end
31
32
  end
32
33
 
33
- def description
34
- @negative ? negative_description : positive_description
34
+ match_for_should_not do |page|
35
+ if @locator
36
+ page.within(@locator) do
37
+ page.not_see? text
38
+ end
39
+ else
40
+ page.not_see? text
41
+ end
35
42
  end
36
43
 
37
- protected
38
-
39
- def negative_description
40
- "not see any of the following: #{@args.join(', ')}"
44
+ failure_message_for_should do |page|
45
+ body = if @locator
46
+ page.find(@locator).text
47
+ else
48
+ page.body
49
+ end
50
+ "expected to see #{text} in #{body}"
41
51
  end
42
52
 
43
- def positive_description
44
- "see all of the following: #{@args.join(', ')}"
53
+ failure_message_for_should_not do |page|
54
+ body = if @locator
55
+ page.find(@locator).text
56
+ else
57
+ page.body
58
+ end
59
+ "expected not to see #{text} in #{body}"
45
60
  end
46
61
  end
47
-
48
- def see(*args)
49
- TestUserEyes.new(false, *args)
50
- end
51
-
52
- def not_see(*args)
53
- TestUserEyes.new(true, *args)
54
- end
55
62
  end
56
63
 
57
64
  class TestUser
@@ -60,15 +67,11 @@ module Bbq
60
67
  include Bbq::RSpecMatchers
61
68
 
62
69
  def see!(*args)
63
- args.each do |arg|
64
- page.should have_content(arg)
65
- end
70
+ see?(*args).should be_true
66
71
  end
67
72
 
68
73
  def not_see!(*args)
69
- args.each do |arg|
70
- page.should have_no_content(arg)
71
- end
74
+ not_see?(*args).should be_true
72
75
  end
73
76
  end
74
77
  end
@@ -87,4 +90,8 @@ RSpec.configuration.include Bbq::RSpecFeature, :type => :acceptance
87
90
  RSpec.configure do |config|
88
91
  config.include Capybara::RSpecMatchers, :type => :acceptance
89
92
  config.include Bbq::RSpecMatchers, :type => :acceptance
93
+
94
+ config.after :each, :type => :acceptance do
95
+ Bbq::Session.pool.release
96
+ end
90
97
  end
@@ -0,0 +1,60 @@
1
+ module Bbq
2
+ module Session
3
+ extend self
4
+
5
+ def next(options = {})
6
+ driver = options.delete(:driver)
7
+ pool = options.delete(:pool)
8
+
9
+ if pool
10
+ pool.next(driver)
11
+ else
12
+ create(driver)
13
+ end
14
+ end
15
+
16
+ def create(driver)
17
+ Capybara::Session.new(driver, Bbq.app)
18
+ end
19
+
20
+ def pool
21
+ @pool ||= Pool.new
22
+ end
23
+
24
+ class Pool
25
+ attr_accessor :idle, :taken
26
+
27
+ def initialize
28
+ @idle = []
29
+ @taken = []
30
+ end
31
+
32
+ def next(driver)
33
+ take_idle(driver) || create(driver)
34
+ end
35
+
36
+ def release
37
+ taken.each(&:reset!)
38
+ idle.concat(taken)
39
+ taken.clear
40
+ end
41
+
42
+ private
43
+
44
+ def take_idle(driver)
45
+ idle.find { |s| s.mode == driver }.tap do |session|
46
+ if session
47
+ idle.delete(session)
48
+ taken.push(session)
49
+ end
50
+ end
51
+ end
52
+
53
+ def create(driver)
54
+ Bbq::Session.create(driver).tap do |session|
55
+ taken.push(session)
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end