2017-07-19 2 views
0

J'ai écrit la spécification de fonctionnalité suivante pour tester l'inscription, la connexion, la récupération de mot de passe et le comportement de verrouillage de compte dans une application Rails 4.2.8 avec Devise.Tester et vous connecter avec Capybara (Rails, RSpec, Devise)

Les tests fonctionnent. Cependant, je suis relativement nouveau à Capybara, donc je voudrais vos suggestions concernant la façon d'améliorer leur lisibilité, maintenabilité, DRYness, vitesse, réduire la fragilité, etc

Validations telles unicité de l'e-mail, la force du mot de passe et ainsi de suite effectuée à la spécification de modèle User. Par conséquent, je n'ai pas re-testé ces comportements ici.

# 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 

Merci.

+1

Remarque: Tout ce que vous attendez de ... {...} .not_to ... ne fait peut-être rien. C'est parce que click_button ne garantit pas que les actions déclenchées par le bouton click finiront. Pour corriger cela, déplacez l'attente 'have_text' suivante dans le bloc' expect {...}. Not_to change..'. –

Répondre

1

Cela pourrait être mieux reçu à https://codereview.stackexchange.com/

Cela dit, je ne suis pas sauvage sur la façon dont open_email en quelque sorte par magie ensembles current_email. Je préférerais que cette méthode l'ait renvoyé, et vous avez vérifié par rapport à cette valeur de retour si possible; Cela peut poser un problème avec les applications multithread ou les suites de tests.

Vos attentes de texte sur la page sont assez cassantes. Si l'une de ces copies change, le test devra également être retravaillé. Personnellement, je suis OK avec ceci, mais cela pourrait potentiellement vous épargner un peu d'effort si vous correspondiez à une expression régulière semi-laxiste, ou mettez ces chaînes dans un fichier de traduction, et vérifié par rapport à I18n.t('email.confirmation.message').

Pour améliorer les performances, vous pouvez utiliser une méthode de connexion qui n'utilise pas login_via_form, je pense que les aides de test Devise comprennent toujours login_as qui définit directement une session connectée pour vous.

Dans l'ensemble, je pense que c'est un excellent travail. Continuez!