轨道上的红宝石 - 测试 RoR 教程中的失败(第 9.4 章)



我正在学习RoR教程(第9.4章)。当所有的 rspec 测试都应该变成绿色时,我就是无法让我的测试工作。我运行捆绑执行 rspec spec/并得到四个失败,出现此错误:

Failures:
  1) User pages index signup page with valid information after saving the user
     Failure/Error: sign_in user
     NoMethodError:
       undefined method `email' for nil:NilClass
     # ./spec/support/utilities.rb:23:in `sign_in'
     # ./spec/requests/user_pages_spec.rb:12:in `block (3 levels) in <top (requi
red)>'
  2) User pages index signup page with valid information after saving the user
     Failure/Error: sign_in user
     NoMethodError:
       undefined method `email' for nil:NilClass
     # ./spec/support/utilities.rb:23:in `sign_in'
     # ./spec/requests/user_pages_spec.rb:12:in `block (3 levels) in <top (requi
red)>'
  3) User pages index signup page with valid information after saving the user
     Failure/Error: sign_in user
     NoMethodError:
       undefined method `email' for nil:NilClass
     # ./spec/support/utilities.rb:23:in `sign_in'
     # ./spec/requests/user_pages_spec.rb:12:in `block (3 levels) in <top (requi
red)>'
  4) Authentication signin with invalid information after visiting another page
     Failure/Error: it { should_not have_selector('div.alert.alert-error') }
       expected #has_selector?("div.alert.alert-error") to return false, got tru
e
     # ./spec/requests/authentication_pages_spec.rb:26:in `block (5 levels) in <
top (required)>'
Finished in 21.33 seconds
81 examples, 4 failures

实用程序.rb:

include ApplicationHelper
def valid_signin(user)
  fill_in "Email",    with: user.email
  fill_in "Password", with: user.password
  click_button "Sign in"
end
RSpec::Matchers.define :have_error_message do |message|
  match do |page|
    expect(page).to have_selector('div.alert.alert-error', text: message)
  end
end
def sign_in(user, options={})
  if options[:no_capybara]
    # Sign in when not using Capybara.
    remember_token = User.new_remember_token
    cookies[:remember_token] = remember_token
    user.update_attribute(:remember_token, User.encrypt(remember_token))
  else
    visit signin_path
    fill_in "Email",    with: user.email
    fill_in "Password", with: user.password
    click_button "Sign in"
  end
end

user_page_spec.rb:

require 'spec_helper'
describe "User pages" do
  subject { page }
  describe "index" do
    let(:user) { FactoryGirl.create(:user) }
    before do
      sign_in user
      visit users_path
    end
    it { should have_title('All users') }
    it { should have_content('All users') }
    describe "pagination" do
      before(:all) { 30.times { FactoryGirl.create(:user) } }
      after(:all)  { User.delete_all }
      it { should have_selector('div.pagination') }
      it "should list each user" do
        User.paginate(page: 1).each do |user|
          expect(page).to have_selector('li', text: user.name)
        end
      end
    end
   describe "delete links" do
      it { should_not have_link('delete') }
      describe "delete links" do
      it { should_not have_link('delete') }
      describe "as an admin user" do
        let(:admin) { FactoryGirl.create(:admin) }
        before do
          sign_in admin
          visit users_path
        end
        it { should have_link('delete', href: user_path(User.first)) }
        it "should be able to delete another user" do
          expect do
            click_link('delete', match: :first)
          end.to change(User, :count).by(-1)
        end
        it { should_not have_link('delete', href: user_path(admin)) }
      end
    end
  end

  describe "profile page" do
    let(:user) { FactoryGirl.create(:user) }
    before { visit user_path(user) }
    it { should have_content(user.name) }
    it { should have_title(user.name) }
  end
    describe "signup page" do
    before { visit signup_path }
    let(:submit) { "Create my account" }
    describe "with invalid information" do
      it "should not create a user" do
        expect { click_button submit }.not_to change(User, :count)
      end
    end
    describe "with valid information" do
      before do
        fill_in "Name",         with: "Example User"
        fill_in "Email",        with: "user@example.com"
        fill_in "Password",     with: "foobar"
        fill_in "Confirmation", with: "foobar"
      end
      it "should create a user" do
        expect { click_button submit }.to change(User, :count).by(1)
      end
      describe "after saving the user" do
        before { click_button submit }
        let(:user) { User.find_by(email: 'user@example.com') }
        it { should have_link('Sign out') }
        it { should have_title(user.name) }
        it { should have_selector('div.alert.alert-success', text: 'Welcome') }
      end
    end
  end
    describe "edit" do
    let(:user) { FactoryGirl.create(:user) }
    before do
      sign_in user
      visit edit_user_path(user)
    end
    describe "page" do
      it { should have_content("Update your profile") }
      it { should have_title("Edit user") }
      it { should have_link('change', href: 'http://gravatar.com/emails') }
    end
    describe "with valid information" do
      let(:new_name)  { "New Name" }
      let(:new_email) { "new@example.com" }
      before do
        fill_in "Name",             with: new_name
        fill_in "Email",            with: new_email
        fill_in "Password",         with: user.password
        fill_in "Confirm Password", with: user.password
        click_button "Save changes"
      end
      it { should have_title(new_name) }
      it { should have_selector('div.alert.alert-success') }
      it { should have_link('Sign out', href: signout_path) }
      specify { expect(user.reload.name).to  eq new_name }
      specify { expect(user.reload.email).to eq new_email }
    end
    end
