我有一个rails-api应用程序,我正在使用Rspec进行测试。该应用程序使用devise_token_auth gem进行身份验证,使用cancancan gem进行授权。
devise_token_auth要求客户端在每个请求中包含这些身份验证标头:
access-token
,client
,expiry
,uid
。使用email
和password
成功进行身份验证后,这些标头在响应中可用。
我决定使用this answer中提供的解决方案在测试期间设置这些标头。
在ability.rb
我有这个:
## models/ability.rb
class Ability
include CanCan::Ability
def initialize(user)
if user.role? :registered
can :create, Post, user_id: user.id
can :update, Post, user_id: user.id
can :destroy, Post, user_id: user.id
can :read, Post
end
end
end
posts#show
中的 PostsController
操作如下所示:
## controllers/posts_controller.rb
class PostsController < ApplicationController
before_action :authenticate_user!
load_and_authorize_resource
def show
render json: @post
end
end
我已经救出了CanCan::AccessDenied
错误,在403
forbidden
ApplicationController
rescue_from CanCan::AccessDenied do |exception|
render json: {"message" => "unauthorized"}.to_json, :status => 403
end
我在spec/support/session_helper.rb
module SessionHelper
def retrieve_access_headers
##I have a user with these credentials and has a "registered" role. in the the test db.
post "/auth/sign_in", params: {:email => "registered_user@gmail.com", :password => "g00dP@ssword"}, headers: {'HTTP_ACCEPT' => "application/json"}
##These two pass
expect(response.response_code).to eq 200
expect(response.body).to match(/"email": "registered_user@gmail.com"/)
access_headers = {"access-token" => response.headers["access-token"],
"client" => response.headers["client"],
"expiry" => response.headers["expiry"],
"uid" => response.headers["uid"],
"token-type" => response.headers["token-type"],
'HTTP_ACCEPT' => "application/json"
}
return access_headers
end
端
我在spec/support/requests_helper.rb
module RequestsHelper
def get_with_token(path, params={}, headers={})
headers.merge!(retrieve_access_headers)
get path, params: params, headers: headers
#### this outputs the expected headers on a json string and they seem fine ####
puts "headers: "+headers.to_json
end
end
我已在rails_helper.rb
中加入了两位助手,如下所示:
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
RSpec.configure do |config|
config.include SessionHelper, type: :request
config.include RequestsHelper, type: :request
end
最后,我在spec/request/posts/show_spec.rb
require 'rspec/its'
require 'spec_helper'
require 'rails_helper'
RSpec.describe 'GET /posts/:id', :type => :request do
let(:post) {create(:post)}
let(:id) {post.id}
let(:request_url) {"/posts/#{id}"}
context 'with a registered user' do
it 'has a status code of 200' do
get_with_token request_url
expect(response).to have_http_status(:success)
end
end
end
我希望这会通过,但它会失败并显示消息:
Failure/Error: expect(response).to have_http_status(:success)
expected the response to have a success status code (2xx) but it was 403
应用程序在浏览器上按预期工作。
我做错了什么?