spec/graphql/schema/warden_spec.rb in graphql-1.8.18 vs spec/graphql/schema/warden_spec.rb in graphql-1.9.0.pre1

- old
+ new

@@ -1,24 +1,48 @@ # frozen_string_literal: true require "spec_helper" -include ErrorBubblingHelpers module MaskHelpers - PhonemeType = GraphQL::ObjectType.define do - name "Phoneme" - description "A building block of sound in a given language" - metadata :hidden_type, true - interfaces [LanguageMemberInterface] + class BaseArgument < GraphQL::Schema::Argument + accepts_definition :metadata + end - field :name, types.String.to_non_null_type - field :symbol, types.String.to_non_null_type - field :languages, LanguageType.to_list_type - field :manner, MannerEnum + class BaseField < GraphQL::Schema::Field + accepts_definition :metadata + argument_class BaseArgument end - MannerEnum = GraphQL::EnumType.define do - name "Manner" + class BaseObject < GraphQL::Schema::Object + accepts_definition :metadata + field_class BaseField + end + + class BaseEnumValue < GraphQL::Schema::EnumValue + accepts_definition :metadata + end + + class BaseEnum < GraphQL::Schema::Enum + accepts_definition :metadata + enum_value_class BaseEnumValue + end + + class BaseInputObject < GraphQL::Schema::InputObject + accepts_definition :metadata + argument_class BaseArgument + end + + class BaseUnion < GraphQL::Schema::Union + accepts_definition :metadata + end + + module BaseInterface + include GraphQL::Schema::Interface + accepts_definition :metadata + field_class BaseField + end + + class MannerType < BaseEnum description "Manner of articulation for this sound" metadata :hidden_input_type, true value "STOP" value "AFFRICATE" value "FRICATIVE" @@ -27,109 +51,112 @@ value "TRILL" do metadata :hidden_enum_value, true end end - LanguageType = GraphQL::ObjectType.define do - name "Language" - field :name, types.String.to_non_null_type - field :families, types.String.to_list_type - field :phonemes, PhonemeType.to_list_type - field :graphemes, GraphemeType.to_list_type + class LanguageType < BaseObject + field :name, String, null: false + field :families, [String], null: false + field :phonemes, "[MaskHelpers::PhonemeType]", null: false + field :graphemes, "[MaskHelpers::GraphemeType]", null: false end - GraphemeType = GraphQL::ObjectType.define do - name "Grapheme" + module LanguageMemberType + include BaseInterface + metadata :hidden_abstract_type, true + description "Something that belongs to one or more languages" + field :languages, [LanguageType], null: false + end + + class GraphemeType < BaseObject description "A building block of spelling in a given language" - interfaces [LanguageMemberInterface] + implements LanguageMemberType - field :name, types.String.to_non_null_type - field :glyph, types.String.to_non_null_type - field :languages, LanguageType.to_list_type + field :name, String, null: false + field :glyph, String, null: false + field :languages, [LanguageType], null: false end - LanguageMemberInterface = GraphQL::InterfaceType.define do - name "LanguageMember" - metadata :hidden_abstract_type, true - description "Something that belongs to one or more languages" - field :languages, LanguageType.to_list_type + class PhonemeType < BaseObject + description "A building block of sound in a given language" + metadata :hidden_type, true + implements LanguageMemberType + + field :name, String, null: false + field :symbol, String, null: false + field :languages, [LanguageType], null: false + field :manner, MannerType, null: false end - EmicUnitUnion = GraphQL::UnionType.define do - name "EmicUnit" + class EmicUnitType < BaseUnion description "A building block of a word in a given language" - possible_types [GraphemeType, PhonemeType] + possible_types GraphemeType, PhonemeType end - WithinInputType = GraphQL::InputObjectType.define do - name "WithinInput" + class WithinInputType < BaseInputObject metadata :hidden_input_object_type, true - argument :latitude, !types.Float - argument :longitude, !types.Float - argument :miles, !types.Float do + argument :latitude, Float, required: true + argument :longitude, Float, required: true + argument :miles, Float, required: true do metadata :hidden_input_field, true end end - CheremeInput = GraphQL::InputObjectType.define do - name "CheremeInput" - input_field :name, types.String + class CheremeInput < BaseInputObject + argument :name, String, required: false end - Chereme = GraphQL::ObjectType.define do - name "Chereme" + class Chereme < BaseObject description "A basic unit of signed communication" - field :name, types.String.to_non_null_type + field :name, String, null: false end - Character = GraphQL::ObjectType.define do - name "Character" - interfaces [LanguageMemberInterface] - field :code, types.Int + class Character < BaseObject + implements LanguageMemberType + field :code, Int, null: false end - QueryType = GraphQL::ObjectType.define do - name "Query" - field :languages, LanguageType.to_list_type do - argument :within, WithinInputType, "Find languages nearby a point" do + class QueryType < BaseObject + field :languages, [LanguageType], null: false do + argument :within, WithinInputType, required: false, description: "Find languages nearby a point" do metadata :hidden_argument_with_input_object, true end end - field :language, LanguageType do + + field :language, LanguageType, null: true do metadata :hidden_field, true - argument :name, !types.String do + argument :name, String, required: true do metadata :hidden_argument, true end end - field :chereme, Chereme do + field :chereme, Chereme, null: false do metadata :hidden_field, true end - field :phonemes, PhonemeType.to_list_type do - argument :manners, MannerEnum.to_list_type, "Filter phonemes by manner of articulation" + field :phonemes, [PhonemeType], null: false do + argument :manners, [MannerType], required: false, description: "Filter phonemes by manner of articulation" end - field :phoneme, PhonemeType do + field :phoneme, PhonemeType, null: true do description "Lookup a phoneme by symbol" - argument :symbol, !types.String + argument :symbol, String, required: true end - field :unit, EmicUnitUnion do + field :unit, EmicUnitType, null: true do description "Find an emic unit by its name" - argument :name, types.String.to_non_null_type + argument :name, String, required: true end end - MutationType = GraphQL::ObjectType.define do - name "Mutation" - field :add_phoneme, PhonemeType do - argument :symbol, types.String + class MutationType < BaseObject + field :add_phoneme, PhonemeType, null: true do + argument :symbol, String, required: false end - field :add_chereme, types.String do - argument :chereme, CheremeInput do + field :add_chereme, String, null: true do + argument :chereme, CheremeInput, required: false do metadata :hidden_argument, true end end end @@ -144,22 +171,28 @@ end def self.after_query(q); end end - Schema = GraphQL::Schema.define do + class Schema < GraphQL::Schema query QueryType mutation MutationType subscription MutationType orphan_types [Character] - resolve_type ->(type, obj, ctx) { PhonemeType } + def self.resolve_type(type, obj, ctx) + PhonemeType + end + instrument :query, FilterInstrumentation + if TESTING_INTERPRETER + use GraphQL::Execution::Interpreter + end end module Data UVULAR_TRILL = OpenStruct.new({name: "Uvular Trill", symbol: "ʀ", manner: "TRILL"}) - def self.unit + def self.unit(name:) UVULAR_TRILL end end def self.query_with_mask(str, mask, variables: {}) @@ -204,20 +237,20 @@ def error_messages(query_result) query_result["errors"].map { |err| err["message"] } end describe "hiding root types" do - let(:mask) { ->(m, ctx) { m == MaskHelpers::MutationType } } + let(:mask) { ->(m, ctx) { m == MaskHelpers::MutationType.graphql_definition } } it "acts as if the root doesn't exist" do - query_string = %|mutation { add_phoneme(symbol: "ϕ") { name } }| + query_string = %|mutation { addPhoneme(symbol: "ϕ") { name } }| res = MaskHelpers.query_with_mask(query_string, mask) assert MaskHelpers::Schema.mutation # it _does_ exist assert_equal 1, res["errors"].length assert_equal "Schema is not configured for mutations", res["errors"][0]["message"] - query_string = %|subscription { add_phoneme(symbol: "ϕ") { name } }| + query_string = %|subscription { addPhoneme(symbol: "ϕ") { name } }| res = MaskHelpers.query_with_mask(query_string, mask) assert MaskHelpers::Schema.subscription # it _does_ exist assert_equal 1, res["errors"].length assert_equal "Schema is not configured for subscriptions", res["errors"][0]["message"] end @@ -556,11 +589,10 @@ assert_nil type end end end - describe "hiding arguments" do let(:mask) { ->(member, ctx) { member.metadata[:hidden_argument] || member.metadata[:hidden_input_type] } } @@ -629,45 +661,23 @@ res = MaskHelpers.query_with_mask(query_string, mask) expected_errors = ["Default value for $nearby doesn't match type WithinInput"] assert_equal expected_errors, error_messages(res) end - describe "with error bubbling disabled" do - it "isn't a valid literal input" do - without_error_bubbling(MaskHelpers::Schema) do - query_string = %| - { - languages(within: {latitude: 1.0, longitude: 2.2, miles: 3.3}) { name } - }| - res = MaskHelpers.query_with_mask(query_string, mask) - expected_errors = - [ - "InputObject 'WithinInput' doesn't accept argument 'miles'" - ] - assert_equal expected_errors, error_messages(res) - end - end + it "isn't a valid literal input" do + query_string = %| + { + languages(within: {latitude: 1.0, longitude: 2.2, miles: 3.3}) { name } + }| + res = MaskHelpers.query_with_mask(query_string, mask) + expected_errors = [ + "Argument 'within' on Field 'languages' has an invalid value. Expected type 'WithinInput'.", + "InputObject 'WithinInput' doesn't accept argument 'miles'" + ] + assert_equal expected_errors, error_messages(res) end - describe "with error bubbling enabled" do - it "isn't a valid literal input" do - with_error_bubbling(MaskHelpers::Schema) do - query_string = %| - { - languages(within: {latitude: 1.0, longitude: 2.2, miles: 3.3}) { name } - }| - res = MaskHelpers.query_with_mask(query_string, mask) - expected_errors = - [ - "Argument 'within' on Field 'languages' has an invalid value. Expected type 'WithinInput'.", - "InputObject 'WithinInput' doesn't accept argument 'miles'" - ] - assert_equal expected_errors, error_messages(res) - end - end - end - it "isn't a valid variable input" do query_string = %| query findLanguages($nearby: WithinInput!) { languages(within: $nearby) { name } }| @@ -758,33 +768,33 @@ { phonemes(manners: [STOP, TRILL]) { symbol } } | res = MaskHelpers.query_with_mask(query_string, mask) # It's not a good error message ... but it's something! expected_errors = [ - "Argument 'manners' on Field 'phonemes' has an invalid value. Expected type '[Manner]'.", + "Argument 'manners' on Field 'phonemes' has an invalid value. Expected type '[Manner!]'.", ] assert_equal expected_errors, error_messages(res) end it "isn't a valid default value" do query_string = %| - query getPhonemes($manners: [Manner] = [STOP, TRILL]){ phonemes(manners: $manners) { symbol } } + query getPhonemes($manners: [Manner!] = [STOP, TRILL]){ phonemes(manners: $manners) { symbol } } | res = MaskHelpers.query_with_mask(query_string, mask) - expected_errors = ["Default value for $manners doesn't match type [Manner]"] + expected_errors = ["Default value for $manners doesn't match type [Manner!]"] assert_equal expected_errors, error_messages(res) end it "isn't a valid variable input" do query_string = %| - query getPhonemes($manners: [Manner]!) { + query getPhonemes($manners: [Manner!]!) { phonemes(manners: $manners) { symbol } } | res = MaskHelpers.query_with_mask(query_string, mask, variables: { "manners" => ["STOP", "TRILL"] }) # It's not a good error message ... but it's something! expected_errors = [ - "Variable manners of type [Manner]! was provided invalid value", + "Variable manners of type [Manner!]! was provided invalid value", ] assert_equal expected_errors, error_messages(res) end it "raises a runtime error" do