测试注册并使用Capybara(Rails,RSpec,Devise)登录

时间:2017-07-19 18:53:45

标签: ruby-on-rails testing rspec devise capybara

我编写了以下功能规范来测试使用Devise的Rails 4.2.8应用程序中的注册,登录,密码恢复和帐户锁定行为。

测试工作正常。但是,我对Capybara来说比较新,所以我想了解如何提高可读性,可维护性,干燥度,速度,降低脆性等方面的建议。

此类电子邮件唯一性,密码强度等验证均在User型号规范中执行。因此,我没有在这里重新测试这些行为。

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

def login_via_form(email, password)
  expect(page).to have_current_url("/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 "/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 "/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 "/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 "/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 "/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 "/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 "/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 个答案:

答案 0 :(得分:1)

https://codereview.stackexchange.com/

可能会更好

那就是说,我对于open_email如何以某种方式神奇地设置current_email并不狂热。我希望该方法返回它,如果可能的话,你检查了该返回值;这可能是多线程应用程序或测试套件的问题。

您对网页上文字的期望非常脆弱。如果该副本中的任何一个发生更改,则还需要重新进行测试。就个人而言,我对此很好,但是如果您要么与半宽松的正则表达式匹配,或者将这些字符串放入翻译文件中,并且针对I18n.t('email.confirmation.message')进行检查,那么它可能会为您节省一些精力。

为了提高性能,您可能希望使用不使用login_via_form的登录方法,我认为Devise测试助手仍然包含直接为您设置登录会话的login_as。< / p>

总的来说,我认为这是一项伟大的工作。坚持下去!