# frozen_string_literal: true RSpec::Matchers.define :have_graphql_fields do |*expected| match do |klass| expected_field_names = expected.map { |name| GraphQLHelpers.fieldnamerize(name) } expect(GraphQLHelpers.keys_for_klass(klass)).to contain_exactly(*expected_field_names) end failure_message do |klass| expected_field_names = expected.map { |name| GraphQLHelpers.fieldnamerize(name) } keys = GraphQLHelpers.keys_for_klass(klass) missing = expected_field_names - keys extra = keys - expected_field_names message = [] message << "is missing fields: <#{missing.inspect}>" if missing.any? message << "contained unexpected fields: <#{extra.inspect}>" if extra.any? message.join("\n") end end RSpec::Matchers.define :have_graphql_field do |field_name| match do |klass| expect(GraphQLHelpers.keys_for_klass(klass)).to include(GraphQLHelpers.fieldnamerize(field_name)) end end RSpec::Matchers.define :have_graphql_mutation do |mutation_class| match do |field| expect(field).to be_present expect(field.resolver).to eq(mutation_class) end end RSpec::Matchers.define :have_graphql_arguments do |*expected| match do |field| expected_argument_names = expected.map { |name| GraphQLHelpers.fieldnamerize(name) } actual = GraphQLHelpers.arguments_for_field(field) argument_names = expected_argument_names expect(actual).to contain_exactly(*argument_names) end failure_message do |field| expected_argument_names = expected.map { |name| GraphQLHelpers.fieldnamerize(name) } keys = GraphQLHelpers.arguments_for_field(field) missing = expected_argument_names - keys extra = keys - expected_argument_names message = [] message << "is missing arguments: <#{missing.inspect}>" if missing.any? message << "contained unexpected arguments: <#{extra.inspect}>" if extra.any? message.join("\n") end end RSpec::Matchers.define :include_graphql_arguments do |*expected| match do |field| expected_argument_names = expected.map { |name| GraphQLHelpers.fieldnamerize(name) } actual = GraphQLHelpers.arguments_for_field(field) argument_names = expected_argument_names expect(actual).to include(*argument_names) end failure_message do |field| expected_argument_names = expected.map { |name| GraphQLHelpers.fieldnamerize(name) } keys = GraphQLHelpers.arguments_for_field(field) missing = expected_argument_names - keys "is missing arguments: <#{missing.inspect}>" if missing.any? end end RSpec::Matchers.define :include_graphql_arguments_with_plurals do |*expected| match do |field| expected_argument_names = expected.map { |name| GraphQLHelpers.fieldnamerize(name) } all = GraphQLHelpers.arguments_for_field(field) plurals = GraphQLHelpers.plural_arguments_for_field(field) expected = all - plurals argument_names = expected_argument_names expect(expected).to include(*argument_names) end failure_message do |field| expected_argument_names = expected.map { |name| GraphQLHelpers.fieldnamerize(name) } all = GraphQLHelpers.arguments_for_field(field) plurals = GraphQLHelpers.plural_arguments_for_field(field) keys = all - plurals missing = expected_argument_names - keys "is missing arguments: <#{missing.inspect}>" end end RSpec::Matchers.define :have_graphql_type do |expected| match do |field| # `expected.to_graphql` does not work on Array types because they are _not_ # GraphQL:: objects. There seems to be two options: # # 1) Grab the return type from the field to compare to `expected`: # expect( # field.metadata[:type_class].instance_variable_get('@return_type_expr') # ).to eq(expected) # # or # # 2) Run `expected` through the private GraphQL API and call `to_graphql` on # the result, while still having to grab important field metadata: # null = field.metadata[:type_class].instance_variable_get('@return_type_null') # expect(field.type).do eq( # GraphQL::Schema::Member::BuildType.parse_type([::Types::PokemonType], null: null).to_graphql # ) # # Neither option seems very great, but at least with option 2, we compare # exactly the expectation. Let's do both? type_class, graphql_type = case field when GraphQL::Schema::Field [field, field.type.to_graphql] else [field.metadata[:type_class], field.type] end null = type_class.instance_variable_get('@return_type_null') parsed_type = GraphQL::Schema::Member::BuildType.parse_type(expected, null: null) parsed_type = parsed_type.to_graphql unless expected.is_a? GraphQL::ScalarType expect(graphql_type).to eq(parsed_type) expect(type_class.instance_variable_get('@return_type_expr').to_s).to eq(expected.to_s) end end RSpec::Matchers.define :have_graphql_resolver do |expected| match do |field| case expected when Method expect(field.metadata[:type_class].resolve_proc).to eq(expected) else expect(field.metadata[:type_class].resolver).to eq(expected) end end end