Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RSpec request spec post an empty array

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.

Valid

{ vendor_district_ids: [2, 4, 5, 6]}

Invalid

{ vendor_district_ids: []}

Request Spec with RSpec

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.

Value inside the controller

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.

Value 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.

Question

Am I doing something wrong inside the request spec or is this a bug from RSpec?

like image 773
DenicioCode Avatar asked Jul 18 '18 07:07

DenicioCode


3 Answers

Found the answer!

Problem

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

Solution

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
like image 138
NemyaNation Avatar answered Sep 18 '22 00:09

NemyaNation


That is actually caused by rack-test >= 0.7.0 [1].

It converts empty arrays to param[]= which is later decoded as [''].

If you try running the same code with e.g. rack-test 0.6.3 you will see that vendor_district_ids isn't added to the query at all:

# rack-test 0.6.3
Rack::Test::Utils.build_nested_query('a' => [])
# => ""

# rack-test >= 0.7.0
Rack::Test::Utils.build_nested_query('a' => [])
# => "a[]="

Rack::Utils.parse_nested_query('a[]=')
# => {"a"=>[""]}

[1] https://github.com/rack-test/rack-test/commit/ece681de8ffee9d0caff30e9b93f882cc58f14cb

like image 33
Maciej Majewski Avatar answered Sep 17 '22 00:09

Maciej Majewski


For everyone wondering — there's a shortcut solution:

post '/posts', params: { ids: [] }, as: :json
like image 37
jibiel Avatar answered Sep 20 '22 00:09

jibiel