end
end

authentication_pages_spec.rb:

require 'spec_helper'
describe "Authentication" do
  subject { page }
  describe "signin page" do
    before { visit signin_path }
    it { should have_content('Sign in') }
    it { should have_title('Sign in') }
  end
describe "signin" do
    before { visit signin_path }
    describe "with invalid information" do
      before { click_button "Sign in" }
      it { should have_title('Sign in') }
      it { should have_selector('div.alert.alert-error') }
      describe "after visiting another page" do
        before { click_link "Home" }
        it { should_not have_selector('div.alert.alert-error') }
      end
    end

  describe "with valid information" do
      let(:user) { FactoryGirl.create(:user) }
      before { sign_in user }
      it { should have_title(user.name) }
      it { should have_link('Users',       href: users_path) }
      it { should have_link('Profile',     href: user_path(user)) }
      it { should have_link('Settings',    href: edit_user_path(user)) }
      it { should have_link('Sign out',    href: signout_path) }
      it { should_not have_link('Sign in', href: signin_path) }

    describe "follower by signout" do
      before {click_link "Sign out"}
      it {should have_link('Sign in')}
      end
    end
  end
 describe "authorization" do
    describe "for non-signed-in users" do
      let(:user) { FactoryGirl.create(:user) }
      describe "when attempting to visit a protected page" do
        before do
          visit edit_user_path(user)
          fill_in "Email", with: user.email
          fill_in "Password", with: user.password
          click_button "Sign in"
        end
        describe "after signing in" do
          it "should render the desired protected page" do
            expect(page).to have_title('Edit user')
          end
        end
      end
      describe "in the Users controller" do
        describe "visiting the edit page" do
          before { visit edit_user_path(user) }
          it { should have_title('Sign in') }
        end

        describe "submitting to the update action" do
          before { patch user_path(user) }
          specify { expect(response).to redirect_to(signin_path) }
        end
      end
        describe "visiting the user index" do
          before { visit users_path }
          it { should have_title('Sign in') }
        end
    end
    describe "as wrong user" do
      let(:user) { FactoryGirl.create(:user) }
      let(:wrong_user) { FactoryGirl.create(:user, email: "wrong@example.com") }
      before { sign_in user, no_capybara: true }
      describe "submitting a GET request to the Users#edit action" do
        before { get edit_user_path(wrong_user) }
        specify { expect(response.body).not_to match(full_title('Edit user')) }
        specify { expect(response).to redirect_to(root_url) }
      end
      describe "submitting a PATCH request to the Users#update action" do
        before { patch user_path(wrong_user) }
        specify { expect(response).to redirect_to(root_url) }
      end
    end
   describe "as non-admin user" do
      let(:user) { FactoryGirl.create(:user) }
      let(:non_admin) { FactoryGirl.create(:user) }
      before { sign_in non_admin, no_capybara: true }
      describe "submitting a DELETE request to the Users#destroy action" do
        before { delete user_path(user) }
        specify { expect(response).to redirect_to(root_url) }
      end
    end
  end
end

用户.rb

