Testing GraphQL in Rails
10 months ago · 2 min read min read
Goals
When we set out to test our GraphQL API we wanted 3 things:
To write GQL queries as a string
To keep network details out of spec files
To keep GQL queries out of individual tests
Assumptions: This article assumes you have a working Rails app with authentication and GraphQL already setup. The examples below are written with devise
, rspec
, factory-bot
, and graphql-ruby
.
Writing Queries
We needed some help. We want to write our queries as strings, and we don’t want our specs to know about network requests. To take care of that, we create a helper method that we will include in all of our Specs.
spec/graphql_helper.rb
module GraphqlHelper
def gql(query)
body = { query: query }
post '/api/graphql', params: body
JSON.parse(response.body)
end
end
RSpec let’s us add modules at configuration time:
spec/rails_helper.rb
RSpec.configure do |config|
config.include GraphqlHelper
# ...
end
What are we testing?
We’re going to write a couple test for querying the currently logged in user.
spec/graph/current_user_spec.rb
require 'rails_helper'
describe 'Current User Graph', type: :request do
it 'is nil when not logged in'
it 'is the signed in user'
end
Note: Make sure to add type: request
to the describe block.
Define the Query
Adding a query method to the test-class helps keep the individual specs clean. Let’s add it as a private method so it’s clearly separated from the specs:
spec/graph/current_user_spec.rb
describe 'Current User Graph', type: :request do
it 'is nil when not logged in'
it 'is the signed in user'
private
def query_user
response = gql <<-GQL
query CurrentUserSpec {
user {
firstName
lastName
}
}
GQL
response.dig('data', 'user')
end
end
It’s often useful to dig the value you’re interested in out of the response. This really makes checking the data easier.
Testing the logged-out state
There is no user when we’re logged out, so we need to test for that. Thanks to our helpers it is a very small test:
spec/graph/current_user.rb
describe 'Current User Graph', type: :request do
it 'is nil when not logged in' do
user_data = query_user
expect(user_data).to be_nil
end
#...
end
Testing the logged-in state
spec/graph/current_user_spec.rb
describe 'Current User Graph', type: :request do
# ...
it 'is the signed in user' do
user = FactoryBot.create(:user)
sign_in user
user_data = query_user
expect(user_data['firstName']).to eq(user.first_name)
expect(user_data['lastName']).to eq(user.last_name)
end
end
Review
Here is the end-state of our current_user_spec
.
require 'rails_helper'
describe 'Current User Graph', type: :request do
it 'is nil when not logged in' do
user_data = query_user
expect(user_data).to be_nil
end
it 'is the signed in user' do
user = FactoryBot.create(:user)
sign_in user
user_data = query_user
expect(user_data['firstName']).to eq(user.first_name)
expect(user_data['lastName']).to eq(user.last_name)
end
private
def query_user
response = gql <<-GQL
query CurrentUserSpec {
user {
firstName
lastName
}
}
GQL
response.dig('data', 'user')
end
end