Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prepare test suite for for v2.4 of the GraphQL gem. #26

Merged
merged 1 commit into from
Nov 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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