xpost from medium - love Dev.to so much, wanted to share here as well.
To start with, a little OpEd on how much I love working with GraphQL. I started tinkering with it about a year ago, and have since completed a project at work where we did a rewrite, the results have been amazing. Pros and cons aside however, I needed a way to test.
This might not be the best solution for you, but this is what had worked on my team, and for our use case.
The tests needed to cover a few aspects. Did the user have access? We use our own Pundit hack. Were the proper arguments sent? And did the response come back as expected? This sounds like a basic controller test, so from there I treated it as such.
Usually, in an RSpec controller test, we have a #get or a #post method that allows us to interact with that endpoint, and I wanted to continue with that pattern. These usually return a #response object with everything we would want to test.
module GraphQL::TestHelpers
attr_accessor :gql_response
# The returned results of a GraphQL query
# @return [data] this is the bulk of the return to test.
# @return [error] any time a query, mutation, subscription throws and error
class GQLResponse
attr_reader :data, :errors
def initialize(args)
@data = args['data'] || nil
@errors = args['errors'] || nil
end
end
# basic query to interact with the GraphQL API.
# @param [query] required The query string that would be passed to the schema.
def query(query, variables: {}, context: {})
converted = variables.deep_transform_keys! {|key| key.to_s.camelize(:lower)} || {}
res = MyRailsAppSchema.execute(query, variables: converted, context: context, operation_name: nil)
@gql_response = GQLResponse.new(res.to_h)
end
alias_method :mutation, :query
end
Once I defined the #query and #mutation methods, passing in the arguments were easy.
mutation createBook($bookInput: BookInputType!){
createBook(bookInput: $bookInput) {
book {
title
author
pages
}
}
}
#Arguments==
{
bookInputType: {
title: "Testing GraphQL-Ruby Mutations With RSpec",
author: "me",
pages: 1
}
}
Say we have a simple book application, and we want to create a new book.
Below are the tests, and while this seems very basic, I hope it's clear enough to understand the ideas behind it.
require 'rails_helper'
require_relative '../test_helpers'
include GraphQL::TestHelpers
describe 'CreateBook', type: :mutation do
describe 'Creating a Book' do
let(:user) {build_stubbed(:user)}
let(:mutation_type) {"createBook"}
let(:mutation_string) {<<- GQL
mutation createBook($bookInput: BookInputType!){
createBook(bookInput: $bookInput) {
book {
title
author
pages
}
}
}
GQL
}
context 'when a user has all the required permissions and parameters' do
before do
mutation mutation_string,
variables: {
bookInputType: {
title: "Testing GraphQL-Ruby Mutations With RSpec",
author: "me",
pages: 1
}
}
},
context: {current_user: user}
end
it 'should return no errors' do
expect(gql_response.errors).to be_nil
end
it 'should return the book object' do
expect(gql_response.data[mutation_type]["book"]).to include("title" => "Testing GraphQL-Ruby Mutations With RSpec")
end
end
context 'when a user has not passed required parameters parameters' do
before do
mutation mutation_string,
variables: {
bookInputType: {
title: "Testing GraphQL-Ruby Mutations With RSpec",
}
}
},
context: {current_user: user}
end
it 'should return errors' do
expect(gql_response.errors).to be_truthy
end
end
end
end
Why did I decide to do it this way? A few reasons. One, I wanted to treat the mutation like any other post request. Data goes in, data comes out. I see a lot of tests trying to do some crazy things just to hit the resolver inside their mutation. I don't really think that's needed. Using the existing interface with the GraphQL Schema should test what you need to. Hope this helps, and I how you provide some feedback. I would love to see how everyone else tests.
I can be found on twitter. :) @rjrobinson
Top comments (1)
And you are right, on my project it allowed me to reduce execution time almost in a half.