graphql_matchers.rb 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. # frozen_string_literal: true
  2. RSpec::Matchers.define :have_graphql_fields do |*expected|
  3. match do |klass|
  4. expected_field_names = expected.map { |name| GraphQLHelpers.fieldnamerize(name) }
  5. expect(GraphQLHelpers.keys_for_klass(klass)).to contain_exactly(*expected_field_names)
  6. end
  7. failure_message do |klass|
  8. expected_field_names = expected.map { |name| GraphQLHelpers.fieldnamerize(name) }
  9. keys = GraphQLHelpers.keys_for_klass(klass)
  10. missing = expected_field_names - keys
  11. extra = keys - expected_field_names
  12. message = []
  13. message << "is missing fields: <#{missing.inspect}>" if missing.any?
  14. message << "contained unexpected fields: <#{extra.inspect}>" if extra.any?
  15. message.join("\n")
  16. end
  17. end
  18. RSpec::Matchers.define :have_graphql_field do |field_name|
  19. match do |klass|
  20. expect(GraphQLHelpers.keys_for_klass(klass)).to include(GraphQLHelpers.fieldnamerize(field_name))
  21. end
  22. end
  23. RSpec::Matchers.define :have_graphql_mutation do |mutation_class|
  24. match do |field|
  25. expect(field).to be_present
  26. expect(field.resolver).to eq(mutation_class)
  27. end
  28. end
  29. RSpec::Matchers.define :have_graphql_arguments do |*expected|
  30. match do |field|
  31. expected_argument_names = expected.map { |name| GraphQLHelpers.fieldnamerize(name) }
  32. actual = GraphQLHelpers.arguments_for_field(field)
  33. argument_names = expected_argument_names
  34. expect(actual).to contain_exactly(*argument_names)
  35. end
  36. failure_message do |field|
  37. expected_argument_names = expected.map { |name| GraphQLHelpers.fieldnamerize(name) }
  38. keys = GraphQLHelpers.arguments_for_field(field)
  39. missing = expected_argument_names - keys
  40. extra = keys - expected_argument_names
  41. message = []
  42. message << "is missing arguments: <#{missing.inspect}>" if missing.any?
  43. message << "contained unexpected arguments: <#{extra.inspect}>" if extra.any?
  44. message.join("\n")
  45. end
  46. end
  47. RSpec::Matchers.define :include_graphql_arguments do |*expected|
  48. match do |field|
  49. expected_argument_names = expected.map { |name| GraphQLHelpers.fieldnamerize(name) }
  50. actual = GraphQLHelpers.arguments_for_field(field)
  51. argument_names = expected_argument_names
  52. expect(actual).to include(*argument_names)
  53. end
  54. failure_message do |field|
  55. expected_argument_names = expected.map { |name| GraphQLHelpers.fieldnamerize(name) }
  56. keys = GraphQLHelpers.arguments_for_field(field)
  57. missing = expected_argument_names - keys
  58. "is missing arguments: <#{missing.inspect}>" if missing.any?
  59. end
  60. end
  61. RSpec::Matchers.define :include_graphql_arguments_with_plurals do |*expected|
  62. match do |field|
  63. expected_argument_names = expected.map { |name| GraphQLHelpers.fieldnamerize(name) }
  64. all = GraphQLHelpers.arguments_for_field(field)
  65. plurals = GraphQLHelpers.plural_arguments_for_field(field)
  66. expected = all - plurals
  67. argument_names = expected_argument_names
  68. expect(expected).to include(*argument_names)
  69. end
  70. failure_message do |field|
  71. expected_argument_names = expected.map { |name| GraphQLHelpers.fieldnamerize(name) }
  72. all = GraphQLHelpers.arguments_for_field(field)
  73. plurals = GraphQLHelpers.plural_arguments_for_field(field)
  74. keys = all - plurals
  75. missing = expected_argument_names - keys
  76. "is missing arguments: <#{missing.inspect}>"
  77. end
  78. end
  79. RSpec::Matchers.define :have_graphql_type do |expected|
  80. match do |field|
  81. # `expected.to_graphql` does not work on Array types because they are _not_
  82. # GraphQL:: objects. There seems to be two options:
  83. #
  84. # 1) Grab the return type from the field to compare to `expected`:
  85. # expect(
  86. # field.metadata[:type_class].instance_variable_get('@return_type_expr')
  87. # ).to eq(expected)
  88. #
  89. # or
  90. #
  91. # 2) Run `expected` through the private GraphQL API and call `to_graphql` on
  92. # the result, while still having to grab important field metadata:
  93. # null = field.metadata[:type_class].instance_variable_get('@return_type_null')
  94. # expect(field.type).do eq(
  95. # GraphQL::Schema::Member::BuildType.parse_type([::Types::PokemonType], null: null).to_graphql
  96. # )
  97. #
  98. # Neither option seems very great, but at least with option 2, we compare
  99. # exactly the expectation. Let's do both?
  100. type_class, graphql_type =
  101. case field
  102. when GraphQL::Schema::Field
  103. [field, field.type.to_graphql]
  104. else
  105. [field.metadata[:type_class], field.type]
  106. end
  107. null = type_class.instance_variable_get('@return_type_null')
  108. parsed_type = GraphQL::Schema::Member::BuildType.parse_type(expected, null: null)
  109. parsed_type = parsed_type.to_graphql unless expected.is_a? GraphQL::ScalarType
  110. expect(graphql_type).to eq(parsed_type)
  111. expect(type_class.instance_variable_get('@return_type_expr').to_s).to eq(expected.to_s)
  112. end
  113. end
  114. RSpec::Matchers.define :have_graphql_resolver do |expected|
  115. match do |field|
  116. case expected
  117. when Method
  118. expect(field.metadata[:type_class].resolve_proc).to eq(expected)
  119. else
  120. expect(field.metadata[:type_class].resolver).to eq(expected)
  121. end
  122. end
  123. end