29

How do I write a spec to check if a new record is created in the database after a successful user signup? Using rspec in Rails 4 with capybara, factorygirl, and database_cleaner gems.

I feel like this situation is common and an answer should be easy to find, but I haven't been able to find one here or via google.

Rimian
  • 36,864
  • 16
  • 117
  • 117
jeffhale
  • 3,759
  • 7
  • 40
  • 56

3 Answers3

51

You probably want the change matcher

You will do something like:

expect { 
  post :create, :user => {:user => :attributes }
}.to change { User.count }

or

expect { 
  post :create, :user => {:user => :attributes }
}.to change(User, :count)

This code says:

expect that running this first block of code to change the value I get when I run that block of code

and is functionally equivalent to writing:

before_count = User.count
post :create, :user => {:user => :attributes }
expect(User.count).not_to eq(before_count)
Rimian
  • 36,864
  • 16
  • 117
  • 117
Taryn East
  • 27,486
  • 9
  • 86
  • 108
  • Though I agree, what your spec actually looks like (if it's a feature spec) will probably be more like what the other guy said - with the expect around the sign-up button click. My example is more like a controller-spec, but gives you an overview of how the change-matcher works in general ;) – Taryn East May 11 '15 at 02:38
  • This doesn't help to check if a present object was successfully updated. In the case the object was present in the database previous to changes, it will not change the count. – Ekkstein Mar 29 '17 at 15:43
  • But what if i need to create few records? Like create User, Address, and Item in the same time? – Piotr Galas Jun 22 '17 at 08:11
  • @PiotrGalas - that's often a good reason for two tests, but there's also a way to chain multiple `change` calls... still, this is a different question than the original one ;) – Taryn East Jun 24 '17 at 03:23
  • 1
    @TarynEast you are right, it is not a part of this quertion. I found question and solution here https://stackoverflow.com/questions/13616631/is-it-possible-for-rspec-to-expect-change-in-two-tables – Piotr Galas Jun 24 '17 at 12:21
12

Since you mentioned capybara so I'm gonna assume you want a feature spec, of course you're going to need to change the details to match your application

require 'rails_helper'
feature 'Users' do # or whatever
  scenario 'creating an account' do
    visit root_path
    click_link 'Sign Up'
    fill_in 'Name', with: 'User 1'
    fill_in 'Email', with: 'email@domain.com'
    fill_in 'Password', with: 'password'
    expect{
      click_button 'Sign up'
    }.to change(User, :count).by(1)
  end
end
Mohammad AbuShady
  • 40,884
  • 11
  • 78
  • 89
6

As you are using factorygirl, you can used factorygirl to create test data

FactoryGirl.define do
 factory :user do
  sequence(:name) { |n| "user #{n}" }
  sequence(:email) { |n| "sampleuser+#{n}@sampleuser.com" }
  password '123456789'
end end

you can used 'FactoryGirl.create(:user)' whenever you want a user record.

To test you can write spec like this

expect{
      post :create, {user: FactoryGirl.attributes_for(:user)}
    }.to change(User, :count).by(1)
user3395363
  • 125
  • 6