Search code examples
ruby-on-railsrspec-rails

RSpec request spec for post action that includes headers results in parms being dropped


I am trying to figure out why I can't use use both params and headers in an request spec.

What works:

RSpec.describe  Api::V1::UsersController, :type => :request  do

  before { host! 'api.localhost:3000'}

  let(:params) {
    {
      "user": {
        "identifier_for_vendor": "BD43813E"
      }
    }
  }

  describe 'Post /users' do
    context 'when request is valid' do
      before {
        post api_users_path,
        params: params
      }

      it "is successful" do
        expect(response).to be_successful
      end
    end
  end
end

What does not:

RSpec.describe  Api::V1::UsersController, :type => :request  do

  let(:params) {
    {
      "user": {
        "identifier_for_vendor": "BD43813E"
      }
    }
  }

  let(:headers) {
    {
      "host": "api.localhost:3000",
      "Accept": "application/vnd.domain_name.v1",
      "Content-Type": "application/vnd.api+json",
      "X-API-Key": "fake087uakey"
    }
  }

  describe 'Post /users' do
    context 'when request is valid' do
      before {
        post api_users_path,
        params: params,
        headers: headers
      }

      it "successful" do
        expect(response).to be_successful
      end
    end
  end
end

The above fails, returning the error:

  1) Api::V1::UsersController Post /users when request is valid is successful 
     Failure/Error: params.require(:user).permit(:identifier_for_vendor)

     ActionController::ParameterMissing:
       param is missing or the value is empty: user

The headers are needed due to having to ensure that valid api-keys are included in the request.

Would appreciate feedback on what I am missing. Thank you

Versions:

  • Ruby version: 2.6.3
  • Rails version: 6.0.3.4
  • RSpec 3.10

Solution

  • So issue had to do with how params and headers objects are created.

    Params:

    • I passed in:
      {"user": {"identifier_for_vendor": "OFJPJ"} }
    
    • the correct object is:
      {:params=>{:user=>{:identifier_for_vendor=>"OFJPJ"}}}
    

    Headers:

    • I passed in:
        {
          "host": "api.localhost:3000",
          "Accept": "application/vnd.domain_name.v1",
          "Content-Type": "application/vnd.api+json",
          "X-API-Key": "fake087uakey"
        }
    
    
    • the correct object is:
    {
      "headers" => {
        "host" => "api.localhost:3000", 
        "Accept" => "application/vnd.domain_name.v1", 
        "X-API-Key" => "api_key"
      }
    }
    

    Final solution looks like this:

    RSpec.describe  Api::V1::UsersController, :type => :request  do
    
      describe 'Post /users' do
        context 'when request is valid' do
    
    
          before do
            post api_users_path,
            :params => params,
            :headers => headers
          end
    
    
          it "is successful" do
            expect(response).to be_successful
          end
    
          it "returns a data of type user" do
            expect(json_data["type"]).to eq("user")
          end
        end
      end
    end
    

    The key to figuring this out was reading the documentation and realizing the my formatting was wrong.