Hartl tutorial chap. 9.3.3. pagination test fail - testing

I would appreciate any help why my test is failing. I am doing it based on Michael Hartl tutorial and I tried almost everything and read a lot of about it, but still clueless.
Tahnks
My test:
describe "pagination" do
before(:all) do
sign_in FactoryGirl.create(:user)
30.times { FactoryGirl.create(:user) }
visit users_path
end
after(:all) { User.delete_all }
it 'has the right div' do
page.should have_selector('div.pagination')
end
it "should list each user" do
User.paginate(page: 1).each do |user|
expect{page}.to have_selector('li', text: user.username)
end
end
My view:
<h1>Všichni uživatelé</h1>
<%= will_paginate %>
<ul class="users">
<% #users.each do |user| %>
<li>
<%= gravatar_for user%>
<%= link_to user.username, user %>
</li>
<% end %>
</ul>
<%= will_paginate(:renderer => BootstrapPagination::Rails)%>
My controller:
def index
#users = User.paginate(page: params[:page])
end
My error:
1) User pages index pagination should list each user
Failure/Error: expect{page}.to have_selector('li', text: user.username)
expected css "li" with text "Person 44" to return something
# ./spec/requests/user_pages_spec.rb:122:in `block (5 levels) in <top (required)>'
# ./spec/requests/user_pages_spec.rb:121:in `block (4 levels) in <top (required)>'

I think the line:
expect{page}.to have_selector('li', text: user.username)
Should be:
expect{page}.to have_selector('li', text: user.user.name)

Related

Rspec issues with Devise

