Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test a GraphQL schema with graphql-ruby?

My goal is to test the types of my GraphQL schema in ruby, I'm using the graphql-ruby gem.

I couldn't find any best practice for this, so I'm wondering what's the best way to test the fields and types of a Schema.

The gem recommends against testing the Schema directly http://graphql-ruby.org/schema/testing.html but I still find valuable to be able to know when the schema changes unexpectedly.

Having a type like this:

module Types
  class DeskType < GraphQL::Schema::Object
    field :id, ID, 'Id of this Desk', null: false
    field :location, String, 'Location of the Desk', null: false
    field :custom_id, String, 'Human-readable unique identifier for this desk', null: false
  end
end

My first approach has been to use the fields hash in the GraphQL::Schema::Object type, for example:

Types::DeskType.fields['location'].type.to_s => 'String!'

Creating an RSpec matcher, I could come up with tests that look like this:

RSpec.describe Types::DeskType do
  it 'has the expected schema fields' do
    fields = {
      'id': 'ID!',
      'location': 'String!',
      'customId': 'String!'
    }

    expect(described_class).to match_schema_fields(fields)
  end
end

This approach has some drawbacks though:

  • The code in the matcher depends on the implementation of the class GraphQL::Schema::Object, any breaking changes will break the test suite after an update.
  • We're repeating code, the tests asserts the same fields in the type.
  • Writing these tests get tedious, and that makes devs less likely to write them.
like image 934
Carlos Martinez Avatar asked Jul 06 '18 04:07

Carlos Martinez


2 Answers

It looks you want to test your schema because you want to know if it is going to break the client. Basically you should avoid this.

Instead you can use gems like: graphql-schema_comparator to print breaking changes.

  1. I suggest to have a rake task for dumping your schema (and commit it in your repo).
  2. You can write some spec to check if the schema was dump - then you will make sure, you have always up-to date schema dump.
  3. Setup your CI to compare schema of current branch with schema on master branch.
  4. Fail your build if schema has dangerous or breaking changes.
  5. You can even generate Schema Changelog using schema-comparator ;) Or you can even use slack notifications to send any schema changes there so your team could easilly track any changes.
like image 77
michal.samluk Avatar answered Oct 05 '22 23:10

michal.samluk


What I feel is an improvement over the first approach I took is to use snapshot testing for the GraphQL Schema, instead of testing each of the types/mutation schemas one by one, I created a single test:

RSpec.describe MySchema do
  it 'renders the full schema' do
    schema = GraphQL::Schema::Printer.print_schema(MySchema)
    expect(schema).to match_snapshot('schema')
  end
end

This approach uses a slightly modified version of the rspec-snapshot gem, see my PR here.

The gem doesn't let you update the snapshot with a single command like in Jest, so I also created a rake task to delete the current snapshot:

namespace :tests do
  desc 'Deletes the schema snapshot'

  task delete_schema_snapshot: :environment do
    snapshot_path = Rails.root.join('spec', 'fixtures', 'snapshots', 'schema.snap')
    File.delete(snapshot_path) if File.exist?(snapshot_path)
  end
end

With this you'll get a pretty RSpec diff when the schema has been modified.

like image 30
Carlos Martinez Avatar answered Oct 05 '22 23:10

Carlos Martinez