Andy Jones
Andy Jones

Reputation: 1104

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?

Upvotes: 1

Views: 2663

Answers (4)

Artur INTECH
Artur INTECH

Reputation: 7396

Provided your test is an integration one it is enough you do the following:

get '/sign_out'
assert last_response.redirect?, 'Response must redirect'
assert_equal '/', URI(last_response.location).path, 'Response must redirect to the root path'

Upvotes: 0

sensadrome
sensadrome

Reputation: 482

Another way would be to test last_response.header['Location']

Upvotes: 1

Andy Jones
Andy Jones

Reputation: 1104

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.

Upvotes: 5

Sir l33tname
Sir l33tname

Reputation: 4340

Your Test is wrong.

A get on a redirect is status code 302. So the right test is:

expect(last_response.status).to eq(302)

Maybe a better way to check this is just assert last_response.ok?

http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.3

Or like the example from github:

get "/"
follow_redirect!

assert_equal "http://example.org/yourexpecedpath", last_request.url
assert last_response.ok?

And yes this is always example.org because you get a mock instead of a real response.

Upvotes: 3

Related Questions