For rspec-rails
users, 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
Notes
Add render_views as a global RSpec configuration
In your rails_helper
, add:
RSpec.configure do |config|
config.render_views
end
Keep in mind that disabling render_views
in a spec group, overrides the global configuration.
Add format:json to your JSON routes
If your API routes namespace doesn’t already enforce json
as the format, enforce them individually:
resources :active_users, only: [:index], defaults: { format: 'json' }
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? You're gonna love these other ones: