Search code examples
ruby-on-rails-4deviserspec-railsrspec3

Testing custom devise registration controller update action with Rspec


I followed this devise wiki documentation on how to write a custom update action for the registration controller when you want to allow users to edit their account without providing their passwords except if changing their passwords themselves. Devise Wiki - How to Allow Users to Edit Account Without Providing a Password.

However, I can't figure out what's missing in my Rspec test to make it pass. Here are the relevant code snippets:

app/controllers/registrations_controller.rb

def update
  @user = User.find(current_user.id)

  successfully_updated = if needs_password?(@user, params)
    @user.update_with_password(devise_parameter_sanitizer.sanitize(:account_update))
  else
    # remove the virtual current_password attribute
    # update_without_password doesn't know how to ignore it
    params[:user].delete(:current_password)
    @user.update_without_password(devise_parameter_sanitizer.sanitize(:account_update))
  end

  if successfully_updated
    set_flash_message :notice, :updated
    # Sign in the user bypassing validation in case their password changed
    sign_in @user, :bypass => true
    redirect_to users_path
  else
    render "edit"
  end
end

spec/factories/users.rb

FactoryGirl.define do
  factory :user do
    email         { Faker::Internet.email }
    password      'XXXXXXXXX'
    first_name    { Faker::Name.first_name }
    middle_name   { Faker::Name.first_name }
    last_name     { Faker::Name.last_name }
  end
end

spec/controllers/registrations_controller_spec.rb

describe "PUT #update" do
  login_pcp

  let(:user) { FactoryGirl.create(:user, first_name: 'Tom') }

  it "changes user attributes" do
    attrs = FactoryGirl.attributes_for(:user, first_name: 'Jerry')
    attrs.delete(:password)
    put :update, user: attrs
    user.reload
    assigns[:user].should_not be_new_record
    expect(user.first_name).to eq 'Jerry'
    expect(flash[:notice]).to eq 'You updated your account successfully.'
  end
end

When I run the spec I get the following error:

Failures:

1) RegistrationsController PUT #update changes user attributes
   Failure/Error: expect(user.first_name).to eq 'Jerry'

   expected: "Jerry"
        got: "Tom"

   (compared using ==)
 # ./spec/controllers/registrations_controller_spec.rb:55:in `block (3 levels) in <top (required)>'

For some reason, it's not saving the update. I'm not sure if a password should be entered in order for the update to take place? Any help would be appreciated. Thanks!


Solution

  • The test now looks like this and it passes:

    describe "PUT #update" do
      before :each do
        @request.env['devise.mapping'] = Devise.mappings[:user]
        user_tom = FactoryGirl.create(:user, email: '[email protected]')
        sign_in user_tom
      end
    
      it "changes user attributes" do
        put :update, user: { email: '[email protected]' }
        subject.current_user.reload
        assigns[:user].should_not be_new_record
        expect(subject.current_user.email).to eq '[email protected]'
        expect(flash[:notice]).to eq 'You updated your account successfully.'
      end
    end