Search code examples
ruby-on-railsruby-on-rails-4rspecrspec-rails

Rspec Rails 4.2.5 Request test pass with basic http auth


The setup is the following. For each http request the manager sends his credentials in the header(name,pw). These get checked against the entries in the db and if they succeed return the desired user object. How is it possible to implement basic http_auth in the request tests? I would like to add only the password and username and test the return value? Which is the goal of request tests,right? I tried the following without much success:

I created an AuthHelper module in spec/support/auth_helper.rb with

module AuthHelper
  def http_login
    user = 'test'
    pw = 'test'
    request.ENV['HTTP_AUTHORIZATION'] =ActionController::HttpAuthentication::Basic.encode_credentials(user,pw)
   end  
end

and use it in the requests/api/user_spec.rb as follows

include AuthHelper
 describe "User API get 1 user object" do     
      before(:each) do
               http_login 
       end

but i receive this error message. How can i fix this and enable my tests to pass http_auth? I read lot of similar topis and questions also here but they apply mostly to older versions of rspec and rails and are not applying to my case

Thanks in advance!

Failure/Error: request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials(user,pw)

 NoMethodError:
   undefined method `env' for nil:NilClass# ./spec/support

 # ./spec/support/auth_helper.rb:5:in `http_login'
 # ./spec/requests/api/user_spec.rb:8:in `block (2 levels) in <top (required)>'

Update

I moved the header generation inside a request. I looked up the Auth verb, so i think the assignment should work. I tested the ActionController call in rails console and received a string. I suppose this is also correct.My whole test now looks like this:

describe "User API get 1 user object", type: :request do  
      it 'Get sends back one User object ' do             
              headers = {   
                            "AUTHORIZATION" =>ActionController::HttpAuthentication::Basic.encode_credentials("test","test")
   #                        "AUTHORIZATION" =>ActionController::HttpAuthentication::Token.encode_credentials("test","test")
              }
              FactoryGirl.create(:user)
              get "/api/1/user", headers
              #json = JSON.parse(response.body)
              expect(response).to be_success
      #       expect(response.content_type).to eq("application/json")
      end     
  end     

receiving the following error:

which incudles the line @buf=["HTTP Basic: Access denied.\n"] so access is still denied.

Failure/Error: expect(response).to be_success
   expected `#<ActionDispatch::TestResponse:0x000000070d1d38 @mon_owner=nil, @mon_count=0, @mon_mutex=#<Thread::Mutex:0x000000070d1c98>, @stream=#<ActionDispatch::Response::Buffer:0x000000070d1c48 @response=#<ActionDispatch::TestResponse:0x000000070d1d38 ...>, 
 @buf=["HTTP Basic: Access denied.\n"], @closed=false>, @header={"X-Frame-Options"=>"SAMEORIGIN", "X-XSS-Protection"=>"1; mode=block", "X-Content-Type-Options"=>"nosniff", "WWW-Authenticate"=>"Basic realm=\"Application\"", "Content-Type"=>"text/html; charset=utf-8", "Cache-Control"=>"no-cache", "X-Request-Id"=>"9c27d4e9-84c0-4ef3-82ed-cccfb19876a0", "X-Runtime"=>"0.134230", "Content-Length"=>"27"}, @status=401, @sending_file=false, @blank=false, 
@cv=#<MonitorMixin::ConditionVariable:0x000000070d1bf8 @monitor=#<ActionDispatch::TestResponse:0x000000070d1d38 ...>, @cond=#<Thread::ConditionVariable:0x000000070d1bd0>>, @committed=false, @sending=false, @sent=false, @content_type=#<Mime::Type:0x00000002af78f8 @synonyms=["application/xhtml+xml"], @symbol=:html, @string="text/html">, @charset="utf-8", @cache_control={:no_cache=>true}, @etag=nil>.success?` 
to return true, got false

SOLUTION This test is not polished (yet) but at least it passes now.

describe "User API get 1 user object", type: :request do  
    it 'Get sends back one User object ' do             
        @env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials(user,pw)
              FactoryGirl.create(:user)

        get "/api/1/user", {}, @env

        JSON.parse(response.body)
        expect(response).to be_success
        expect(response.status).to eq 200
    end     
end     

Solution

  • Read the error carefully: undefined method `env' for nil:NilClass means request is nil. Are you trying to set the header before a test while you are defining the request later on in the test?

    You might want to look at the documentation for an example on how to set headers.

    If you're still stuck, post one of your tests as well.