Search code examples
rspecsinatrarspec-rails

Rspec render_template equivalent for Sinatra?


I'm building a Sinatra app currently that will be outputting JSON templates as part of an API. When testing with rails and the rspec-rails gem I was able to call:

response.should render_template('template-name')

However since I'm not using Rails I'm assuming this won't work. What's the alternative to use for Sinatra for testing the json output? Thanks!


Solution

  • There are some docs on using Rack Test with RSpec here, but this is how I set my stuff up. By wrapping the app in a module's class method it makes it a lot easier to run in the specs, then it's just a case of validating the response via last_response.body (which is the short answer to your question).

    # config.ru
    
    require 'rubygems'
    require "bundler/setup"
    
    root = File.expand_path File.dirname(__FILE__)
    require File.join( root , "./app/config.rb" )
    
    # everything was moved into a separate module/file 
    # to make it easier to set up tests
    
    map "/" do
      run HelloWorld.app
    end
    

    # app/config.rb
    require 'main'
    
    module HelloWorld
      def self.app
        Rack::Builder.app do
          # middleware setup here, cookies etc
          run App
        end
      end
    end
    

    # app/main.rb
    require 'sinatra/base'
    
    module HelloWorld
      class App < Sinatra::Base
        get "/", :provides => :json do
          {key: "value"}.to_json
        end
      end
    end
    

    # spec/spec_helper.rb
    
    require 'rspec'
    Spec_dir = File.expand_path( File.dirname __FILE__ )
    
    require 'rack/test'
    
    Dir[ File.join( Spec_dir, "/support/**/*.rb")].each do |f|
      require f
    end
    

    # spec/support/shared/all_routes.rb
    
    require 'hello_world'  # <-- your sinatra app
    
    shared_context "All routes" do
      include Rack::Test::Methods
      let(:app){
        HelloWorld.app 
      }
    end
    
    shared_examples_for "Any route" do
      subject { last_response }
      it { should be_ok }
    end
    

    # spec/hello_world_spec.rb
    require 'spec_helper'
    
    describe 'getting some JSON' do
      include_context "All pages"
    
      let(:expected) {
        '{"key": "value"}'
      }
    
      before do
        get '/', {}, {"HTTP_ACCEPT" => "application/json" }
      end
      it_should_behave_like "Any route"
    
      subject { last_response.body }
      it { should == expected }
    end