I just ran into an issue which routed me to this question. The accepted solution guided me to the more effective implementation as of rack-test 0.6.3
.
I manually created ./spec/helpers/rspec_http_request_override_helper.rb
module RspecHttpRequestsOverrideHelper
def get(uri, params = {}, env = {}, &block)
super(uri, params, set_json_headers(env), &block)
end
def post(uri, params = {}, env = {}, &block)
super(uri, convert_to_json(params), set_json_headers(env), &block)
end
def put(uri, params = {}, env = {}, &block)
super(uri, convert_to_json(params), set_json_headers(env), &block)
end
def delete(uri, params = {}, env = {}, &block)
super(uri, convert_to_json(params), set_json_headers(env), &block)
end
# override other HTTP methods if necessary
private
def set_json_headers(env={})
env.merge({'ACCEPT' => "application/json", 'CONTENT_TYPE' => 'application/json'}) unless env.nil?
end
def convert_to_json(params={})
params.to_json unless params.nil?
end
end
Then I added the below to my spec_helper.rb
# require assuming project root is loaded into ruby's class paths
require './spec/helpers/rspec_http_request_override_helper'
RSpec.configure do |config|
config.include RspecHttpRequestsOverrideHelper
# Other settings
end
And that was it!
Note: The get
method above doesn't convert the params value to json intentionally. Param values are encoded into the query string and then sent. Not as part of the HTTP body in the request, even though the GET
http method supports sending a body; see here for more details.
My issue was that the rspec test helpers for an API I am building were converting boolean types to string types when sending the request to the API. Turns out when you don't specify a content-type header for json
the data is passed as multipart/form-data
or x-www-form-urlencoded
depending on the HTTP method; see here for more details. This was converting my special data types, which are valid in json like integers and booleans, into strings. And effectively needing me to convert them on the API's end. It wasn't until I added validation for the input into my API that this was exposed. Yay for validations and tests!
Now, I needed to effectively apply a content-type header to all my requests and convert the params to json when sending the requests; I was calling the http methods with the params value being a ruby hash. I have over 200 tests so going in an manually changing them all would not have been an optimal solution. So I implemented the below solution. Which works very well.
I decided to follow the same method definition as rack-test was and then I could effectively call super after editing the requests.
My failing tests now started passing and my previous tests where none the wiser.
Hopefully this helps others who run into a similar issue.