在Railscast on Devise and OmniAuth之后我实现了OmniauthCallbacksController < Devise::OmniauthCallbacksController
,其中包含一个处理OmniAuth回调的方法:
def all
user = User.from_omniauth(request.env["omniauth.auth"])
if user.persisted?
sign_in_and_redirect user
else
session["devise.user_attributes"] = user.attributes
redirect_to new_user_registration_url
end
end
alias_method :facebook, :all
routes.rb中:
devise_for :users, controllers: {omniauth_callbacks: "omniauth_callbacks", :sessions => "sessions" }
我想自定义这个,所以我试图用RSpec来测试它。问题是如何测试此方法和重定向?
如果在我放置user_omniauth_callback_path(:facebook)
的规范中,它没有抱怨路线不存在,但似乎没有实际调用该方法。
根据this answer“控制器测试使用四个HTTP谓词(GET,POST,PUT,DELETE),无论您的控制器是否为RESTful。”我试过了get user_...
等等,但在这里确实抱怨路线不存在。事实上,如果我rake routes
它显示此路线没有HTTP动词:
user_omniauth_callback [BLANK] /users/auth/:action/callback(.:format) omniauth_callbacks#(?-mix:facebook)
你能看到我错过的东西吗?
修改
因此,在this question之后调用该方法的一种方法是:
controller.send(:all)
然而,我遇到了提问者遇到的同样错误:
ActionController::RackDelegation#content_type delegated to @_response.content_type, but @_response is nil
答案 0 :(得分:5)
你需要做三件事来完成这件事。
这是一个可能的解决方案,在规范中输入 (例如spec / feature / login_spec.rb)。 。
let(:current_user) { FactoryGirl.create(:user) }
before do
OmniAuth.config.test_mode = true
OmniAuth.config.mock_auth[:facebook] = OmniAuth::AuthHash.new({
provider: :facebook,
uid:'12345',
info: {
name: "Joe"
}
})
User.stub(:from_omniauth).and_return(current_user)
end
我从谷歌身份验证中对此进行了调整,因此Facebook可能需要更多字段,但这些字段只是required by omniauth docs。您应该能够通过查看数据库模式并查找与文档匹配的字段来查找正确的字段。
在我的情况下,最小值足以通过请求阶段并转移到返回我的用户的stubed out方法。
此示例还使用FactoryGirl。
它可能不完美,但我希望它有所帮助。祝你好运!
-Dan
答案 1 :(得分:3)
如果您点击此处并且您正在运行 rspec 3.4 ,则此示例应该适用于您:
describe Users::OmniauthCallbacksController, type: :controller do
let(:current_user) { FactoryGirl.create(:user) }
before do
OmniAuth.config.test_mode = true
OmniAuth.config.mock_auth[:your_oauth_provider_here] = OmniAuth::AuthHash.new(
provider: :your_oauth_provider_here,
uid: rand(5**10),
credentials: { token: ENV['CLIENT_ID'], secret: ENV['CLIENT_SECRET'] }
)
request.env['devise.mapping'] = Devise.mappings[:user]
allow(@controller).to receive(:env) { { 'omniauth.auth' => OmniAuth.config.mock_auth[:your_oauth_provider_here] } }
allow(User).to receive(:from_omniauth) { current_user }
end
describe '#your_oauth_provider_here' do
context 'new user' do
before { get :your_oauth_provider_here }
it 'authenticate user' do
expect(warden.authenticated?(:user)).to be_truthy
end
it 'set current_user' do
expect(current_user).not_to be_nil
end
it 'redirect to root_path' do
expect(response).to redirect_to(root_path)
end
end
end
end
答案 2 :(得分:1)
我在为RSpec
扭动OmniauthCallbacksController
时遇到了问题,对此做了一些研究并且它对我有用。这是我的代码,如果有人发现有必要。测试是为了快乐的路径,它应该适用于RSpec eg. 3.x
require 'spec_helper'
describe OmniauthCallbacksController, type: :controller do
describe "#linkedin" do
let(:current_user) { Fabricate(:user) }
before(:each) do
OmniAuth.config.test_mode = true
OmniAuth.config.mock_auth[:linkedin] = OmniAuth::AuthHash.new({provider: :linkedin, uid: '12345', credentials: {token: 'linkedin-token', secret: 'linkedin-secret'}})
request.env["devise.mapping"] = Devise.mappings[:user]
@controller.stub!(:env).and_return({"omniauth.auth" => OmniAuth.config.mock_auth[:linkedin]})
User.stub(:from_auth).and_return(current_user)
end
describe "#linkedin" do
context "with a new linkedin user" do
before { get :linkedin }
it "authenticate user" do
expect(warden.authenticated?(:user)).to be_truthy
end
it "set current_user" do
expect(subject.current_user).not_to be_nil
end
it "redirect to root_path" do
expect(response).to redirect_to(root_path)
end
end
end
end
end