graphql 1.9.0.pre1 → 1.9.0.pre2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (235) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql.rb +5 -1
  3. data/lib/graphql/analysis/ast/analyzer.rb +1 -1
  4. data/lib/graphql/analysis/ast/visitor.rb +6 -1
  5. data/lib/graphql/backwards_compatibility.rb +1 -1
  6. data/lib/graphql/dig.rb +19 -0
  7. data/lib/graphql/directive.rb +13 -1
  8. data/lib/graphql/directive/include_directive.rb +1 -7
  9. data/lib/graphql/directive/skip_directive.rb +1 -8
  10. data/lib/graphql/execution/interpreter.rb +23 -13
  11. data/lib/graphql/execution/interpreter/resolve.rb +56 -0
  12. data/lib/graphql/execution/interpreter/runtime.rb +174 -74
  13. data/lib/graphql/execution/lazy.rb +7 -1
  14. data/lib/graphql/execution/lookahead.rb +71 -6
  15. data/lib/graphql/execution_error.rb +1 -1
  16. data/lib/graphql/introspection/entry_points.rb +5 -1
  17. data/lib/graphql/introspection/type_type.rb +4 -4
  18. data/lib/graphql/language.rb +0 -1
  19. data/lib/graphql/language/block_string.rb +37 -0
  20. data/lib/graphql/language/document_from_schema_definition.rb +1 -1
  21. data/lib/graphql/language/lexer.rb +55 -36
  22. data/lib/graphql/language/lexer.rl +8 -3
  23. data/lib/graphql/language/nodes.rb +27 -4
  24. data/lib/graphql/language/parser.rb +55 -55
  25. data/lib/graphql/language/parser.y +11 -11
  26. data/lib/graphql/language/printer.rb +1 -1
  27. data/lib/graphql/language/visitor.rb +22 -13
  28. data/lib/graphql/literal_validation_error.rb +6 -0
  29. data/lib/graphql/query.rb +13 -0
  30. data/lib/graphql/query/arguments.rb +2 -1
  31. data/lib/graphql/query/context.rb +3 -10
  32. data/lib/graphql/query/executor.rb +1 -1
  33. data/lib/graphql/query/validation_pipeline.rb +1 -1
  34. data/lib/graphql/relay/connection_resolve.rb +1 -1
  35. data/lib/graphql/relay/relation_connection.rb +1 -1
  36. data/lib/graphql/schema.rb +81 -11
  37. data/lib/graphql/schema/argument.rb +1 -1
  38. data/lib/graphql/schema/build_from_definition.rb +2 -4
  39. data/lib/graphql/schema/directive.rb +103 -0
  40. data/lib/graphql/schema/directive/feature.rb +66 -0
  41. data/lib/graphql/schema/directive/include.rb +25 -0
  42. data/lib/graphql/schema/directive/skip.rb +25 -0
  43. data/lib/graphql/schema/directive/transform.rb +48 -0
  44. data/lib/graphql/schema/enum_value.rb +2 -2
  45. data/lib/graphql/schema/field.rb +63 -17
  46. data/lib/graphql/schema/input_object.rb +1 -0
  47. data/lib/graphql/schema/member/base_dsl_methods.rb +4 -2
  48. data/lib/graphql/schema/member/build_type.rb +33 -1
  49. data/lib/graphql/schema/member/has_fields.rb +8 -73
  50. data/lib/graphql/schema/relay_classic_mutation.rb +6 -1
  51. data/lib/graphql/schema/resolver.rb +1 -1
  52. data/lib/graphql/static_validation.rb +2 -1
  53. data/lib/graphql/static_validation/all_rules.rb +1 -0
  54. data/lib/graphql/static_validation/base_visitor.rb +25 -10
  55. data/lib/graphql/static_validation/definition_dependencies.rb +3 -3
  56. data/lib/graphql/static_validation/{message.rb → error.rb} +11 -11
  57. data/lib/graphql/static_validation/interpreter_visitor.rb +14 -0
  58. data/lib/graphql/static_validation/literal_validator.rb +54 -11
  59. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +34 -5
  60. data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +31 -0
  61. data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +2 -2
  62. data/lib/graphql/static_validation/rules/argument_names_are_unique_error.rb +30 -0
  63. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +7 -1
  64. data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +35 -0
  65. data/lib/graphql/static_validation/rules/directives_are_defined.rb +5 -1
  66. data/lib/graphql/static_validation/rules/directives_are_defined_error.rb +29 -0
  67. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +11 -2
  68. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations_error.rb +31 -0
  69. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +11 -2
  70. data/lib/graphql/static_validation/rules/fields_are_defined_on_type_error.rb +32 -0
  71. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +14 -2
  72. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections_error.rb +31 -0
  73. data/lib/graphql/static_validation/rules/fields_will_merge.rb +24 -6
  74. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +32 -0
  75. data/lib/graphql/static_validation/rules/fragment_names_are_unique.rb +5 -1
  76. data/lib/graphql/static_validation/rules/fragment_names_are_unique_error.rb +29 -0
  77. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +8 -1
  78. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible_error.rb +35 -0
  79. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +5 -1
  80. data/lib/graphql/static_validation/rules/fragment_types_exist_error.rb +29 -0
  81. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +6 -1
  82. data/lib/graphql/static_validation/rules/fragments_are_finite_error.rb +29 -0
  83. data/lib/graphql/static_validation/rules/fragments_are_named.rb +4 -1
  84. data/lib/graphql/static_validation/rules/fragments_are_named_error.rb +26 -0
  85. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +5 -1
  86. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types_error.rb +30 -0
  87. data/lib/graphql/static_validation/rules/fragments_are_used.rb +13 -3
  88. data/lib/graphql/static_validation/rules/fragments_are_used_error.rb +29 -0
  89. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +4 -1
  90. data/lib/graphql/static_validation/rules/mutation_root_exists_error.rb +26 -0
  91. data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +2 -2
  92. data/lib/graphql/static_validation/rules/no_definitions_are_present_error.rb +25 -0
  93. data/lib/graphql/static_validation/rules/operation_names_are_valid.rb +9 -2
  94. data/lib/graphql/static_validation/rules/operation_names_are_valid_error.rb +28 -0
  95. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +7 -1
  96. data/lib/graphql/static_validation/rules/required_arguments_are_present_error.rb +35 -0
  97. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +47 -0
  98. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present_error.rb +35 -0
  99. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +4 -1
  100. data/lib/graphql/static_validation/rules/subscription_root_exists_error.rb +26 -0
  101. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +4 -3
  102. data/lib/graphql/static_validation/rules/unique_directives_per_location_error.rb +29 -0
  103. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +20 -6
  104. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed_error.rb +39 -0
  105. data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +5 -1
  106. data/lib/graphql/static_validation/rules/variable_names_are_unique_error.rb +29 -0
  107. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +8 -1
  108. data/lib/graphql/static_validation/rules/variable_usages_are_allowed_error.rb +38 -0
  109. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +12 -2
  110. data/lib/graphql/static_validation/rules/variables_are_input_types_error.rb +32 -0
  111. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +18 -2
  112. data/lib/graphql/static_validation/rules/variables_are_used_and_defined_error.rb +37 -0
  113. data/lib/graphql/static_validation/validator.rb +24 -14
  114. data/lib/graphql/tracing/new_relic_tracing.rb +2 -2
  115. data/lib/graphql/tracing/skylight_tracing.rb +2 -2
  116. data/lib/graphql/unauthorized_field_error.rb +23 -0
  117. data/lib/graphql/version.rb +1 -1
  118. data/spec/graphql/analysis/ast_spec.rb +40 -0
  119. data/spec/graphql/authorization_spec.rb +93 -20
  120. data/spec/graphql/base_type_spec.rb +3 -1
  121. data/spec/graphql/execution/interpreter_spec.rb +127 -4
  122. data/spec/graphql/execution/lazy_spec.rb +49 -0
  123. data/spec/graphql/execution/lookahead_spec.rb +113 -21
  124. data/spec/graphql/execution/multiplex_spec.rb +2 -1
  125. data/spec/graphql/introspection/type_type_spec.rb +1 -1
  126. data/spec/graphql/language/lexer_spec.rb +72 -3
  127. data/spec/graphql/language/printer_spec.rb +18 -6
  128. data/spec/graphql/query/arguments_spec.rb +21 -0
  129. data/spec/graphql/query/context_spec.rb +10 -0
  130. data/spec/graphql/schema/build_from_definition_spec.rb +144 -29
  131. data/spec/graphql/schema/directive/feature_spec.rb +81 -0
  132. data/spec/graphql/schema/directive/transform_spec.rb +39 -0
  133. data/spec/graphql/schema/enum_spec.rb +5 -3
  134. data/spec/graphql/schema/field_extension_spec.rb +3 -3
  135. data/spec/graphql/schema/field_spec.rb +19 -0
  136. data/spec/graphql/schema/input_object_spec.rb +81 -0
  137. data/spec/graphql/schema/member/build_type_spec.rb +46 -0
  138. data/spec/graphql/schema/member/scoped_spec.rb +3 -3
  139. data/spec/graphql/schema/printer_spec.rb +244 -96
  140. data/spec/graphql/schema/relay_classic_mutation_spec.rb +26 -0
  141. data/spec/graphql/schema/resolver_spec.rb +1 -1
  142. data/spec/graphql/schema/warden_spec.rb +35 -11
  143. data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +212 -72
  144. data/spec/graphql/static_validation/rules/argument_names_are_unique_spec.rb +2 -2
  145. data/spec/graphql/static_validation/rules/arguments_are_defined_spec.rb +72 -29
  146. data/spec/graphql/static_validation/rules/directives_are_defined_spec.rb +4 -2
  147. data/spec/graphql/static_validation/rules/directives_are_in_valid_locations_spec.rb +4 -2
  148. data/spec/graphql/static_validation/rules/fields_are_defined_on_type_spec.rb +10 -5
  149. data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +10 -5
  150. data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +2 -1
  151. data/spec/graphql/static_validation/rules/fragment_names_are_unique_spec.rb +2 -1
  152. data/spec/graphql/static_validation/rules/fragment_spreads_are_possible_spec.rb +6 -3
  153. data/spec/graphql/static_validation/rules/fragment_types_exist_spec.rb +4 -2
  154. data/spec/graphql/static_validation/rules/fragments_are_finite_spec.rb +4 -2
  155. data/spec/graphql/static_validation/rules/fragments_are_named_spec.rb +2 -1
  156. data/spec/graphql/static_validation/rules/fragments_are_on_composite_types_spec.rb +6 -3
  157. data/spec/graphql/static_validation/rules/fragments_are_used_spec.rb +22 -2
  158. data/spec/graphql/static_validation/rules/mutation_root_exists_spec.rb +2 -1
  159. data/spec/graphql/static_validation/rules/operation_names_are_valid_spec.rb +6 -3
  160. data/spec/graphql/static_validation/rules/required_arguments_are_present_spec.rb +13 -4
  161. data/spec/graphql/static_validation/rules/required_input_object_attributes_are_present_spec.rb +58 -0
  162. data/spec/graphql/static_validation/rules/subscription_root_exists_spec.rb +2 -1
  163. data/spec/graphql/static_validation/rules/unique_directives_per_location_spec.rb +14 -7
  164. data/spec/graphql/static_validation/rules/variable_default_values_are_correctly_typed_spec.rb +14 -7
  165. data/spec/graphql/static_validation/rules/variable_usages_are_allowed_spec.rb +8 -4
  166. data/spec/graphql/static_validation/rules/variables_are_input_types_spec.rb +8 -4
  167. data/spec/graphql/static_validation/rules/variables_are_used_and_defined_spec.rb +6 -3
  168. data/spec/graphql/static_validation/validator_spec.rb +6 -4
  169. data/spec/graphql/tracing/new_relic_tracing_spec.rb +10 -0
  170. data/spec/graphql/tracing/skylight_tracing_spec.rb +10 -0
  171. data/spec/graphql/types/iso_8601_date_time_spec.rb +1 -2
  172. data/spec/integration/mongoid/star_trek/schema.rb +5 -5
  173. data/spec/integration/rails/graphql/relay/relation_connection_spec.rb +37 -8
  174. data/spec/integration/rails/graphql/schema_spec.rb +2 -2
  175. data/spec/integration/rails/spec_helper.rb +10 -0
  176. data/spec/integration/tmp/app/graphql/types/bird_type.rb +7 -0
  177. data/spec/integration/tmp/dummy/Gemfile +45 -0
  178. data/spec/integration/tmp/dummy/README.rdoc +28 -0
  179. data/spec/integration/tmp/dummy/Rakefile +6 -0
  180. data/spec/integration/tmp/dummy/app/assets/javascripts/application.js +16 -0
  181. data/spec/integration/tmp/dummy/app/assets/stylesheets/application.css +15 -0
  182. data/spec/integration/tmp/dummy/app/controllers/application_controller.rb +5 -0
  183. data/spec/integration/tmp/dummy/app/controllers/graphql_controller.rb +43 -0
  184. data/spec/integration/tmp/dummy/app/graphql/dummy_schema.rb +34 -0
  185. data/spec/integration/tmp/dummy/app/graphql/types/base_enum.rb +4 -0
  186. data/spec/integration/tmp/dummy/app/graphql/types/base_input_object.rb +4 -0
  187. data/spec/integration/tmp/dummy/app/graphql/types/base_interface.rb +5 -0
  188. data/spec/integration/tmp/dummy/app/graphql/types/base_object.rb +4 -0
  189. data/spec/integration/tmp/dummy/app/graphql/types/base_scalar.rb +4 -0
  190. data/spec/integration/tmp/dummy/app/graphql/types/base_union.rb +4 -0
  191. data/spec/integration/tmp/dummy/app/graphql/types/mutation_type.rb +10 -0
  192. data/spec/integration/tmp/dummy/app/graphql/types/query_type.rb +15 -0
  193. data/spec/integration/tmp/dummy/app/helpers/application_helper.rb +2 -0
  194. data/spec/integration/tmp/dummy/app/views/layouts/application.html.erb +14 -0
  195. data/spec/integration/tmp/dummy/bin/bundle +3 -0
  196. data/spec/integration/tmp/dummy/bin/rails +4 -0
  197. data/spec/integration/tmp/dummy/bin/rake +4 -0
  198. data/spec/integration/tmp/dummy/bin/setup +29 -0
  199. data/spec/integration/tmp/dummy/config.ru +4 -0
  200. data/spec/integration/tmp/dummy/config/application.rb +32 -0
  201. data/spec/integration/tmp/dummy/config/boot.rb +3 -0
  202. data/spec/integration/tmp/dummy/config/environment.rb +5 -0
  203. data/spec/integration/tmp/dummy/config/environments/development.rb +38 -0
  204. data/spec/integration/tmp/dummy/config/environments/production.rb +76 -0
  205. data/spec/integration/tmp/dummy/config/environments/test.rb +42 -0
  206. data/spec/integration/tmp/dummy/config/initializers/assets.rb +11 -0
  207. data/spec/integration/tmp/dummy/config/initializers/backtrace_silencers.rb +7 -0
  208. data/spec/integration/tmp/dummy/config/initializers/cookies_serializer.rb +3 -0
  209. data/spec/integration/tmp/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  210. data/spec/integration/tmp/dummy/config/initializers/inflections.rb +16 -0
  211. data/spec/integration/tmp/dummy/config/initializers/mime_types.rb +4 -0
  212. data/spec/integration/tmp/dummy/config/initializers/session_store.rb +3 -0
  213. data/spec/integration/tmp/dummy/config/initializers/to_time_preserves_timezone.rb +10 -0
  214. data/spec/integration/tmp/dummy/config/initializers/wrap_parameters.rb +9 -0
  215. data/spec/integration/tmp/dummy/config/locales/en.yml +23 -0
  216. data/spec/integration/tmp/dummy/config/routes.rb +61 -0
  217. data/spec/integration/tmp/dummy/config/secrets.yml +22 -0
  218. data/spec/integration/tmp/dummy/db/seeds.rb +7 -0
  219. data/spec/integration/tmp/dummy/public/404.html +67 -0
  220. data/spec/integration/tmp/dummy/public/422.html +67 -0
  221. data/spec/integration/tmp/dummy/public/500.html +66 -0
  222. data/spec/integration/tmp/dummy/public/favicon.ico +0 -0
  223. data/spec/integration/tmp/dummy/public/robots.txt +5 -0
  224. data/spec/support/dummy/schema.rb +2 -2
  225. data/spec/support/error_bubbling_helpers.rb +23 -0
  226. data/spec/support/jazz.rb +53 -6
  227. data/spec/support/lazy_helpers.rb +26 -8
  228. data/spec/support/new_relic.rb +3 -0
  229. data/spec/support/skylight.rb +3 -0
  230. data/spec/support/star_wars/schema.rb +13 -9
  231. data/spec/support/static_validation_helpers.rb +3 -1
  232. metadata +145 -22
  233. data/lib/graphql/language/comments.rb +0 -45
  234. data/spec/graphql/schema/member/has_fields_spec.rb +0 -132
  235. data/spec/integration/tmp/app/graphql/types/family_type.rb +0 -9
