Search code examples
ruby-on-railsrspecrspec-rails

Rspec ArgumentError: wrong number of arguments (given 2, expected 0)


I have rspec test for nested object (comment), it is nested in posts object. Here is the routes.rb:

  use_doorkeeper

  resources :posts do
    resources :comments 
  end

  root "posts#index"
end

Here is part of comments controller:

 class CommentsController < ApplicationController
  before_action :find_comment, only: [:destroy]
  before_action :authenticate_user!, only: [:destroy]

  def create
    @post = Post.find(params['post_id'])
    @comment = @post.comments.create(params[:comment].permit(:name, :comment, :user_id, :best, :file))
    respond_to do |format|
      format.html { redirect_to post_path(@post) }
      format.js
    end
  end
  private

  def find_comment
    @post = Post.find(params[:post_id])
    @comment = @post.comments.find(params[:id])
  end
end

And here is rspec test:

 require 'rails_helper'

    RSpec.describe CommentsController, type: :controller do
      let(:user) { create(:user) }
      let(:post) { create(:post) }
    
      sign_in_user
    
      setup do
        allow(controller).to receive(:current_user).and_return(user)
      end
    
      describe 'POST #create' do
        context 'with valid attributes' do
          let!(:posts) { post :create, params: { post_id: post, comment: attributes_for(:comment) } }
    
          it 'saves the new comment in the database' do
            expect {{ comment: attributes_for(:comment) } }.to change(Comment, :count).by(1)
          end
        end
      end
    
    end

Additional factory file for comments:

 FactoryBot.define do
  factory :comment do
    comment { 'Comment' }
    name { 'Name' }
    post
    user_id { create(:user).id }
  end
end

Macros to authorize user:

 module ControllerMacros
  def sign_in_user
    before do
      @user = create(:user)
      @request.env['devise.mapping'] = Devise.mappings[:user]
      sign_in @user
    end
  end
end

So when I run spec test, I got this error:

 ArgumentError: wrong number of arguments (given 2, expected 0)

What may be the problem, why can't I run CREATE rspec?


Solution

  • You have a couple of things going on here. The error is because your let(:post) memoized helper is overriding the name of the post method. So, when you call post :create ... it is very unhappy. So, you just need to change the name of your memoized helper to something other than :post.

    The second issue is your expectation will never pass:

    expect {{ comment: attributes_for(:comment) } }.to change(Comment, :count).by(1)
    

    When you use the expect {}...to change() form, RSpec literally checks that what's inside the expect block drives the specified change. In your case, the code inside the expect block doesn't create a Comment record in the database, it just returns a hash of attributes for a mock Comment so it will never pass. You do create a new Comment at the start of the context block, but it doesn't count since it's outside the expect block.

    One way to fix that is to simply move the POST into the expect block:

    RSpec.describe CommentsController, type: :controller do
      let(:user) { create(:user) }
      let(:faux_post) { create(:post) } // Different name to avoid clash
    
      // ... stuff omitted
      
      describe 'POST #create' do
        context 'with valid attributes' do
          it 'saves the new comment in the database' do
            expect do
              post :create, params: { post_id: faux_post, comment: attributes_for(:comment) }
            end.to change(Comment, :count).by(1)
          end
        end
      end
    end