Pro tip if you're testing a Sinatra app mounted on Rails

Lets say you just extracted some part of Rails application to a smaller, more contained Sinatra app. Now, you mounted it on your rails router and you're ready to add a new feature. You write some specs with Rspec. But the errors you get aren't quite what you were expecting.

Lets say you have a spec file called app_spec.rb that looks like this:

require 'spec_helper'

describe '/app' do  
  it 'returns a 200' do
    get '/app'
    expect(last_response.status).to eq 200
  end
end  

Your Sinatra app is a single file in your lib called sinatra_app.rb with this code:

class SinatraApp < Sinatra::Base  
  get '/app' do
    raise 'bug'
    status 200
  end
end  

And, don't forget, you mounted the app on your routes.rb file.

require './lib/sinatra_app'  
mount SinatraApp, at: '/'  

There's clearly a bug on the Sinatra app. When you call the /app endpoint, it's gonna raise an exception before it sets the status to 200.

When you run your specs, this is what you get:

rspec  
F

Failures:

  1) /app returns a 200
     Failure/Error: expect(last_response.status).to eq 200

       expected: 200
            got: 500

       (compared using ==)
     # ./spec/app_spec.rb:6:in `block (2 levels) in <top (required)>'

Finished in 0.38244 seconds (files took 2.54 seconds to load)  
1 example, 1 failure

Failed examples:

rspec ./spec/app_spec.rb:4 # /app returns a 200  

Well, this isn't too bad. It tells you that you were expecting a 200 but you got a 500 instead. But it could be a lot better. Your code is raising an exception, and it would be much better if the test output gave you that information with a stack trace.

The reason why it's not showing you the exception, is because Sinatra is catching it and giving it a nice output before returning the control back to Rails. This is done by a piece of middleware called ShowExceptions.

Now, if we look at Sinatra's source code, it's easy to find that this middleware is only mounted by default in development mode. But we're in test mode. What went wrong?

Well, the answer is quite simple. Sinatra looks at an environment variable called RACK_ENV to determine which environment you're on. Rails, uses RAILS_ENV. When you run your specs, the framework is setting the later but not the former. So, all you have to you is go to your spec_helper.rb and add the following line:

ENV['RACK_ENV'] ||= 'test'

Run your specs again and you get:

rspec  
F

Failures:

  1) /app returns a 200
     Failure/Error: get '/app'
     RuntimeError:
       bug
     # ./lib/sinatra_app.rb:3:in `block in <class:SinatraApp>'
     # /Users/andre/.rvm/gems/ruby-2.1.1/gems/sinatra-1.4.5/lib/sinatra/base.rb:1603:in `call'
     (...)
     # /Users/andre/.rvm/gems/ruby-2.1.1/gems/rack-test-0.6.3/lib/rack/test.rb:58:in `get'
     # ./spec/app_spec.rb:5:in `block (2 levels) in <top (required)>'

Finished in 0.8245 seconds (files took 2.55 seconds to load)  
1 example, 1 failure

Failed examples:

rspec ./spec/app_spec.rb:4 # /app returns a 200  

Slightly more verbose but gives you all the information you need to dive in your code and fix that bug.