Reputation: 217
I have my problems with my rspec tests particularly with the has_content method. Here are some of the code snippets. I have been following the Ruby on Rails tutorials from Michael Hartl, in case you don't know.
has_content always returns false even though the microposts have set its respective content.
resulting test
Run options: include {:line_numbers=>[61]}
..FFF
Failures:
1) User pages profile page microposts should have content 0
Failure/Error: it { should have_content(user.microposts.count) }
expected #has_content?(0) to return true, got false
# ./spec/requests/user_pages_spec.rb:72:in `block (4 levels) in <top (required)>'
2) User pages profile page microposts should have content "Foo Bar"
Failure/Error: it { should have_content(m2.content) }
expected #has_content?("Foo Bar") to return true, got false
# ./spec/requests/user_pages_spec.rb:71:in `block (4 levels) in <top (required)>'
3) User pages profile page microposts should have content "Lorem Ipsum"
Failure/Error: it { should have_content(m1.content) }
expected #has_content?("Lorem Ipsum") to return true, got false
# ./spec/requests/user_pages_spec.rb:70:in `block (4 levels) in <top (required)>'
Finished in 0.74407 seconds
5 examples, 3 failures
Failed examples:
rspec ./spec/requests/user_pages_spec.rb:72 # User pages profile page microposts should have content 0
rspec ./spec/requests/user_pages_spec.rb:71 # User pages profile page microposts should have content "Foo Bar"
rspec ./spec/requests/user_pages_spec.rb:70 # User pages profile page microposts should have content "Lorem Ipsum"
Randomized with seed 43497
[Finished in 1.3s with exit code 1]
user_pages_spec.rb
describe "profile page" do
let(:user) { FactoryGirl.create(:user) }
let(:m1) { FactoryGirl.create(:micropost, user: user, content: "Lorem Ipsum") }
let(:m2) { FactoryGirl.create(:micropost, user: user, content: "Foo Bar") }
before { visit user_path(user) }
it { should have_selector('h1', text: user.name) }
it { should have_title(full_title(user.name)) }
describe "microposts" do
it { should have_content(m1.content) }
it { should have_content(m2.content) }
it { should have_content(user.microposts.count) }
end
end
show.hml.erb
<% provide(:title, @user.name) %>
<div class='row'>
<aside class='col-md-4'>
<section>
<h1>
<%= gravatar_for @user, size: 50 %>
<%= @user.name %>
</h1>
</section>
</aside>
<div class="col-md-8">
<% if @user.microposts.any? %>
<h3>Microposts (<%= @user.microposts.count %>)</h3>.
<ol class="microposts">
<%= render @microposts %>
</ol>
<% end %>
</div>
</div>
_micropost.html.erb
<li>
<span class="content">
<%= micropost.content %>
</span>
<span class="timestamp">
Posted <%= time_ago_in_words(micropost.created_at) %>
</span>
</li>
micropost.erb
class Micropost < ActiveRecord::Base
attr_accessible :content
belongs_to :user
validates :user_id, presence: true
validates :content, presence: true, length: { maximum: 140 }
default_scope { order('microposts.created_at DESC') }
end
user.rb
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation
has_secure_password
has_many :microposts, dependent: :destroy
# remaning lines are for validation
end
===EDIT (answer to problem)===
I used let! instead to force the method's invocation before each example.
let!(:m1) { FactoryGirl.create(:micropost, user: user, content: "Lorem Ipsum") }
let!(:m2) { FactoryGirl.create(:micropost, user: user, content: "Foo Bar") }
Upvotes: 0
Views: 761
Reputation: 44675
let
method defines a method with given block, so every time you call user
you create a new one, and every time you call m1
or m2
you create new micropost with a new user. Instead do:
before(:each) do
@user = FactoryGirl.create(:user)
@m1 = FactoryGirl.create(:micropost, user: user, content: "Lorem Ipsum")
@m2 = FactoryGirl.create(:micropost, user: user, content: "Foo Bar")
visit user_path(@user)
end
// Use the instance variables in your tests, or wrap them in methods:
let(:user) { @user }
let(:m1) { @m2 }
let(:m2) { @m1 }
Upvotes: 1