2014-03-29 57 views
0

我正在參加RoR教程(第9.4章)。當所有的rspec測試都應該變成綠色時,我就不能讓我的工作。我運行包的exec rspec的投機/和送四失敗,此錯誤:測試失敗RoR教程(9.4章)

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 

utilities.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: "[email protected]" 
     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: '[email protected]') } 

     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) { "[email protected]" } 
     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: "[email protected]") } 
     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 

user.r b

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+\-.][email protected][a-z\d\-]+(\.[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 

factories.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: "[email protected]", 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('[email protected]') LIMIT 1 
=> true 

irb(main):003:0> **user.errors** 
=> #<ActiveModel::Errors:0x49dd678 @base=#<User id: nil, name: "Person 1", email 
: "[email protected]", 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。也許這將有助於找到失敗的原因/

+0

您需要分享實際的代碼和測試,不僅僅是測試結果。 – 2014-03-29 09:06:19

+0

@GraemeMcLean Ok – detskai

+0

讓我們看看'app/models/user.rb' – yoppuyoppu

回答

1

其中end陳述在user_page_spec.rb是錯位的。 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"兩次,嵌套在自己的內部,雖然這不會是錯誤的原因;它只是重複一次測試。

1

如果我們看到spec/factories.rb中定義了factory :user這將會很好,因爲您已經以不同的方式定義了VALID_EMAIL_REGEX。

對於初學者來說,你可以恢復正則表達式狀態回到原來的:

VALID_EMAIL_REGEX = /\A[\w+\-.][email protected][a-z\d\-.]+\.[a-z]+\z/i 

看到它的驗證部分與factory :user工作。

並刪除第二個has_secure_password以保證安全。

+0

我刪除了第二個has_secure_password並更改了VALID_EMAIL_REGEX。但仍然有相同的4個故障。 – detskai

相關問題