Skip to content

Commit

Permalink
Merge pull request #26 from block/myron/upgrade-graphql-2.4/step1
Browse files Browse the repository at this point in the history
Prepare test suite for for v2.4 of the GraphQL gem.
  • Loading branch information
myronmarston authored Nov 8, 2024
2 parents fd87ea9 + faab28a commit b7ca9d8
Show file tree
Hide file tree
Showing 10 changed files with 74 additions and 27 deletions.
3 changes: 2 additions & 1 deletion elasticgraph-graphql/spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@ def build_datastore_core(**options, &block)
meta[:builds_graphql] = true
end

config.when_first_matching_example_defined(:resolver) { require_relative "support/resolver" }
config.when_first_matching_example_defined(:ensure_no_orphaned_types) { require_relative "support/ensure_no_orphaned_types" }
config.when_first_matching_example_defined(:query_adapter) { require_relative "support/query_adapter" }
config.when_first_matching_example_defined(:resolver) { require_relative "support/resolver" }
config.prepend ElasticGraph::GraphQLSpecHelpers, absolute_file_path: %r{/elasticgraph-graphql/}
end

Expand Down
51 changes: 51 additions & 0 deletions elasticgraph-graphql/spec/support/ensure_no_orphaned_types.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Copyright 2024 Block, Inc.
#
# Use of this source code is governed by an MIT-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/MIT.
#
# frozen_string_literal: true

module ElasticGraph
class GraphQL
# Before v2.4 of the GraphQL gem, `GraphQL::Schema#types` returned _all_ types defined by the SDL string.
# Beginning in v2.4, orphaned types (that is, types not reachable from the root `Query` type) are no longer
# included. We have a number of unit tests that define orphaned types since we don't want or need a full
# schema for such a test.
#
# To avoid issues as part of upgrading to v2.4, we need to ensure that our tests don't depend on orphaned
# types that are unavailable in v2.4 and later. This mixin provides a simple solution: it adds on an indexed
# type (`IndexedTypeToEnsureNoOrphans`) with a field for each defined type, ensuring that no defined types
# are orphans.
#
# Apply it to an example or example group using the `:ensure_no_orphaned_types` tag.
module EnsureNoOrphanedTypes
def build_graphql(schema_definition: nil, **options, &block)
schema_def = lambda do |schema|
original_types = schema.state.types_by_name.keys
schema_definition.call(schema)

# If a test is taking are of defining its own indexed types, we don't need to do anything further.
return if schema.state.object_types_by_name.values.any?(&:indexed?)

added_types = schema.state.types_by_name.keys - original_types

schema.object_type "IndexedTypeToEnsureNoOrphans" do |t|
added_types.each do |type_name|
t.field type_name, type_name
end

t.field "id", "ID"
t.index "indexed_types"
end
end

super(schema_definition: schema_def, **options, &block)
end
end

::RSpec.configure do |c|
c.include EnsureNoOrphanedTypes, :ensure_no_orphaned_types
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class GraphQL
}
type Query {
float: Float # so the Float type exists
colors(args: ColorArgs): [Color!]!
colors2(args: ColorArgs): [Color2!]!
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ module Resolvers
end

schema.object_type "Person" do |t|
t.field "id", "ID"
t.field "name", "String"
t.field "identifiers", "PersonIdentifiers"
t.field "ssn", "String", name_in_index: "identifiers.ssn", graphql_only: true
Expand All @@ -36,6 +37,7 @@ module Resolvers
t.field "nicknames", "[String!]"
t.field "alt_nicknames", "[String!]", name_in_index: "nicknames", graphql_only: true
t.field "doc_count", "Int"
t.index "people"
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,9 @@ def build_graphql(**options)
def generate_schema_artifacts(**options)
super(**options) do |schema|
schema.object_type "Widget" do |t|
t.field "id", "ID"
t.paginated_collection_field "natural_numbers", "Int"
t.index "widgets"
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ module Resolvers
favorite_quote(truncate_to: Int, foo_bar_bazz: Int): String
favorite_quote2(trunc_to: Int): String
}
type Query {
person: Person
}
EOS
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
module ElasticGraph
class GraphQL
class Schema
RSpec.describe EnumValue do
RSpec.describe EnumValue, :ensure_no_orphaned_types do
it "inspects well" do
enum_value = define_schema do |s|
s.enum_type "ColorSpace" do |t|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
module ElasticGraph
class GraphQL
class Schema
RSpec.describe Field do
RSpec.describe Field, :ensure_no_orphaned_types do
it "exposes the name as a lowercase symbol" do
field = define_schema do |schema|
schema.object_type "Color" do |t|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
module ElasticGraph
class GraphQL
class Schema
RSpec.describe Type do
RSpec.describe Type, :ensure_no_orphaned_types do
it "exposes the name as a capitalized symbol" do
type = define_schema do |schema|
schema.object_type "Color"
Expand Down Expand Up @@ -102,15 +102,6 @@ class Schema
t.field "node", "Color!"
end

# This must be raw SDL because our schema definition API provides no way to define custom `input` types--it
# generates them based on our indexed types. Using `raw_sdl` lets us define what the test expects. We may want
# to update what the test expects to use generated filter types in the future so we don't have to use `raw_sdl`
# here.
%w[Some PersonEdge PersonConnection].each do |type|
schema.raw_sdl "input #{type}FilterInput { foo: Int }"
schema.raw_sdl "input #{type}ListFilterInput { foo: Int }"
end

schema.object_type "WrappedTypes" do |t|
t.field "int", "Int"
t.field "non_null_int", "Int!"
Expand Down Expand Up @@ -147,6 +138,9 @@ class Schema
t.field "non_null_list_of_indexed_aggregation", "[PersonAggregation]!", filterable: false, groupable: false do |f|
f.mapping type: "object"
end

t.field "id", "ID"
t.index "wrapped_types"
end
end
end
Expand Down Expand Up @@ -395,9 +389,9 @@ class Schema
end

it "can model an input type" do
type = schema.type_named(:SomeFilterInput)
type = schema.type_named(:IntFilterInput)

expect(type.name).to eq :SomeFilterInput
expect(type.name).to eq :IntFilterInput
expect(type).to only_satisfy_predicates(:nullable?, :object?)
expect(type.unwrap_fully).to be type
expect(type.unwrap_non_null).to be type
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

module ElasticGraph
class GraphQL
RSpec.describe Schema do
RSpec.describe Schema, :ensure_no_orphaned_types do
it "can be instantiated with directives that have custom scalar arguments" do
define_schema do |schema|
schema.scalar_type "_FieldSet" do |t|
Expand Down Expand Up @@ -79,17 +79,9 @@ class GraphQL
s.object_type "Color"
end

expect(schema.defined_types).to include(
schema.type_named(:Options),
schema.type_named(:Color),
schema.type_named(:Query)
).and exclude(
schema.type_named(:Int),
schema.type_named(:Float),
schema.type_named(:Boolean),
schema.type_named(:String),
schema.type_named(:ID)
)
expect(schema.defined_types).to all be_a Schema::Type
expect(schema.defined_types.map(&:name)).to include(:Options, :Color, :Query)
.and exclude(:Int, :Float, :Boolean, :String, :ID)
end
end

Expand Down

0 comments on commit b7ca9d8

Please sign in to comment.