How to properly format RSpec update test - ruby-on-rails

I am learning how to test controllers in Rails. I have this action in my Posts Controller:
def update
#post = Post.new(post_params)
if #post.save
redirect_to posts_path
flash[:success] = "Your post has been updated"
else
render 'edit'
end
end
Pretty basic update action. I want to test it. This is the test I have right now:
require 'rails_helper'
RSpec.describe PostsController, type: :controller do
let!(:test_post) { Post.create(title: "testing", body: "testing") }
describe "PUT update" do
context "when valid" do
it "updates post" do
patch :update, id: test_post, post: {title: 'other', body: 'other'}
test_post.reload
expect(test_post.title).to eq('other')
end
end
end
end
This test does not pass. This is the error I get from RSpec:
1) PostsController PUT update when valid updates post
Failure/Error: expect(test_post.title).to eq('other')
expected: "other"
got: "testing"
(compared using ==)
I would appreciate some guidance. Thanks!

In your update action, you're creating a new Post, not updating an existing Post:
def update
#post = Post.new(post_params) <= here
if #post.save
redirect_to posts_path
flash[:success] = "Your post has been updated"
else
render 'edit'
end
end
You need to find your existing Post record, then update it. Which might look something more like:
def update
#post = Post.find_by(id: params[:id]) <= might need to be different depending on how you have structured your params
if #post.update_attributes(post_params)
redirect_to posts_path
flash[:success] = "Your post has been updated"
else
render 'edit'
end
end

Related

POST :create rspec controller testing error, wrong number of arguments 2 for 0

I'm trying to test my Post_comments#create action in the controller specs with rspec and I keep getting this error message:
Failure/Error: post :create, :post_id => post.to_param, :post_comment => attributes_for(:post_comment, comment: "New")
ArgumentError:
wrong number of arguments (2 for 0)
# ./spec/controllers/post_comments_controller_spec.rb:95:in `block (4 levels) in <top (required)>'
My Post Comments controller:
class PostCommentsController < ApplicationController
before_action :find_todo_list
def index
#post_comment = #post.post_comments.all
end
def show
#post_comment = #post.post_comments.find(params[:id])
end
def new
#post_comment = #post.post_comments.new
end
def edit
#post_comment = #post.post_comments.find(params[:id])
end
def create
#post_comment = #post.post_comments.new(post_comment_params)
if
#post_comment.save
redirect_to post_post_comments_path
flash[:success] = "Comment added successfully!"
else
flash.now[:error] = "Comment could not be saved"
render 'new'
end
end
def update
#post_comment = #post.post_comments.find(params[:id])
if
#post_comment.update(post_comment_params)
redirect_to post_post_comment_path
flash[:success] = "Comment successfully updated"
else
flash.now[:error] = "Comment could not be updated"
render 'edit'
end
end
def destroy
#post_comment = #post.post_comments.find(params[:id])
#post_comment.destroy
redirect_to post_post_comments_path
flash[:success] = "The comment was successfully deleted"
end
end
private
def find_todo_list
#post = Post.find_by(params[:post_id])
end
def post_comment_params
params.require(:post_comment).permit(:comment)
end
My controller spec that keeps failing:
describe "POST #create" do
context "flash messages" do
let(:post) {create(:post)}
it "sets flash success" do
post :create, :post_id => post.to_param, :post_comment => attributes_for(:post_comment, comment: "New")
expect(flash[:success]).to eq("Comment added successfully!")
end
end
end
I'm using factory girl so here is my factory for post comments, which has a belongs_to association with a post...duh
factory :post_comment do
comment "Post comment"
post
end
Any help would really help me out, thanks!
let(:post) {create(:post)}
# ...
post :create
let is a fancy way of defining a method on the current RSpec example. post is now a method that accepts 0 arguments, thus the message wrong number of arguments (2 for 0).
Try naming your Post object something else.

RSpec ActiveRecord::RecordNotFound Couldn't find User with 'id'=

