RubyTutorial 10.5.2 Rspec test micropost pagination - ruby-on-rails-3

While going through the Learn Rails book written by Michael Hartl, I'm stumped on one of the exercises.
Learn Rails by Example by Michael Hartl
"Add tests for micropost pagination"
My incorrect test, placed in the 'describe "for signed-in users" do' is as follow:
describe "pagination" do
before(:all) do
30.times { FactoryGirl.create(:micropost, user: user) }
end
after(:all) { user.feed.delete_all }
page.should have_selector('div.pagination') }
it "should list each micropost" do
user.feed.paginate(page: 1).each do |user|
page.should have_selector('li', text: user.name)
end
end
end
The test shows as passed no matter if I do page.should or page.should_not.
Any 'hint/help' would be appreciated

While browsing through some of the repos I found the answer to my question - I needed to visit the root_path again, after creating the additional microposts.
describe "pagination" do
it "should paginate the feed" do
30.times { FactoryGirl.create(:micropost, user: user, content: "Consectetur adipiscing elit") }
visit root_path
page.should have_selector("div.pagination")
end
end

I think you should put an after all filter to do the clean-up to the mass insertions of the microposts; as your implementation stands (unless you do it in another part of your test code not shown here) it does not delete the created microposts.
This can be easily done through the following code:
describe "pagination" do
after(:all) { user.microposts.delete_all unless user.microposts.nil? }
it "should paginate the feed" do
40.times { FactoryGirl.create(:micropost, user: user) }
visit root_path
page.should have_selector('div.pagination')
end
end

Related

"Expected css... to return something" : rspec fail while test by hand works (can't reproduce the fail myself)

I'm working on a training app which is an Ogame-Like game (https://github.com/arnlen/ogame-like).
I'm using rspec (with Capybara) in order to test my app.
I'm stacked for several hours because rspec is complaining for an error which *I can't reproduce * by myself with my browser.
Here is my rspec code :
describe 'Planet pages' do
let(:user){FactoryGirl.create(:user)}
before {sign_in user}
subject {page}
describe "new planet page" do
before {visit new_planet_path}
describe "with valid information" do
before do
visit new_planet_path
fill_in "Name", with: "MyPlanet"
click_button "Validate"
end
# This test doesn't pass
it {should have_selector('h1', text: "Planet")}
end
end
end
The failure :
1) Planet pages new planet page with valid information
Failure/Error: it {should have_selector('h1', text: "Planet")}
expected css "h1" with text "Planet" to return something
# ./spec/requests/planet_pages_spec.rb:34:in `block (4 levels) in <top (required)>'
Here is the involved code.
My function "sign_in" used by rspec (location : spec/support/utilities.rb)
def sign_in(user)
visit signin_path
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Sign in"
end
My UsersController
class UsersController < ApplicationController
before_filter :signed_in_user, only: [:index, :show, :edit, :update, :destroy]
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
sign_in #user
redirect_to new_planet_path
else
render 'new'
end
[...]
My PlanetsController
class PlanetsController < ApplicationController
before_filter :signed_in_user
def index
#planets = current_user.planets
end
def new
#planet = Planet.new
end
def create
#planet = Planet.new(name: params[:planet][:name],
coordinates: generate_coordinates,
metal_ressource: 1000,
user_id: current_user.id)
if #planet.save
flash[:success] = "Welcome on your first planet!"
redirect_to action: 'index'
else
flash[:error] = "Error naming your planet"
render 'new'
end
end
end
And My Planet Index view
<% #planets.each do |planet| %>
<h1>Planet : <%= planet.name %></h1>
<p><%= "Coordinates : #{planet.coordinates}" %></p>
<% end %>
I tried to user the Capybara method "save_and_open_page", but rspec raised an error "undefined method"
I also tried step by step debugging by iterations on my spec file, and it revealed that the error occurs right after the "click_button 'Validate'". For an unknown reason, rspec seems not to be able to reach the planets_path ("index" action from PlanetsController).
I'm out, if anybody has an idea, I take it !
EDIT : SOLVED - Found the problem!
Using the "save_and_open_page" method from Capybara, I figured out what was going on: the planet created by rspec didn't have any coordinates, which was not allowed by the model.
How to debug with the wonderful "save_and_open_page" method
Add this to your gemfile : "gem 'launchy'"
Install it : bundle install
Put the command "save_and_open_page" wherever you want
Hope it could help. :)
Capybara also has a save_page method, which is easier to use as it does not seem to need the "launchy" gem. The pages are saved in tmp/capybara. In the rspec tests, be sure to use save_page inside before, it, or some other block. It will not work as a separate command. Example:
before { visit signup_path; save_page }

RSpec uniqueness email test fails with FactoryGirl

