rspec testing a nested if function - ruby-on-rails-3

IM very new to rspec testing and need alittle bit of help.
Im testing a controller for my timesheet and im trying to test this piece of code.
if params[:user_id] == nil
if current_user == nil
redirect_to new_user_session_path
else
#user_id = current_user.id
end
else
#user_id = params[:user_id]
end
im not sure if its even worth testing but it seems theres a lack of tutorials for the beginner out there, so i wouldnt know.
thanks in advance

You can do this in rspec using describe statements and before(:each) to setup each scenario and test it
describe "test the controller" do
before(:each) do
#user = Factory(:user)
end
describe "for non signed in users" do
it "should redirect to sign in page" do
get :action
response.should redirect_to(new_user_session_path)
end
end
describe "for signed in users" do
before(:each) do
sign_in(#user)
end
it "should be successful" do
get :action
response.should be_success
end
end
end
Just use different describe statements and setup each test with before(:each) and you should be fine.

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 }

Ruby on Rails 3 Tutorial - Ch. 3; Sec. 3 - "undefined method `describe' for PagesController:Class"

I am following the code and what the pages say specifically, and the only thing I'm missing is the rspec gem for Ruby on Rails, as I was unable to get it (gives this error for rspec installation: "E: Unable to locate package rspec" so any help with that would be greatly appreciated) due to the inability to locate the package.
This is my entire pages_controller_spec.rb file, and the error displayed when the rails server tried to connect to the page is displayed in the title (if it's unable to be seen here it is again: "undefined method `describe' for PagesController:Class").
Note: I have also tried the code without "require 'spec_helper'" and it still will not operate.
class PagesController < ApplicationController
def home
end
def contact
end
def about
end
require 'spec_helper'
describe PagesController do
render_views
describe "GET 'home'" do
it "should be successful" do
get 'home'
response.should be_success
end
it "should have the right title" do
get 'home'
response.should have_selector("title",
:content => "Ruby on Rails Tutorial Sample App | Home")
end
end
describe "GET 'contact'" do
it "should be successful" do
get 'contact'
response.should be_success
end
it "should have the right title" do
get 'contact'
response.should have_selector("title",
:content => "Ruby on Rails Tutorial Sample App | Contact")
end
end
describe "GET 'about'" do
it "should be successful" do
get 'about'
response.should be_success
end
it "should have the right title" do
get 'about'
response.should have_selector("title",
:content => "Ruby on Rails Tutorial Sample App | About")
end
end
end
end
you need additional end before spec helper require simply you are in the controller class and he is trying to call describe as method on controller. add it and it will be fine.
so it should be like this:
class PagesController < ApplicationController
def home
end
def contact
end
def about
end
end
and rest of file.

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.

factory_girl rspec test failure with before_filter

I have a newbie question here. I've been following along with the rails tutorial and I've hit a snag in my tests. When I implement the following filter...
class UsersController < ApplicationController
before_filter :authenticate, :only => [:edit, :update]
...all of my user_controller_spec.rb tests related to 'GET edit' and 'PUT update' start to fail where before they passed. Here's one that should have returned true, but returned false:
describe "GET 'edit" do
before(:each) do
#user = Factory(:user)
test_sign_in(#user)
end
it "should be successful" do
get :edit, :id => #user
response.should be_success
end
end
And this is my test_sign_in code in spec_helper.rb
def test_sign_in(user)
controller.sign_in(user)
end
The sign_in method is in SessionsHelper, which is incuded in ApplicationController:
def sign_in(user)
cookies.permanent.signed[:remember_token] = [user.id, user.salt]
current_user = user
end
I don' know how to further investigate. My guess is that since Rspec was unable to 'GET edit' there must be a log of that request that I can look at, but the test only tells me it returned false. Where can I look next?
Update: What I found in log/test.log is that every 'Processing by UsersController#index as HTML' line is followed by a redirect as follows:
Processing by UsersController#index as HTML
[1m [35mUser Load (0.2ms) [0m SELECT "users".* FROM "users" WHERE "users"."id" IS NULL LIMIT 1
Redirected to http://test.host/signin
Does this mean that every test index action is followed by a redirect to signin? If this were true it would seem consistent with tests including the test_sign_in method (above) failing and other tests like this one passing:
describe "GET 'index' for non-signed-in users" do
it "should deny access" do
get :index
response.should redirect_to(signin_path)
end
end
I'm going to try to wrap my head around the test_sign_in method again.
You need to call self in the sign_in helper.
def sign_in(user)
cookies.permanent.signed[:remember_token] = [user.id, user.salt]
self.current_user = user
end

TDD with RSpec and Rails: testing controller actions with no view

As I continue to learn my way around TDD with RSpec 2 and Rails 3.1, I can't seem to find a solution to this problem.
I have a Users controller with a new and create action. In my UsersController spec, I have
users_controller_spec.rb
describe "POST 'create'" do
before(:each) do
#attr = Factory.attributes_for(:user)
end
it "should assign an #user variable" do
post :create, :user => #attr
assigns[:user].should_not be_nil
assigns[:user].should be_kind_of(User)
end
end
and in my UsersController,
users_controller.rb
def create
#user = User.new(params[:user])
end
This spec is failing with
1) UsersController POST 'create' should assign an #user variable
Failure/Error: post :create, :user => #attr
ActionView::MissingTemplate:
I can continue to implement application code to get this test to pass, but I feel like this test should be passing as it is.
Any suggestions?
Your create method needs to do something. Either render a template or redirect. Since you're not telling it to redirect it's assuming that you want it to render a template but when it can't find a create.html.erb file it throws an error.
You're best bet is to do either this:
def create
#user = User.new(params[:user])
redirect_to root_url
end
or this:
def create
#user = User.new(params[:user])
render :nothing => true
end
To test rendering nothing you'll want:
expect(response).to render_template(nil)
I've come across this recently myself. It seems one possibility would be to rescue the error in your test.
it "should assign an #user variable" do
begin
post :create, :user => #attr
rescue ActionView::MissingTemplate
# This is okay because(/as long as) we test the render/redirect
# in a separate spec where we don't rescue this exception.
end
assigns[:user].should_not be_nil
assigns[:user].should be_kind_of(User)
end
I don't know how "correct" this solution is. On one hand, it definitely emphasizes the "testing one thing at a time" mentality, on the other, it seems kind of ugly.
Edit
I suppose you could make some nice wrappers in your spec helper, something like
def post?(action, params = {})
post action, params
rescue ActionView::MissingTemplate
end