Testing GraphQL in Rails
Writing clean RSpec tests with Rails and graphql-ruby.
Search for a command to run...
Writing clean RSpec tests with Rails and graphql-ruby.
No comments yet. Be the first to comment.
Design tokens are not enough to ensure visual consistency. Could a grammar help us with that goal?
Using RSpec custom matchers to make clean ActionMailer mocks
How using the RSpec `change` matcher can make your Rails tests easier to read and maintain.
Greater confidence. Fewer specs.
When we set out to test our GraphQL API we wanted 3 things:
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, andgraphql-ruby.
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
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.
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.
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
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
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