Skip to main content
Rails GraphQL provides several features to make testing your GraphQL API easier and more efficient. Use these tools to validate documents, stub field values, and test your schema behavior.

Validating Documents

You can validate GraphQL documents without executing them using the valid? method. This runs through the entire organize step and returns true if the document is valid.

Basic Validation

Validate a simple query:
GraphQL.valid?('{ welcome }')
# => true

With Context and Variables

Validation includes checking the document structure, context, and variables:
GraphQL.valid?(
  'query GetUser($id: ID!) { user(id: $id) { name } }',
  variables: { id: '123' }
)
# => true

Implementation

The valid? method is implemented in lib/rails/graphql/request.rb:175:
def valid?(document)
  reset!

  log_execution(document, event: 'validate.graphql') do
    @document = initialize_document(document)
    run_document(with: :compile)
    @log_extra[:result] = @errors.empty?
  end
end
It leverages the compile process to check for errors without executing resolvers.
Use valid? in your test suite to ensure that query strings are properly formatted before testing execution logic.

Stubbing Field Values

Stub field return values using prepared data. This feature is particularly useful for testing without database calls or external dependencies.

Simple Stubbing

Stub data using the data_for parameter:
GraphQL.execute('{ users { id name } }', data_for: {
  'query.users' => [User.new]
})
The format is gql_name.field for type fields or {query,mutation,subscription}.field for schema-level fields.

Advanced Stubbing with Request Instance

For more control, use a request instance with options:
request = GraphQL.request
request.prepare_data_for('User.id', [1, 2], repeat: :cycle)
request.execute('{ users { id name } }')

Repeat Options

Control how stubbed values are used:
  • Default - Use values in order, then return nil
  • repeat: :cycle - Cycle through values repeatedly
  • repeat: :last - Keep returning the last value

Complex Example

request = GraphQL.request

# Stub multiple fields
request.prepare_data_for('query.users', [
  User.new(id: 1, name: 'Alice'),
  User.new(id: 2, name: 'Bob')
])

request.prepare_data_for('User.posts', [
  [Post.new(title: 'First Post')],
  [Post.new(title: 'Second Post')]
])

result = request.execute(<<~GRAPHQL)
  {
    users {
      id
      name
      posts {
        title
      }
    }
  }
GRAPHQL

Implementation

The prepare_data_for method is in lib/rails/graphql/request.rb:201:
def prepare_data_for(field, value, **options)
  field = PreparedData.lookup(self, field)

  if prepared_data.key?(field)
    prepared_data[field].push(value)
  else
    prepared_data[field] = PreparedData.new(field, value, **options)
  end
end

Test Examples

RSpec Example

RSpec.describe 'GraphQL API' do
  describe 'users query' do
    it 'returns valid structure' do
      query = '{ users { id name email } }'
      expect(GraphQL.valid?(query)).to be true
    end

    it 'returns stubbed users' do
      query = '{ users { id name } }'
      users = [
        User.new(id: 1, name: 'Alice'),
        User.new(id: 2, name: 'Bob')
      ]

      result = GraphQL.execute(query, data_for: { 'query.users' => users })
      data = JSON.parse(result)

      expect(data['data']['users']).to eq([
        { 'id' => 1, 'name' => 'Alice' },
        { 'id' => 2, 'name' => 'Bob' }
      ])
    end
  end
end

Minitest Example

class GraphQLTest < ActiveSupport::TestCase
  test 'validates complex query' do
    query = <<~GRAPHQL
      query GetUserPosts($userId: ID!) {
        user(id: $userId) {
          name
          posts {
            title
            comments { text }
          }
        }
      }
    GRAPHQL

    assert GraphQL.valid?(query, variables: { userId: '1' })
  end

  test 'stubs nested data' do
    request = GraphQL.request
    request.prepare_data_for('query.user', User.new(id: 1, name: 'Alice'))
    request.prepare_data_for('User.posts', [
      Post.new(title: 'Hello World')
    ])

    result = request.execute('{ user { name posts { title } } }')
    data = JSON.parse(result)

    assert_equal 'Alice', data['data']['user']['name']
    assert_equal 'Hello World', data['data']['user']['posts'][0]['title']
  end
end

Testing Best Practices

Validate First

Use valid? to test document structure before testing execution

Stub External Calls

Stub database queries and API calls for faster, isolated tests

Test Error Cases

Verify that invalid queries return appropriate errors

Use Type Safety

Test with properly typed variables to catch type mismatches
More testing features will be added for RSpec and Rubocop in future releases.

Introspection

Use introspection to programmatically test schema structure

Parser

Validate document parsing with the GraphQL parser

Build docs developers (and LLMs) love