Search code examples
ruby-on-railsrubyrspecrspec-rails

Rails 5 - Rspec Expect Change Count Not Working


This might be something really simple, but I can't get Rspec's expect change count to detect when a new record is created through the controller's create method.

Here is my test:

it "saves the new Post in the database" do
  expect{
    process :create, method: :post, params: { post: attributes_for(:post) }
  }.to change{Post.count}.by(1)  
end

it just errors with:

expected result to have changed by 1, but was changed by 0

Looking at the test.log it doesnt seem to show any errors when the post is created:

  [1m[35m (0.0ms)[0m  [1m[36mbegin transaction[0m
  [1m[35m (0.1ms)[0m  [1m[34mSELECT COUNT(*) FROM "posts"[0m
  Processing by PostsController#create as HTML
  Parameters: {"post"=>{"content"=>"Quas adipisci illum repellat sapiente eos. Quae temporibus facilis. Corporis odit eaque reiciendis eum tempora. Nam dolor sint pariatur.", "excerpt"=>"Dicta veritatis voluptate at. Sed voluptatem corrupti sed impedit quae consequatur. Velit voluptates nisi est nihil. Explicabo qui animi expedita rerum.", "image_url"=>"https://hd.unsplash.com/photo-1413781892741-08a142b23dfe", "keywords"=>"blog, post, key, words", "post_type"=>"article", "published"=>"false", "title"=>"Pariatur laborum ut nostrum quis rem sunt libero."}}
  [1m[35m (0.0ms)[0m  [1m[35mSAVEPOINT active_record_1[0m
  [1m[36mPost Exists (0.1ms)[0m  [1m[34mSELECT  1 AS one FROM "posts" WHERE "posts"."title" = ? LIMIT ?[0m  [["title", "Pariatur laborum ut nostrum quis rem sunt libero."], ["LIMIT", 1]]
  [1m[35m (0.0ms)[0m  [1m[31mROLLBACK TO SAVEPOINT active_record_1[0m
  Rendering /home/nitrous/code/blog/app/views/posts/index.html.haml within layouts/application
  Rendered /home/nitrous/code/blog/app/views/posts/index.html.haml within layouts/application (0.0ms)
  Completed 200 OK in 9ms (Views: 0.6ms | ActiveRecord: 0.2ms)
  [1m[35m (0.1ms)[0m  [1m[34mSELECT COUNT(*) FROM "posts"[0m
  [1m[35m (0.1ms)[0m  [1m[31mrollback transaction[0m

The post model validates that the title is unique.

I can see that the log says 'Post Exists' but if it does and this is the reason it's not saving a new Post. Why is that?


Solution

  • Ok, so I figured out why it wasn't saving a new Post record. For whatever reason, the author that was supposed to be assigned to the post in the :post factory was not being created. This meant that a validation failed.

    This is the :post factory I was using:

    FactoryGirl.define do
      factory :post do
        title { Faker::Lorem.sentence }
        excerpt { Faker::Lorem.paragraph }
        content { Faker::Lorem.paragraph }
        published false
        published_at nil
        post_type "article"
        keywords "blog, post, key, words"
        author
      end
    end
    

    And this was my :author factory for my Devise Author model:

    FactoryGirl.define do
      factory :author do
        email { Faker::Internet.email }
        password "password"
        password_confirmation "password"
      end
    end
    

    When I was generating the attributes using the FactoryGirl

    attributes_for(:post)
    

    method, the author was not being created and therefore the author_id attribute of the post was not being set.

    To fix this I had to create the author in the test then set the author_id attribute in the attributes_for method.

    So my working test now looks like this:

    it "saves the new Post in the database" do
      author = create(:author)
      expect{
        process :create, method: :post, params: { post: attributes_for(:post, author_id: author.id) }
      }.to change{Post.count}.by(1)  
    end
    

    Although this solves my original problem, I'm not sure why the Author was not being created and associated to the Post within the attributes_for call.