Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rspec: add some header requests inside routing specs

I'm working on a Rails application having a REST API in JSON format and versioned (according to this excellent Ryan's cast: http://railscasts.com/episodes/350-rest-api-versioning).

For instance, there is a spec/requests spec:

require 'spec_helper'

describe "My Friends" do
  describe "GET /my/friends.json" do
    it "should get my_friends_path" do
      get v1_my_friends_path, {}, {'HTTP_ACCEPT' => 'application/vnd.myapp+json; level=1'}
      response.status.should be(401)
    end
  end
end

And it works well. But (keeping this example) how can we write the routing spec? For instance this spec isn't correct:

require 'spec_helper'

describe "friends routing" do
  it "routes to #index" do
    get("/my/friends.json", nil, {'HTTP_ACCEPT' => 'application/vnd.myapp+json; level=1'}).
      should route_to({ action: "index",
                    controller: "api/v1/private/my/friends",
                        format: "json" })
  end
end

I tried different ways (such as request.headers['Accept'] and @request.headers['Accept'], where request is undefined and @request is nil); I really don't see how to do.

I'm on Ruby 1.9.3, Rails 3.2.6 and rspec-rails 2.11.0. Thanks.

like image 363
T5i Avatar asked Jul 11 '12 16:07

T5i


2 Answers

By combining the ideas from Cristophe's and Piotr's answers, I came up with a solution that worked for me. I'm using rspec and rails 3.0.

it 'should route like i want it to' do 
  Rack::MockRequest::DEFAULT_ENV["HTTP_ACCEPT"] = "*/*"
  {get: "/foo/bar"}.
    should route_to(
    controller: 'foo',
    action: 'bar',
  )
  Rack::MockRequest::DEFAULT_ENV.delete "HTTP_ACCEPT"
end
like image 76
Jeff Gran Avatar answered Oct 13 '22 18:10

Jeff Gran


Currently you can't send addititional Headers in Routing specs, this is due to line 608 in actionpack-3.2.5/lib/action_dispatch/routing/route_set.rb where it says:

env = Rack::MockRequest.env_for(path, {:method => method})

path is your requested path "/my/friends.json" and method is :get The resulting env contains something like the following:

{
 "rack.version"=>[1, 1],
 "rack.input"=>#<StringIO:0xb908f5c>,
 "rack.errors"=>#<StringIO:0xb908fac>,
 "rack.multithread"=>true,
 "rack.multiprocess"=>true,
 "rack.run_once"=>false,
 "REQUEST_METHOD"=>"GET",
 "SERVER_NAME"=>"your-url.com", # if path was http://your-url.com/
 "SERVER_PORT"=>"80",
 "QUERY_STRING"=>"",
 "PATH_INFO"=>"/",
 "rack.url_scheme"=>"http",
 "HTTPS"=>"off",
 "SCRIPT_NAME"=>"",
 "CONTENT_LENGTH"=>"0"
}

If you are able to mock Rack::MockRequest::env_for it should be possible to inject other headers than the ones generated by env_for (see Hash above).

Other than that you are currently using the route_to matcher wrong, you should call it on a Hash where you specify the method and the path like this:

{ get: '/' }.should route_to(controller: 'main', action: 'index')

Let us know if you were able to Mock out that env_for and let it return your headers, would be nice to know.

Regards Christoph

like image 29
Christoph Geschwind Avatar answered Oct 13 '22 17:10

Christoph Geschwind