Skip to content

Validate that GraphQL response fixtures match their test queries

License

Notifications You must be signed in to change notification settings

gmac/graphql-response_validator

Repository files navigation

GraphQL response validator

Testing GraphQL queries using fixture responses runs the risk of false-positive tests when a query changes without its static response getting updated. This gem provides a simple utility for validating response fixtures against the shape of a query to assure that they match.

gem "graphql-response_validator"

Then:

require "graphql/response_validator"

Usage

Build a test query and its response data into a GraphQL::ResponseValidator, then assert that the fixture is correct for the query as part of your test:

def test_my_stuff
  request = %|{ widget { id title } }|
  response = {
    "data" => {
      "widget" => { 
        "id" => "1", 
        "name" => "My widget", # << wrong, should be `title`
      },
    },
  }
  
  # check that the query is valid...
  query = GraphQL::Query.new(MySchema, query: request)
  assert query.static_errors.none?, query.static_errors.map(&:message).join("\n")

  # check that the response is valid...
  fixture = GraphQL::ResponseValidator.new(query, response)
  assert fixture.valid?, fixture.errors.map(&:message).join("\n")
  # Results in: "Expected data to provide field `widget.title`"
end

Abstract selections

Abstract selections must include a type identity so that the validator knows what selection path(s) to follow. This can be done by including a __typename in abstract selection scopes:

def test_my_stuff
  request = %|{ 
    node(id: 1) { 
      ... on Product { title }
      ... on Order { totalCost }
      __typename 
    }
  }|
  response = {
    "data" => {
      "node" => { 
        "title" => "Ethereal wishing well", 
        "__typename" => "Product",
      },
    },
  }
  
  query = GraphQL::Query.new(MySchema, query: request)
  fixture = GraphQL::ResponseValidator.new(query, response)

  assert fixture.valid?, fixture.errors.first&.message
end

Alternatively, you can use a system __typename__ hint that exists only in response data, and this can be pruned from the response data after validating it:

def test_my_stuff
  request = %|{ 
    node(id: 1) { 
      ... on Product { title }
      ... on Order { totalCost }
    }
  }|
  response = {
    "data" => {
      "node" => { 
        "totalCost" => 23, 
        "__typename__" => "Order",
      },
    },
  }
  
  query = GraphQL::Query.new(MySchema, query: request)
  fixture = GraphQL::ResponseValidator.new(query, response)

  assert fixture.valid?, fixture.errors.first&.message

  expected_result = { "data" => { "node" => { "totalCost" => 23 } } }
  assert_equal expected_result, fixture.prune!.to_h
end

About

Validate that GraphQL response fixtures match their test queries

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages