[Ruby] Various GraphQL tests

2 minute read

Introduction

Recently, I implemented the API with Graphql-ruby. Of course, I need to write a test for graphql, but since there seems to be various ways, I will summarize it as a memorandum.

How to actually hit the api

First, I will explain how to actually hit the api. The following is an example.

spec.rb


RSpec.describe User, type: :request do
  describe'user' do
    it'what the specified usr can get' do
      user = create(:user)

      post'/graphql', params: {query: query(id: user.id)}
      json = JSON.parse(response.body)
      data = json['data']['user']

      expect(data).to include(
        'id' => user.id
      )
      end
    end
  end

  def query(id:)
    <<~GRAPHQL
      query {
        user(id: "#{id}"){
          id
          name
        }
      }
   GRAPHQL
  end
end

It is a straightforward implementation that actually defines the query and posts it to the local api. However, this has some troublesome points as follows.

  • You need to have rails running
  • It is troublesome to check each in Perth or json format to expect
  • context cannot be specified (current_user cannot be specified)
  • query is troublesome to write

How to hit # execute Then, hit execute directly. This is also from the example

spec.rb


RSpec.describe User, type: :request do
  describe'user' do
    it'what the specified usr can get' do
      user = create(:user)
      
      Replace #AppSchema with the defined schema name
      ret = AppSchema.execute(query(id: user.id) context:{current_user: user})
      data = ret['data']['user']

      expect(data).to include(
        'id' => user.id
      )
      end
    end
  end

  def query(id:)
    <<~GRAPHQL
      query {
        user(id: "#{id}"){
          id
          name
        }
      }
   GRAPHQL
  end
end

I received the parse and response to json, and the description disappeared and it was a little cleaner. Also, since context can be passed as an argument, it is easy to test. On the other hand, writing a query or extracting the id from the json format is troublesome. The json format is quite inconvenient especially when the query becomes complicated and the nesting becomes deep.

How to hit # resolver only Now let’s take a look at an example.

spec.rb


RSpec.describe User, type: :request do
  describe'resolver' do
    it'what the user can get' do
      user = create(:user)

 # class_name is the class name of the resolve where the logic is written
      mutation = [class_name].new(field: nil, object: nil, context:{current_user: user})
      ret = mutation.resolve(id: user.id)
      expect(ret).to eq user
    end
  end
end

It’s pretty clean. As you can see, I am new to the class that resolve is written and read the resolve method directly. With this method, the return value will be a user object, so the test is very easy to write.

Which one do you use?

In my case, I use execute directly when testing the interface with the front such as ObjectType, and when testing other logic, I use resolver directly. I rarely use the method to hit the first api.

Above, I have summarized the test methods that I know. I’m happy if people can comment that there are other good ways.