3

I'm using Rack::Test to test my app and need to test the posting of data via AJAX.

My test looks like:

describe 'POST /user/' do
  include Rack::Test::Methods
  it 'must allow user registration with valid information' do
    post '/user', {
      username: 'test_reg',
      password: 'test_pass',
      email: 'test@testreg.co'
    }.to_json, {"CONTENT_TYPE" => 'application/json', "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest"}
    last_response.must_be :ok?
    last_response.body.must_match 'test_reg has been saved'
  end
end

But at the server end it's not receiving the POSTed data.

I also tried just passing in the params hash without the to_json but that made no difference.

Any idea how to do this?

Dave Sag
  • 13,266
  • 14
  • 86
  • 134

2 Answers2

4

Your post endpoint must parse the posted JSON body itself, which I assume you already do. Can you post how your end point works, also the rack-test, rack,ruby and sinatra version numbers? Please mention also how you test whether the server's receiving anything -- namely test mockup may confuse your detection.

    post '/user' do
       json_data = JSON.parse(request.body.read.to_s)
       # or # json_data = JSON.parse(request.env["rack.input"].read)
       ...
    end
diminish
  • 91
  • 1
  • 4
  • Interesting. In my actual application code Sinatra's `params` variable gets populated automagically with the data coming in from the AJAX request, but when data is sent from the test I can extract it as you recommend, but `params` is not populated. Indeed when I add the `JSON.parse` line to my code I get a `JSON::ParserError`. This makes me suspect that issue is with the way the `jQuery forms` plugin's `ajaxSubmit` method is sending the data. Seems my error is not in the test after all. Thanks you've given me a line of enquiry to explore further. – Dave Sag Sep 18 '13 at 00:46
2

Okay so my solution is a little weird and specific to the way I am triggering my JSON request in the first place, namely using jQuery Validation and jQuery Forms plugins on the client end. jQuery Forms doesn't bundle the form fields into a stringified Hash as I'd expected, but sends the form fields via AJAX but as a classic URI encoded params string. So by changing my test to the following, it now works fine.

describe 'POST /user/' do
  include Rack::Test::Methods
  it 'must allow user registration with valid information' do
    fields = {
      username: 'test_reg',
      password: 'test_pass',
      email: 'test@testreg.co'
    }
    post '/user', fields, {"HTTP_X_REQUESTED_WITH" => "XMLHttpRequest"}
    last_response.must_be :ok?
    last_response.body.must_match 'test_reg has been saved'
  end
end

Of course this is specific to the way the jQuery Forms plugin works and not at all how one would normally go about testing the POSTing of JSON data via AJAX. I hope this helps others.

Dave Sag
  • 13,266
  • 14
  • 86
  • 134
  • 1
    Is that necessary? I was under the impression that if you drop the Content-Type and URI.encode_www_form that it would process the form as either JSON or Form-URL-Encoded automatically. (You haven't mentioned here or in the question whether you tried without the third (ie. the hash) argument to post().) – Rob Howard Sep 18 '13 at 07:13
  • Thanks @RobHoward, I altered my tests and you are right. I've updated my answer accordingly. I still need the `HTTP_X_REQUESTED_WITH` param tho so the server knows it's an AJAX thing. Cheers D – Dave Sag Sep 19 '13 at 06:52
  • 1
    THANK YOU. I was attempting to get a test case to work and it was failing because I could not figure out how to get it to send an xhr request (in Padrino with Minitest if that's any help). adding the `HTTP_X_REQUESTED_WITH` header solved this! – Oranges13 Feb 09 '16 at 18:53