Search code examples
ruby-on-railsrubyrspectddvcr

JSON::ParserError: unexpected token at '' on Rails Rspec


I'm quite having an issue on my Rspec. So basically what I want is to send a request to the API, and have a proper response. When I send the data to the API endpoint, and I puts what it sends, it looks like it sends all the data correctly, but at the response level, it says that I am not sending the required parameters. (I am also using VCR to test)

My RSPEC:

require 'rails_helper'

describe 'Create Vendor', type: :request do
  let(:user) { create(:alter_user) }
  let(:vendor_attributes) do
    {
      #These are all the required parameters
      vendor: {
        token: '',
        refcode: '',
        request_type: 'renters',
        first_name: 'Tony',
        last_name: 'Stark',
        phone: '6504881234',
        phone_type: 'mobile',
        email: '[email protected]',
        address1: '123 Main Street',
        address_city: 'Palo Alto',
        address_state: 'CA',
        address_zip: '94301',
        DOB: '1982-10-27'
      }
    }
  end

  after do
    VCR.eject_cassette
  end

  it 'creates a vendor' do
    VCR.use_cassette('create_vendor') do
      post '/api/v2/vendor', params: vendor_attributes.to_json, headers: {'Content-Type' => 'application/json', Authorization: "Token token=#{user.key}"}
      response_body = JSON.parse(response.body)
      expect(response_body['refcode']).to eq('corp-api-test')
    end
  end

  it 'fails if the vendor is missing attributes' do
    VCR.use_cassette('create_vendor_missing_attributes') do
      post '/api/v2/vendor', params: {vendor: {last_name: 'Stark', phone: '6504881234'}}.to_json, headers: {'Content-Type' => 'application/json', Authorization: "Token token=#{user.key}"}
      expect(response.status).to eq(422)
    end
  end

  it 'requires Authorization token header' do
    post '/api/v2/vendor', params: vendor_attributes.to_json, headers: {'Content-Type' => 'application/json'}
    expect(response.status).to eq(401)
  end
end

When I execute the rspec filePath I receive this:

Create Vendor
Post Request----: {"request_type":"renters","first_name":"Tony","last_name":"Stark","phone":"6504881234","phone_type":"mobile","email":"[email protected]","address1":"123 Main Street","address_city":"Palo Alto","address_state":"CA","address_zip":"94301","DOB":"1982-10-27","token":"6ed469496be882f0163c453627fbcac15b773733db123a7c2faf68f42ea7586a","refcode":"corp-api-test"}

-----------------------------------------------------
Response----: {:action=>"new_vendor", :user_hash=>"e59871c35edb7f622c97acfcc20955e9", :result=>"success", :agent_phone=>"888-888-8888", :vendor_uuid=>"242992518092902061", :policy_shell_uuids=>{"RENT"=>"243548182003445420"}, :marketing_headline=>"Test Marketing Headline", :marketing_content=>"<ul><li>Test Marketing Content</li></ul>"}

-----------------------------------------------------
It was successful
  creates a vendor (FAILED - 1)
Post Request----: {"last_name":"Stark","phone":"6504881234","token":"6ed469496be882f0163c453627fbcac15b773733db123a7c2faf68f42ea7586a","refcode":"corp-api-test"}

-----------------------------------------------------
Response----: {:result=>"error", :message=>"missing fields: first_name is a required field, email is a required field, address1 is a required field, address_city is a required field, address_state is a required field, address_zip is a required field, DOB is a required field, phone_type is a required field"}

-----------------------------------------------------
  fails if the vendor is missing attributes
  requires Authorization token header

Failures:

  1) Create Vendor creates a vendor
     Failure/Error: response_body = JSON.parse(response.body)

     JSON::ParserError:
       809: unexpected token at ''
     # ./spec/requests/create_vendor_spec.rb:34:in `block (3 levels) in <top (required)>'
     # ./spec/requests/create_vendor_spec.rb:32:in `block (2 levels) in <top (required)>'
     # ./spec/spec_helper.rb:85:in `block (3 levels) in <top (required)>'
     # ./spec/spec_helper.rb:84:in `block (2 levels) in <top (required)>'

This is my vendor controller

As you can see here I print what I send to the API, it sends the data but then it fails to create a vendor.

