I am current developing an API endpoint in rails. I want to be sure the endpoint response with the correct error status if the data I need is invalid. I need an array of ids. One of the invalid values is an empty array.
{ vendor_district_ids: [2, 4, 5, 6]}
{ vendor_district_ids: []}
So I want to have a request spec to control my behaviour.
require 'rails_helper'
RSpec.describe Api::PossibleAppointmentCountsController, type: :request do
let(:api_auth_headers) do
{ 'Authorization' => 'Bearer this_is_a_test' }
end
describe 'POST /api/possible_appointments/counts' do
subject(:post_request) do
post api_my_controller_path,
params: { vendor_district_ids: [] },
headers: api_auth_headers
end
before { post_request }
it { expect(response.status).to eq 400 }
end
end
As you can see I use an empty array in my param inside the subject
block.
In my controller I am fetching the data with
params.require(:vendor_district_ids)
and the value is the following
<ActionController::Parameters {"vendor_district_ids"=>[""], "controller"=>"api/my_controller", "action"=>"create"} permitted: false>
The value of vendor_district_ids
is an array with an empty string. I do not have the same value when I make a post with postman
.
If I post
{ "vendor_district_ids": [] }
the controller will receive
<ActionController::Parameters {"vendor_district_ids"=>[], "controller"=>"api/my_controller", "action"=>"create"} permitted: false>
And here is the array empty.
Am I doing something wrong inside the request spec or is this a bug from RSpec
?
Found the answer!
The problem is found inside Rack's query_parser
not actually inside rack-test as the previous answer indicates.
The actual translation of "paramName[]="
into {"paramName":[""]}
happens in Rack's query_parser.
An example of the problem:
post '/posts', { ids: [] }
{"ids"=>[""]} # By default, Rack::Test will use HTTP form encoding, as per docs: https://github.com/rack/rack-test/blob/master/README.md#examples
Convert your params into JSON, by requiring the JSON gem into your application using 'require 'json'
and appending your param hash with .to_json
.
And specifying in your RSPEC request that the content-type of this request is JSON.
An example by modifying the example above:
post '/posts', { ids: [] }.to_json, { "CONTENT_TYPE" => "application/json" }
{"ids"=>[]} # explicitly sending JSON will work nicely