1

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?

Andy Jones
  • 1,074
  • 1
  • 10
  • 21

3 Answers3

4

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.

Andy Jones
  • 1,074
  • 1
  • 10
  • 21
3

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.

Sir l33tname
  • 4,026
  • 6
  • 38
  • 49
  • last_response.ok? (`expect(last_response).to be(ok)`) fails too, because, I think, it's also testing the status. – Andy Jones Oct 31 '14 at 14:05
  • Perhaps I could have made the bigger point clearer -- I want to test which page I eventually get. Rack/Test is returning some page that doesn't exist --- http://example.org/test -- not the page that the actual app redirects to when run. – Andy Jones Oct 31 '14 at 14:12
  • And why? My understanding is that you write a test for the redirect and one for the actual site and your good – Sir l33tname Oct 31 '14 at 15:15
  • Why do I want to test that a GET on page A redirects to page B? Because that's what it the app is supposed to do. (Auth framework is getting in the way here, basically, but details) Why doesn't it work? That's what I want to know... – Andy Jones Oct 31 '14 at 15:46
  • 1
    @AndyJones I agree with Sir l33tname here, you don't need to test the page you get on a redirect, just that the 302 comes backs with the correct location to redirect to. You can test that location separately. – ian Nov 02 '14 at 00:47
  • @Iain. "You can test the location separately". Yes? _How?_ That _is_ what I am asking in the question? (In my actual code Sinatra is redirecting requests to all pages because of OmniAuth. I've got a 'developer' strategy running for the test, but I still get a redirect.) – Andy Jones Nov 03 '14 at 08:40
  • @AndyJones I update my answer a bit, essentially you just test that a get on location X returns a redirect to location Y – Sir l33tname Nov 03 '14 at 09:14
  • 1
    @sirl33tname -- I am -- it doesn't work -- for more information please reread the question ... – Andy Jones Nov 04 '14 at 10:17
1

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

sensadrome
  • 472
  • 2
  • 7