def corp_new_vendor_v2
    arguments = create_vendor_arguments
    https = Net::HTTP.new(VENDOR_CREATE_VENDOR_URI.host, VENDOR_CREATE_VENDOR_URI.port)
    https.use_ssl = true
    post_request = Net::HTTP::Post.new(VENDOR_CREATE_VENDOR_URI)
    post_request['Content-Type'] = 'application/json'
    post_request.body = JSON.dump(arguments)
    
    print "Post Request----: #{post_request.body}\n\n"
    print "-----------------------------------------------------\n"
    response = JSON.parse(https.request(post_request).read_body).symbolize_keys
    print "Response----: #{response}\n\n"
    print "-----------------------------------------------------\n"
    if response[:result] == 'success'
      puts 'It was successful'
    else
      render json: { error: response[:message] }, status: :unprocessable_entity
    end
  end

  # This is used once we touch the new vendor endpoint, and response with a response
  def create_vendor_attributes(response)
    response.slice(:action, :user_hash, :result, :vendor_uuid, :policy_shell_uuids, :refcode, :return_URL)
  end

  def create_vendor_params
    params.require(:vendor).permit(
      :request_type, :first_name, :last_name, :phone, :phone_type, :email, :address1, :address_city, :address_state, :address_zip, :DOB
    )
  end

  def create_vendor_arguments
    create_vendor_params.to_h.merge(token: CORP_RENTER_TOKEN, refcode: CORP_REFCODE)
  end
end

What am I missing here? On my spec I'm sending everything but I keep receiving the par JSON error.

I will appreciate the help!

EDIT

binding.pry

Create Vendor
# here it sends all the data as in the unit testing
Post Request (Unit Test)----: {"request_type":"renters","first_name":"Tony","last_name":"Stark","phone":"6504881234","phone_type":"mobile","email":"[email protected]","address1":"123 Main Street","address_city":"Palo Alto","address_state":"CA","address_zip":"94301","DOB":"1982-10-27","token":"6ed469496be882f0163c453627fbcac15b773733db123a7c2faf68f42ea7586a","refcode":"corp-api-test"}

-----------------------------------------------------
# And here it responds correctly
Response----(Unit Test): {:action=>"new_vendor", :user_hash=>"e59871c35edb7f622c97acfcc20955e9", :result=>"success", :agent_phone=>"888-888-8888", :vendor_uuid=>"242992518092902061", :policy_shell_uuids=>{"RENT"=>"243548182003445420"}, :marketing_headline=>"Test Marketing Headline", :marketing_content=>"<ul><li>Test Marketing Content</li></ul>"}

-----------------------------------------------------
  creates a vendor (FAILED - 1)
    # Here for some reason it only sends two parameters
Post Request----(Not Unit Test): {"last_name":"Stark","phone":"6504881234","token":"6ed469496be882f0163c453627fbcac15b773733db123a7c2faf68f42ea7586a","refcode":"corp-api-test"}

-----------------------------------------------------
    # And obviously the server response with an error cause it's not sending all the required data.
Response----(Not Unit Test): {:result=>"error", :message=>"missing fields: first_name is a required field, email is a required field, address1 is a required field, address_city is a required field, address_state is a required field, address_zip is a required field, DOB is a required field, phone_type is a required field"}

create method

def create
    vendor_new_vendor_v2
end

which uses these two methods to sends the parameters

  def create_vendor_params
    params.require(:vendor).permit(
      :request_type, :first_name, :last_name, :phone, :phone_type, :email, :address1, :address_city, :address_state, :address_zip, :DOB
    )
  end

  def create_vendor_arguments
    create_vendor_params.to_h.merge(token: CORP_RENTER_TOKEN, refcode: CORP_REFCODE)
  end

specs

  it 'creates a vendor' do
    VCR.use_cassette('create_vendor') do
      post '/api/v2/vendor', params: vendor_attributes.to_json, headers: {'Content-Type' => 'application/json', Authorization: "Token token=#{user.key}"}
      response_body = JSON.parse(response.body)
      expect(response_body['refcode']).to eq('corp-api-test')
    end
  end


#I just saw that these two `last_name`and `phone`are being printed on the puts I did above. 
  it 'fails if the vendor is missing attributes' do
    VCR.use_cassette('create_vendor_missing_attributes') do
      post '/api/v2/vendor', params: {vendor: {last_name: 'Stark', phone: '6504881234'}}.to_json, headers: {'Content-Type' => 'application/json', Authorization: "Token token=#{user.key}"}
      expect(response.status).to eq(422)
    end
  end

  it 'requires Authorization token header' do
    post '/api/v2/vendor', params: vendor_attributes.to_json, headers: {'Content-Type' => 'application/json'}
    expect(response.status).to eq(401)
  end
end

Solution

  • You are missing the render :json for the success.

    Update your controller with the following

    if response[:result] == 'success'
          render json: response, status: :ok
        else
          render json: { error: response[:message] }, status: :unprocessable_entity
        end