设置Cookie.在Rails 5控制器集成测试中签名



想象一下有控制器集成测试调用控制器方法的情况,其中cookie.signed用于某些完整性检查。

控制器

# app/controllers/foo_controller.rb
def index
  entity = FooEntity.find_by_id(params[:id])
  if entity.nil?
    raise ActionController::BadRequest, 'Could not find requested entity.'
  else
    @is_authorized = entity.token == cookies.signed[:token]
    if @is_authorized
      # Success! The path to be tested.
    else
      raise ActionController::BadRequest, 'Unauthorized cookie token.'
    end
  end
end

控制器测试

# app/test/controllers/foo_test.rb
require 'test_helper'
class FooControllerTest < ActionDispatch::IntegrationTest
  test 'should be working' do
    cookies.signed[:token] = '7e5201169ef160e31058d2a1976a5552'
    get '/foobar/123'
  end
end

但是,我不确定如何在测试中获得cookie.signed设置。上面的测试代码引发了例外:

nomethoderror:未定义的方法"签名" :: test :: cookiejar:0x007fe90965ccd8

试图搜索解决方案,但我能找到的是本文,https://sikac.hu/reconstruct-a-cookie-jar-jar-jar-jar-and-read-sign--cookie-cookie-in-capybara-f71df387f9ff,但无法弄清楚如何构造ActionDispatch::Request对象。

这似乎是Rails 5 及更高版本中的(链接的问题大于cookies.encrypted,但也适用于cookies.signed(。问题在于,在控制器测试中,cookie jar是一个Rack::Test::CookieJar类实例,不支持签名/加密的cookie 。另一方面,在应用程序本身中,cookie jar是一个ActionDispatch::Cookies::CookieJar类实例,支持这两种特殊的cookie类型。

但是,要在控制器测试中构造签名的cookie,您可以手动创建一个ActionDispatch请求cookie jar并使用该检索签名的cookie值:

# app/test/controllers/foo_test.rb
require 'test_helper'
class FooControllerTest < ActionDispatch::IntegrationTest
  test 'should be working' do
    my_cookies = ActionDispatch::Request.new(Rails.application.env_config.deep_dup).cookie_jar
    my_cookies.signed[:token] = '7e5201169ef160e31058d2a1976a5552'
    cookies[:token] = my_cookies[:token]
    get '/foobar/123'
  end
end

第一个测试行创建了一个新的ActionDispatch请求,并使用应用程序请求默认环境设置(它们定义了用于签名cookie的秘密(,并返回其cookie jar。然后,您只需为所需值设置:token签名的cookie(此cookie jar di 具有定义为ActionDispatch::Cookies::CookieJar而不是Rack::Test::CookieJarsigned方法(。最后,您通过无需 signed访问器访问签名的cookie value ,并使用此值设置同名 test test cookie 。P>

现在,当测试到达控制器代码时,控制器应在cookies.signed[:token] cookie中看到正确的值。

这对我有用:

## file: app/spec/controllers/api/v2/donations_controller_spec.rb
RSpec.describe Api::V2::DonationsController, type: :request do
 let(:donor) { Fabricate(:donor) }
  before do
     cookies = ActionDispatch::Request.new(Rails.application.env_config.deep_dup).cookie_jar
     @tmp = cookies.signed[:donor_jwtapi] = { value: { token: donor.token} , httponly: true }
 end
 describe 'POST#create' do
   it 'create a bank account donation' do
     post api_v2_donations_path, params: {donor_id: donor.id}, headers: { Cookie: "donor_jwtapi=#{@tmp[:value]};" }, as: :json
     json_response = JSON.parse response.body
     expect(response).to have_http_status :ok
     expect(json_response['error']).to be false
   end
  end
end

最新更新