@@ -50,6 +50,32 @@ describe GraphQL::Schema::RelayClassicMutation do
50
50
 
51
51
  assert_equal "Sitar", res["data"]["addSitar"]["instrument"]["name"]
52
52
  end
53
+
54
+ it "supports extras" do
55
+ res = Jazz::Schema.execute <<-GRAPHQL
56
+ mutation {
57
+ hasExtras(input: {}) {
58
+ nodeClass
59
+ int
60
+ }
61
+ }
62
+ GRAPHQL
63
+
64
+ assert_equal "GraphQL::Language::Nodes::Field", res["data"]["hasExtras"]["nodeClass"]
65
+ assert_nil res["data"]["hasExtras"]["int"]
66
+
67
+ # Also test with given args
68
+ res = Jazz::Schema.execute <<-GRAPHQL
69
+ mutation {
70
+ hasExtras(input: {int: 5}) {
71
+ nodeClass
72
+ int
73
+ }
74
+ }
75
+ GRAPHQL
76
+ assert_equal "GraphQL::Language::Nodes::Field", res["data"]["hasExtras"]["nodeClass"]
77
+ assert_equal 5, res["data"]["hasExtras"]["int"]
78
+ end
53
79
  end
54
80
 
55
81
  describe "loading multiple application objects" do
