Class: RackBox

Inherits:
Object
  • Object
show all
Defined in:
lib/rackbox/rackbox.rb,
lib/rackbox/app.rb,
lib/rackbox/matchers.rb,
lib/rackbox/spec/helpers.rb

Overview

To add blackbox testing to a Rails app, in your spec_helper.rb

require 'rackbox'

Spec::Runner.configure do |config|
  config.use_blackbox = true
end

Defined Under Namespace

Modules: Matchers, SpecHelpers Classes: App, Bin

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.app(options = { }) ⇒ Object

the Rack appliction to do ‘Black Box’ testing against

To set, in your spec_helper.rb or someplace:

RackBox.app = Rack::Adapter::Rails.new :root => '/root/directory/of/rails/app', :environment => 'test'

If not explicitly set, uses RAILS_ROOT (if defined?) and RAILS_ENV (if defined?)



116
117
118
# File 'lib/rackbox/rackbox.rb', line 116

def app
  @app
end

.verboseObject

to turn on some verbosity / logging, set:

RackBox.verbose = true


18
19
20
# File 'lib/rackbox/rackbox.rb', line 18

def verbose
  @verbose
end

Class Method Details

.build_query(params_hash = { }) ⇒ Object

helper method for taking a Hash of params and turning them into POST params

>> RackBox.build_query :hello => ‘there’

> ‘hello=there’

>> RackBox.build_query :hello => ‘there’, :foo => ‘bar’

> ‘hello=there&foo=bar’

>> RackBox.build_query :user => { :name => ‘bob’, :password => ‘secret’ }

> ‘user=bob&user=secret’



165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/rackbox/rackbox.rb', line 165

def build_query params_hash = { }
  # check to make sure no values are Hashes ...
  # if they are, we need to flatten them!
  params_hash.each do |key, value|
    # params_hash  :a => { :b => X, :c => Y }
    # needs to be  'a[b]' => X, 'a[b]' => Y
    if value.is_a? Hash
      inner_hash = params_hash.delete key # { :b => X, :c => Y }
      inner_hash.each do |subkey, subvalue|
        new_key = "#{ key }[#{ subkey }]" # a[b] or a[c]
        puts "warning: overwriting query parameter #{ new_key }" if params_hash[new_key]
        params_hash[new_key] = subvalue # 'a[b]' => X or a[c] => Y
      end
      # we really shouldn't keep going thru the #each now that we've altered data!
      return build_query(params_hash)
    end
  end
  Rack::Utils.build_query params_hash
end

.req(app_or_request, url = nil, options = {}) ⇒ Object

A port of Merb’s request() method, used in tests

At the moment, we’re using #req instead because #request conflicts with an existing RSpec-Rails method

Usage:

req '/'
req 
req url_for(:controller => 'login')

req '/', :method => :post, :params => { 'chunky' => 'bacon' }

req '/', :data => "some XML data to POST"

TODO take any additional options and pass them along to the environment, so we can say

req '/', :user_agent => 'some custom user agent'


38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/rackbox/rackbox.rb', line 38

def req app_or_request, url = nil, options = {}
  puts "RackBox#request url:#{ url.inspect }, options:#{ options.inspect }" if RackBox.verbose

  # handle RackBox.request '/foo'
  if app_or_request.is_a?(String) && ( url.nil? || url.is_a?(Hash) )
    options        = url || {}
    url            = app_or_request
    app_or_request = RackBox.app
  end

  # need to find the request or app
  mock_request = nil
  if app_or_request.is_a? Rack::MockRequest
    mock_request = app_or_request
  elsif app_or_request.nil?
    if RackBox.app.nil?
      raise "Not sure howto to execute a request against app or request: #{ app_or_request.inspect }"
    else
      mock_request = Rack::MockRequest.new(RackBox.app) # default to RackBox.app if nil
    end
  elsif app_or_request.respond_to? :call
    mock_request = Rack::MockRequest.new(app_or_request)
  else
    raise "Not sure howto to execute a request against app or request: #{ app_or_request.inspect }"
  end

  options[:method] ||= ( options[:params] || options[:data] ) ? :post : :get # if params, default to POST, else default to GET
  options[:params] ||= { }

  if options[:data]
    # input should be the data we're likely POSTing ... this overrides any params
    input = options[:data]
  else
    # input should be params, if any
    input = RackBox.build_query options[:params]
  end

  # add HTTP BASIC AUTH support
  #
  # TODO: DRY this up!
  #
  if options[:auth]
    options[:http_basic_authentication] = options[:auth]
    options.delete :auth
  end
  if options[:basic_auth]
    options[:http_basic_authentication] = options[:basic_auth]
    options.delete :basic_auth
  end
  if options[:http_basic_authentication]
    username, password = options[:http_basic_authentication]
    options.delete :http_basic_authentication
    require 'base64'
    # for some reason, nase64 encoding adds a \n
    encoded_username_and_password = Base64.encode64("#{ username }:#{ password }").sub(/\n$/, '')
    options['HTTP_AUTHORIZATION'] = "Basic #{ encoded_username_and_password }"
  end

  headers = options.dup
  headers.delete :data   if headers[:data]
  headers.delete :params if headers[:params]
  headers.delete :method if headers[:method]

  # merge input
  headers[:input] = input
  
  puts "  requesting #{ options[:method].to_s.upcase } #{ url.inspect } #{ headers.inspect }" if RackBox.verbose
  mock_request.send options[:method], url, headers
end