RSpec test redirect - ruby-on-rails

please help check the redirect. i have controller:
def create
#poll = current_user.polls.build(poll_params)
if #poll.save
flash[:success] = 'Голосование создано'
redirect_to user_polls_path(current_user)
else
flash.now[:error] = 'Голосование не создано'
#user = User.find(params[:user_id])
render 'new'
end
end
spec/requests/polls_spec.rb:
require 'rails_helper'
RSpec.describe "Polls", type: :request do
describe "return check" do
it "#create" do
#user = FactoryGirl.create(:user)
#poll = FactoryGirl.create(:poll, user: #user)
# binding.pry ##user OK, #poll OK
expect(#poll).to redirect_to(user_polls_path #user)
end
end
end
but after run in console i get folloew error message:
$ rspec spec/requests
...F
Failures:
1) Polls return 200 status code for GET /polls #create
Failure/Error: expect(#poll.save).to redirect_to(user_polls_path #user)
NoMethodError:
undefined method `response_code' for nil:NilClass

Use
expect(response).to redirect_to(user_polls_path #user)
What redirect_to does behind the scenes is to check the response_code property of the object used in expect.
This is why you are getting the undefined method 'response_code' for nil:NilClass error.

Related

rspec for the controller without factory girl

I am trying to write spec code for my controller it gets failed. And i am not sure where it gets failed.
Controller Code
def index
#users = User.all
end
def update
authorize! :update, #user
respond_to do |format|
if #user.update(user_params)
format.html { redirect_to user_index_path }
else
format.html { render :index }
end
end
end
private
def set_user
#user = User.find(params[:id])
end
def user_params
params.permit(:active)
end
Spec Code for the above controller
RSpec.describe UserController, type: :controller do
describe 'GET #index' do
let(:user) {User.create!(name: "hari")}
context 'with user details'do
it 'loads correct user details' do
get :index
expect(response).to permit(:user)
end
end
context 'without user details' do
it 'doesnot loads correct user details' do
get :index
expect(response).not_to permit(:user)
end
end
end
describe 'Patch #update' do
context 'when valid params' do
let(:attr) do
{active: 'true'}
end
before(:each) do
#user = subject.current_user
put :update, params: { user: attr }
#user.reload
end
it 'redirects to user_index_path ' do
expect(response).redirect_to(user_index_path)
end
it 'sets active state' do
expect(#user.active?('true')).to be true
end
end
context 'when invalid param' do
let(:attr) do
{active: 'nil'}
end
before(:each) do
#user = subject.current_user
put :update, params: { user: attr }
#user.reload
end
it 'render index' do
expect(respone.status).to eq(200)
end
it 'doesnot change active state' do
expect(#user.active?(nil)).to be true
end
end
end
end
I am just a beginner and tried the spec code for my controller by checking https://relishapp.com/rspec/rspec-rails/docs/gettingstarted. Can you help me where my spec goes wrong or could anyone give me a few test examples for these methods or could redirect me to an rspec guide? the index method is getting failed
and my
terminal log is
1) UserController GET #index with user details loads correct user details
Failure/Error: expect(response).to permit(:user)
NoMethodError:
undefined method `permit' for #<RSpec::ExampleGroups::UserController::GETIndex::WithUserDetails:0x00005614152406b0>
Did you mean? print
# ./spec/controllers/user_controller_spec.rb:10:in `block (4 levels) in <top (required)>'

Rails Rspec - undefined method `session'

Im testing my Session Controller but Im getting this error, the log in feature works, I tested it on the browser but Im new to testing on Rspec and can't get this to work
Failure/Error: expect(response.session[:user_id]).to eq(#user_attr.id)
NoMethodError:
undefined method `session' for #<ActionController::TestResponse:0xd30df10>
# ./spec/controllers/sessions_controller_spec.rb:20:in `block (3 levels) in <top (required)>'
This is the code of my controller:
def new
#user = User.new
end
def create
#user = User.find_by(username: params[:user][:username])
if #user && #user.authenticate(params[:user][:password])
session[:user_id] = #user.id
redirect_to root_path
else
render :new
end
end
Rspec code:
require 'rails_helper'
RSpec.describe SessionsController, type: :controller do
describe "get Login page" do
it "returns http status" do
get :new
expect(response).to have_http_status(:success)
end
end
describe "session" do
before(:each) do
#user = FactoryGirl.create(:user)
#user_attr = FactoryGirl.attributes_for(:user)
end
it "gives session" do
request.session[:user_id] = nil
post :create, user: #user_attr
expect(response.session[:user_id]).to eq(#user_attr.id)
end
end
end
session is a variable that is available without the request/response context as shown in your example. If you want to manipulate it or check the values it contains, you can simply do something like this:
it "gives session" do
session[:user_id] = nil
post :create, user: #user_attr
expect(session[:user_id]).to eq(#user_attr.id)
end

If I stub out .save method in my controller test how can I check the correct show template is rendered?

I am trying to test a controller create method in a rails app using RSpec as shown below:
def create
#user = User.new(user_params)
if #user.save
redirect_to user_path(#user.id)
else
render new_user_path
flash[:error] = "User not saved"
end
end
However if i stub out .new to prevent the test from using Active Record and the User model by forcing it to return true the id of the #user is not set by .save as normal so I cannot test for it redirecting to user_path(#user.id) as #user.id is nil
Here is my initial test for RSpec:
it "creates a user and redirects" do
expect_any_instance_of(User).to receive(:save).and_return(true)
post :create, { user: {name: "John", username: "Johnny98", email: "johnny98#example.com"} }
expect(assigns(:user).name).to eq("John")
expect(response).to redirect_to user_path(assigns(:user))
end
How should I test for this redirect in RSpec.
You should use mocks - https://www.relishapp.com/rspec/rspec-mocks/docs.
user = double("user", id: 1, save: true)
Then you should mock you method with double you've just created
expect(User).to receive(:new).and_return(user)
And then test redirect.
expect(response).to redirect_to user_path(user)
I hope this will help.
I would do it in this way:
it 'should redirect to a user if save returned true' do
#user_instance = double
#user_id = double
allow(User).to receive(:new).and_return(#user_instance)
allow(#user_instance).to receive(:save).and_return(true)
allow(#user_instance).to receive(:id).and_return(#user_id)
post :create, {:user => valid_attributes}
expect(response).to redirect_to(user_path(#user_id))
end

Controller specs throwing up undefined method

I'm really struggling with Rspec DSL! I read a lot on SO and across the internet, so I'm posting my particular issue because my feeble mind can't get to the solution.
Have a post method in my controller that updates a user's email. Works fine, but I'm struggling with the spec because all I'm getting are undefined methods for NilClass (even though I've tried stubbing every object and method, etc).
users_controller.rb
def update_user_email
#user = User.find_by_id(params[:id])
new_email = params[:user][:new_email].downcase.strip
user_check = User.find_by_email('new_email')
if user_check.blank?
#user.email = new_email
#user.save
flash[:notice] = "Email updated to #{new_email}"
else
flash[:alert] = "This email is already being used by someone else!"
end
respond_with #user do |format|
format.html { redirect_to admin_user_path(#user) }
format.json { head :no_content }
end
end
Here's the spec I'm trying to write. What test should I be writing, if not this, and what can I do to prevent undefined method on NilClass errors!
users_controller_spec.rb
describe Admin::UsersController do
let!(:user) { FactoryGirl.create(:user, password: 'oldpass', email: 'bar#foo.com') }
...
describe "admin actions for each user" do
it "resets user email" do
post :update_user_email, {user: {new_email: 'foo#bar.com'} }
response.status.should == 200
end
end
...
end
And the error:
Admin::UsersController admin actions for each user resets user email
Failure/Error: post :update_user_email, {user: {new_email: 'foo#bar.com'} }
NoMethodError:
undefined method `email=' for nil:NilClass
The line that is failing is:
#user = User.find_by_id(params[:id)
Since you are not passing the id in during your test the user is not being found, and therefore you are trying to call email= on nil. Here is how you can clean up your controller and test.
class YourController < ApplicationController
before_filter :find_user, only: [:update_user_email]
def update_user_email
new_email = params[:user][:new_email].downcase.strip
user_check = User.where(email: new_email)
if user_check.blank?
#user.email = new_email
#user.save
flash[:notice] = "Email updated to #{new_email}"
else
flash[:alert] = "This email is already being used by someone else!"
end
respond_with #user do |format|
format.html { redirect_to admin_user_path(#user) }
format.json { head :no_content }
end
end
def find_user
#user = User.find(params[:id])
rescue ActiveRecord::RecordNotFound
flash[:error] = "It looks like that user does not exist"
# redirect or render
end
end
# your test
describe "admin actions for each user" do
it "resets user email" do
post :update_user_email, id: user.id, user: {new_email: 'foo#bar.com'}
response.status.should == 200
end
end
You may also want to consider moving the logic out of the controller and into a service object. That controller method is getting a little long.
The issue is that you also need to pass the id of the User you're wanting to update. The line which is failing is #user.email = new_email, since #user is nil.
To get your test to pass now, you'll need to change your post method to:
post :update_user_email, {id:'bar#foo.com', user: {new_email: 'foo#bar.com'} }
As an aside, it is possible to say that it may be better for you to actually be doing this in the UsersController#update method, in order to maintain RESTful routes. And as for enforcing unique email address - it might be better to do this in the User class with validations.
In your post :update_user_email you're not passing :id... so #user = User.find_by_id... is not finding a user so #user is a nil object.
post :update_user_email, id: user.id, {user: {new_email: 'foo#bar.com'} }

Testing create action in polymorphic comments controller Rspec - undefined method `comments' for nil:NilClass

I'm trying to test the POST create action within my polymorphic comments controller. When running the spec below they fail with the error:
undefined method `comments' for nil:NilClass
Which I think means that #commentable isn't being created/set up properly, so it doesn't exist. ATM I am stubbing out the load_commentable method and returning the FactoryGirl question object, however this still doesn't seem to solve anything.
How can I amend my spec so that the commentable object is created properly and the comment is created within the scope of #commentable, as in the actual controller?
comments_controller.rb
def create
#comment = #commentable.comments.build(params[:comment])
#comment.user_id = current_user.id
respond_to do |format|
if #comment.save
format.html { redirect_to #commentable, notice: 'Comment created'}
format.js
else
format.html { redirect_to #commentable, notice: "Content can't be blank" }
format.js
end
end
end
def load_commentable
resource, id = request.path.split('/')[1,2]
#commentable = resource.singularize.classify.constantize.find(id)
end
comments_controller_spec.rb
describe CommentsController do
include Devise::TestHelpers
include AnswerHelper
before(:each) do
#user = create(:user)
#user2 = create(:user)
sign_in #user
sign_in #user2
#commentable = create(:question, user: #user2)
#comment = create(:comment, user: #user)
#vote = attributes_for(:vote, user: #user2, votable_id: #commentable)
controller.stub!(:load_commentable).and_return(#commentable)
controller.stub!(:current_user).and_return(#user)
#request.env['HTTP_REFERER'] = "http://test.host/questions/#{#commentable.id}"
stub_model_methods
end
describe "POST create" do
describe "with valid params" do
it "creates a new comment" do
expect {
post :create, comment: attributes_for(:comment), commentable: #commentable
}.to change(Comment, :count).by(1)
end
it "assigns a newly created comment as #comment" do
post :create, comment: attributes_for(:comment), commentable: #commentable
assigns(:comment).should be_a(Comment)
assigns(:comment).should be_persisted
end
end
describe "with invalid params" do
it "assigns a newly created but unsaved comment as #comment" do
Comment.any_instance.stub(:save).and_return(false)
post :create, comment: attributes_for(:comment), commentable: #commentable
assigns(:comment).should be_a_new(Comment)
end
end
end
factory.rb
factory :comment do
user
commentable_id :question
commentable_type "Question"
content "a comment"
votes_count 5
end
rspec resullts
1) CommentsController POST create with valid params creates a new comment
Failure/Error: post :create, comment: attributes_for(:comment), commentable: #commentable
NoMethodError:
undefined method `comments' for nil:NilClass
# ./app/controllers/comments_controller.rb:19:in `create'
# ./spec/controllers/comments_controller_spec.rb:24:in `block (5 levels) in <top (required)>'
# ./spec/controllers/comments_controller_spec.rb:23:in `block (4 levels) in <top (required)>'
The problem here is that you're stubbing out load_commentable, which is what is responsible for setting the instance variable #commentable in your controller. Since you're stubbing it, it never gets called, and the ivar never gets set - you can't set ivars in your controller from your rspec test suite directly.
Since you're creating a record, you don't actually need to stub anything, and can just pass the #commentable.id, then let it be looked up from the database. If you want to avoid the find for some reason, though, you could use:
Question.stub(:find).with(#commentable.id).and_return(#commentable)
This will cause your controller to use your #commentable object, and assign it to #commentable in the controller, at which point the test should continue to run normally.

Resources