rubysinatrarspec2rack-test

How do I use Rack/Test to test Sinatra redirects? The App works, but the test doesn't


It would appear that either I am missing something very basic, or Rack/Test can't cope with Sinatra doing a redirect.

Presumably there is a way around this or Rack/Test would be useless. Can anyone tell me what I should be doing to get it to work here?

(Edit: What I ultimately want to achieve is to test which page I eventually get, not the status. In the test, the last_response object is pointing to a page that doesn't exist in my app, and certainly not the page you actually get when you run it.)

An example app:

require 'sinatra'
require 'haml'

get "/" do
  redirect to('/test')
end

get '/test' do
  haml :test
end

This works as you would expect. Going to either '/' or '/test' gets you the contents of views/test.haml.

But this test does not work:

require_relative '../app.rb'
require 'rspec'
require 'rack/test'

describe "test" do
  include Rack::Test::Methods

  def app
    Sinatra::Application
  end

  it "tests" do
    get '/'
    expect(last_response.status).to eq(200)
  end
end

This is what happens when you run the test:

1) test tests
   Failure/Error: expect(last_response.status).to eq(200)

     expected: 200
          got: 302

And this is what last_response.inspect looks like:

#<Rack::MockResponse:0x000000035d0838 @original_headers={"Content-Type"=>"text/html;charset=utf-8", "Location"=>"http://example.org/test", "Content-Length"=>"0", "X-XSS-Protection"=>"1; mode=block", "X-Content-Type-Options"=>"nosniff", "X-Frame-Options"=>"SAMEORIGIN"}, @errors="", @body_string=nil, @status=302, @header={"Content-Type"=>"text/html;charset=utf-8", "Location"=>"http://example.org/test", "Content-Length"=>"0", "X-XSS-Protection"=>"1; mode=block", "X-Content-Type-Options"=>"nosniff", "X-Frame-Options"=>"SAMEORIGIN"}, @chunked=false, @writer=#<Proc:0x000000035cfeb0@/home/jonea/.rvm/gems/ruby-1.9.3-p547@sandbox/gems/rack-1.5.2/lib/rack/response.rb:27 (lambda)>, @block=nil, @length=0, @body=[]>

I wonder if Rack/Test has just arbitrarily decided to insert 'http://example.org' into the redirect?


Solution

  • As @sirl33tname points out, a redirect is still a redirect, so the best possible status I can expect is 302, not 200. If I want to test whether I got a good page at the end of the redirect, I should test ok? not the status.

    But if I want to test what URL I eventually end up with, though, I need to do a tiny bit more, because Rack/Test is basically a mocking system (sic) and returns a mock of a page on a redirect, not the actual page.

    But this is easy enough to override, it turns out, with follow_redirect!.

    The test becomes:

    it "tests" do
      get '/'
      follow_redirect!
      expect(last_response.status).to be_ok
    
      # ...and now I can test for the contents of test.haml, too...
      expect(last_response.body).to include('foo')
    end
    

    And that does the job.