2013-05-08 69 views
7

Railscast on Devise and OmniAuth我已經實現了OmniauthCallbacksController < Devise::OmniauthCallbacksController其中包含一個方法來處理OmniAuth回調:Rspec的:測試重定向在設計:: OmniauthCallbacksController子

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 

回答

5

你需要做三件事才能完成。

  • 進入OmniAuth測試環境
  • 創建OmniAuth測試模擬
  • 存根你from_omniauth方法返回一個用戶

這裏是一個可能的解決方案,在規範本身 (規格進入例如/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。通過查看數據庫模式並查找與文檔匹配的字段,您應該能夠找到正確的字段。

在我的情況,最低是足夠將請求傳遞相位和移動到存根方法返回我的用戶。

這個例子也使用FactoryGirl

它可能不是完美的,但我希望它能幫助。祝你好運!

-Dan

+0

完美。在很多層面上都很有幫助,特別是我將其視爲控制器規範而不是功能規範。非常感激! – 2013-05-16 13:00:22

+1

很高興幫助!這讓我跪了一天半。我很高興別人能從我的沮喪中受益!語法遠沒有?如果是這樣,請使用正確的解決方案編輯。謝謝! – 2013-05-16 13:53:24

+1

語法運行完美。我做的唯一的變化是在[我的答案](http://stackoverflow.com/a/9915796/1450420)中找到了spec_helper.rb,這是我的答案。 – 2013-05-16 14:01:26

1

我的扭動RSpecOmniauthCallbacksController遇到問題,做一些這方面的研究,併爲我工作。這是我的代碼,如果有人認爲有必要的話。測試是幸福的路徑,它應該爲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 
+0

你有沒有調整過這個在rspec 3.4中工作? – 2016-05-21 01:24:52

+0

是調整和編輯。 – 2017-05-16 07:54:49

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