2017-07-19 98 views
0

我編寫了以下功能規範,以測試在使用Devise的Rails 4.2.8應用程序中註冊,登錄,密碼恢復和帳戶鎖定行爲。測試註冊並使用Capybara(Rails,RSpec,Devise)登錄

測試工作。但是,我對水豚相對來說比較陌生,所以我想就如何提高他們的可讀性,可維護性,乾燥度,速度,降低脆弱性等方面提出建議。

驗證此類郵件的唯一性,密碼強度等在User型號規格上執行。因此,我沒有在這裏重新測試這些行爲。

# spec/features/user_registration_spec.rb 
require 'rails_helper' 

def login_via_form(email, password) 
    expect(page).to have_current_url("https://stackoverflow.com/users/sign_in") 
    fill_in "Email", with: email 
    fill_in "Password", with: password 
    click_button "Sign in" 
end 

RSpec::Matchers.define :be_logged_in do |user_first_name| 
    match do |page| 
    expect(page).to have_current_path "/" 
    expect(page).to have_content "Hello #{user_first_name}" 
    end 
    failure_message do |actual| 
    "expected the current path to be /, actual path is #{page.current_path}" \ 
    "\nexpected to find a 'Hello #{user_first_name}' in '#{page.text}'." 
    end 
end 

describe "User self-management", type: :feature, js: true do 
    let!(:user) { FactoryGirl.create(:user) } 
    let(:valid_attributes) { FactoryGirl.attributes_for(:user) } 

    it "registers a new user" do 
    visit "/" 

    click_link "Sign up" 

    fill_in "Email", with: valid_attributes[:email] 
    fill_in "Password", with: valid_attributes[:password] 
    fill_in "Password confirmation", with: valid_attributes[:password] 
    fill_in "First name", with: valid_attributes[:first_name] 
    fill_in "Last name", with: valid_attributes[:last_name] 
    select "United States", from: "Country" 
    select "New York", from: "State" 
    select "New York", from: "City" 
    fill_in "Sangha", with: "My Sangha" 
    fill_in "Phone number", with: "+1 212-555-0187" 
    fill_in "Facebook url", with: "http://www.facebook.com/johndoe" 
    click_button "Sign up" 

    # The user may only login *after* confirming her e-mail 
    expect(page).to have_content "A message with a confirmation link has been" \ 
     " sent to your email address. Please follow the link to activate your" \ 
     " account." 
    expect(page).to have_current_path "https://stackoverflow.com/users/sign_in" 

    # Find email sent to the given recipient and set the current_email variable 
    # Implemented by https://github.com/DockYard/capybara-email 
    open_email(valid_attributes[:email]) 
    expect(current_email.subject).to eq "Confirmation instructions" 
    current_email.click_link "Confirm my account" 

    expect(page).to have_content "Your email address has been successfully " \ 
           "confirmed." 

    login_via_form(valid_attributes[:email], 
        valid_attributes[:password]) 
    expect(page).to have_content "Signed in successfully." 
    expect(page).to be_logged_in(valid_attributes[:first_name]) 
    end 

    it "performs password recovery (creates a new password)" do 
    visit "https://stackoverflow.com/users/sign_in" 
    click_link "Forgot your password?" 
    fill_in "Email", with: user.email 
    click_button "Send me reset password instructions" 

    expect(page).to have_text "You will receive an email with instructions " \ 
           "on how to reset your password in a few minutes." 

    # Find email sent to the given recipient and set the current_email variable 
    open_email(user.email) 
    expect(current_email.subject).to eq "Reset password instructions" 
    current_email.click_link "Change my password" 

    fill_in "New password", with: valid_attributes[:password] 
    fill_in "Confirm new password", with: valid_attributes[:password] 
    click_button "Change my password" 

    expect(page).to have_content "Your password has been changed " \ 
           "successfully. You are now signed in." 
    expect(page).to be_logged_in(user.first_name) 

    open_email(user.email) 
    expect(current_email.subject).to eq "Password Changed" 
    expect(current_email.body). to have_text "We're contacting you to notify " \ 
     "you that your password has been changed." 
    end 

    describe "resend confirmation e-mail" do 
    context "with an already confirmed e-mail address" do 
     it "warns the user and does not send a new confirmation e-mail" do 
     # Our factory creates users with confirmed e-mails 
     visit "https://stackoverflow.com/users/sign_in" 
     click_link "Didn't receive confirmation instructions?" 
     fill_in "Email", with: user.email 
     expect { 
      click_button "Resend confirmation instructions" 
     }.not_to change(ActionMailer::Base.deliveries, :count) 
     expect(page).to have_text "Email was already confirmed" 
     end 
    end 

    context "with an unconfirmed e-mail address" do 
     it "sends a new confirmation e-mail" do 
     # Unconfirm user (our factory creates users with confirmed e-mails) 
     user.update(confirmed_at: nil) 

     visit "https://stackoverflow.com/users/sign_in" 
     click_link "Didn't receive confirmation instructions?" 
     fill_in "Email", with: user.email 
     click_button "Resend confirmation instructions" 

     expect(page).to have_text "You will receive an email with " \ 
      "instructions for how to confirm your email address in a few minutes." 

     open_email(user.email) 
     expect(current_email.subject).to eq "Confirmation instructions" 
     current_email.click_link "Confirm my account" 

     expect(page).to have_content "Your email address has been " \ 
      "successfully confirmed." 

     login_via_form(user.email, user.password) 
     expect(page).to have_content "Signed in successfully." 
     expect(page).to be_logged_in(user.first_name) 
     end 
    end 
    end 

    it "locks the account after 5 failed login attempts" do 
    visit "https://stackoverflow.com/users/sign_in" 

    3.times do 
     login_via_form(user.email, "bogus") 
     expect(page).to have_text "Invalid Email or password." 
    end 

    login_via_form(user.email, "bogus") 
    expect(page).to have_text "You have one more attempt before your " \ 
     "account is locked." 

    login_via_form(user.email, "bogus") 
    expect(page).to have_text "Your account is locked." 

    open_email(user.email) 
    expect(current_email.subject).to eq "Unlock instructions" 
    current_email.click_link "Unlock my account" 

    expect(page).to have_content "Your account has been unlocked " \ 
     "successfully. Please sign in to continue." 

    login_via_form(user.email, user.password) 
    expect(page).to have_content "Signed in successfully." 
    expect(page).to be_logged_in(user.first_name) 
    end 

    context "account is locked, didn't receive unlocking instructions" do 
    it "sends a new unlocking instructions e-mail" do 
     user.update(locked_at: DateTime.now) 

     visit "https://stackoverflow.com/users/sign_in" 
     click_link "Didn't receive unlock instructions?" 
     fill_in "Email", with: user.email 
     click_button "Resend unlock instructions" 

     expect(page).to have_text "You will receive an email with instructions " \ 
     "for how to unlock your account in a few minutes." 

     open_email(user.email) 
     expect(current_email.subject).to eq "Unlock instructions" 
     current_email.click_link "Unlock my account" 

     expect(page).to have_content "Your account has been unlocked " \ 
     "successfully. Please sign in to continue." 

     login_via_form(user.email, user.password) 
     expect(page).to have_content "Signed in successfully." 
     expect(page).to be_logged_in(user.first_name) 
    end 
    end 

    context "account is not locked, attempts to re-send unlocking instructions" do 
    it "warns the user and does not send a new confirmation e-mail" do 
     # Our factory creates users with confirmed e-mails 
     visit "https://stackoverflow.com/users/sign_in" 
     click_link "Didn't receive unlock instructions?" 
     fill_in "Email", with: user.email 
     expect { 
     click_button "Resend unlock instructions" 
     }.not_to change(ActionMailer::Base.deliveries, :count) 
     expect(page).to have_text "Email was not locked" 
    end 
    end 
end 

謝謝。

+1

注意:所有'期望{...}。不要改變...'可能實際上並沒有做任何事情。這是因爲'click_button'不能保證等待由按鈕點擊觸發的操作完成。爲了解決這個問題,可以在'expect {...}。not_to change..'塊中加入以下'have_text'期望值。 –

回答

1

這可能在https://codereview.stackexchange.com/

也就是說可以更好地接受,我不是野生open_email如何神奇地設置current_email。我寧願該方法返回它,並且如果可能的話,你檢查該返回值;這可能是多線程應用程序或測試套件的問題。

您對頁面文本的期望很脆弱。如果任何副本發生變化,測試也需要重新進行。就我個人而言,我可以這樣做,但如果您與半鬆散的正則表達式匹配,或者將這些字符串放入翻譯文件中,並且對照I18n.t('email.confirmation.message')進行檢查,它可以爲您節省一些工作量。

爲了提高性能,您可能希望使用不使用login_via_form的登錄方法,我認爲設計測試助手仍然包括login_as,它可以爲您直接設置登錄會話。

總體而言,我認爲這是很棒的工作。保持!

相關問題