class User < ActiveRecord::Base
  has_secure_password
  before_save { self.email = email.downcase }
  before_create :create_remember_token
  validates :name, presence: true, length: { maximum: 50 }
  VALID_EMAIL_REGEX = /A[w+-.]+@[a-zd-]+(.[a-z]+)*.[a-z]+z/i
  validates :email, presence: true, format: { with: VALID_EMAIL_REGEX },
                    uniqueness: { case_sensitive: false }
  has_secure_password
  validates :password, length: { minimum: 6 }
  def User.new_remember_token
    SecureRandom.urlsafe_base64
  end
  def User.encrypt(token)
    Digest::SHA1.hexdigest(token.to_s)
  end
  private
    def create_remember_token
      self.remember_token = User.encrypt(User.new_remember_token)
    end
end

工厂.rb:

FactoryGirl.define do
  factory :user do
    sequence(:name)  { |n| "Person #{n}" }
    sequence(:email) { |n| "person_#{n}@example.com"}
    password "foobar"
    password_confirmation "foobar"
    factory :admin do
      admin true
    end
  end
end

导轨控制台测试:

irb(main):001:0> **user = FactoryGirl.build(:user)**
=> #<User id: nil, name: "Person 1", email: "person_1@example.com", created_at:
nil, updated_at: nil, password_digest: "$2a$04$LiRdaarU6QaX9PJa1uFjE.5e44SYRsmy1
OMY8A4EKZow...", remember_token: nil, admin: false>
irb(main):002:0> **user.valid?**
  User Exists (1.0ms)  SELECT 1 AS one FROM "users" WHERE LOWER("users"."email")
 = LOWER('person_1@example.com') LIMIT 1
=> true
irb(main):003:0> **user.errors**
=> #<ActiveModel::Errors:0x49dd678 @base=#<User id: nil, name: "Person 1", email
: "person_1@example.com", created_at: nil, updated_at: nil, password_digest: "$2
a$04$LiRdaarU6QaX9PJa1uFjE.5e44SYRsmy1OMY8A4EKZow...", remember_token: nil, admi
n: false>, @messages={}>

我更改了 users_controller.rb,现在我只有 3 (1-3) 次失败

users_controller.rb:

          class UsersController < ApplicationController
  before_action :signed_in_user, only: [:index, :edit, :update, :destroy]
  before_action :correct_user,   only: [:edit, :update]
  before_action :admin_user,     only: :destroy
  def index
    @users = User.paginate(page: params[:page])
  end
  def show
    @user = User.find(params[:id])
  end
  def new
    @user = User.new
  end
   def create
    @user = User.new(user_params)
    if @user.save
      sign_in @user
      flash[:success] = "Welcome to the Sample App!"
      redirect_to @user
    else
      render 'new'
    end
  end
   def edit
   end
  def update
    if @user.update_attributes(user_params)
      flash[:success] = "Profile updated"
      redirect_to @user 
      # Handle a successful update.
    else
      render 'edit'
    end
  end
  def destroy
    User.find(params[:id]).destroy
    flash[:success] = "User deleted."
    redirect_to users_url
  end
  private
  def user_params
      params.require(:user).permit(:name, :email, :password,
                                   :password_confirmation)
    end
    # Before filters
    def signed_in_user
      unless signed_in?
        store_location
        redirect_to signin_url, notice: "Please sign in."
      end
    end

    def correct_user
      @user = User.find(params[:id])
      redirect_to(root_url) unless current_user?(@user)
    end

  def admin_user
      redirect_to(root_url) unless current_user.admin?
    end
end

实际项目版本 - https://tranquil-waters-6116.herokuapp.com .也许这将有助于找到失败的原因/

如果我们也能看到factory :user在您的spec/factories.rb中是如何定义的,那就太好了,因为您对VALID_EMAIL_REGEX的定义不同。

对于初学者,您可以将正则表达式条件恢复为原始条件:

  VALID_EMAIL_REGEX = /A[w+-.]+@[a-zd-.]+.[a-z]+z/i

确保验证部分与您的factory :user一起工作。

为了安全起见,请移除第二has_secure_password

user_page_spec.rb 中的end语句之一放错了位置。 describe "index"块应在 describe "profile page" 之前结束。

describe "index" do
  ...
  describe "pagination" do
    ...
  end
  describe "delete links" do
    ...
  end
end
describe "profile page" do
  ...
end
describe "signup page" do
  ...
end 
etc.
注册

适用于注册的新用户,因此测试不应让用户先登录。

顺便说一句,你也有两次describe "delete links",嵌套在自身内部,尽管这不是错误的原因;它只是重复一个测试。

相关内容

  • 没有找到相关文章

最新更新