rspec controller testing, Expected response to be a <redirect>, but was <200>
Asked Answered
H

2

5

I'm using rspec and Factory Girl for testing. When testing the POST #create section of my posts_controller I'm getting the error in the title.

Failures:

  1) PostsController POST #create with valid attributes redirects to the post
     Failure/Error: response.should redirect_to Post.last
       Expected response to be a <redirect>, but was <200>
     # ./spec/controllers/posts_controller_spec.rb:59:in `block (4 levels) in <top (required)>'

This is the code from the spec being tested. I'm sure it's not the most efficient way of doing this, but it does work.

  def create

    @post = Post.new(
      :text => post_params[:text],
      :embed => post_params[:embed],
      :user => current_user,
      :title => post_params[:title],
      :tag_list => post_params[:tag_list],
      :cagegory_ids => post_params[:category_ids]
    )


    if @post.save
      redirect_to @post
    else
      render 'new'
    end

  end

...

  private    
    def post_params
      params.require(:post).permit(:title, :text, :embed, :user_id, :tag_list,
                               :category_ids => [])
    end

Here's the factory.

FactoryGirl.define do  
  factory :post do
    title { Faker::Lorem.characters(char_count = 20) }
    text { Faker::Lorem.characters(char_count = 150) }
    user
    categories {
      Array(5..10).sample.times.map do
        FactoryGirl.create(:category)
      end
    }
  end
end

And the relevant part of the spec

  describe "POST #create" do
    context "with valid attributes" do
      it "saves the new post" do
        expect{
                post :create, post: FactoryGirl.create(:post).attributes
              }.to change(Post,:count).by(1)

      end

      it "redirects to the post" do
        post :create, post: FactoryGirl.create(:post).attributes
        response.should redirect_to Post.last
      end        
    end
  end

The other test, "saves the new post," works fine. I've tried other variations of the redirect_to line, such as "redirect_to(posts_path(assigns[:post])) and it throws the same error.

Any ideas?

Heretofore answered 15/2, 2014 at 19:24 Comment(2)
It'd be nice if you could post the controller code you're hitting.Valdivia
Yep, I meant to add that. Edited the post with the controller code, though I'm sure it could be more efficient.Heretofore
H
4

OK, I fixed my problem. It isn't pretty but it works.

The issue is with Factory Girl and associations, and I'm definitely not the first to have that problem, but none of the other solutions worked.

I ended up adding this before :each at the top of the POST #create section...

  describe "POST #create" do
    before :each do
      Post.destroy_all
      @cat = FactoryGirl.create(:category)
      @newpost = FactoryGirl.build(:post)
      @post_params = {category_ids: [@cat.id]}.merge(@newpost.attributes)
    end
...

...to put the post params into a new hash that I could call later on in the code like this...

  it "saves the new post" do
    expect{
             post :create, post: @post_params
           }.to change(Post,:count).by(1)
  end

  it "redirects to the post" do
    post :create, post: @post_params
    response.should redirect_to Post.last
  end 

So this is solved. It adds a bit of overhead to the test but it works. I won't mark this as THE solution for a couple of days in case someone else comes around with some better, simpler code. I definitely welcome any more ideas.

Heretofore answered 16/2, 2014 at 5:10 Comment(0)
O
3

I assume the problem is in factory. Most likely post instance didn't pass validations and controller renders new view, which is not redirect, but success 200. Add logger in the controller and take a look if record actually saves. You can also read through test log tail -f log/test.log.

Osmond answered 15/2, 2014 at 19:30 Comment(4)
Hmm, that seems to be it. It's balking on category_id being an unpermitted parameter. I have a validation in place making sure it has categories assigned. Interestingly, the one before the failing test isn't erroring out, it's working fine. And the code itself works in production. I thought .attributes was passing the post_params to it but apparently not.Heretofore
AND, sorry to keep hitting you with these things. Adding a logger doesn't seem to help me here. It saves when running the code, so no errors are there to report, but in test it isn't showing anything from the logger.Heretofore
OK, even after changing my post_params to permit! it still isn't working. tailing the log shows that the post it creates has category_id => nil. The factory has worked well on all my model tests, it will validate with no problems. I'm assuming there's some syntax in how I'm calling FactoryGirl in this test maybe? I'm not sure.Heretofore
I believe the issue was the create call on the factory. That was creating the record in the DB, thus when the attributes were posted, the record already existed, an error happened, and it rendered the new action with a 200, rather than redirecting after a successful creation of a new record.Illtempered

© 2022 - 2024 — McMap. All rights reserved.