How to test JSON result from Ruby on Rails functional tests?

Ruby on-RailsJsonTdd

Ruby on-Rails Problem Overview


How can I assert my Ajax request and test the JSON output from Ruby on Rails functional tests?

Ruby on-Rails Solutions


Solution 1 - Ruby on-Rails

In Rails >= 5

Use ActionDispatch::TestResponse#parsed_body.

Example:

user = @response.parsed_body
assert_equal "Mike", user['name']

In Rails up to 4.x

Use JSON.parse, which takes a string as input and returns a Ruby hash that the JSON represents.

Example:

user = JSON.parse(@response.body)
assert_equal "Mike", user['name']

Solution 2 - Ruby on-Rails

Rails has JSON support built in:

def json_response
    ActiveSupport::JSON.decode @response.body
end

No need for a plugin

Then you can do something like this:

assert_equal "Mike", json_response['name']

Solution 3 - Ruby on-Rails

If you are using RSpec, json_spec is worth a look

https://github.com/collectiveidea/json_spec

Solution 4 - Ruby on-Rails

Also for short JSON responses you can simply match a string of the JSON to @response.body. This prevents having to rely on yet another gem.

assert_equal '{"total_votes":1}', @response.body

Solution 5 - Ruby on-Rails

In newer versions of rails, you can leverage parsed_body to get access to this in your tests without any work.

>Calling parsed_body on the response parses the response body based on the last response MIME type. > > Out of the box, only :json is supported. But for any custom MIME types you've registered, you can add your own encoders...

https://api.rubyonrails.org/v5.2.1/classes/ActionDispatch/IntegrationTest.html

Solution 6 - Ruby on-Rails

None of the answers provides a nice maintainable way to verify a JSON response. I find this one to be the best:

https://github.com/ruby-json-schema/json-schema

It provides a nice implementation for the standard json schema

You can write a schema like:

schema = {
    "type"=>"object",
    "required" => ["a"],
    "properties" => {
        "a" => {
            "type" => "integer",
            "default" => 42
        },
        "b" => {
            "type" => "object",
            "properties" => {
                "x" => {
                    "type" => "integer"
                }
            }
        }
    }
}

and use it like: JSON::Validator.validate(schema, { "a" => 5 })

Best way to verify it against my android client implementation.

Solution 7 - Ruby on-Rails

Actually, you can use implicitly the JSON module:

assert_equal assigns(:user).to_json, @response.body

Solution 8 - Ruby on-Rails

As noted, you use JSON.parse to test the JSON, but where you perform that assertion depends on how you are rendering the JSON.

If you are generating the JSON in the controller, you parse the JSON in controller functional tests (as the other answers are showing). If you are rendering JSON, with a view using Jbuilder, rabl or another gem that takes this approach, then parse the JSON in the view unit tests not the controller functional tests. Unit tests are generally faster to execute and easier to write - e.g., you can build models in-memory rather than create them in the database.

Solution 9 - Ruby on-Rails

You can use the [AssertJson gem][1] for a nice DSL which allows you to check for keys and values which should exist in your JSON response.

Add the gem to your Gemfile:

group :test do
  gem 'assert_json'
end

This is a quick example how your functional/controller test could look like (the example is an adaption from their [README][2]):

class ExampleControllerTest < ActionController::TestCase
  include AssertJson

  def test_my_action
    get :my_action, :format => 'json'
    # => @response.body= '{"key":[{"inner_key":"value1"}]}'

    assert_json(@response.body) do
      has 'key' do
        has 'inner_key', 'value1'
      end
      has_not 'key_not_included'
    end
  end

end

You just have to include the AssertJson module in your test and use the assert_json block where you can check the response for existent and non-existant keys and values. Hint: it's not immediately visible in the [README][2], but to check for a value (e.g. if your action just returns an array of strings) you can do

  def test_my_action
    get :my_action, :format => 'json'
    # => @response.body= '["value1", "value2"]'

    assert_json(@response.body) do
      has 'value1'
      has 'value2'
      has_not 'value3'
    end
  end

[1]: https://github.com/xing/assert_json "AssertJson gem" [2]: https://github.com/xing/assert_json/blob/master/README.md

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionWilliam YeungView Question on Stackoverflow
Solution 1 - Ruby on-RailsnicholaidesView Answer on Stackoverflow
Solution 2 - Ruby on-RailsJoshView Answer on Stackoverflow
Solution 3 - Ruby on-RailsacwView Answer on Stackoverflow
Solution 4 - Ruby on-RailsEricView Answer on Stackoverflow
Solution 5 - Ruby on-RailsMark G.View Answer on Stackoverflow
Solution 6 - Ruby on-RailsVedant AgarwalaView Answer on Stackoverflow
Solution 7 - Ruby on-RailsDamienView Answer on Stackoverflow
Solution 8 - Ruby on-RailsJay MitchellView Answer on Stackoverflow
Solution 9 - Ruby on-RailsrkallenseeView Answer on Stackoverflow