How to RSpec a Rails JSON API responses with Jbuilder

How to RSpec a Rails JSON API responses with Jbuilder

Want to write a Rails API controller test and make sure it includes exactly what your Jbuilder serializer returns? You need to enable `render_views`. Learn why in this post.

Even though controller specs are not recommended since rspec_rails 3.5, you might find yourself in a codebase that still have them.

When testing a controller action that uses Jbuilder as a serializer, and you want to test that the response includes exactly what you expect from the Jbuilder serializer, you need to enable render_views in your specs.

That’s because in RSpec, rendering the content of view templates is disabled by default.

But when using Jbuilder, you do want to render views because that’s how Jbuilder serializes the response. And that’s what render_views does: it enables view rendering for controllers specs.

What’s the difference between render_template and render_views?

render_template

Allows the template to be rendered, but not the content itself. The response body is an empty string. This is the default configuration in RSpec. It allows you to assert expect(response).to render_template("index").

render_views

Allows rendering the contents of the template. This allows us to inspect the JSON response: expect(response.body).to eq "{email: "email@example.com"}".

Testing JSON API responses serialized by Jbuilder in Rails

Let’s see an example:

# app/api/v1/users/active_users_controller.rb

def index
  @users = User.active
end

In the view/serializer, we extract only the attributes we want from an user:

# app/views/api/v1/users/active_users/index.json.jbuilder

json.array! @users do |user|
  json.extract! user,
    :email,
    :full_name,
    :last_sign_in_at
end

How to test a Rails Controller JSON response with RSpec

Let’s verify our API response is returning exactly what we want:

RSpec.describe Api::V1::ActiveUsersController, type: :controller do
  render_views # <- you need to add this!

  describe "GET /index.json" do
    it "returns a JSON response with the attributes specified in the jbuilder serializer" do
      get :index, format: :json

      parsed_body = JSON.parse(response.body)

      expect(parsed_body.first.keys)
        .to contain_exactly("email", "full_name", "last_sign_in_at")
    end
  end

Add render_views as a global RSpec configuration

If you want to have render_views configured by default, add the following to your rails_helper file:

RSpec.configure do |config|
  config.render_views
end

Keep in mind that disabling render_views in a spec group, overrides the global configuration.


To save others time when they run into this situation, I opened a PR on Jbuilder to include this extra configuration in their documentation.

And that’s it! Now you can sleep well at night knowing that your Jbuilder serializer is rendering exactly what you want, and nothing more than that 🛌💤.

Did you like this article? Then you're gonna love these other ones: