Writing Integration Tests
Validating verbose JSON API responses in tests can be a pain. We could use something like json_matchers to validate a schema, but we hope to do one better - let’s validate full payloads with a few simple helpers, using full-stack rspec request specs.
Let’s say we’re testing the show
action of our employees controller, sideloading the employee’s department. Follow the Quickstart to make sure your rails_helper.rb
is setup correctly first.
Let’s say we’re testing the show
action of our employees controller, sideloading the employee’s department.
Let’s begin with vanilla RSpec of what the test might look like:
require 'rails_helper'
RSpec.describe 'employees#show', type: :request do
let!(:homer) { Employee.create!(name: 'Homer Simpson') }
let!(:safety) { employee.create_department!(name: 'Safety') }
it 'renders an employee, sideloading department' do
get "/api/employees/#{homer.id}", params: {
include: 'department'
}
# ... code asserting json response ...
end
end
To avoid painful json assertions, let’s use jsonapi_spec_helpers. Start by adding some setup code:
# spec/rails_helper.rb
require 'jsonapi_spec_helpers'
RSpec.configure do |config|
config.include JsonapiSpecHelpers
end
And now to validate the response, we’ll call assert_payload
:
assert_payload(:employee, homer, json_item)
assert_payload(:department, safety, json_include('departments'))
assert_payload
takes three arguments:
- The name of a payload we’ve defined (we haven’t done this yet).
- The record we want to compare against
- The relevant slice of json.
json_item
andjson_includes
are helpful methods to target the right slice. You can see all helpers in the documentation forjsonapi_spec_helpers
.
OK, so we want to take a record, response JSON, and compare them against something pre-defined. Let’s write those definitions; they look very similar to something you’d write for factory_girl:
# spec/payloads/employee.rb
JsonapiSpecHelpers::Payload.register(:employee) do
key(:name)
key(:email)
timestamps!
end
# spec/payloads/department.rb
JsonapiSpecHelpers::Payload.register(:department) do
key(:name)
end
assert_payload
will do four things:
- Ensure keys that are not in the payload definition are not present.
- Ensure all keys in the registered payload are present.
- Ensures no value in a key/value pair is
nil
(this is overrideable). - Ensures each key matches the expected record value. In other words,
we’re doing something like
expect(json['email']).to eq(homer.email)
.
The comparison value can be customized. Let’s say we serialize the
name
attribute as a combination of the employee’s first_name
and
last_name
:
key(:name) { |record| "#{record.first_name} #{record.last_name}" }
Optionally, validate against a type as well. If both the expected and actual values match, but are the incorrect type, the test will fail:
key(:salary, Integer)
You can also customize/override payloads at runtime in your test. Let’s
say we only serialize salary
when the current user is an admin. Your
test could look something like:
sign_in(:user)
assert_payload(:employee, homer, json_item)
sign_in(:admin)
assert_payload(:employee, homer, json_item) do
key(:salary)
end
For documentation on all the spec helpers we provide, check out the jsonapi_spec_helpers gem.