@@ -181,7 +181,7 @@ describe GraphQL::Schema::Resolver do
181
181
 
182
182
  class IntegerWrapper < GraphQL::Schema::Object
183
183
  implements HasValue
184
- field :value, Integer, null: false, method: :object
184
+ field :value, Integer, null: false, method: :itself
185
185
  end
186
186
 
187
187
  class PrepResolver9 < BaseResolver
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  require "spec_helper"
3
+ include ErrorBubblingHelpers
3
4
 
4
5
  module MaskHelpers
5
6
  class BaseArgument < GraphQL::Schema::Argument
@@ -185,6 +186,7 @@ module MaskHelpers
185
186
  instrument :query, FilterInstrumentation
186
187
  if TESTING_INTERPRETER
187
188
  use GraphQL::Execution::Interpreter
189
+ use GraphQL::Analysis::AST
188
190
  end
189
191
  end
190
192
 
@@ -663,17 +665,39 @@ describe GraphQL::Schema::Warden do
663
665
  assert_equal expected_errors, error_messages(res)
664
666
  end
665
667
 
666
- it "isn't a valid literal input" do
667
- query_string = %|
668
- {
669
- languages(within: {latitude: 1.0, longitude: 2.2, miles: 3.3}) { name }
670
- }|
671
- res = MaskHelpers.query_with_mask(query_string, mask)
672
- expected_errors = [
673
- "Argument 'within' on Field 'languages' has an invalid value. Expected type 'WithinInput'.",
674
- "InputObject 'WithinInput' doesn't accept argument 'miles'"
675
- ]
676
- assert_equal expected_errors, error_messages(res)
668
+ describe "with error bubbling disabled" do
669
+ it "isn't a valid literal input" do
670
+ without_error_bubbling(MaskHelpers::Schema) do
671
+ query_string = %|
672
+ {
673
+ languages(within: {latitude: 1.0, longitude: 2.2, miles: 3.3}) { name }
674
+ }|
675
+ res = MaskHelpers.query_with_mask(query_string, mask)
676
+ expected_errors =
677
+ [
678
+ "InputObject 'WithinInput' doesn't accept argument 'miles'"
679
+ ]
680
+ assert_equal expected_errors, error_messages(res)
681
+ end
682
+ end
683
+ end
684
+
685
+ describe "with error bubbling enabled" do
686
+ it "isn't a valid literal input" do
687
+ with_error_bubbling(MaskHelpers::Schema) do
688
+ query_string = %|
689
+ {
690
+ languages(within: {latitude: 1.0, longitude: 2.2, miles: 3.3}) { name }
691
+ }|
692
+ res = MaskHelpers.query_with_mask(query_string, mask)
693
+ expected_errors =
694
+ [
695
+ "Argument 'within' on Field 'languages' has an invalid value. Expected type 'WithinInput'.",
696
+ "InputObject 'WithinInput' doesn't accept argument 'miles'"
697
+ ]
698
+ assert_equal expected_errors, error_messages(res)
699
+ end
700
+ end
677
701
  end
