2011-12-07 78 views
4

縮短版本:如何在rspec中爲sinatra使用omniauth?

使用了西納特拉的omniauth寶石,我不能讓rspec的登錄工作,讓我的會議後續請求。

基於從http://benprew.posterous.com/testing-sessions-with-sinatra建議,並關閉會話,我已經分離出的問題是:

app.send(:set, :sessions, false) # From http://benprew.posterous.com/testing-sessions-with-sinatra 
    get '/auth/google_oauth2/callback', nil, {"omniauth.auth" => OmniAuth.config.mock_auth[:google_oauth2] } 
    # last_request.session => {"uid"=>"222222222222222222222", :flash=>{:success=>"Welcome"}} 
    # last_response.body => "" 

    follow_redirect! 
    # last_request.session => {:flash=>{}} 
    # last_response.body => Html for the homepage, which is what I want 

我如何RSpec的遵循重定向並保留會話變量?這在Sinatra中可能嗎?

http://benprew.posterous.com/testing-sessions-with-sinatra,似乎我不得不發送每個需要登錄的get/post請求上的會話變量,但這在重定向的情況下不起作用。


細節:

我試圖使用omniauth寶石西納特拉與以下設置:

spec_helper.rb

ENV['RACK_ENV'] = 'test' 

# Include web.rb file 
require_relative '../web' 
# Include factories.rb file 
require_relative '../test/factories.rb' 

require 'rspec' 
require 'rack/test' 
require 'factory_girl' 
require 'ruby-debug' 

# Include Rack::Test in all rspec tests 
RSpec.configure do |conf| 
    conf.include Rack::Test::Methods 
    conf.mock_with :rspec 
end 

web_spec.rb

describe "Authentication:" do 
    before do 
    OmniAuth.config.test_mode = true 
    OmniAuth.config.add_mock(:google_oauth2, { 
     :uid => '222222222222222222222', 
     :info => { 
     :email => "[email protected].com", 
     :name => 'Someone' 
     } 
    }) 
    end 

    describe "Logging in as a new user" do 
    it "should work" do 
     get '/auth/google_oauth2/' 

     last_response.body.should include("Welcome") 
    end 
    end 
end 

當嘗試進行身份驗證時,我得到一個<h1>Not Found</h1>響應。我錯過了什麼?

Integration testing頁omniauth文檔中,它提到增加了兩個環境變量:

before do 
    request.env["devise.mapping"] = Devise.mappings[:user] 
    request.env["omniauth.auth"] = OmniAuth.config.mock_auth[:twitter] 
end 

但似乎是唯一的軌道,因爲我加入

request.env["omniauth.auth"] = OmniAuth.config.mock_auth[:google_oauth2] 

before塊我的規範和我得到這個錯誤:

Failure/Error: request.env["omniauth.auth"] = OmniAuth.config.mock_auth[:google_oauth2] 
ArgumentError: 
    wrong number of arguments (0 for 1) 

編輯:

調用get

get '/auth/google_oauth2/', nil, {"omniauth.auth" => OmniAuth.config.mock_auth[:google_oauth2]} 

似乎last_request.env["omniauth.auth"]等於給我

{"provider"=>"google_oauth2", "uid"=>"222222222222222222222", "info"=>{"email"=>"[email protected]", "name"=>"Someone"}} 

這似乎是正確的,但仍然last_response.body返回

<h1>Not Found</h1> 
+0

我發現這個http://stackoverflow.com/a/3892401/111884,這似乎步入正軌,但我無法讓它工作。 – zlog

回答

3

部分答案...

回調URL更好地工作,與添加的請求環境變量:

get '/auth/google_oauth2/callback', nil, {"omniauth.auth" => OmniAuth.config.mock_auth[:google_oauth2]} 
follow_redirect! 

last_response.body.should include("Welcome") 

然而,這並不重定向,這對於我的應用程序知道有人登錄,需要經過會話工作。更新了問題以反映這一點。

+0

實際上,我需要會話才能登錄才能工作,所以答案對我的應用程序並不適用。 – zlog

0

使用this gist(源自https://stackoverflow.com/a/3892401/111884)來存儲會話數據,我得到了測試來存儲會話,允許我通過會話進一步請求。

雖然可能有一個更簡單的方法。

設置代碼:

# Omniauth settings 
OmniAuth.config.test_mode = true 
OmniAuth.config.add_mock(:google_oauth2, { 
    :uid => '222222222222222222222', 
    :info => { 
    :email => "[email protected]", 
    :name => 'Someone' 
    } 
}) 


# Based on https://gist.github.com/375973 (from https://stackoverflow.com/a/3892401/111884) 
class SessionData 
    def initialize(cookies) 
    @cookies = cookies 
    @data = cookies['rack.session'] 
    if @data 
     @data = @data.unpack("m*").first 
     @data = Marshal.load(@data) 
    else 
     @data = {} 
    end 
    end 

    def [](key) 
    @data[key] 
    end 

    def []=(key, value) 
    @data[key] = value 
    session_data = Marshal.dump(@data) 
    session_data = [session_data].pack("m*") 
    @cookies.merge("rack.session=#{Rack::Utils.escape(session_data)}", URI.parse("//example.org//")) 
    raise "session variable not set" unless @cookies['rack.session'] == session_data 
    end 
end 

def login!(session) 
    get '/auth/google_oauth2/callback', nil, { "omniauth.auth" => OmniAuth.config.mock_auth[:google_oauth2] } 
    session['uid'] = last_request.session['uid'] 

    # Logged in user should have the same uid as login credentials 
    session['uid'].should == OmniAuth.config.mock_auth[:google_oauth2]['uid'] 
end 

# Based on Rack::Test::Session::follow_redirect! 
def follow_redirect_with_session_login!(session) 
    unless last_response.redirect? 
    raise Error.new("Last response was not a redirect. Cannot follow_redirect!") 
    end 

    get(last_response["Location"], {}, { "HTTP_REFERER" => last_request.url, "rack.session" => {"uid" => session['uid']} }) 
end 

def get_with_session_login(path) 
    get path, nil, {"rack.session" => {"uid" => session['uid']}} 
end 

rspec的示例代碼:

describe "Authentication:" do 

    def session 
    SessionData.new(rack_test_session.instance_variable_get(:@rack_mock_session).cookie_jar) 
    end 

    describe "Logging in as a new user" do 
    it "should create a new account with the user's name" do 
     login!(session) 
     last_request.session[:flash][:success].should include("Welcome") 

     get_with_session_login "/" 
     follow_redirect_with_session_login!(session) 
     last_response.body.should include("Someone") 
    end 
    end 
end 
相關問題