2013-05-08 9 views
7

Po Railscast on Devise and OmniAuth Mam wdrożyła OmniauthCallbacksController < Devise::OmniauthCallbacksController który zawiera jedną metodę, aby obsłużyć zwrotnego OmniAuth:rspec: Test przekierowania w Devise :: OmniauthCallbacksController podklasy

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" } 

Chciałbym to spersonalizować, więc próbuję przetestować go za pomocą RSpec. Pytanie brzmi: jak przetestować tę metodę i przekierowania?

Jeśli w specyfikacji zamieściłem user_omniauth_callback_path(:facebook), nie narzeka ona na nieistnienie trasy, ale nie wydaje się, że tak naprawdę wywołuje tę metodę.

Zgodnie z this answer "testy kontrolera wykorzystują cztery czasowniki HTTP (GET, POST, PUT, DELETE), niezależnie od tego, czy kontroler jest restestowany." Próbowałem get user_... itd., Ale tutaj narzeka, że ​​trasa nie istnieje. I rzeczywiście, jeśli robię rake routes to widać nie ma czasownik HTTP dla tej trasy:

user_omniauth_callback [BLANK] /users/auth/:action/callback(.:format) omniauth_callbacks#(?-mix:facebook) 

można zobaczyć, co mi brakuje?

EDIT

Więc po this question jeden sposób wywołania metody jest:

controller.send(:all) 

Jednak ja następnie uruchomić do tego samego błędu, że pytający wpadł:

ActionController::RackDelegation#content_type delegated to @_response.content_type, but @_response is nil 

Odpowiedz

5

Aby to osiągnąć, musisz zrobić trzy rzeczy.

  • wprowadzić środowisku testowym OmniAuth
  • stworzyć test OmniAuth mock
  • stub się metodę from_omniauth zwrócić użytkownikowi

Oto możliwe rozwiązanie, wprowadzone w specyfikacji samego (SPEC /feature/login_spec.rb na przykład). . .

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 

I dostosowany to z uwierzytelniania google, facebook, więc mogą wymagać więcej pól, ale te są jedynymi required by omniauth docs. Powinieneś być w stanie znaleźć poprawne pola, patrząc na schemat bazy danych i znalezienie pól pasujących do dokumentacji.

W moim przypadku minimum wystarczyło, aby przejść fazę żądania i przejść do metody wykluczania, zwracającej mojego użytkownika.

W tym przykładzie użyto również FactoryGirl.

Może nie być doskonały, ale mam nadzieję, że to pomaga. Powodzenia!

-Dan

+0

Perfect. Pomocna na wielu poziomach, nie mówiąc o tym, że myślałem o tym jako o specyfikacji kontrolera, a nie o funkcji. Bardzo doceniane! –

+1

Cieszę się, że mogę Ci pomóc! To doprowadziło mnie do kolan przez półtora dnia. Cieszę się, że ktoś może skorzystać z mojej frustracji! Czy składnia była daleko? Jeśli tak, edytuj za pomocą właściwego rozwiązania. Dzięki! –

+1

Składnia działa idealnie. Jedyną zmianą, jaką wprowadziłem, było wciągnięcie trochę w spec_helper.rb po [tej odpowiedzi] (http://stackoverflow.com/a/9915796/1450420), którą znalazłem dzięki twojej odpowiedzi. –

1

ja doznaję problemu dla wijąc RSpec dla OmniauthCallbacksController, zrobić kilka badań na ten temat i to działa na mnie. Oto moje kody, jeśli ktoś uzna to za konieczne. Testy są dla szczęśliwej drogi i powinien działać dla wersji News of 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

czy dostosowałeś to do pracy w rspec 3.4? –

+0

Tak dostosowany i edytowany. –

3

Jeśli trafisz to i używasz rspec 3,4 przykład ten powinien pracować dla Ciebie:

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