In my tickets_controller.rb:
def create
#ticket = #project.tickets.build(ticket_params)
#ticket.author = current_user
if #ticket.save
flash[:notice] = "Ticket has been created."
redirect_to [#project, #ticket]
else
flash.now[:alert] = "Ticket has not been created."
render "new"
end
end
So I assumed, I should be OK to pass the test, but it's giving me the errors below.
I'm under impression it's not invoking the email address from current_user.email...
The repo here https://github.com/tenzan/ticketee.
Deployed version here https://github.com/tenzan/ticketee
$ rspec spec/features/creating_tickets_spec.rb
...F
Failures:
1) Users can create new tickets with valid attributes
Failure/Error: expect(page).to have_content "Author: #{user.email}"
expected to find text "Author: test4#example.com" in "Internet Explorer Non-standards compliance My pages are ugly!"
# ./spec/features/creating_tickets_spec.rb:36:in `block (3 levels) in <top (required)>'
# ./spec/features/creating_tickets_spec.rb:35:in `block (2 levels) in <top (required)>'
Finished in 0.64558 seconds (files took 1.3 seconds to load)
4 examples, 1 failure
Failed examples:
rspec ./spec/features/creating_tickets_spec.rb:30 # Users can create new tickets with valid attributes
UPDATE 1:
show.html.erb for ticket:
<header>
<h2><%= #ticket.name %></h2>
<ul class="actions">
<li><%= link_to "Edit Ticket", [:edit, #project, #ticket],
class: "edit" %></li>
<li><%= link_to "Delete Ticket", [#project, #ticket], method: :delete,
data: { confirm: "Are you sure you want to delete this ticket?"},
class: "delete" %></li>
</ul>
</header>
<table id="attributes">
<tr>
<th>Author: </th>
<td><%= #ticket.author.email %></td>
</tr>
<tr>
<th>Created: </th>
<td><%= time_ago_in_words(#ticket.created_at) %> ago</td>
</tr>
</table>
<div id="ticket">
<header>
<h1><%= #project.name %></h1>
</header>
<header>
<h2><%= #ticket.name %></h2>
</header>
<%= simple_format(#ticket.description) %>
</div>
creating_tickets_specs.rb:
require 'rails_helper'
RSpec.feature 'Users can create new tickets' do
let(:user) { FactoryGirl.create(:user) }
before do
login_as(user)
project = FactoryGirl.create(:project, name: "Internet Explorer")
visit project_path(project)
click_link "New Ticket"
end
scenario "with valid attributes" do
fill_in "Name", with: "Non-standards compliance"
fill_in "Description", with: "My pages are ugly!"
click_button "Create Ticket"
expect(page).to have_content "Ticket has been created."
within("#ticket") do
expect(page).to have_content "Author: #{user.email}"
end
end
scenario "when providing invalid attributes" do
click_button "Create Ticket"
expect(page).to have_content "Ticket has not been created."
expect(page).to have_content "Name can't be blank"
expect(page).to have_content "Description can't be blank"
end
scenario "with an invalid description" do
fill_in "Name", with: "Non-standards compliance"
fill_in "Description", with: "It sucks"
click_button "Create Ticket"
expect(page).to have_content "Ticket has not been created."
expect(page).to have_content "Description is too short"
end
end
A couple things
After you set author on ticket, are you calling save?
What is in the show template where it's blowing up?
Typically I would write your controller code as:
current_user.tickets.create ticket_params
Which, assuming the relationships are set up correctly, will automatically set up the relationships as you would expect.
Rspec was looking for "Author: test4#example.com" within ticket tag as per within("#ticket") as described in the creating_tickets_spec.rb, but in my case it was out of that scope.
So, putting it inside solved the issue.

Rspec test describing listing items on index failing

Rspec/TDD beginner. I have a spec that is failing and I don't know why. Everything works in the browser as it should. I am using Kaminari for pagination, which defaults to 25 items per page.
spec:
describe "Question Pages" do
subject { page }
describe "index page" do
before { visit questions_path }
before { 25.times { FactoryGirl.create(:question) } }
after { Question.delete_all }
it { should have_selector('h1', 'All Questions') }
it "should list the questions" do
Question.page(1).each do |question|
page.should have_link(question.title, href: question_path(question))
end
end
end
end
failure:
1) Question Pages index page should list the questions
Failure/Error: page.should have_link(question.title, href: question_path(question))
Capybara::ExpectationNotMet:
expected to find link "Lorem Ipsum 33" but there were no matches
# ./spec/features/question_pages_spec.rb:17:in `block (4 levels) in <top (required)>'
# ./spec/features/question_pages_spec.rb:16:in `block (3 levels) in <top (required)>'
Why is it failing on item number 33 when I told it to make 25?
factory:
FactoryGirl.define do
factory :question do
sequence(:title) { |i| "Lorem Ipsum #{i}" }
body "Dolor sit amet"
passed false
end
end
view:
<h1>All Questions</h1>
<%= paginate #questions %>
<ul class="questions">
<% #questions.each do |question| %>
<li>
<section class="question_<%= question.id %> clearfix">
<h2><%= link_to truncate(question.title, length: 62), question_path(question) %></h2>
<p><%= truncate(question.body, length: 70) %></p>
</li>
<% end %>
</ul>
controller:
class QuestionsController < ApplicationController
def index
#questions = Question.page(params[:page])
end
end
ruby 1.9.3p429, rails 3.2.13, rspec-rails 2.13.1, capybara 2.1.0, kaminari 0.14.1, faker 1.0.1, factory_girl_rails 4.1.0
can you ensure that you are creating factories before visit ?
Maybe something like instead of
before { visit questions_path }
before { 25.times { FactoryGirl.create(:question) } }
that
before do
25.times { FactoryGirl.create(:question) }
visit questions_path
end
If it will not help maybe you can display content of page?
puts page.inspect

No Method Error for "comments", can't find and correct the nil value to make the comment post

I'm relatively new to rails and am trying to pull off my first polymorphic association with comments.
I am running rails 3.2.3
Edit - When I try to post a comment, my log is returning this error:
Started POST "/comments" for 127.0.0.1 at 2012-05-20 13:17:38 -0700
Processing by CommentsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"SOLcF71+WpfNLtpBFpz2qOZVaqcVCHL2AVZWwM2w0C4=", "comment"=>{"text"=>"Test this comment"}, "commit"=>"Create Comment"}
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = 101 LIMIT 1
Completed 500 Internal Server Error in 126ms
NoMethodError (undefined method `Comment' for nil:NilClass):
app/controllers/comments_controller.rb:13:in `create'
I have tried out many different solutions offered on SO and elsewhere, including the answer from Jordan below, due, I'm sure, to my own inexperience, but have been unable to resolve the error.
The trace calls out line 13 in the Comments Controller and I commented after that line below to mark the error:
class CommentsController < ApplicationController
def index
#commentable = find_commentable
#comments = #commentable.comments
end
def new
#post = Post.find(params[:post_id])
end
def create
#commentable = find_commentable
#comment = #commentable.comments.build(params[:comment]) #<<<<LINE 13
if #comment.save
flash[:notice] = "Successfully created comment."
redirect_to :id => nil
else
render :action => 'new'
end
end
private
def find_commentable
params.each do |name, value|
if name =~ /(.+)_id$/
return $1.classify.constantize.find(value)
end
end
nil
end
end
Posts Controller:
def show
#post = Post.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render :json => #post }
end
end
Comment template (in post show)
<ul id="comments">
<% if #comments %>
<h2>Comments</h2>
<% #comments.each do |comment| %>
<li><%= comment.text %></li>
<% end %>
<% else %>
<h2>Comment:</h2>
<% end %>
</ul>
<%= simple_form_for [#commentable,Comment.new], :html => { :class => 'form-horizontal', :multipart => true } do |f| %>
<fieldset>
<%= f.input :text %>
Upload Photo <%= f.file_field :photo %>
</fieldset>
<div class="form-actions">
<%= f.submit nil, :class => 'btn btn-primary' %>
</div>
<% end %>
Post show:
<p id="notice"><%= notice %></p>
<div class="row">
<div class="span2 offset1">
<%= image_tag #post.photo.url(:show) %>
</div>
<div class="span5">
<h1><%= #post.title %></h1>
<p><%= #post.index_text.html_safe %></p>
<p><%= #post.show_text.html_safe %></p>
<%= render "comments/comment" %>
<%= render "comments/form" %>
<% if can? :update, #course %>
<%= link_to 'Edit Post', edit_post_path(#post), :class => 'btn btn-mini' %>
<%= link_to 'Delete Post', #post,
confirm: 'Are you sure?',
method: :delete,
:class => 'btn btn-mini' %>
<%= link_to 'New Post', new_post_path, :class => 'btn btn-mini' %>
<% end %>
</div>
<nav class="span2 offset1">
<ul class="well">
<li>Category 1</li>
<li>Category 2</li>
</ul>
</nav>
</div>
<div class="row offset2">
<%= link_to 'Back to Posts', posts_path, :class => 'btn btn-mini' %>
</div>
Routes:
resources :posts, :has_many => :comments
resources :comments
It is probably something obvious that someone with more experience can resolve. Let me know if anything comes to mind. Brian
The problem is that #commentable is nil, which means that CommentsController#find_commentable is returning nil. I think your regular expression is sound, so that means one of two things is happening in find_commentable:
There aren't any keys in params that match your regex.
Your regex is matching but there aren't any records in the resulting table with the id in value.
Debug this as usual by inspecting params and the records in your database to make sure they look like you expect them to look.
The problem is your find_commentable method.
Here are the params passed to your CommentsController#create:
Started POST "/comments" for 127.0.0.1 at 2012-05-20 13:17:38 -0700
Processing by CommentsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"SOLcF71+WpfNLtpBFpz2qOZVaqcVCHL2AVZWwM2w0C4=", "comment"=>{"text"=>"Test this comment"}, "commit"=>"Create Comment"}
Here is your CommentsController#create:
def create
#commentable = find_commentable
#comment = #commentable.comments.build(params[:comment]) #<<<<LINE 13
def find_commentable
params.each do |name, value|
if name =~ /(.+)_id$/
return $1.classify.constantize.find(value)
end
end
nil
end
As you can see, find_commentable expects a param like xx_id (for example, comments_id) which it uses to search for an appropriate class (in case of comments_id, it will be Comment), otherwise it returns nil. Refer classify and constantize here.
Your params do not contain any such param. So, you always get a nil object.
Your find_commentable needs some rework. I think in case of nested_fields, it should be an expression like
/(.+)_attributes$/
instead of
/(.+)_id$/.
And you need to have
:accepts_nested_attributes_for :commentable
in your Comment model class.
I tried both of the above answers, but the problem continued.
I ended up consulting with a friend who suggested the following solution, which I like because it's more elegant than my original attempt and easier to read (for later, when I or someone else need to return to the code):
def find_commentable
if params[:post_id]
Post.find(params[:post_id])
#elsif params[:other_id]
# Other.find(params[:other_id])
else
# error out?
end
end
The commented out section will refer to other associations once I get them up and running.

Undefined Method 'NameOfField' for #<Model:0x000...>

I'm totally stumped on this error. Would really appreciate some help :).
To reproduce the error, you can pull the program from https://github.com/WaleyChen/twitter_clone. Then run 'bundle exec rspec spec/'.
I have an rspec test for my controller defined as:
require 'spec_helper'
describe FrontpageController do
render_views # render the views inside the controller tests, so not just test the actions
describe "GET 'frontpage'" do
it "should be successful" do
get 'frontpage'
response.should be_success
end
it "should have the right title" do
get 'frontpage'
response.should have_selector("title", :content => "Twitter")
end
end
end
When I run my rspec tests, I get the following error:
Failures:
1) FrontpageController GET 'frontpage' should be successful
Failure/Error: get 'frontpage'
ActionView::Template::Error:
undefined method `full_name' for #<User:0x007fbfce43dce0>
# ./app/views/frontpage/frontpage.html.erb:22:in `block in _app_views_frontpage_frontpage_html_erb___4518234645475110659_70230885952360'
# ./app/views/frontpage/frontpage.html.erb:21:in `_app_views_frontpage_frontpage_html_erb___4518234645475110659_70230885952360'
# ./spec/controllers/frontpage_controller_spec.rb:8:in `block (3 levels) in <top (required)>'
2) FrontpageController GET 'frontpage' should have the right title
Failure/Error: get 'frontpage'
ActionView::Template::Error:
undefined method `full_name' for #<User:0x007fbfcc99a410>
# ./app/views/frontpage/frontpage.html.erb:22:in `block in _app_views_frontpage_frontpage_html_erb___4518234645475110659_70230885952360'
# ./app/views/frontpage/frontpage.html.erb:21:in `_app_views_frontpage_frontpage_html_erb___4518234645475110659_70230885952360'
# ./spec/controllers/frontpage_controller_spec.rb:13:in `block (3 levels) in <top (required)>'
Here's the controller:
class FrontpageController < ApplicationController
def frontpage
#user = User.new
#sign_up = User.new
end
def sign_up
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
end
end
end
Here's the view, that's causing the error:
<%= form_for #user, :url =>"sign_up" do |form| %>
<%= form.text_field :full_name, :placeholder => "Full name" %>
</br>
<%= form.text_field :email, :placeholder => "Email" %>
</br>
<%= form.text_field :pw, :placeholder => "Password" %>
</br>
<%= form.text_field :username, :placeholder => "Username" %>
</br>
<%= form.submit "Sign up" %>
<% end %>
Here's user.rb:
class User < ActiveRecord::Base
end
Here's schema.rb:
ActiveRecord::Schema.define(:version => 20111106084309) do
create_table "users", :force => true do |t|
t.string "full_name"
t.string "email"
t.string "username"
t.string "pw"
t.datetime "created_at"
t.datetime "updated_at"
end
end
You need to make sure your test database is up to date with all the migrations:
rake db:test:prepare
However, you may have a problem with that as your migrations are broken; you have two migrations named "CreateUsers" which Rails will complain about. It looks like you should delete the more recent one, and then uncomment the t.string :email line in the original one.
Also, if you use bundle exec rake rspec instead of bundle exec rspec spec it'll make sure your database migrations are up to date before running the tests. I just cloned your repo and did this and it passed the tests just fine.

Failure/Error: get :show, :id => #user

I have an issue on the Learn Rails by Example book Chapter 7 where at the end of the chapter I get these error messages in the rspec spec
1) UsersController should have the right title Failure/Error: get :show, :id => #user ActionController::RoutingError: No route matches {:id=>nil, :controller=>"users", :action=>"show"} # ./spec/controllers/users_controller_spec.rb:36:in `block (2 levels) in '
2) UsersController should include the user's name Failure/Error: get :show, :id => #user ActionController::RoutingError: No route matches {:id=>nil, :controller=>"users", :action=>"show"} # ./spec/controllers/users_controller_spec.rb:41:in `block (2 levels) in '
3) UsersController should have a profile image Failure/Error: get :show, :id => #user ActionController::RoutingError: No route matches {:id=>nil, :controller=>"users", :action=>"show"} # ./spec/controllers/users_controller_spec.rb:46:in `block (2 levels) in '
Below is all relevant code that I have done,
spec/controllers/users_controller_spec.rb
it "should have the right title" do
get :show, :id => #user
response.should have_selector("title", :content => #user.name)
end
it "should include the user's name" do
get :show, :id => #user
response.should have_selectori("h1", :content => #user.name)
end
it "should have a profile image" do
get :show, :id => #user
response.should have_selector("h1>img", :class => "gravatar")
end
end
app/controllers/Users_controller.rb
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
#title = #user.name
end
app/helpers/users_helper.rb
module UsersHelper
def gravatar_for(user, options = { :size => 50 })
gravatar_image_tag(user.email.downcase, :alt => user.name,
:class => 'gravatar',
:gravatar => options)
end
end
app/views/users/show.html.erb
<%= #user.name %>, <%= #user.email %>
<table class="profile" summary="Profile Information">
<tr>
<td class="main">
<h1>
<%= gravatar_for #user %>
<%= #user.name %>
</h1>
</td>
<td class="sidebar round">
<strong>Name</strong> <%= #user.name %><br />
<strong>URL</strong> <%= link_to user_path(#user), #user %>
</td>
</tr>
</table>
spec/factories.rb
Factory.define :user do |user|
user.name "Michael Hartl"
user.email "mhartl#example.com"
user.password "foobar"
user.password_confirmation "foobar"
end
I think you needed
get :show, :id => #user.id
or even just
get :show, :id => '1'
Instead you were using the entire object as a parameter.
This strongly indicates you didn't set up the #user instance variable in before block for these tests. I would say that was for certain if I could see the whole test, but it certainly looks like it.