Reputation: 15161
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
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
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