rack::test snippets

Testing sessions with Sinatra and Rack::Test

Tagged session, test, sinatra, rack, cookie, rack::test, mocha  Languages ruby

You need support for testing sessions when, for example, testing authentication. The only way I've managed to get sessions to work with Sinatra and Rack::Test is by going through the whole stack, in other words calling the authentication controller as shown here:

@user = Factory(:user) # create a dummy user
User.expects(:authenticate).with(any_parameters).returns(@user) # make authenticate return the dummy user
post "/sign-in", {:email => @user.email, :password => @user.password} # login to the application and set a session variable.

After this the session populated and we're logged in when accessing the application again:

post "/articles", {:title => 'Sessions suck', :body => '...'}

On a side note, there are two ways of specifying sessions that used to work, but which no longer work with Sinatra 1.0:

get '/', :env => { :session => {:abc => 'adf'} }
get '/', {}, :session => {:abc => 'adf'}
get '/', {}, "rack.session" => {:abc => 'adf'}

The session is always empty.

There are many discussions about sessions and Rack::Test, but not one of them has a solution that works for me: * rack.session variable is missing env under test environment * Sessions with rspec and Rack.Test

How to test modular Sinatra apps with Rack::Test

Tagged sinatra, rack::test, urlmap  Languages ruby

Let's say you have this in your config.ru:

run Rack::URLMap.new \
  "/" => HomeController.new,
  "/user" => UserController.new

and you want to test both / and /user at the same time.

The solution is to return an instance of Rack::Builder instead of, for example, HomeController, which this snippet does by reading config.ru and evaluating it:

def app
  eval "Rack::Builder.new {( " + File.read(File.dirname(__FILE__) + '/../config.ru') + "\n )}"
end

The code was found on the internets and might not work if Sinatra/Rack is changed.

How to test one controller in isolation

To test just one controller use this code:

def app
    Rack::Builder.new do
      run ProductsController
    end
end

or even simpler:

def app
    ProductsController
end