2011-07-07 65 views
12

我正在使用Rails 3.1.0.rc4,我正在與水豚的新牛排般的DSL和Rspec(使用設計認證)進行集成測試Rails - 集成測試和Capybara丟失會話 - CSRF相關?

我遇到的問題是,當我跑一個集成測試,來自水豚的機架測試驅動程序似乎完全失去了用戶的登錄會話,事實上,該會話似乎只是完全清除。

經過幾天的調試,我完全喪失了原因。通過中間件堆棧一行接一行,我相信我已經排除了這個問題,因爲ActiveRecord::SessionStore正在導致這個問題。我已閱讀here,如果Rails將無法驗證CSRF令牌,則會清除會話,這使我相信我的某些配置錯誤,並且出於某種原因,這一個測試未正確驗證CSRF令牌。

這是在我的session_store.rb在/初始化目錄:

MyApp::Application.config.session_store :active_record_store 

有誰誰在軌知道CSRF保護對爲什麼這可能會發生的任何線索?

另外,這裏有一些事情需要注意:

  • 我想實際測試的事情的作品在瀏覽器本身,僅這一項測試丟棄會話
  • 會議似乎得到在將動作url提交給另一個服務器的表單提交後丟棄。我正在使用VCR gem來捕獲測試中對這個外部服務器的請求/響應,雖然我認爲我已經將外部請求作爲問題來處理,但這可能與CSRF令牌沒有進行身份驗證有直接關係,從而清除會話。
  • 涉及使用會話登錄/其他測試不會放棄會話

誰能給我任何線索,什麼是究竟怎麼回事,爲什麼一個測試似乎只是隨意放棄自己的會話和失敗包在我身上?我已經做了很多調試,並嘗試了所有我能想到的事情。

+0

我有同樣的問題... ARGH ... – Lichtamberg

回答

20

我是新來的水豚,我也有類似的問題。

我試圖登錄用戶做這樣的事情:

post user_session_path, :user => {:email => user.email, :password => 'superpassword'} 

,那就是好的工作,直到我試圖做一些與水豚,比如訪問一個頁面,只是測試,如果用戶正在登錄在這個簡單的測試不及格:

visit root_path 
page.should have_content("logout") #if the user is logged in then the logout link should be present 

起初我還以爲是水豚清除會話,但我錯了。我花了一些時間才意識到的事情是,駕駛水豚使用處理自己的會話,所以,從水豚的角度來看,我的用戶從未登錄。要做到這一點,你必須這樣做

page.driver.post user_session_path, :user => {:email => user.email, :password => 'superpassword'} 

不知道這是你的情況,但希望有所幫助。

+0

謝謝ariera。這對我有用! – John

+0

謝謝,ariera!也適用於我。好的偵察。 – evanrmurphy

+2

它似乎停止在後來的水豚工作。我有一些像前一個版本一樣好的東西。現在,我升級到2.1,它以這種方式失敗。鑑於這個答案的日期,它可能是自從水豚以來一直這樣工作1.很好的解釋! – froderik

7

做的手工方式很簡單:

it "does something after login" do 
    password = "secretpass" 
    user = Factory(:user, :password => password) 
    visit login_path 
    fill_in "Email", :with => user.email 
    fill_in "Password", :with => password 
    click_button "Log in" 
    visit # somewhere else and do something 
end 

然後就可以打破這種伸到功能在你的「spec_helper.rb」:

# at the bottom of 'spec_helper.rb' 
def make_user_and_login 
    password = "secretpass" 
    @user = Factory(:user, :password => password) 
    visit login_path 
    fill_in "Email", :with => @user.email 
    fill_in "Password", :with => password 
    click_button "Log in" 
end 

,並在任何使用它你的測試(可能要求規格):

it "does something after login" do 
    make_user_and_login 
    # now test something that requires a logged in user 
    # you have access to the @user instance variable 
end 
0

這可能是一個長鏡頭,但我相信,我們在一個糟糕的狀態後,結束了click_button 'Sign in'並立即致電visit elsewhere

我的理論是當我們點擊按鈕時,請求還沒有完成,我們通過訪問另一條路徑來殺死它。

從水豚文檔:

當發出到DSL指令,例如:

click_link('foo') click_link('bar') expect(page).to have_content('baz')

若點擊FOO鏈路上觸發異步過程,如Ajax請求,當完成時會將條形鏈接添加到頁面,點擊條形鏈接將會失敗,因爲該鏈接尚不存在。 然而水豚很聰明,在放棄並拋出錯誤之前,可以在短時間內重新找到鏈接。

如果是這種情況,解決方法很簡單:給水豚一些東西尋找,讓它等到請求完成。這可以簡單如添加:

expect(page).to have_text('Signed in as [email protected]')

2

我能夠在配置/初始化/ test.rb

# Disable request forgery protection in test environment 
config.action_controller.allow_forgery_protection = true 

在此之前,該CSRF <meta>這個值設置爲true來解決這個錯誤標籤不打印到<head>。改變這個值後,他們終於出現。