Edit
Using the answers to the question I changed the test to the following which tests correctly and passes..
describe "when email is already taken" do
let(:user_with_same_email) { #user.dup }
before do
user_with_same_email.email.upcase!
user_with_same_email.save
end
it { user_with_same_email.should_not be_valid }
end
Note: Not using let(:user_with_same_email) { #user.dup } makes the test fail as it cannot find the variable user_with_same_email if it's simply duplicated in the before block as in the chosen answer to this question.
I have a User model and a user_spec.rb test file which has various validations against the User models attributes.
Previously I was writing the following at the top of my user_spec.rb file to test the User model:
describe User do
before do
#user = User.new(name: "Example User", email: "user#example.com",
password: "foobar88", password_confirmation: "foobar88")
end
...
I wanted to move this model creation to FactoryGirl so I created a factories.rb file:
FactoryGirl.define do
factory :user do
name "foo"
email { "#{name}#example.com" }
password "foobar99"
password_confirmation "foobar99"
end
end
I then changed my user_spec.rb:
describe User do
before do
#user = FactoryGirl.create(:user)
end
...
Now every test passes as before except one:
describe "when email is already taken" do
before do
user_with_same_email = #user.dup
user_with_same_email.email = #user.email.upcase
user_with_same_email.save
end
it { should_not be_valid }
end
Now unless `FactoryGirl is skipping my email uniqueness validation I can't figure out what is going wrong here.
My User model validation code:
class User < ActiveRecord::Base
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i unless const_defined?(:VALID_EMAIL_REGEX)
has_secure_password
attr_accessible :name, :email, :password, :password_confirmation
has_many :programs
before_save { self.email.downcase! }
validates :name, presence: true, length: { maximum: 50 }
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
The problem is that when you say it { should_not be_valid }, RSpec checks the subject. in this case the subject is User.new (you have "describe User" at the top so unless you specified something else this is the default).
You want to check the user_with_same_email for validity instead.
edit:
Try this, I think it might work:
describe "when email is already taken" do
before do
#user_with_same_email = #user.dup
#user_with_same_email.email = #user.email.upcase
#user_with_same_email.save
end
it { #user_with_same_email.should_not be_valid }
end
Looks like perhaps you're doing (or referencing) Michael Hartl's Rails Tutorial. Here's what my code looks like for what you're doing, so I hope it can be of use:
spec/models/user_spec.rb
describe User do
let(:user) { valid_user }
subject { user }
# ...
context "when email address is already taken" do
before { save_user(user) }
it { should_not be_valid }
end
# ...
end
spec/support/utilities.rb (to create a specific user)
def valid_user
User.new(name: "Example User",
email: "user#example.com",
password: "foobar",
password_confirmation: "foobar")
end
# ...
def save_user(user)
user_with_same_email = user.dup
user_with_same_email.email.upcase!
user_with_same_email.save
end
For reference: spec/factories.rb (to just create any old random user)
FactoryGirl.define do
factory :user do
sequence(:name) { |n| "Person #{n}" }
sequence(:email) { |n| "person_#{n}#example.com" }
password "foobar"
password_confirmation "foobar"
# ...
end
# ...
end
Update: Found the answer you were looking for at this StackOverflow answer outlining the same problem. I tested it with my code as well and it worked for me.
Update 2: Changed my code around as well, using FactoryGirl.build for times when I want a user but don't want it saved to the database. This StackOverflow answer helped me understand.
spec/models/user_spec.rb
describe User do
let(:user) { FactoryGirl.create(:user) }
subject { user }
# ...
context "when email address is already taken" do
let(:user_with_same_email) do
FactoryGirl.build(:user, email: user.email)
end
subject { user_with_same_email }
before do
user_with_same_email.email.upcase!
user_with_same_email.save
end
it { should_not be_valid }
end
# ...
end
Thanks for asking this question. Gave me some food for thought and some refactoring to do in my own code.

Problems Using Thinking Sphinx with Rails 3.2.1

I am attempting to implement Thinking Sphinx 2.0.10 which from my understanding is compatible with Rails 3. I am very new to programming using Ruby on Rails. I have gone through quite a few articles on StackOverflow but could not find a solution to my problem.
I installed the gem without the :require parameter using in my Gemfile.
gem 'thinking-sphinx', '2.0.10'
I have a working Rails application that displays a list that I would like to add a search to.
Here is my code for defining the indexes in my model file.
define_index do
indexes :email, :sortable => true
indexes :name, :sortable => true
indexes microposts.content, :as => :micropost_content
end
Here is the Rails code in my controller file. The commented out line is the original code that is working. I have a default for will_paginate I think in the application controller for 15 records per page.
def index
#users = User.search params[:search], :per_page => 15
# #users = User.paginate(page: params[:page])
end
Here is the search box that I added to my index page.
<p>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", :name => nil %>
</p>
Here is my rSpec code. This is the original code that I was using before I attempted to implement Thinking Sphinx.
describe "index" do
let(:user) { FactoryGirl.create(:user) }
before(:each) do
sign_in user
visit users_path
end
it { should have_selector('title', text: 'All users') }
describe "pagination" do
before(:all) { 15.times { FactoryGirl.create(:user) } }
after(:all) { User.delete_all }
let(:first_page) { User.paginate(page: 1) }
let(:second_page) { User.paginate(page: 2) }
it { should have_link('Next') }
it { should have_link('2') }
it { should_not have_link('delete') }
it "should list each user" do
User.all[0..2].each do |user|
page.should have_selector('li', text: user.name)
end
end
it "should list the first page of users" do
first_page.each do |user|
page.should have_selector('li', text: user.name)
end
end
it "should not list the second page of users" do
second_page.each do |user|
page.should_not have_selector('li', text: user.name)
end
end
describe "as an admin user" do
let(:admin) { FactoryGirl.create(:admin) }
before do
sign_in admin
visit users_path
end
it { should have_link('delete', href: user_path(User.first)) }
it "should be able to delete another user" do
expect { click_link('delete') }.to change(User, :count).by(-1)
end
it { should_not have_link('delete', href: user_path(admin)) }
end
end
end
When I run my rSpec test I get the following error:
Failure/Error: visit users_path
ActionView::Template::Error:
getaddrinfo: nodename nor servname provided, or not known
The page displays just fine. When I enter text in the search box and click the button nothing happens which is no surprise to me.
I am able to run Sphinx on the terminal. The searches work fine. I just do not know enough to debug this problem with Thinking Sphinx. I have searched many pages on this website and many others the past few days but none of them are dealing with this issue. Any help would be appreciated.
Did you initialize the sphinx database?
Usually you just need to do something like:
rake ts:rebuild
This should automatically run rake ts:conf for you and rebuild your indexes.
You could also use rake ts:in to update the indexes.
A simple way to test if this is working is to run the rails console (rails c) and try manually searching your users (User.search).
If you get any results, the indexes are available and you can troubleshoot your views/controllers next ;)

Capybara and Rails, why using should have_content in spec gives me "You are being redirected."?

I'm writing an integration test for a rails application using Capybara within Rspec. After filling out a form, the user presses submit.
If I run the test I get:
expected there to be content "Welcome to course builder" in "You are
being redirected."
I am trying to test the resulted page content, here is the test:
describe PagesController do
describe "Quiz testing in chapter" do
def page_view
Capybara::Node::Simple.new(#response.body)
end
render_views
login_student
it "should fail if user chosen wrong answer" do
page= create_quiz_page_with_two_choices_first_correct
post :answer_quiz, :page_id=>page.id, :submitted_single_answer=>'2'
page_view.should have_content("Welcome to course builder")
end
end
end
in the PagesController
def answer_quiz
...
respond_to do |format|
format.html { redirect_to page }
format.json { head :ok }
end
end
I just started using Capybara, so am I missing something obvious here? Why am I stuck with the redirect response?
Thanks!
hopewise
login_student needs to go in a before block:
before(:each) do
login_student
end
However even that probably won't fix the problem. When using Capybara it is recommended to actually login by visiting the login page for each example, so:
before(:each) do
visit login_path # log in test user
end
it "should do something awesome" do
visit "/awesome"
page.should have_content("You rock!")
end
It's also helpful to write a special case to handle logins in the test environment, so you can avoid having to create a user for test logins.

I am having trouble testing my controller's update action using Rspec, what am I doing wrong?

I am trying to test the failing branch of the update action on my controller but I am having trouble with the test. This is what I have and it fails on the last
describe "PUT 'article/:id'" do
.
.
.
describe "with invalid params" do
it "should find the article and return the object" do
Article.stub(:find).with("1").and_return(#article)
end
it "should update the article with new attributes" do
Article.stub(:update_attributes).and_return(false)
end
it "should render the edit form" do
response.should render_template("edit")
end
end
end
Any ideas as to why the last part fails to render the template?
You're splitting up the parts of your test incorrectly. Each it call is actually a new example and the state is reset before/after each one.
What you should be doing is:
describe "with invalid params" do
before do
#article = Article.create(valid_params_go_here)
end
it "should find the article and return the object" do
put :update, { :id => #article.id, :article => { :title => "" } }
response.should render_template("edit")
end
end
By doing it this way, the #article is set up before hand (although you could use a mock one if you really wanted to) and the request to the update action and the assertion that it actually renders the edit template all happen in the one example.
For people who are coming here in 2018, some updates(pun not intended) have been made. It's important to include "params" before listing the params. Additionally, you should use expect and not "should" since it will be deprecated in Rails 6.0.
describe "with invalid params" do
before(:each) do
#article = Article.create(valid_params_go_here)
end
describe "PATCH update/:id" do
it "should find the article and return the object" do
put :update, params: { id: #article.id, article: { title: "" } }
expect(response).to be_redirect
end
end