DEV Community

Masumi Kawasaki πŸ’­
Masumi Kawasaki πŸ’­

Posted on Edited on

How to Write Tests for GraphQL Resolvers in RSpec

Before, we wrote resolvers and their corresponding tests in the following manner (with slight modifications to the code):

module Resolvers
  class Users < Resolvers::Base
    type ObjectTypes::User.connection_type, null: false

    description 'Find users by roles. You can pass XXX_role or [XXX_role, YYY_role].'

    argument :role, [EnumTypes::User::Role]

    def resolve(role:)
      if role&.include?('evaluation_role')
        User.evaluation_users
      elsif role&.include?('level_aptitude_role')
        User.level_aptitude_users
      else
        User.where(role: role)
      end
    end
  end
end
Enter fullscreen mode Exit fullscreen mode
require 'rails_helper'

RSpec.describe Resolvers::Users do
  describe '#resolve' do
    context 'when role includes evaluation_role' do
      it 'returns evaluation test users filtered by service' do
        user1 = create(:user, role: 'evaluation_role')
        user2 = create(:user, role: 'evaluation_role')
        allow(User).to receive(:evaluation_test_users).and_return([user1, user2])

        result = described_class.new(object: nil, field: nil, context: nil).resolve(role: ['evaluation_role'])

        expect(result).to contain_exactly(user1, user2)
      end
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

Recent Issue with Resolver

After upgrading graphql-ruby from version 2.3.7 to 2.3.10, I encountered the error undefined method 'types' for nil:NilClass. This change is due to modifications in the library, and upon raising an issue and contacting the author, I was informed that resolvers are not supported outside of GraphQL queries.

https://github.com/rmosolgo/graphql-ruby/commit/db7a9bcaceb77dc0af78b73e0d5c2ad849c27598#diff-fdbf285d34242cb3cb7b1e56e80f5d39bc600246e72b7bb32190e555432f156cR39

The author suggested the following alternatives:
1.Using the run_graphql_field Helper:
This method provides a complete GraphQL context.
More details can be found here.
https://graphql-ruby.org/testing/helpers.html

2.Creating a Dummy Query::Context Instance:
Instead of passing context: nil, create a dummy instance.
Though not part of the public API, this workaround should work for now.

query_ctx = GraphQL::Query.new(MySchema, "{ __typename }").context
Enter fullscreen mode Exit fullscreen mode

This Time I Used the First Method, But Here Are Sample Codes for Both

require 'rails_helper'

RSpec.describe Resolvers::Users, type: :graphql do
  describe '#resolve' do
    subject { run_graphql_field("Query.users", nil, arguments: { role: role }).items }

    let!(:user1) { create(:user, role: 'evaluation_role') }
    let!(:user2) { create(:user, role: 'evaluation_role') }

    context 'when role includes evaluation_role' do
      let(:role) { 'evaluation_role' }

      it {
        expect(subject).to eq [user2, user2]
      }
    end
  end
end
Enter fullscreen mode Exit fullscreen mode
require 'rails_helper'

RSpec.describe Resolvers::Users do
  describe '#resolve' do
    subject { resolver.resolve(role: role) }

    let(:query_ctx) { GraphQL::Query.new(TofflerSchema, "{ __typename }").context }
    let(:resolver) { described_class.new(object: nil, context: query_ctx, field: nil) }
    let!(:user1) { create(:user, role: 'evaluation_role') }
    let!(:user2) { create(:user, role: 'evaluation_role') }

    context 'when role includes evaluation_role' do
      let(:role) { 'evaluation_role' }

      it {
        expect(subject).to eq [user2, user1]
      }
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

I have configured the helper as follows:

 config.with_options type: :graphql do |graphql_config|
    graphql_config.include GraphQL::Testing::Helpers.for(MySchema)
  end
Enter fullscreen mode Exit fullscreen mode

I have taken the first method of using run_graphql_field this time. Using a dummy Query::Context instance is better as it requires less changes to the existing code base, but I decided it was better to use run_graphql_field for future maintenance as it is not a public API.

πŸ‡―πŸ‡΅ This article is also available in Japanese:
https://zenn.dev/geeknees/articles/842f04ee5d48a3

Top comments (0)