ironsand
ironsand

Reputation: 15161

Rpsec check existence and value of a record

I want to test a existence of a User model attribute. So I write like this.

describe "Authentications" do
  it "sign up with twitter" do
    visit new_user_session_path
    expect { click_link "Sign up with Twitter"}.to change(User, :count).by(1)
  end
  describe "new user" do
    let(:new_user) { User.last }
    it "should have slug" do
      #new_user its(:slug) { should eq("foo") }
      new_user.slug should exist
    end
  end
end

First test passes, but second test fails with error like this.

  1) Authentications new user should have slug
     Failure/Error: new_user.slug should exist
     NoMethodError:
       "new user" does not respond to either #exist? or #exists?
     # ./spec/features/autentication_spec.rb:13:in `block (3 levels) in <top (required)>'

I think I'm calling method wrong way. How should I use it?

After all I want to check not only existence of it but also the value of it. But it fails also.

Upvotes: 1

Views: 2446

Answers (2)

Leo Correa
Leo Correa

Reputation: 19809

If you want to validate presence of a value you should use the method present? that Rails provides.

expect(new_user.slug).to be_present should work for what you want.

Upvotes: 8

Peter Alfvin
Peter Alfvin

Reputation: 29419

First of all, the failing expectation you have is equivalent to:

new_user.slug(subject.should(exist))

This is why your failure message refers to "new user", which is the description of our example and thus the implicit value of subject.

Presumably, you intended the should to have been applied to new_user.slug, in which case, you should have written:

new_user.slug.should exist

However, that will only exist if the value of new_user.slug has an exist? method defined on it (per https://www.relishapp.com/rspec/rspec-expectations/v/2-99/docs/built-in-matchers/exist-matcher), which strings do not.

If you want to test whether something is simply truthy, then you can use:

new_user.slug.should be

If you want to exclude false as a value, then you can use:

new_user.slug.should_not be_nil

The rest of this answer deals with a separate matter, which may or may not impact your test depending on whether or not you have a User in your database prior to the overall describe block being invoked.

Assuming you're operating with transactions on, the user created in your initial it block does not exist in the body of your subsequent describe, so User.first is going to return nil, which explains your errors.

If you want to check that your sign in changes the user count by one and use that sign in with a separate test, you can use a let expression as in the following:

describe "Authentications" do
  let(:sign_in) do
    visit new_user_session_path
    click_link "Sign up with Twitter"
  end
  it "sign up with twitter" do
    expect { sign_in }.to change(User, :count).by(1)
  end
  describe "new user" do
    let(:new_user) { User.last }
    before { sign_in }
    it "should have slug" do
      #new_user its(:slug) { should eq("foo") }
      new_user.slug should exist
    end
  end
end

If you want to combine these tests for purposes of understanding the slug failure, you can do so as follows:

describe "Authentications" do
  it "sign up with twitter" do
    visit new_user_session_path
    expect { click_link "Sign up with Twitter" }.to change(User, :count).by(1)
    User.last.slug should exist
  end
end

Upvotes: 1

Related Questions