678
702
 
679
703
  it "isn't a valid variable input" do
@@ -3,6 +3,7 @@ require "spec_helper"
3
3
 
4
4
  describe GraphQL::StaticValidation::ArgumentLiteralsAreCompatible do
5
5
  include StaticValidationHelpers
6
+ include ErrorBubblingHelpers
6
7
 
7
8
  let(:query_string) {%|
8
9
  query getCheese {
@@ -20,65 +21,119 @@ describe GraphQL::StaticValidation::ArgumentLiteralsAreCompatible do
20
21
  }
21
22
  |}
22
23
 
23
- it "finds undefined or missing-required arguments to fields and directives" do
24
- # `wacky` above is handled by ArgumentsAreDefined, so only 6 are tested below
25
- assert_equal(8, errors.length)
24
+ describe "with error bubbling disabled" do
25
+ it "finds undefined or missing-required arguments to fields and directives" do
26
+ without_error_bubbling(schema) do
27
+ # `wacky` above is handled by ArgumentsAreDefined, missingSource is handled by RequiredInputObjectAttributesArePresent
28
+ # so only 4 are tested below
29
+ assert_equal(6, errors.length)
30
+
31
+ query_root_error = {
32
+ "message"=>"Argument 'id' on Field 'stringCheese' has an invalid value. Expected type 'Int!'.",
33
+ "locations"=>[{"line"=>3, "column"=>7}],
34
+ "path"=>["query getCheese", "stringCheese", "id"],
35
+ "extensions"=>{"code"=>"argumentLiteralsIncompatible", "typeName"=>"Field", "argumentName"=>"id"},
36
+ }
37
+ assert_includes(errors, query_root_error)
26
38
 
