RSpec Request - How to set http authorization header for all requests

后端 未结 4 2175
清歌不尽
清歌不尽 2021-02-07 06:01

I\'m using rspec request to test a JSON API that requires an api-key in the header of each request.

I know I can do this:

get \"/v1/users/janedoe.json\"         


        
相关标签:
4条回答
  • 2021-02-07 06:15

    I don't think you should depend on the header if you are not testing the header itself, you should stub the method that checks if the HTTP_AUTORIZATION is present and make it return true for all specs except the spec that tests that particular header

    something like... on the controller

    Controller...
      before_filter :require_http_autorization_token
    
      methods....
    
      protected
      def require_http_autorization_token
        something
      end
    

    on the spec

    before(:each) do
      controller.stub!(:require_http_autorization_token => true)
    end
    
    describe 'GET user' do
      it 'returns something' do
        #call the action without the auth token
      end
    
      it 'requires an http_autorization_token' do
        controller.unstub(:require_http_autorization_token)
        #test that the actions require that token
      end
    end
    

    that way one can forget the token and test what you really want to test

    0 讨论(0)
  • 2021-02-07 06:24

    To set it in a before hook you need to access it like

    config.before(:each) do
      controller.request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Token.encode_credentials('mytoken')
    end
    

    I too hated the giant hash, but preferred to be explicit in authorizing the user in different steps. After all, it's a pretty critical portion, and . So my solution was:

    #spec/helpers/controller_spec_helpers.rb
    module ControllerSpecHelpers
      def authenticate user
        token = Token.where(user_id: user.id).first || Factory.create(:token, user_id: user.id)
        request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Token.encode_credentials(token.hex)
      end
    end
    
    #spec/spec_helper.rb
    RSpec.configure do |config|
      ...
      config.include ControllerSpecHelpers, :type => :controller
    

    then I can use it like so

    describe Api::V1::Users, type: :controller do
      it 'retrieves the user' do
        user = create :user, name: "Jane Doe"
        authorize user
        get '/v1/users/janedoe.json'
      end
    end
    

    I find this great for testing different authorization levels. Alternatively, you could have the helper method spec out the authorize function and get the same result, like so

    #spec/helpers/controller_spec_helpers.rb
    module ControllerSpecHelpers
      def authenticate
        controller.stub(:authenticate! => true)
      end
    end
    

    However, for ultimate speed and control, you can combine them

    #spec/helpers/controller_spec_helpers.rb
    module ControllerSpecHelpers
      def authenticate user = nil
        if user
          token = Token.where(user_id: user.id).first || Factory.create(:token, user_id: user.id)
          request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Token.encode_credentials(token.hex)
        else
          controller.stub(:authenticate! => true)
        end
      end
    end
    

    and then authorize entire blocks with

    #spec/spec_helper.rb
    ...
    RSpec.configure do |config|
      ...
      config.before(:each, auth: :skip) { authenticate }
    
    #**/*_spec.rb
    describe Api::V1::Users, type: :controller do
      context 'authorized', auth: :skip do
        ...
    
    0 讨论(0)
  • 2021-02-07 06:25

    I know that this question has already been answered but here's my take on it. Something which worked for me:

    request.headers['Authorization'] = token
    

    instead of:

    request.env['Authorization'] = token
    
    0 讨论(0)
  • 2021-02-07 06:37

    This is another way to do it if you are doing a post.

    @authentication_params = { 'HTTP_AUTHORIZATION' => ActionController::HttpAuthentication::Token.encode_credentials(Temp::Application.config.api_key) }
    
    expect { post "/api/interactions", @interaction_params, @authentication_params }.to change(Interaction, :count).by(1)
    

    Note interaction_params is just a json object I am passing in.

    0 讨论(0)
提交回复
热议问题