diff options
Diffstat (limited to 'actionpack/test/dispatch/request/json_params_parsing_test.rb')
-rw-r--r-- | actionpack/test/dispatch/request/json_params_parsing_test.rb | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/actionpack/test/dispatch/request/json_params_parsing_test.rb b/actionpack/test/dispatch/request/json_params_parsing_test.rb new file mode 100644 index 0000000000..2a48a12497 --- /dev/null +++ b/actionpack/test/dispatch/request/json_params_parsing_test.rb @@ -0,0 +1,201 @@ +# frozen_string_literal: true + +require "abstract_unit" + +class JsonParamsParsingTest < ActionDispatch::IntegrationTest + class TestController < ActionController::Base + class << self + attr_accessor :last_request_parameters + end + + def parse + self.class.last_request_parameters = request.request_parameters + head :ok + end + end + + def teardown + TestController.last_request_parameters = nil + end + + test "parses json params for application json" do + assert_parses( + { "person" => { "name" => "David" } }, + "{\"person\": {\"name\": \"David\"}}", "CONTENT_TYPE" => "application/json" + ) + end + + test "parses boolean and number json params for application json" do + assert_parses( + { "item" => { "enabled" => false, "count" => 10 } }, + "{\"item\": {\"enabled\": false, \"count\": 10}}", "CONTENT_TYPE" => "application/json" + ) + end + + test "parses json params for application jsonrequest" do + assert_parses( + { "person" => { "name" => "David" } }, + "{\"person\": {\"name\": \"David\"}}", "CONTENT_TYPE" => "application/jsonrequest" + ) + end + + test "does not parse unregistered media types such as application/vnd.api+json" do + assert_parses( + {}, + "{\"person\": {\"name\": \"David\"}}", "CONTENT_TYPE" => "application/vnd.api+json" + ) + end + + test "nils are stripped from collections" do + assert_parses( + { "person" => [] }, + "{\"person\":[null]}", "CONTENT_TYPE" => "application/json" + ) + assert_parses( + { "person" => ["foo"] }, + "{\"person\":[\"foo\",null]}", "CONTENT_TYPE" => "application/json" + ) + assert_parses( + { "person" => [] }, + "{\"person\":[null, null]}", "CONTENT_TYPE" => "application/json" + ) + end + + test "logs error if parsing unsuccessful" do + with_test_routing do + output = StringIO.new + json = "[\"person]\": {\"name\": \"David\"}}" + post "/parse", params: json, headers: { "CONTENT_TYPE" => "application/json", "action_dispatch.show_exceptions" => true, "action_dispatch.logger" => ActiveSupport::Logger.new(output) } + assert_response :bad_request + output.rewind && err = output.read + assert err =~ /Error occurred while parsing request parameters/ + end + end + + test "occurring a parse error if parsing unsuccessful" do + with_test_routing do + $stderr = StringIO.new # suppress the log + json = "[\"person]\": {\"name\": \"David\"}}" + exception = assert_raise(ActionDispatch::Http::Parameters::ParseError) do + post "/parse", params: json, headers: { "CONTENT_TYPE" => "application/json", "action_dispatch.show_exceptions" => false } + end + assert_equal JSON::ParserError, exception.cause.class + assert_equal exception.cause.message, exception.message + ensure + $stderr = STDERR + end + end + + test "raw_post is not empty for JSON request" do + with_test_routing do + post "/parse", params: '{"posts": [{"title": "Post Title"}]}', headers: { "CONTENT_TYPE" => "application/json" } + assert_equal '{"posts": [{"title": "Post Title"}]}', request.raw_post + end + end + + private + def assert_parses(expected, actual, headers = {}) + with_test_routing do + post "/parse", params: actual, headers: headers + assert_response :ok + assert_equal(expected, TestController.last_request_parameters) + end + end + + def with_test_routing + with_routing do |set| + set.draw do + ActiveSupport::Deprecation.silence do + post ":action", to: ::JsonParamsParsingTest::TestController + end + end + yield + end + end +end + +class RootLessJSONParamsParsingTest < ActionDispatch::IntegrationTest + class UsersController < ActionController::Base + wrap_parameters format: :json + + class << self + attr_accessor :last_request_parameters, :last_parameters + end + + def parse + self.class.last_request_parameters = request.request_parameters + self.class.last_parameters = params.to_unsafe_h + head :ok + end + end + + def teardown + UsersController.last_request_parameters = nil + end + + test "parses json params for application json" do + assert_parses( + { "user" => { "username" => "sikachu" }, "username" => "sikachu" }, + "{\"username\": \"sikachu\"}", "CONTENT_TYPE" => "application/json" + ) + end + + test "parses json params for application jsonrequest" do + assert_parses( + { "user" => { "username" => "sikachu" }, "username" => "sikachu" }, + "{\"username\": \"sikachu\"}", "CONTENT_TYPE" => "application/jsonrequest" + ) + end + + test "parses json with non-object JSON content" do + assert_parses( + { "user" => { "_json" => "string content" }, "_json" => "string content" }, + "\"string content\"", "CONTENT_TYPE" => "application/json" + ) + end + + test "parses json params after custom json mime type registered" do + Mime::Type.unregister :json + Mime::Type.register "application/json", :json, %w(application/vnd.rails+json) + assert_parses( + { "user" => { "username" => "meinac" }, "username" => "meinac" }, + "{\"username\": \"meinac\"}", "CONTENT_TYPE" => "application/json" + ) + ensure + Mime::Type.unregister :json + Mime::Type.register "application/json", :json, %w( text/x-json application/jsonrequest ) + end + + test "parses json params after custom json mime type registered with synonym" do + Mime::Type.unregister :json + Mime::Type.register "application/json", :json, %w(application/vnd.rails+json) + assert_parses( + { "user" => { "username" => "meinac" }, "username" => "meinac" }, + "{\"username\": \"meinac\"}", "CONTENT_TYPE" => "application/vnd.rails+json" + ) + ensure + Mime::Type.unregister :json + Mime::Type.register "application/json", :json, %w( text/x-json application/jsonrequest ) + end + + private + def assert_parses(expected, actual, headers = {}) + with_test_routing(UsersController) do + post "/parse", params: actual, headers: headers + assert_response :ok + assert_equal(expected, UsersController.last_request_parameters) + assert_equal(expected.merge("action" => "parse"), UsersController.last_parameters) + end + end + + def with_test_routing(controller) + with_routing do |set| + set.draw do + ActiveSupport::Deprecation.silence do + post ":action", to: controller + end + end + yield + end + end +end |