27
- query_root_error = {
28
- "message"=>"Argument 'id' on Field 'stringCheese' has an invalid value. Expected type 'Int!'.",
29
- "locations"=>[{"line"=>3, "column"=>7}],
30
- "fields"=>["query getCheese", "stringCheese", "id"],
31
- }
32
- assert_includes(errors, query_root_error)
39
+ directive_error = {
40
+ "message"=>"Argument 'if' on Directive 'skip' has an invalid value. Expected type 'Boolean!'.",
41
+ "locations"=>[{"line"=>4, "column"=>30}],
42
+ "path"=>["query getCheese", "cheese", "source", "if"],
43
+ "extensions"=>{"code"=>"argumentLiteralsIncompatible", "typeName"=>"Directive", "argumentName"=>"if"},
44
+ }
45
+ assert_includes(errors, directive_error)
33
46
 
34
- directive_error = {
35
- "message"=>"Argument 'if' on Directive 'skip' has an invalid value. Expected type 'Boolean!'.",
36
- "locations"=>[{"line"=>4, "column"=>30}],
37
- "fields"=>["query getCheese", "cheese", "source", "if"],
38
- }
39
- assert_includes(errors, directive_error)
47
+ input_object_field_error = {
48
+ "message"=>"Argument 'source' on InputObject 'DairyProductInput' has an invalid value. Expected type 'DairyAnimal!'.",
49
+ "locations"=>[{"line"=>6, "column"=>40}],
50
+ "path"=>["query getCheese", "badSource", "product", "source"],
51
+ "extensions"=>{"code"=>"argumentLiteralsIncompatible", "typeName"=>"InputObject", "argumentName"=>"source"},
52
+ }
53
+ assert_includes(errors, input_object_field_error)
40
54
 
