remi-rackbox 1.1.0 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2009 ryan "remi" Taylor
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,88 @@
1
+ = RackBox
2
+
3
+ RackBox adds Merb-style blackbox testing]blackbox] to Rack apps (including Rails)
4
+
5
+ This currently only works with RSpec.
6
+
7
+ == Screencast
8
+
9
+ Watch the Screencast[http://remi.org/2009/01/29/introducing-rackbox_merb-esque-blackbox-testing-for-rack-and-rails-apps.html]
10
+
11
+ == Installation
12
+
13
+ $ sudo gem install remi-rackbox -s http://gems.github.com
14
+
15
+ NOTE: right now, RackBox requires thin. Soon, I'll likely remove thin as
16
+ a dependency and will only require rack.
17
+
18
+ == Rails (fast!)
19
+
20
+ $ sudo gem install rspec rspec-rails thin
21
+ $ sudo gem install remi-rackbox -s http://gems.github.com
22
+
23
+ $ rails new_app
24
+ $ cd new_app
25
+ $ ./script/generate rspec
26
+ $ ./script/generate blackbox_spec Home Page
27
+
28
+ $ rake spec
29
+
30
+
31
+ == Rails (manual)
32
+
33
+ To write RackBox tests in Rails apps, make a `blackbox` directory under your `spec` directory
34
+ and add this to the Spec configure block in your `spec_helper.rb` file:
35
+
36
+ config.use_blackbox = true
37
+
38
+ Also, add `require 'rackbox'` to the top of your `spec_helper.rb`
39
+
40
+ You can see a working example of blackbox testing a Rails application here: examples/rails](http://github.com/remi/rackbox/tree/master/examples/rails)
41
+
42
+ == Rack
43
+
44
+ To write RackBox tests in Rack apps, I'm currently assuming that you have a `config.ru` rackup file.
45
+ If so, your app should load, otherwise you can explicitly configure RackBox to read your Rack app:
46
+
47
+ RackBox.app = your Rack app]
48
+
49
+ Basides that, the configuration is the same as Rails. Make a `blackbox` directory under your
50
+ `spec` directory and add this to the Spec configure block in your `spec_helper.rb` file:
51
+
52
+ config.use_blackbox = true
53
+
54
+ Also, add `require 'rackbox'` to the top of your `spec_helper.rb`
55
+
56
+ You can see a working example of blackbox testing a Rack application here: examples/rack](http://github.com/remi/rackbox/tree/master/examples/rack)
57
+
58
+ NOTE: If you want to be able to use nice RSpec matchers like `request('/').should have_tag('p')` in your
59
+ blackbox specs in your Rack apps, you should `sudo gem install webrat` and RackBox will include
60
+ Webrat's helpers in your specs.
61
+
62
+ == Usage
63
+
64
+ Ideally, the usage of RackBox should be identical to Merb-style blackbox testing. I need to find good documentation
65
+ on how things work in Merb so I can duplicate any functionality I'm missing. For now, it's really simple!
66
+
67
+ describe Foo do
68
+
69
+ it 'should have foxes on the home page' do
70
+ request('/').body.should include('Foxes')
71
+ end
72
+
73
+ it 'should let me know that I was logged in' do
74
+ response = request(login_path, :method => :post, :params => { 'user' => 'bob', :password => 'secret' })
75
+ response.body.should include('Welcome bob, you were successfully logged in!')
76
+ end
77
+
78
+ end
79
+
80
+ `request` gives you a `Rack::Response`](http://rack.rubyforge.org/doc/classes/Rack/Response.html) which has
81
+ `body`, `headers`, `status` methods (and more](http://rack.rubyforge.org/doc/classes/Rack/Response.html))
82
+
83
+ == TODO
84
+
85
+ * request('/', :data => 'some XML or something')
86
+ * request('/', :format => :json) # simple helpers for content type request accepts
87
+ * request('/', 'Content-Length' => 'x') # anything passed in that we don't handle, throw into the request ENV ... but :content_length should work too?
88
+ * get usage documentation working for `./script/generate blackbox_spec`
@@ -1,17 +1,39 @@
1
1
  RackBox
2
2
  =======
3
3
 
4
- [RackBox][] adds [Merb][]-style blackbox testing to [Rack][] apps (including [Rails][])
4
+ [RackBox][] adds [Merb][]-style [blackbox testing][blackbox] to [Rack][] apps (including [Rails][])
5
5
 
6
6
  This currently only works with [RSpec][].
7
7
 
8
+ Screencast
9
+ ----------
10
+
11
+ [Watch the 'Screencast'][screencast]
12
+
8
13
  Installation
9
14
  ------------
10
15
 
11
16
  $ sudo gem install remi-rackbox -s http://gems.github.com
12
17
 
13
- Rails
14
- -----
18
+ NOTE: right now, [RackBox][] requires [thin][]. Soon, I'll likely remove [thin][] as
19
+ a dependency and will only require [rack][].
20
+
21
+ Rails (fast!)
22
+ -------------
23
+
24
+ $ sudo gem install rspec rspec-rails thin
25
+ $ sudo gem install remi-rackbox -s http://gems.github.com
26
+
27
+ $ rails new_app
28
+ $ cd new_app
29
+ $ ./script/generate rspec
30
+ $ ./script/generate blackbox_spec Home Page
31
+
32
+ $ rake spec
33
+
34
+
35
+ Rails (manual)
36
+ --------------
15
37
 
16
38
  To write [RackBox][] tests in [Rails][] apps, make a `blackbox` directory under your `spec` directory
17
39
  and add this to the Spec configure block in your `spec_helper.rb` file:
@@ -39,6 +61,10 @@ Also, add `require 'rackbox'` to the top of your `spec_helper.rb`
39
61
 
40
62
  You can see a working example of blackbox testing a [Rack][] application here: [examples/rack](http://github.com/remi/rackbox/tree/master/examples/rack)
41
63
 
64
+ NOTE: If you want to be able to use nice RSpec matchers like `request('/').should have_tag('p')` in your
65
+ blackbox specs in your [Rack][] apps, you should `sudo gem install webrat` and [RackBox][] will include
66
+ [Webrat][]'s helpers in your specs.
67
+
42
68
  Usage
43
69
  -----
44
70
 
@@ -64,13 +90,19 @@ on how things work in [Merb][] so I can duplicate any functionality I'm missing.
64
90
  TODO
65
91
  ----
66
92
 
67
- Before I make a screencast and post it to my blog, I wanna finish these ...
93
+ - request('/', :format => :json) # simple helpers for content type request accepts
94
+ - get usage documentation working for `./script/generate blackbox_spec`
68
95
 
69
- - add a rails generator so you can install the gem and then ./script/generate blackbox\_spec
70
96
 
71
97
 
72
- [rackbox]: http://github.com/remi/rackbox
73
- [merb]: http://merbivore.com
74
- [rack]: http://rack.rubyforge.org
75
- [rails]: http://rubyonrails.org
76
- [rspec]: http://rspec.info
98
+ [rackbox]: http://github.com/remi/rackbox
99
+ [merb]: http://merbivore.com
100
+ [rack]: http://rack.rubyforge.org
101
+ [rails]: http://rubyonrails.org
102
+ [rspec]: http://rspec.info
103
+ [webrat]: http://github.com/brynary/webrat
104
+ [thin]: http://code.macournoyer.com/thin
105
+ [screencast]: http://remi.org/2009/01/29/introducing-rackbox_merb-esque-blackbox-testing-for-rack-and-rails-apps.html
106
+ [rubygem]: http://www.rubygems.org
107
+ [blackbox]: http://en.wikipedia.org/wiki/Black_box_testing
108
+ [sinatra]: http://sinatra.github.com
data/Rakefile CHANGED
@@ -34,7 +34,7 @@ Rake::RDocTask.new do |rdoc|
34
34
  rdoc.rdoc_dir = 'rdoc'
35
35
  rdoc.title = 'rackbox'
36
36
  rdoc.options << '--line-numbers' << '--inline-source'
37
- rdoc.rdoc_files.include('README*')
37
+ rdoc.rdoc_files.include('RDOC_README.rdoc')
38
38
  rdoc.rdoc_files.include('lib/**/*.rb')
39
39
  end
40
40
 
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :major: 1
3
3
  :minor: 1
4
- :patch: 0
4
+ :patch: 1
@@ -14,6 +14,7 @@ require 'rackbox/rack/sticky_sessions'
14
14
  require 'rackbox/rack/extensions_for_rspec'
15
15
 
16
16
  require 'rackbox/rackbox'
17
+ require 'rackbox/app'
17
18
 
18
19
  require 'rspec/custom_matcher'
19
20
  require 'rackbox/matchers'
@@ -0,0 +1,30 @@
1
+ class RackBox
2
+
3
+ # represents a rack appliction
4
+ #
5
+ # gives us some helpers on a rack app
6
+ # like the ability to use the #request
7
+ # method on it easily
8
+ #
9
+ class App
10
+ attr_accessor :rack_app, :mock_request
11
+
12
+ def initialize rack_app
13
+ @rack_app = rack_app
14
+ reset_request
15
+ end
16
+
17
+ def reset_request
18
+ @mock_request = Rack::MockRequest.new @rack_app
19
+ end
20
+ alias reset reset_request
21
+
22
+ # sessions are sticky!
23
+ #
24
+ # to reset, @rackbox_app.reset
25
+ def request url, options = {}
26
+ RackBox.request @mock_request, url, options
27
+ end
28
+ end
29
+
30
+ end
@@ -1,24 +1,30 @@
1
- # Custom RSpec matchers
2
- module RackBox::Matchers
3
- def self.included base
4
-
5
- # this should really just be matcher(:foo){ ... }
6
- # but there's a bit of other meta logic to deal with here
7
- Object.send :remove_const, :RedirectTo if defined? RedirectTo
8
- undef redirect_to if defined? redirect_to
1
+ class RackBox
9
2
 
10
- # the actual matcher logic
11
- matcher(:redirect_to, base) do |response, url|
12
- return false unless response['Location']
13
- if url =~ /^\//
14
- # looking for a relative match, eg. should redirect_to('/login')
15
- relative_location = response['Location'].sub(/^https?:\/\//,'').sub(/^[^\/]*/,'')
16
- # ^ there's probably a helper on Rack or CGI to do this
17
- relative_location.downcase == url.downcase
18
- else
19
- response['Location'].downcase == url.downcase
3
+ # Custom RSpec matchers
4
+ module Matchers
5
+
6
+ def self.included base
7
+
8
+ # this should really just be matcher(:foo){ ... }
9
+ # but there's a bit of other meta logic to deal with here
10
+ Object.send :remove_const, :RedirectTo if defined? RedirectTo
11
+ undef redirect_to if defined? redirect_to
12
+
13
+ # the actual matcher logic
14
+ matcher(:redirect_to, base) do |response, url|
15
+ return false unless response['Location']
16
+ if url =~ /^\//
17
+ # looking for a relative match, eg. should redirect_to('/login')
18
+ relative_location = response['Location'].sub(/^https?:\/\//,'').sub(/^[^\/]*/,'')
19
+ # ^ there's probably a helper on Rack or CGI to do this
20
+ relative_location.downcase == url.downcase
21
+ else
22
+ response['Location'].downcase == url.downcase
23
+ end
20
24
  end
25
+
21
26
  end
22
27
 
23
28
  end
29
+
24
30
  end
@@ -1,3 +1,4 @@
1
+
1
2
  # To add blackbox testing to a Rails app,
2
3
  # in your spec_helper.rb
3
4
  #
@@ -8,7 +9,76 @@
8
9
  # end
9
10
  #
10
11
  class RackBox
12
+
13
+ # i am an rdoc comment on RackBox's eigenclass
11
14
  class << self
15
+
16
+ # to turn on some verbosity / logging, set:
17
+ # RackBox.verbose = true
18
+ attr_accessor :verbose
19
+
20
+ # A port of Merb's request() method, used in tests
21
+ #
22
+ # At the moment, we're using #req instead because #request conflicts
23
+ # with an existing RSpec-Rails method
24
+ #
25
+ # Usage:
26
+ #
27
+ # req '/'
28
+ # req login_path
29
+ # req url_for(:controller => 'login')
30
+ #
31
+ # req '/', :method => :post, :params => { 'chunky' => 'bacon' }
32
+ #
33
+ # req '/', :data => "some XML data to POST"
34
+ #
35
+ # TODO take any additional options and pass them along to the environment, so we can say
36
+ # req '/', :user_agent => 'some custom user agent'
37
+ #
38
+ def req app_or_request, url, options = {}
39
+ puts "RackBox#request url:#{ url.inspect }, options:#{ options.inspect }" if RackBox.verbose
40
+
41
+ # need to find the request or app
42
+ mock_request = nil
43
+ if app_or_request.is_a? Rack::MockRequest
44
+ mock_request = app_or_request
45
+ elsif app_or_request.nil?
46
+ if RackBox.app.nil?
47
+ raise "Not sure howto to execute a request against app or request: #{ app_or_request.inspect }"
48
+ else
49
+ mock_request = Rack::MockRequest.new(RackBox.app) # default to RackBox.app if nil
50
+ end
51
+ elsif app_or_request.respond_to? :call
52
+ mock_request = Rack::MockRequest.new(app_or_request)
53
+ else
54
+ raise "Not sure howto to execute a request against app or request: #{ app_or_request.inspect }"
55
+ end
56
+
57
+ options[:method] ||= ( options[:params] || options[:data] ) ? :post : :get # if params, default to POST, else default to GET
58
+ options[:params] ||= { }
59
+
60
+ if options[:data]
61
+ # input should be the data we're likely POSTing ... this overrides any params
62
+ input = options[:data]
63
+ else
64
+ # input should be params, if any
65
+ input = RackBox.build_query options[:params]
66
+ end
67
+
68
+ headers = options.dup
69
+ headers.delete :data if headers[:data]
70
+ headers.delete :params if headers[:params]
71
+ headers.delete :method if headers[:method]
72
+
73
+ # merge input
74
+ headers[:input] = input
75
+
76
+ puts " requesting #{ options[:method].to_s.upcase } #{ url.inspect } #{ headers.inspect }" if RackBox.verbose
77
+ mock_request.send options[:method], url, headers
78
+ end
79
+
80
+ alias request req unless defined? request
81
+
12
82
  # the Rack appliction to do 'Black Box' testing against
13
83
  #
14
84
  # To set, in your spec_helper.rb or someplace:
@@ -1,34 +1,23 @@
1
- # Helper methods to include in specs that want to use blackbox testing
2
- #
3
- # This module has the RackBox::SpecHelpers#request method, which is
4
- # the main method used by RackBox blackbox tests
5
- #
6
- module RackBox::SpecHelpers
1
+ class RackBox
7
2
 
8
- # A port of Merb's request() method, used in tests
3
+ # Helper methods to include in specs that want to use blackbox testing
9
4
  #
10
- # At the moment, we're using #req instead because #request conflicts
11
- # with an existing RSpec-Rails method
5
+ # TODO For backwards compatibility, I would like to keep a SpecHelpers
6
+ # module, but this needs to be renamed because this isn't spec
7
+ # specific at all! it needs to be easy to RackBox::App.new(rack_app).request
8
+ # or something like that (something generic)
12
9
  #
13
- # Usage:
14
- #
15
- # req '/'
16
- # req login_path
17
- # req url_for(:controller => 'login')
10
+ # This module has the RackBox::SpecHelpers#request method, which is
11
+ # the main method used by RackBox blackbox tests
18
12
  #
19
- # req '/', :method => :post, :params => { 'chunky' => 'bacon' }
20
- #
21
- # TODO support inner hashes, so { :foo => { :chunky => :bacon } } becomes 'foo[chunky]=bacon'
22
- #
23
- # TODO take any additional options and pass them along to the environment, so we can say
24
- # req '/', :user_agent => 'some custom user agent'
25
- #
26
- def req url, options = {}
27
- options[:method] ||= (options[:params]) ? :post : :get # if params, default to POST, else default to GET
28
- options[:params] ||= { }
29
- @rackbox_request.send options[:method], url, :input => RackBox.build_query(options[:params])
30
- end
13
+ module SpecHelpers
14
+
15
+ # moved logic into RackBox#request, where it can easily be re-used
16
+ def req url, options = {}
17
+ RackBox.request @rackbox_request, url, options
18
+ end
31
19
 
32
- alias request req unless defined? request
20
+ alias request req unless defined? request
33
21
 
22
+ end
34
23
  end
@@ -0,0 +1,14 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe RackBox, 'custom request headers' do
4
+
5
+ before do
6
+ @rack_app = lambda {|env| [ 200, { }, env.inspect ] }
7
+ end
8
+
9
+ it "#request should take any non-special options and assume they're request headers" do
10
+ RackBox.request(@rack_app, '/').body.should_not include('"HTTP_ACCEPT"=>"application/json"')
11
+ RackBox.request(@rack_app, '/', 'HTTP_ACCEPT' => 'application/json').body.should include('"HTTP_ACCEPT"=>"application/json"')
12
+ end
13
+
14
+ end
@@ -0,0 +1,33 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe RackBox, 'POSTing data' do
4
+
5
+ before do
6
+ @rack_app1 = lambda {|env| [ 200, { }, "you POSTed data: #{ env['rack.input'].read }" ] }
7
+ @rack_app2 = lambda {|env|
8
+ req = Rack::Request.new env
9
+ [ 200, { }, "you POSTed data: #{ req.body.read }" ]
10
+ }
11
+ @method_app = lambda {|env| [ 200, { }, "method: #{ env['REQUEST_METHOD'] }" ] }
12
+ end
13
+
14
+ it 'should make it easy to POST data, eg. curl -D "XML"' do
15
+ RackBox.request(@rack_app1, '/', :data => 'hi there').body.should include('you POSTed data: hi there')
16
+ RackBox.request(@rack_app2, '/', :data => 'hi there').body.should include('you POSTed data: hi there')
17
+ end
18
+
19
+ it "should default to POST if method isn't explicitly set and we set :data" do
20
+ RackBox.request(@method_app, '/').body.should include('method: GET')
21
+ RackBox.request(@method_app, '/', :method => :put).body.should include('method: PUT')
22
+ RackBox.request(@method_app, '/', :data => 'hi').body.should include('method: POST')
23
+ RackBox.request(@method_app, '/', :data => 'hi', :method => :put).body.should include('method: PUT')
24
+ end
25
+
26
+ it "should default to POST if method isn't explicitly set and we set :params" do
27
+ RackBox.request(@method_app, '/').body.should include('method: GET')
28
+ RackBox.request(@method_app, '/', :method => :put).body.should include('method: PUT')
29
+ RackBox.request(@method_app, '/', :params => { :x => 5 }).body.should include('method: POST')
30
+ RackBox.request(@method_app, '/', :params => { :x => 5 }, :method => :put).body.should include('method: PUT')
31
+ end
32
+
33
+ end
@@ -0,0 +1,17 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe RackBox, '#request' do
4
+
5
+ before do
6
+ @rack_app = lambda {|env| [ 200, { }, "you requested path #{ env['PATH_INFO'] }" ] }
7
+ end
8
+
9
+ it 'should be easy to run the #request method against any Rack app' do
10
+ RackBox::App.new(@rack_app).request('/hello').body.should include('you requested path /hello')
11
+ end
12
+
13
+ it 'should be even easier to run the #request method against any Rack app' do
14
+ RackBox.request(@rack_app, '/hello').body.should include('you requested path /hello')
15
+ end
16
+
17
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: remi-rackbox
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - remi
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-01-29 00:00:00 -08:00
12
+ date: 2009-02-09 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -25,6 +25,8 @@ files:
25
25
  - Rakefile
26
26
  - VERSION.yml
27
27
  - README.markdown
28
+ - LICENSE
29
+ - RDOC_README.rdoc
28
30
  - lib/rackbox.rb
29
31
  - lib/rspec
30
32
  - lib/rspec/custom_matcher.rb
@@ -36,9 +38,13 @@ files:
36
38
  - lib/rackbox/spec
37
39
  - lib/rackbox/spec/configuration.rb
38
40
  - lib/rackbox/spec/helpers.rb
41
+ - lib/rackbox/app.rb
39
42
  - lib/rackbox/rackbox.rb
40
43
  - lib/rackbox/matchers.rb
41
- - spec/rackbox_spec.rb
44
+ - spec/request_method_spec.rb
45
+ - spec/posting_data_spec.rb
46
+ - spec/rackbox_build_query_spec.rb
47
+ - spec/custom_request_header_specs.rb
42
48
  - spec/spec_helper.rb
43
49
  - examples/sinatra
44
50
  - examples/sinatra/run-specs