Rspec testing templates being rendered - ruby-on-rails

Im trying to test a condition where on successful signup a Success Template is rendered by the following controller code
def create
#user = User.new(params[:user])
if #user.save
render :template => "success"
else
flash[:notice] = "Oops Somethings not quite right! :("
render :action => "new"
end
end
I am using the following spec to test out this code
before(:each) do
#user = User.new
#user.attributes = valid_attributes
#params = valid_attributes
#user.stub!(:save).and_return(true)
end
def do_post
post :create
end
it "should create new user " do
count = User.count
do_post
user = User.new(#params)
user.save.should eql(true)
User.count.should eql(count + 1)
end
it "should render the success page on successful signup" do
do_post
#user.save
response.should render_template("success") if #user.save
end
But the example fails "it should render success page on successful signup" with this error message
1)
'UsersController handling POST /users should render the success page on successful signup' FAILED
expected "success", got "users/new.html.erb"
./spec/controllers/users_controller_spec.rb:67:
The success view is an template stored in the views/users/ without an action. Im guessing im making a very fundamental mistake and would like some help .

You are stubbing the #user variable in the test, but the controller will instantiate a new instance so the stub won't be in place.
It's not a good idea to use a stub in this case just to emulate a successful save call. Why don't you supply valid data instead and make sure the action is successful?
The following code is for RSpec > 2.1 and it uses the expect syntax.
before(:each) do
#params = valid_attributes
end
it "should create new user" do
#_before = User.count
post :create, :user => #params
expect(assigns(:user)).to_not be_new_record
expect(User.count).to eq(#_before + 1)
end
it "should render the success page on successful signup" do
post :create, :user => #params
expect(response).to be_successful
expect(response).to render_template("success")
end
Finally, change
render :template => "success"
to
render :action => "success"
For previous RSpec versions or if you have to use the should syntax, use
before(:each) do
#params = valid_attributes
end
it "should create new user" do
#_before = User.count
post :create, :user => #params
assigns(:user).should_not be_new_record
User.count.should == (#_before + 1)
end
it "should render the success page on successful signup" do
post :create, :user => #params
response.should be_successful
response.should render_template("success")
end

Related

'undefined method' post with Rails and Rspec

Got stuck with:
' undefined method `post' for #<Class:0x000001058c0f68> (NoMethodError)'
on testing controller create action.
I'm using Rails 4, rpsec, and Factory Girl
Controller:
def create
#post = Post.new(post_params)
#post.user_id = current_user.id
if #post.save
flash[:success] = "Yay! Post created!"
redirect_to root_path
else
# flash[:error] = #post.errors.full_messages
render 'new'
end
end
Test:
describe '#create' do
post 'create', FactoryGirl.attributes_for(:post, user: #user)
response.should be_successful
end
I think post method is accessible inside it method block:
describe 'create' do
it 'should be successful' do
post :create, FactoryGirl.attributes_for(:post, user: #user)
response.should be_success
end
end
BTW I think you need to test for redirect, not success status.
Sorry for being off-topic but I just want to give you some advice.
Consider following best practices and use RSpec's expect syntax instead of should. Read more about why the should syntax is a bad idea here: http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
This is how I would rewrite your example:
describe 'create' do
it 'responds with 201' do
post :create, attributes_for(:post, user: #user)
expect(response.status).to eq(201)
end
end
In the example I'm using FactoryGirl's short syntax method attributes_for instead of FactoryGirl.attributes_for, it saves a few bytes. Here's how to make the short methods available (in spec/test_helper.rb):
RSpec.configure do |config|
config.include FactoryGirl::Syntax::Methods
end
I'm testing for the status code 201 which Rails will return by default for a successful create action (redirect should be 3xx).This makes the test more specific.
Hope it's any help for writing better specs.
The issue comes from the fact that post should be used inside an it statement. I usually test my controllers like this:
describe 'POST "create"' do
let(:user) { User.new }
let(:params) { FactoryGirl.attributes_for(:post, user: user) }
let(:action) { post :create, params }
let!(:post) { Post.new }
before do
Post.should_receive(:new).and_return(post)
end
context 'on success' do
before do
post.should_receive(:save).and_return(true)
end
it 'renders success' do
action
expect(response).to be_success
end
it 'redirects' do
action
expect(response).to be_redirected
end
it 'sets flash message' do
action
expect(flash[:success]).to_not be_empty
end
end
context 'on failure' do
before do
post.should_receive(:save).and_return(false)
end
it 'renders new' do
action
expect(response).to render_template(:new)
end
end
end

Rspec redirect to testing

In my controller when an user creates a new post, he/she is redirected to the page that contains the newly created post. I'm wanting to create a test in rspec to cover this redirect but am having trouble with it. Specifically, I want to know what to write in the refirst_to argument. Here is the controller code below..
def create
#micropost = Micropost.new(params[:micropost])
respond_to do |format|
if #micropost.save
format.html {redirect_to #micropost}
else
format.html {render action: 'edit'}
end
end
end
Here is the rspec test...
before do
#params = FactoryGirl.build(:micropost)
end
it "redirects to index" do
#clearly #params.id doesn't work. its telling me instead of a redirect im getting a
#200
#response.should redirect_to(#params.id)
end
Assuming that #params will create a valid Micropost (otherwise .save will fail and you'll be rendering :edit)...
it "redirects to index on successful save" do
post :create, :micropost => #params.attributes
response.should be_redirect
response.should redirect_to(assigns[:micropost])
end
it "renders :edit on failed save" do
post :create, :micropost => {}
response.should render ... # i don't recall the exact syntax...
end

Rspec POST controller create test fails but web based submission works

I have the following rspec test for create method in my
describe "with valid information" do
it "should respond with success" do
post 'create', :show_secretary_id => #show_secretary.id, :show => #show
response.should be_success
end
it "should incremenet the show count" do
expect do
post 'create', :show_secretary_id => #show_secretary.id, :show => #show
end.to change(Show,'count').by(1)
end
end
The test fails. However, when I try the create method in the browser, it works. Any ideas on what I am missing?
EDIT: My Controller Code
def create
#show_secretary = ShowSecretary.find_by_id(params[:show_secretary_id])
#show = #show_secretary.shows.build(params[:show])
if #show.save
flash[:notice] = "Successfully created show"
redirect_to show_path #show
else
render 'new'
end
end
EDIT: #show_secretary, #show
These two objects are ActiveRecords created and built by FactoryGirl respectively.
#show_secretary = FactoryGirl.create(:show_secretary_user).verifiable
#show = FactoryGirl.build(:show)
Replace
#show = FactoryGirl.build(:show)
with:
#show = FactoryGirl.attributes_for(:show)

testing "create" method in ruby with rspec

I have written this controller code in Ruby on Rails
class PostsController < ApplicationController
before_filter :authenticate_user!
def index
#posts = Post.all(:order => "created_at DESC")
respond_to do |format|
format.html
end
end
def create
#post = Post.create(:message => params[:message])
respond_to do |format|
if #post.save
format.html { redirect_to posts_path }
format.js
else
flash[:notice] = "Message failed to save."
format.html { redirect_to posts_path }
end
end
end
end
and corresponding to this I have written the following test case :-
require 'spec_helper'
describe PostsController do
describe "GET 'index'" do
it "returns http success" do
get 'index'
response.should be_success
end
end
describe "#create" do
it "creates a successful mesaage post" do
#post = Post.create(message: "Message")
#post.should be_an_instance_of Post
end
end
end
I am getting failures on both. Please take a look on the code and help me figure out.
I suspect you are not logged in since you are using Devise?
Maybe you need to include the devise testhelpers:
describe PostsController do
include Devise::TestHelpers
before(:each) do
#user = User.create(...)
sign_in #user
end
#assertions go here
end
As Tigraine states, it appears as though you probably are not logged in (with Devise) when the tests get executed. However, showing the failures would help in narrowing down the problem further.
On top of that, the second test isn't really an integration test and I would probably prefer something like the following to test the same condition. There are two types of test you could do:
# inside 'describe "#create"'
let(:valid_params) { {'post' => {'title' => 'Test Post'} }
it 'creates a new Post' do
expect {
post :create, valid_params
}.to change(Post, :count).by(1)
end
# and / or
it 'assigns a new Post' do
post :create, valid_params
assigns(:post).should be_a(Post)
assigns(:post).should be_persisted
end
Don't forget to add this line into your spec_helper.rb
require "devise/test_helpers"
include Devise::TestHelpers
Nevertheless, here is link for Devise wiki - How to test Controllers where you can find more info about this approach. I recommend writing the before method without (:each), what I remember it sometimes causes problems.
before do
#user = FactoryGirl.create(:user)
sign_in #user
end
Can always use:
puts response.inspect
To see how your response looks like.

Stubbing a before_filter with RSpec

I'm having trouble understanding why I can't seem to stub this controller method :load_user, since all of my tests fail if I change the actual implementation of :load_user to not return and instance of #user.
Can anybody see why my stub (controller.stub!(:load_user).and_return(#user)) seems to fail to actually get called when RSpec makes a request to the controller?
require 'spec_helper'
describe TasksController do
before(:each) do
#user = Factory(:user)
sign_in #user
#task = Factory(:task)
User.stub_chain(:where, :first).and_return(#user)
controller.stub!(:load_user).and_return(#user)
end
#GET Index
describe "GET Index" do
before(:each) do
#tasks = 7.times{Factory(:task, :user => #user)}
#user.stub!(:tasks).and_return(#tasks)
end
it "should should find all of the tasks owned by a user" do
#user.should_receive(:tasks).and_return(#tasks)
get :index, :user_id => #user.id
end
it "should assign all of the user's tasks to the view" do
get :index, :user_id => #user.id
assigns[:tasks].should be(#tasks)
end
end
#GET New
describe "GET New" do
before(:each) do
#user.stub_chain(:tasks, :new).and_return(#task)
end
it "should return a new Task" do
#user.tasks.should_receive(:new).and_return(#task)
get :new, :user_id => #user.id
end
end
#POST Create
describe "POST Create" do
before(:each) do
#user.stub_chain(:tasks, :new).and_return(#task)
end
it "should create a new task" do
#user.tasks.should_receive(:new).and_return(#task)
post :create, :user_id => #user.id, :task => #task.to_s
end
it "saves the task" do
#task.should_receive(:save)
post :create, :user_id => #user.id, :task => #task
end
context "when the task is saved successfully" do
before(:each) do
#task.stub!(:save).and_return(true)
end
it "should set the flash[:notice] message to 'Task Added Successfully'"do
post :create, :user_id => #user.id, :task => #task
flash[:notice].should == "Task Added Successfully!"
end
it "should redirect to the user's task page" do
post :create, :user_id => #user.id, :task => #task
response.should redirect_to(user_tasks_path(#user.id))
end
end
context "when the task isn't saved successfully" do
before(:each) do
#task.stub(:save).and_return(false)
end
it "should return to the 'Create New Task' page do" do
post :create, :user_id => #user.id, :task => #task
response.should render_template('new')
end
end
end
it "should attempt to authenticate and load the user who owns the tasks" do
context "when the tasks belong to the currently logged in user" do
it "should set the user instance variable to the currently logged in user" do
pending
end
end
context "when the tasks belong to another user" do
it "should set the flash[:notice] to 'Sorry but you can't view other people's tasks.'" do
pending
end
it "should redirect to the home page" do
pending
end
end
end
end
class TasksController < ApplicationController
before_filter :load_user
def index
#tasks = #user.tasks
end
def new
#task = #user.tasks.new
end
def create
#task = #user.tasks.new
if #task.save
flash[:notice] = "Task Added Successfully!"
redirect_to user_tasks_path(#user.id)
else
render :action => 'new'
end
end
private
def load_user
if current_user.id == params[:user_id].to_i
#user = User.where(:id => params[:user_id]).first
else
flash[:notice] = "Sorry but you can't view other people's tasks."
redirect_to root_path
end
end
end
Can anybody see why my stub doesn't work? Like I said, my tests only pass if I make sure that load_user works, if not, all my tests fail which makes my think that RSpec isn't using the stub I created.
Stubbing out load_user breaks your tests because stubbing the method neuters it. When the controller calls load_user, it is no longer running your original code. It's now just returning whatever you specify in and_return(...) (which is getting returned to the ActionController callback stack, which ignores anything other than false).
Your controller code isn't using the return value of that method; it's using the variable instantiated within it. Since the original code for the load_user method isn't being run, the #user instance variable is never instantiated. (The #user variable in your tests is only visible to your tests.)
But with all the other stubs you have, I don't see any reason why you should need to stub out load_user at all. As long as you're stubbing current_user to return #user (which I assume is being done in the sign_in method), then there shouldn't be any need.
you can also try to verify that the stub works by doing an assertion like
controller.current_user.should == #user

Resources