There are many answered questions about this topic but I can't seem to apply the answers to my issue. I'm getting the following error:
ItemsController POST create redirect to show page
Failure/Error: #user = User.find(params[:user_id])
ActiveRecord::RecordNotFound:
Couldn't find User with 'id'=
I know the reason for the error is because the user_id is nil but I can't seem to figure out the reason why. I'm still fairly new to Rails so excuse me if this is a really easy fix.
RSpec Test
require 'rails_helper'
RSpec.describe ItemsController, type: :controller do
describe "POST create" do
it "redirect to show page" do
post :create, user_id: #user, item: { name: "name"}
expect(response).to redirect_to(user_show_path)
end
end
end
Items Controller
class ItemsController < ApplicationController
def create
#user = User.find(params[:user_id])
#item = Item.new(item_params)
#item.user = current_user
if #item.save
#item = Item.update_items(params[:items])
redirect_to current_user, notice: "Item was saved successfully."
else
flash[:error] = "Error creating item. Please try again."
render user_show_path
end
end
private
def item_params
params.require(:item).permit(:name)
end
end
Routes
user_items POST /users/:user_id/items(.:format) items#create
...and I've implemented Devise for the user part. Thanks in advance for the help!
You need to create #user before using it. You can use factory_girl gem or directly do
#user = User.create
post :create, user_id: #user.id, item: { name: "name"}
Hope this works

How to run minitest for controller methods?

post_controller file
class PostsController < ActionController::Base
before_action :authenticate_user!
def index
#post = current_user.posts.paginate(page: params[:page], per_page: 5)
respond_to do |format|
format.html
format.json { render json: #post }
end
end
def new
#post = Post.new
end
def create
#post = current_user.posts.build(post_param)
if #post.save
redirect_to action: 'index'
else
render 'new'
end
post_controller_test
require 'test_helper'
class PostsControllerTest < ActionController::TestCase
include Devise::TestHelpers
def setup
#user = users(:Bob)
#post = Post.new
end #passed
test 'logged in should get show' do
sign_in #user
get :index
assert_response :success
end #passed
test 'not authenticated should get redirect' do
get :index
assert_response :redirect
end #passed
test 'should get index' do
get :index
assert_response :success
assert_not_nil assigns(:posts)
end #failing
test "should destroy post" do
assert_difference('Post.count', -1) do
delete :destroy, id: #post
end
assert_redirected_to posts_path
end #failing
...
devise is setup and working fine but why I am getting 302 error in last two cases. Is it because I am not passing #user parameters to it? I did but it was still throwing the same error. I also checked out my routes file which is fine because post_controller is working fine in development mode.
What I am doing wrong here?
Edit-1
I tried to create test cases for create method
def setup
#user = users(:bob)
#p = posts(:one)
#post = Post.new
end
test 'should create post' do
sign_in #user
assert_difference('Post.count') do
post :create, post: { name: #p.name, value: #p.value}
end
end
I am getting ActionController::ParameterMissing: param is missing or the value is empty: post while in my controller class I do have
params.require(:post).permit(:name, :value, :user_id)
I also have all parameters in my .yml file i.e.
one:
name: 2
value: 3
It looks like you need to sign in before trying the index action. You're also testing the wrong instance variable name. You're testing #posts, but you've defined #post in the controller. Try this test instead:
test 'should get index' do
sign_in #user
get :index
assert_response :success
assert_not_nil assigns(:post)
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

Called id for nil, which would mistakenly be 4 in controller tests

I have this error in two of my tests:
test "should create question" do
assert_difference('Question.count') do
post :create, question: { question: 'apple', answer: "good", holder_id: 2}
end
end
test "should not create question" do
invalid_answer = "a" * 145
assert_difference('Question.count',0) do
post :create, question: { answer: invalid_answer }
end
assert_template 'new'
end
My create action
#create action
def create
#question = Question.new(params[:question])
#holder = Holder.find_by_id(#question.holder.id)
if #question.save
flash[:success] = "Question Saved"
redirect_to holder_path(#question.holder_id)
else
render 'new'
end
end
The stack trace shows it is on the create line both times. But, how come I get the Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id error?
Do I need to create an object first and then pass that in to the post create?
#question = Question.new(params[:question])
#holder = Holder.find_by_id(#question.holder.id)
Yes you were right, you need to create the Holder instance before running this test.
But why do you create all the ivars, do you need them in new?
If not it seems the code can be dryed up to
def create
question = Question.new(params[:question])
if question.save
flash[:success] = "Question Saved"
redirect_to holder_path(question.holder) # but some checks are in order here, no?
else
render 'new'
end
end
HTH
Robert

Resources