Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Let TestResponse assign a parser. #25771

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
58 changes: 3 additions & 55 deletions actionpack/lib/action_dispatch/testing/integration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
require 'rack/test'
require 'minitest'

require 'action_dispatch/testing/request_encoder'

module ActionDispatch
module Integration #:nodoc:
module RequestHelpers
Expand Down Expand Up @@ -383,7 +385,6 @@ def process(method, path, params: nil, headers: nil, env: nil, xhr: false, as: n
response = _mock_session.last_response
@response = ActionDispatch::TestResponse.from_response(response)
@response.request = @request
@response.response_parser = RequestEncoder.parser(@response.content_type)
@html_document = nil
@url_options = nil

Expand All @@ -402,59 +403,6 @@ def build_expanded_path(path, request_encoder)
path = request_encoder.append_format_to location.path
location.query ? "#{path}?#{location.query}" : path
end

class RequestEncoder # :nodoc:
@encoders = {}

attr_reader :response_parser

def initialize(mime_name, param_encoder, response_parser, url_encoded_form = false)
@mime = Mime[mime_name]

unless @mime
raise ArgumentError, "Can't register a request encoder for " \
"unregistered MIME Type: #{mime_name}. See `Mime::Type.register`."
end

@url_encoded_form = url_encoded_form
@path_format = ".#{@mime.symbol}" unless @url_encoded_form
@response_parser = response_parser || -> body { body }
@param_encoder = param_encoder || :"to_#{@mime.symbol}".to_proc
end

def append_format_to(path)
if @url_encoded_form
path
else
path + @path_format
end
end

def content_type
@mime.to_s
end

def encode_params(params)
@param_encoder.call(params)
end

def self.parser(content_type)
mime = Mime::Type.lookup(content_type)
encoder(mime ? mime.ref : nil).response_parser
end

def self.encoder(name)
@encoders[name] || WWWFormEncoder
end

def self.register_encoder(mime_name, param_encoder: nil, response_parser: nil)
@encoders[mime_name] = new(mime_name, param_encoder, response_parser)
end

register_encoder :json, response_parser: -> body { JSON.parse(body) }

WWWFormEncoder = new(:url_encoded_form, -> params { params }, nil, true)
end
end

module Runner
Expand Down Expand Up @@ -777,7 +725,7 @@ def app=(app)
end

def register_encoder(*args)
Integration::Session::RequestEncoder.register_encoder(*args)
RequestEncoder.register_encoder(*args)
end
end

Expand Down
54 changes: 54 additions & 0 deletions actionpack/lib/action_dispatch/testing/request_encoder.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
module ActionDispatch
class RequestEncoder # :nodoc:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, should we move this to be under ActionDispatch::TestResponse? I feel like ActionDispatch::RequestEncoder sounds like it's being used in non-test environments. :(

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ActionDispatch::TestResponse::RequestEncoder doesn't exactly seem right either 😄

I'll put it in the Testing module which testing/integration.rb also uses.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah nope, it doesn't use that namespace. Anyway, I think it's fine to keep it as is then. It's nodoc'ed and under the testing/ folder.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@encoders = {}

attr_reader :response_parser

def initialize(mime_name, param_encoder, response_parser, url_encoded_form = false)
@mime = Mime[mime_name]

unless @mime
raise ArgumentError, "Can't register a request encoder for " \
"unregistered MIME Type: #{mime_name}. See `Mime::Type.register`."
end

@url_encoded_form = url_encoded_form
@path_format = ".#{@mime.symbol}" unless @url_encoded_form
@response_parser = response_parser || -> body { body }
@param_encoder = param_encoder || :"to_#{@mime.symbol}".to_proc
end

def append_format_to(path)
if @url_encoded_form
path
else
path + @path_format
end
end

def content_type
@mime.to_s
end

def encode_params(params)
@param_encoder.call(params)
end

def self.parser(content_type)
mime = Mime::Type.lookup(content_type)
encoder(mime ? mime.ref : nil).response_parser
end

def self.encoder(name)
@encoders[name] || WWWFormEncoder
end

def self.register_encoder(mime_name, param_encoder: nil, response_parser: nil)
@encoders[mime_name] = new(mime_name, param_encoder, response_parser)
end

register_encoder :json, response_parser: -> body { JSON.parse(body) }

WWWFormEncoder = new(:url_encoded_form, -> params { params }, nil, true)
end
end
9 changes: 7 additions & 2 deletions actionpack/lib/action_dispatch/testing/test_response.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
require 'action_dispatch/testing/request_encoder'

module ActionDispatch
# Integration test methods such as ActionDispatch::Integration::Session#get
# and ActionDispatch::Integration::Session#post return objects of class
Expand All @@ -10,6 +12,11 @@ def self.from_response(response)
new response.status, response.headers, response.body
end

def initialize(*) # :nodoc:
super
@response_parser = RequestEncoder.parser(content_type)
end

# Was the response successful?
alias_method :success?, :successful?

Expand All @@ -19,8 +26,6 @@ def self.from_response(response)
# Was there a server-side error?
alias_method :error?, :server_error?

attr_writer :response_parser # :nodoc:

def parsed_body
@parsed_body ||= @response_parser.call(body)
end
Expand Down
8 changes: 8 additions & 0 deletions actionpack/test/dispatch/test_response_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,12 @@ def assert_response_code_range(range, predicate)
assert_response_code_range 500..599, :server_error?
assert_response_code_range 400..499, :client_error?
end

test "response parsing" do
response = ActionDispatch::TestResponse.create(200, {}, '')
assert_equal response.body, response.parsed_body

response = ActionDispatch::TestResponse.create(200, { 'Content-Type' => 'application/json' }, '{ "foo": "fighters" }')
assert_equal({ 'foo' => 'fighters' }, response.parsed_body)
end
end