41
- input_object_error = {
42
- "message"=>"Argument 'product' on Field 'badSource' has an invalid value. Expected type '[DairyProductInput]'.",
43
- "locations"=>[{"line"=>6, "column"=>7}],
44
- "fields"=>["query getCheese", "badSource", "product"],
45
- }
46
- assert_includes(errors, input_object_error)
55
+ fragment_error = {
56
+ "message"=>"Argument 'source' on Field 'similarCheese' has an invalid value. Expected type '[DairyAnimal!]!'.",
57
+ "locations"=>[{"line"=>13, "column"=>7}],
58
+ "path"=>["fragment cheeseFields", "similarCheese", "source"],
59
+ "extensions"=> {"code"=>"argumentLiteralsIncompatible", "typeName"=>"Field", "argumentName"=>"source"}
60
+ }
61
+ assert_includes(errors, fragment_error)
62
+ end
63
+ end
64
+ it 'works with error bubbling enabled' do
65
+ with_error_bubbling(schema) do
66
+ assert_equal(9, errors.length)
67
+
68
+ query_root_error = {
69
+ "message"=>"Argument 'id' on Field 'stringCheese' has an invalid value. Expected type 'Int!'.",
70
+ "locations"=>[{"line"=>3, "column"=>7}],
71
+ "path"=>["query getCheese", "stringCheese", "id"],
72
+ "extensions"=>{"code"=>"argumentLiteralsIncompatible", "typeName"=>"Field", "argumentName"=>"id"},
73
+ }
74
+ assert_includes(errors, query_root_error)
47
75
 
48
- input_object_field_error = {
49
- "message"=>"Argument 'source' on InputObject 'DairyProductInput' has an invalid value. Expected type 'DairyAnimal!'.",
50
- "locations"=>[{"line"=>6, "column"=>40}],
51
- "fields"=>["query getCheese", "badSource", "product", "source"],
52
- }
53
- assert_includes(errors, input_object_field_error)
76
+ directive_error = {
77
+ "message"=>"Argument 'if' on Directive 'skip' has an invalid value. Expected type 'Boolean!'.",
78
+ "locations"=>[{"line"=>4, "column"=>30}],
79
+ "path"=>["query getCheese", "cheese", "source", "if"],
80
+ "extensions"=>{"code"=>"argumentLiteralsIncompatible", "typeName"=>"Directive", "argumentName"=>"if"},
81
+ }
82
+ assert_includes(errors, directive_error)
54
83
 
55
- missing_required_field_error = {
56
- "message"=>"Argument 'product' on Field 'missingSource' has an invalid value. Expected type '[DairyProductInput]'.",
57
- "locations"=>[{"line"=>7, "column"=>7}],
58
- "fields"=>["query getCheese", "missingSource", "product"],
59
- }
60
- assert_includes(errors, missing_required_field_error)
84
+ input_object_error = {
85
+ "message"=>"Argument 'product' on Field 'badSource' has an invalid value. Expected type '[DairyProductInput]'.",
86
+ "locations"=>[{"line"=>6, "column"=>7}],
87
+ "path"=>["query getCheese", "badSource", "product"],
88
+ "extensions"=>{"code"=>"argumentLiteralsIncompatible", "typeName"=>"Field", "argumentName"=>"product"},
89
+ }
90
+ assert_includes(errors, input_object_error)
61
91
 
62
- fragment_error = {
63
- "message"=>"Argument 'source' on Field 'similarCheese' has an invalid value. Expected type '[DairyAnimal!]!'.",
64
- "locations"=>[{"line"=>13, "column"=>7}],
65
- "fields"=>["fragment cheeseFields", "similarCheese", "source"],
66
- }
67
- assert_includes(errors, fragment_error)
92
+ input_object_field_error = {
93
+ "message"=>"Argument 'source' on InputObject 'DairyProductInput' has an invalid value. Expected type 'DairyAnimal!'.",
94
+ "locations"=>[{"line"=>6, "column"=>40}],
95
+ "path"=>["query getCheese", "badSource", "product", "source"],
96
+ "extensions"=>{"code"=>"argumentLiteralsIncompatible", "typeName"=>"InputObject", "argumentName"=>"source"},
97
+ }
98
+ assert_includes(errors, input_object_field_error)
99
+
100
+ missing_required_field_error = {
101
+ "message"=>"Argument 'product' on Field 'missingSource' has an invalid value. Expected type '[DairyProductInput]'.",
102
+ "locations"=>[{"line"=>7, "column"=>7}],
103
+ "path"=>["query getCheese", "missingSource", "product"],
104
+ "extensions"=>{"code"=>"argumentLiteralsIncompatible", "typeName"=>"Field", "argumentName"=>"product"}
105
+ }
106
+ assert_includes(errors, missing_required_field_error)
107
+
108
+ fragment_error = {
109
+ "message"=>"Argument 'source' on Field 'similarCheese' has an invalid value. Expected type '[DairyAnimal!]!'.",
110
+ "locations"=>[{"line"=>13, "column"=>7}],
111
+ "path"=>["fragment cheeseFields", "similarCheese", "source"],
112
+ "extensions"=> {"code"=>"argumentLiteralsIncompatible", "typeName"=>"Field", "argumentName"=>"source"}
113
+ }
114
+ assert_includes(errors, fragment_error)
115
+ end
116
+ end
68
117
  end
69
118
 
70
- describe "using input objects for enums" do
119
+ describe "using input objects for enums it adds an error" do
71
120
  let(:query_string) { <<-GRAPHQL
72
121
  {
73
122
  yakSource: searchDairy(product: [{source: {a: 1, b: 2}, fatContent: 1.1}]) { __typename }
74
123
  }
75
124
  GRAPHQL
76
125
  }
