RSpec Request - как настроить HTTP-заголовок авторизации для всех запросов

Я использую запрос rspec для тестирования API JSON, для которого требуется api-ключ в заголовке каждого запроса.

Я знаю, что могу это сделать:

get "/v1/users/janedoe.json", {}, { 'HTTP_AUTHORIZATION'=>"Token token=\"mytoken\"" }

Но это утомительно делать это для каждого запроса.

Я попытался установить request.env в предыдущем блоке, но я получаю no method NilClass error, поскольку запрос не существует.

Мне нужно каким-то образом, возможно, в spec-helper, чтобы глобально получить этот заголовок, отправленный со всеми запросами.

Ответ 1

Я не думаю, что вы должны зависеть от заголовка, если вы не тестируете сам заголовок, вы должны заглушить метод, который проверяет наличие HTTP_AUTORIZATION и делает его возвратом true для всех спецификаций, кроме спецификации, которая проверяет этот конкретный заголовок

что-то вроде... на контроллере

Controller...
  before_filter :require_http_autorization_token

  methods....

  protected
  def require_http_autorization_token
    something
  end

на 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

таким образом можно забыть токен и проверить, что вы действительно хотите проверить

Ответ 2

Чтобы установить его в верхний крючок, вам нужно получить к нему доступ, например

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

Я тоже ненавидел гигантский хеш, но предпочитал быть явным в авторизации пользователя на разных этапах. В конце концов, это довольно критическая часть, и. Итак, я решил:

#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

то я могу использовать его так:

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

Я считаю, что это отлично подходит для тестирования разных уровней авторизации. В качестве альтернативы вы могли бы использовать вспомогательный метод для определения функции авторизации и получить тот же результат, например:

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

Однако для максимальной скорости и контроля вы можете комбинировать их

#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

а затем разрешить целые блоки с помощью

#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
    ...

Ответ 3

Это еще один способ сделать это, если вы делаете сообщение.

@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)

Обратите внимание, что взаимодействие_парам - это просто объект json, который я передаю.

Ответ 4

Я знаю, что на этот вопрос уже был дан ответ, но здесь я беру на себя это. Что-то, что сработало для меня:

request.headers['Authorization'] = token

вместо:

request.env['Authorization'] = token