2017-07-19 62 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,它可以为您直接设置登录会话。

总体而言,我认为这是很棒的工作。保持!

相关问题