77
-
78
- it "adds an error" do
79
- # TODO:
80
- # It's annoying that this error cascades up, there should only be one:
81
- assert_equal 2, errors.length
126
+ it "works with error bubbling disabled" do
127
+ without_error_bubbling(schema) do
128
+ assert_equal 1, errors.length
129
+ end
130
+ end
131
+ it "works with error bubbling enabled" do
132
+ with_error_bubbling(schema) do
133
+ # TODO:
134
+ # It's annoying that this error cascades up, there should only be one:
135
+ assert_equal 2, errors.length
136
+ end
82
137
  end
83
138
  end
84
139
 
@@ -120,7 +175,8 @@ describe GraphQL::StaticValidation::ArgumentLiteralsAreCompatible do
120
175
  assert_equal [{
121
176
  "message"=>"Argument 'arg' on Field 'field' has an invalid value. Expected type 'Int!'.",
122
177
  "locations"=>[{"line"=>3, "column"=>11}],
123
- "fields"=>["query", "field", "arg"],
178
+ "path"=>["query", "field", "arg"],
179
+ "extensions"=>{"code"=>"argumentLiteralsIncompatible", "typeName"=>"Field", "argumentName"=>"arg"}
124
180
  }], errors
125
181
  end
126
182
  end
@@ -143,7 +199,8 @@ describe GraphQL::StaticValidation::ArgumentLiteralsAreCompatible do
143
199
  assert_equal [{
144
200
  "message"=>"Argument 'arg' on Field 'field' has an invalid value. Expected type '[Int!]'.",
145
201
  "locations"=>[{"line"=>3, "column"=>11}],
146
- "fields"=>["query", "field", "arg"],
202
+ "path"=>["query", "field", "arg"],
203
+ "extensions"=>{"code"=>"argumentLiteralsIncompatible", "typeName"=>"Field", "argumentName"=>"arg"}
147
204
  }], errors
148
205
  end
149
206
  end
@@ -186,20 +243,42 @@ describe GraphQL::StaticValidation::ArgumentLiteralsAreCompatible do
186
243
  }
187
244
  |}
188
245
 
189
- it "finds errors" do
190
- assert_equal 2, errors.length
191
-
192
- assert_includes errors, {
193
- "message"=> "Argument 'arg' on Field 'field' has an invalid value. Expected type 'Input'.",
194
- "locations"=>[{"line"=>3, "column"=>11}],
195
- "fields"=>["query", "field", "arg"]
196
- }
197
-
198
- assert_includes errors, {
199
- "message"=>"Argument 'b' on InputObject 'Input' has an invalid value. Expected type 'Int!'.",
200
- "locations"=>[{"line"=>3, "column"=>22}],
201
- "fields"=>["query", "field", "arg", "b"]
202
- }
246
+ describe "it finds errors" do
247
+ it "works with error bubbling disabled" do
248
+ without_error_bubbling(schema) do
249
+ assert_equal 1, errors.length
250
+ refute_includes errors, {
251
+ "message"=>"Argument 'arg' on Field 'field' has an invalid value. Expected type 'Input'.",
252
+ "locations"=>[{"line"=>3, "column"=>11}],
253
+ "path"=>["query", "field", "arg"],
254
+ "extensions"=>{"code"=>"argumentLiteralsIncompatible", "typeName"=>"Field", "argumentName"=>"arg"}
255
+ }
256
+ assert_includes errors, {
257
+ "message"=>"Argument 'b' on InputObject 'Input' has an invalid value. Expected type 'Int!'.",
258
+ "locations"=>[{"line"=>3, "column"=>22}],
259
+ "path"=>["query", "field", "arg", "b"],
260
+ "extensions"=>{"code"=>"argumentLiteralsIncompatible", "typeName"=>"InputObject", "argumentName"=>"b"}
261
+ }
262
+ end
263
+ end
264
+ it "works with error bubbling enabled" do
265
+ with_error_bubbling(schema) do
266
+ assert_equal 2, errors.length
267
+ assert_includes errors, {
268
+ "message"=>"Argument 'arg' on Field 'field' has an invalid value. Expected type 'Input'.",
269
+ "locations"=>[{"line"=>3, "column"=>11}],
270
+ "path"=>["query", "field", "arg"],
271
+ "extensions"=>{"code"=>"argumentLiteralsIncompatible", "typeName"=>"Field", "argumentName"=>"arg"}
272
+ }
273
+
274
+ assert_includes errors, {
275
+ "message"=>"Argument 'b' on InputObject 'Input' has an invalid value. Expected type 'Int!'.",
276
+ "locations"=>[{"line"=>3, "column"=>22}],
277
+ "path"=>["query", "field", "arg", "b"],
278
+ "extensions"=>{"code"=>"argumentLiteralsIncompatible", "typeName"=>"InputObject", "argumentName"=>"b"}
279
+ }
280
+ end
281
+ end
203
282
  end
204
283
  end
205
284
  end
