legendary_rob
legendary_rob

Reputation: 13012

Rails/Rspec JSON integers being converted to strings when testing post call

I am testing a JSON request to our API, It will respond with JSON. It seems like all the integers within the JSON get converted to strings as we post them to the controller consider action.

Controller

  def consider
    binding.pry # binding no# 2 used to check the params after post from test.
    if ParametersValidator.is_valid?(params)
      application_handler = ApplicationHandler.new(request_interactor)
      render json: application_handler.result
    else
      render json: ParametersValidator.failed_params(params).to_json
    end
  end

The ParamaterValidator validates the structure and types of data coming in.

Test

render_views
let(:json) { JSON.parse(response.body) }
..
..

it 'returns the result in the correct format for the AUTOMATIC APPROVE decision' do
  automatic_approve_params = relative_json_file(relative_file('automatic_approve_params'))
  expected_approve_params = {
    "status" => "accepted",
    "automated" => true,
    "rate" => 6,
    "amount" => 30000,
    "term" => 10,
    "pre_approved_amount" => 2500,
    "comments" => ""
  }
  @request.headers['HTTP_X_AUTH_SIG'] = Rails.application.secrets['authorization']['token']
  request.env["HTTP_ACCEPT"] = 'application/json'

  binding.pry  # binding no# 1 to inspect the params before post

  post :consider, automatic_approve_params, format: :json
  expect(json).to eq(expected_approve_params)
end

Binding no#1

{
 "student_id"=>1,
 "age"=>22,
 "name"=>"John",
 "age_range"=>"22-25",
 "criminal_record"=>false,
 "declared_bankrupt"=>false,
 "declared_insolvent"=>false,
 "declared_sequestrated"=>false,
 "defaulted_on_loan"=>false,
 "post_study_salary"=>100000000,
 "first_nationality"=>"PL",
 "second_nationality"=>"",
 "citizenship"=>"PL",
}

Binding no#2

{
 "student_id"=>"1",
 "age"=>"22",
 "name"=>"John",
 "age_range"=>"22-25",
 "criminal_record"=>false,
 "declared_bankrupt"=>false,
 "declared_insolvent"=>false,
 "declared_sequestrated"=>false,
 "defaulted_on_loan"=>false,
 "post_study_salary"=>"100000000",
 "first_nationality"=>"PL",
 "second_nationality"=>"",
 "citizenship"=>"PL",
}

The test log is showing that the request is

Processing by Api::V1::CreditApplicationsController#consider as JSON

Inspecting the request just before the post action you will see the params are fine, then in the controller before I run anything I inspect the params and they are all strings.

Using postman to test the API with the JSON works as expected but it seems that rspec when posting to the consider action will convert all the params to strings. I have read a few dozen posts that claim by adding format: :json to the post action it will remedy this, however I have had no such luck.

I am obviously doing something wrong but I have tried pretty much everything I know.

Upvotes: 22

Views: 10275

Answers (4)

Ayer
Ayer

Reputation: 140

None of the other answers worked for me and after a lot of tries, I found the solution to this issue. If you pass the params converted with to_json and pass 'CONTENT_TYPE' => 'application/json' as env, integer will be passed as is to the controllers.

let(:params) do
  {
    down_payment: 10_000,
    asking_price: 100_000,
    payment_schedule: 'weekly',
    amortization_period: 5
  }
end

it 'works' do
  post '/', params.to_json, 'CONTENT_TYPE' => 'application/json'
end

This will work as expected.

Upvotes: 0

Rich Kuzsma
Rich Kuzsma

Reputation: 1577

In Rails 5, use as: :json instead of format: :json, e.g. post :consider, params: automatic_approve_params, as: :json

Upvotes: 21

Selvamani
Selvamani

Reputation: 7684

We can try this

post 'orders.json', JSON.dump(order: {boolean: true, integer: 123}), "CONTENT_TYPE" => "application/json"

Upvotes: 1

HannesBenson
HannesBenson

Reputation: 842

After replicating the issue you are having I managed to resolve it in a controller spec using the following:

post :consider, automatic_approve_params.merge(format: :json)

In my local tests I removed the request.env["HTTP_ACCEPT"] = 'application/json' and it still worked as you expect it to. Hope it helps.

Upvotes: 24

Related Questions