How to send raw post data in a Rails functional test?

后端 未结 12 1548
感情败类
感情败类 2020-12-13 12:07

I\'m looking to send raw post data (e.g. unparamaterized JSON) to one of my controllers for testing:

class LegacyOrderUpdateControllerTest < ActionControl         


        
相关标签:
12条回答
  • 2020-12-13 12:42

    Looking at stack trace running a test you can acquire more control on request preparation: ActionDispatch::Integration::RequestHelpers.post => ActionDispatch::Integration::Session.process => Rack::Test::Session.env_for

    You can pass json string as :params AND specify a content type "application/json". In other case content type will be set to "application/x-www-form-urlencoded" and your json will be parsed properly.

    So all you need is to specify "CONTENT_TYPE":

    post :index, '{"foo":"bar", "bool":true}', "CONTENT_TYPE" => 'application/json'
    
    0 讨论(0)
  • 2020-12-13 12:44

    Version for Rails 5:

    post :create, body: '{"foo": "bar", "bool": true}'
    

    See here - body string parameter is treated as raw request body.

    0 讨论(0)
  • 2020-12-13 12:47

    For those using Rails5+ integration tests, the (undocumented) way to do this is to pass a string in the params argument, so:

    post '/path', params: raw_body, headers: { 'Content-Type' => 'application/json' }
    
    0 讨论(0)
  • 2020-12-13 12:52

    The post method expects a hash of name-value pairs, so you'll need to do something like this:

    post :index, :data => '{"foo":"bar", "bool":true}'
    

    Then, in your controller, get the data to be parsed like this:

    post_data = params[:data]
    
    0 讨论(0)
  • 2020-12-13 12:59

    As of Rails 4.1.5, this was the only thing that worked for me:

    class LegacyOrderUpdateControllerTest < ActionController::TestCase
      def setup
        @request.headers["Content-Type"] = 'application/json'
      end
    
      test "sending json" do
        post :index, '{"foo":"bar", "bool":true}'.to_json, { account_id: 5, order_id: 10 }
      end
    end
    

    for a url at /accounts/5/orders/10/items. This gets the url params conveyed as well as the JSON body. Of course, if orders is not embedded then you can leave off the params hash.

    class LegacyOrderUpdateControllerTest < ActionController::TestCase
      def setup
        @request.headers["Content-Type"] = 'application/json'
      end
    
      test "sending json" do
        post :index, '{"foo":"bar", "bool":true}'.to_json
      end
    end
    
    0 讨论(0)
  • 2020-12-13 13:02

    I ran across the same issue today and found a solution.

    In your test_helper.rb define the following method inside of ActiveSupport::TestCase:

    def raw_post(action, params, body)
      @request.env['RAW_POST_DATA'] = body
      response = post(action, params)
      @request.env.delete('RAW_POST_DATA')
      response
    end
    

    In your functional test, use it just like the post method but pass the raw post body as the third argument.

    class LegacyOrderUpdateControllerTest < ActionController::TestCase
      test "sending json" do
        raw_post :index, {}, {:foo => "bar", :bool => true}.to_json
      end
    end
    

    I tested this on Rails 2.3.4 when reading the raw post body using

    request.raw_post
    

    instead of

    request.body.read
    

    If you look at the source code you'll see that raw_post just wraps request.body.read with a check for this RAW_POST_DATA in the request env hash.

    0 讨论(0)
提交回复
热议问题