@@ -215,15 +294,15 @@ describe GraphQL::StaticValidation::ArgumentLiteralsAreCompatible do
215
294
  assert_includes(errors, {
216
295
  "message"=>"Argument 'name' on Field '__type' has an invalid value. Expected type 'String!'.",
217
296
  "locations"=>[{"line"=>3, "column"=>9}],
218
- "fields"=>["query", "__type", "name"],
297
+ "path"=>["query", "__type", "name"],
298
+ "extensions"=>{"code"=>"argumentLiteralsIncompatible", "typeName"=>"Field", "argumentName"=>"name"}
219
299
  })
220
300
  end
221
301
  end
222
302
 
223
303
  describe "custom error messages" do
224
304
  let(:schema) {
225
-
226
- CoerceTestTimeType = GraphQL::ScalarType.define do
305
+ CoerceTestTimeType ||= GraphQL::ScalarType.define do
227
306
  name "Time"
228
307
  description "Time since epoch in seconds"
229
308
 
@@ -238,17 +317,26 @@ describe GraphQL::StaticValidation::ArgumentLiteralsAreCompatible do
238
317
  coerce_result ->(value, ctx) { value.to_f }
239
318
  end
240
319
 
241
- CoerceTestQueryType = GraphQL::ObjectType.define do
320
+ CoerceTestDeepTimeType ||= GraphQL::InputObjectType.define do
321
+ name "range"
322
+ description "Time range"
323
+ argument :from, !CoerceTestTimeType
324
+ argument :to, !CoerceTestTimeType
325
+ end
326
+
327
+ CoerceTestQueryType ||= GraphQL::ObjectType.define do
242
328
  name "Query"
243
329
  description "The query root of this schema"
244
330
 
245
331
  field :time do
246
332
  type CoerceTestTimeType
247
- argument :value, !CoerceTestTimeType
333
+ argument :value, CoerceTestTimeType
334
+ argument :range, CoerceTestDeepTimeType
248
335
  resolve ->(obj, args, ctx) { args[:value] }
249
336
  end
250
337
  end
251
338
 
339
+
252
340
  GraphQL::Schema.define do
253
341
  query CoerceTestQueryType
254
342
  end
@@ -260,14 +348,66 @@ describe GraphQL::StaticValidation::ArgumentLiteralsAreCompatible do
260
348
  }
261
349
  |}
262
350
 
263
- it "sets error message from a CoercionError if raised" do
264
- assert_equal 1, errors.length
351
+ describe "with a shallow coercion" do
352
+ it "sets error message from a CoercionError if raised" do
353
+ assert_equal 1, errors.length
265
354
 
266
- assert_includes errors, {
267
- "message"=> "cannot coerce to Float",
268
- "locations"=>[{"line"=>3, "column"=>9}],
269
- "fields"=>["query", "time", "value"]
355
+ assert_includes errors, {
356
+ "message"=> "cannot coerce to Float",
357
+ "locations"=>[{"line"=>3, "column"=>9}],
358
+ "path"=>["query", "time", "value"],
359
+ "extensions"=>{"code"=>"argumentLiteralsIncompatible", "typeName"=>"CoercionError"}
360
+ }
361
+ end
362
+ end
363
+
364
+ describe "with a deep coercion" do
365
+ let(:query_string) {%|
366
+ query {
367
+ time(range: { from: "a", to: "b" })
368
+ }
369
+ |}
370
+
371
+ from_error = {
372
+ "message"=>"cannot coerce to Float",
373
+ "locations"=>[{"line"=>3, "column"=>23}],
374
+ "path"=>["query", "time", "range", "from"],
375
+ "extensions"=>{"code"=>"argumentLiteralsIncompatible", "typeName"=>"CoercionError"},
376
+ }
377
+
378
+ to_error = {
379
+ "message"=>"cannot coerce to Float",
380
+ "locations"=>[{"line"=>3, "column"=>23}],
381
+ "path"=>["query", "time", "range", "to"],
382
+ "extensions"=>{"code"=>"argumentLiteralsIncompatible", "typeName"=>"CoercionError"},
383
+ }
384
+
385
+ bubbling_error = {
386
+ "message"=>"cannot coerce to Float",
387
+ "locations"=>[{"line"=>3, "column"=>11}],
388
+ "path"=>["query", "time", "range"],
389
+ "extensions"=>{"code"=>"argumentLiteralsIncompatible", "typeName"=>"CoercionError"},
270
390
  }
391
+
392
+ describe "sets deep error message from a CoercionError if raised" do
393
+ it "works with error bubbling enabled" do
394
+ with_error_bubbling(schema) do
395
+ assert_equal 3, errors.length
396
+ assert_includes(errors, from_error)
397
+ assert_includes(errors, to_error)
398
+ assert_includes(errors, bubbling_error)
399
+ end
400
+ end
401
+
402
+ it "works without error bubbling enabled" do
403
+ without_error_bubbling(schema) do
404
+ assert_equal 2, errors.length
405
+ assert_includes(errors, from_error)
406
+ assert_includes(errors, to_error)
407
+ refute_includes(errors, bubbling_error)
408
+ end
409
+ end
410
+ end
271
411
  end
272
412
  end
273
413
  end