graphql 1.8.7 → 1.9.0

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 (368) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/install_generator.rb +2 -1
  3. data/lib/generators/graphql/scalar_generator.rb +20 -0
  4. data/lib/generators/graphql/templates/base_scalar.erb +4 -0
  5. data/lib/generators/graphql/templates/scalar.erb +13 -0
  6. data/lib/graphql/analysis/ast/analyzer.rb +62 -0
  7. data/lib/graphql/analysis/ast/field_usage.rb +28 -0
  8. data/lib/graphql/analysis/ast/max_query_complexity.rb +23 -0
  9. data/lib/graphql/analysis/ast/max_query_depth.rb +18 -0
  10. data/lib/graphql/analysis/ast/query_complexity.rb +114 -0
  11. data/lib/graphql/analysis/ast/query_depth.rb +66 -0
  12. data/lib/graphql/analysis/ast/visitor.rb +255 -0
  13. data/lib/graphql/analysis/ast.rb +82 -0
  14. data/lib/graphql/analysis.rb +1 -0
  15. data/lib/graphql/argument.rb +5 -0
  16. data/lib/graphql/authorization.rb +1 -0
  17. data/lib/graphql/backwards_compatibility.rb +1 -1
  18. data/lib/graphql/base_type.rb +1 -1
  19. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +1 -2
  20. data/lib/graphql/compatibility/schema_parser_specification.rb +2 -6
  21. data/lib/graphql/dig.rb +19 -0
  22. data/lib/graphql/directive/include_directive.rb +1 -7
  23. data/lib/graphql/directive/skip_directive.rb +1 -8
  24. data/lib/graphql/directive.rb +13 -1
  25. data/lib/graphql/enum_type.rb +8 -0
  26. data/lib/graphql/execution/execute.rb +36 -17
  27. data/lib/graphql/execution/instrumentation.rb +2 -0
  28. data/lib/graphql/execution/interpreter/execution_errors.rb +29 -0
  29. data/lib/graphql/execution/interpreter/hash_response.rb +46 -0
  30. data/lib/graphql/execution/interpreter/resolve.rb +58 -0
  31. data/lib/graphql/execution/interpreter/runtime.rb +597 -0
  32. data/lib/graphql/execution/interpreter.rb +99 -0
  33. data/lib/graphql/execution/lazy.rb +8 -1
  34. data/lib/graphql/execution/lookahead.rb +351 -0
  35. data/lib/graphql/execution/multiplex.rb +37 -29
  36. data/lib/graphql/execution.rb +2 -0
  37. data/lib/graphql/execution_error.rb +1 -1
  38. data/lib/graphql/field.rb +1 -7
  39. data/lib/graphql/integer_encoding_error.rb +12 -0
  40. data/lib/graphql/internal_representation/rewrite.rb +127 -142
  41. data/lib/graphql/introspection/dynamic_fields.rb +8 -2
  42. data/lib/graphql/introspection/entry_points.rb +11 -6
  43. data/lib/graphql/introspection/enum_value_type.rb +4 -0
  44. data/lib/graphql/introspection/schema_type.rb +7 -2
  45. data/lib/graphql/introspection/type_type.rb +9 -5
  46. data/lib/graphql/invalid_null_error.rb +1 -1
  47. data/lib/graphql/language/block_string.rb +37 -0
  48. data/lib/graphql/language/document_from_schema_definition.rb +10 -7
  49. data/lib/graphql/language/lexer.rb +55 -36
  50. data/lib/graphql/language/lexer.rl +8 -3
  51. data/lib/graphql/language/nodes.rb +440 -362
  52. data/lib/graphql/language/parser.rb +56 -56
  53. data/lib/graphql/language/parser.y +12 -12
  54. data/lib/graphql/language/printer.rb +2 -2
  55. data/lib/graphql/language/visitor.rb +158 -15
  56. data/lib/graphql/language.rb +0 -1
  57. data/lib/graphql/literal_validation_error.rb +6 -0
  58. data/lib/graphql/query/arguments.rb +3 -2
  59. data/lib/graphql/query/arguments_cache.rb +1 -1
  60. data/lib/graphql/query/context.rb +14 -5
  61. data/lib/graphql/query/executor.rb +1 -1
  62. data/lib/graphql/query/result.rb +1 -1
  63. data/lib/graphql/query/validation_pipeline.rb +35 -11
  64. data/lib/graphql/query/variable_validation_error.rb +10 -1
  65. data/lib/graphql/query.rb +16 -2
  66. data/lib/graphql/relay/base_connection.rb +2 -0
  67. data/lib/graphql/relay/connection_instrumentation.rb +3 -1
  68. data/lib/graphql/relay/connection_resolve.rb +1 -1
  69. data/lib/graphql/relay/node.rb +2 -28
  70. data/lib/graphql/relay/relation_connection.rb +1 -1
  71. data/lib/graphql/schema/argument.rb +13 -5
  72. data/lib/graphql/schema/base_64_encoder.rb +4 -4
  73. data/lib/graphql/schema/build_from_definition.rb +2 -4
  74. data/lib/graphql/schema/default_type_error.rb +1 -1
  75. data/lib/graphql/schema/directive/feature.rb +66 -0
  76. data/lib/graphql/schema/directive/include.rb +25 -0
  77. data/lib/graphql/schema/directive/skip.rb +25 -0
  78. data/lib/graphql/schema/directive/transform.rb +48 -0
  79. data/lib/graphql/schema/directive.rb +103 -0
  80. data/lib/graphql/schema/enum_value.rb +3 -2
  81. data/lib/graphql/schema/field/connection_extension.rb +50 -0
  82. data/lib/graphql/schema/field/scope_extension.rb +18 -0
  83. data/lib/graphql/schema/field.rb +273 -64
  84. data/lib/graphql/schema/field_extension.rb +69 -0
  85. data/lib/graphql/schema/input_object.rb +16 -8
  86. data/lib/graphql/schema/interface.rb +1 -0
  87. data/lib/graphql/schema/loader.rb +22 -16
  88. data/lib/graphql/schema/member/base_dsl_methods.rb +8 -2
  89. data/lib/graphql/schema/member/build_type.rb +33 -1
  90. data/lib/graphql/schema/member/has_arguments.rb +6 -2
  91. data/lib/graphql/schema/member/has_fields.rb +18 -70
  92. data/lib/graphql/schema/member/has_path.rb +25 -0
  93. data/lib/graphql/schema/member/instrumentation.rb +10 -7
  94. data/lib/graphql/schema/member.rb +2 -0
  95. data/lib/graphql/schema/mutation.rb +6 -48
  96. data/lib/graphql/schema/non_null.rb +5 -1
  97. data/lib/graphql/schema/object.rb +18 -4
  98. data/lib/graphql/schema/printer.rb +1 -1
  99. data/lib/graphql/schema/relay_classic_mutation.rb +42 -9
  100. data/lib/graphql/schema/resolver/has_payload_type.rb +65 -0
  101. data/lib/graphql/schema/resolver.rb +45 -20
  102. data/lib/graphql/schema/subscription.rb +97 -0
  103. data/lib/graphql/schema/traversal.rb +11 -7
  104. data/lib/graphql/schema.rb +186 -38
  105. data/lib/graphql/static_validation/all_rules.rb +3 -2
  106. data/lib/graphql/static_validation/base_visitor.rb +199 -0
  107. data/lib/graphql/static_validation/default_visitor.rb +15 -0
  108. data/lib/graphql/static_validation/definition_dependencies.rb +62 -68
  109. data/lib/graphql/static_validation/{message.rb → error.rb} +11 -11
  110. data/lib/graphql/static_validation/interpreter_visitor.rb +14 -0
  111. data/lib/graphql/static_validation/literal_validator.rb +54 -11
  112. data/lib/graphql/static_validation/no_validate_visitor.rb +10 -0
  113. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +87 -16
  114. data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +31 -0
  115. data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +11 -11
  116. data/lib/graphql/static_validation/rules/argument_names_are_unique_error.rb +30 -0
  117. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +52 -8
  118. data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +35 -0
  119. data/lib/graphql/static_validation/rules/directives_are_defined.rb +12 -15
  120. data/lib/graphql/static_validation/rules/directives_are_defined_error.rb +29 -0
  121. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +19 -14
  122. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations_error.rb +31 -0
  123. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +17 -19
  124. data/lib/graphql/static_validation/rules/fields_are_defined_on_type_error.rb +32 -0
  125. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +30 -14
  126. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections_error.rb +31 -0
  127. data/lib/graphql/static_validation/rules/fields_will_merge.rb +356 -29
  128. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +32 -0
  129. data/lib/graphql/static_validation/rules/fragment_names_are_unique.rb +20 -13
  130. data/lib/graphql/static_validation/rules/fragment_names_are_unique_error.rb +29 -0
  131. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +37 -29
  132. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible_error.rb +35 -0
  133. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +25 -17
  134. data/lib/graphql/static_validation/rules/fragment_types_exist_error.rb +29 -0
  135. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +12 -10
  136. data/lib/graphql/static_validation/rules/fragments_are_finite_error.rb +29 -0
  137. data/lib/graphql/static_validation/rules/fragments_are_named.rb +7 -11
  138. data/lib/graphql/static_validation/rules/fragments_are_named_error.rb +26 -0
  139. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +16 -16
  140. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types_error.rb +30 -0
  141. data/lib/graphql/static_validation/rules/fragments_are_used.rb +21 -14
  142. data/lib/graphql/static_validation/rules/fragments_are_used_error.rb +29 -0
  143. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +10 -14
  144. data/lib/graphql/static_validation/rules/mutation_root_exists_error.rb +26 -0
  145. data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +30 -30
  146. data/lib/graphql/static_validation/rules/no_definitions_are_present_error.rb +25 -0
  147. data/lib/graphql/static_validation/rules/operation_names_are_valid.rb +25 -17
  148. data/lib/graphql/static_validation/rules/operation_names_are_valid_error.rb +28 -0
  149. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +17 -18
  150. data/lib/graphql/static_validation/rules/required_arguments_are_present_error.rb +35 -0
  151. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +47 -0
  152. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present_error.rb +35 -0
  153. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +10 -14
  154. data/lib/graphql/static_validation/rules/subscription_root_exists_error.rb +26 -0
  155. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +28 -17
  156. data/lib/graphql/static_validation/rules/unique_directives_per_location_error.rb +29 -0
  157. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +35 -27
  158. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed_error.rb +39 -0
  159. data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +15 -14
  160. data/lib/graphql/static_validation/rules/variable_names_are_unique_error.rb +29 -0
  161. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +41 -30
  162. data/lib/graphql/static_validation/rules/variable_usages_are_allowed_error.rb +38 -0
  163. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +18 -14
  164. data/lib/graphql/static_validation/rules/variables_are_input_types_error.rb +32 -0
  165. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +73 -65
  166. data/lib/graphql/static_validation/rules/variables_are_used_and_defined_error.rb +37 -0
  167. data/lib/graphql/static_validation/validation_context.rb +8 -51
  168. data/lib/graphql/static_validation/validator.rb +23 -15
  169. data/lib/graphql/static_validation.rb +5 -3
  170. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +21 -2
  171. data/lib/graphql/subscriptions/event.rb +28 -5
  172. data/lib/graphql/subscriptions/subscription_root.rb +66 -0
  173. data/lib/graphql/subscriptions.rb +16 -2
  174. data/lib/graphql/tracing/active_support_notifications_tracing.rb +0 -1
  175. data/lib/graphql/tracing/appsignal_tracing.rb +1 -1
  176. data/lib/graphql/tracing/data_dog_tracing.rb +1 -1
  177. data/lib/graphql/tracing/new_relic_tracing.rb +3 -3
  178. data/lib/graphql/tracing/platform_tracing.rb +17 -1
  179. data/lib/graphql/tracing/prometheus_tracing.rb +1 -1
  180. data/lib/graphql/tracing/scout_tracing.rb +1 -1
  181. data/lib/graphql/tracing/skylight_tracing.rb +3 -3
  182. data/lib/graphql/tracing.rb +8 -8
  183. data/lib/graphql/types/float.rb +1 -1
  184. data/lib/graphql/types/int.rb +11 -2
  185. data/lib/graphql/types/iso_8601_date_time.rb +15 -1
  186. data/lib/graphql/types/relay/base_connection.rb +15 -1
  187. data/lib/graphql/types/relay/node.rb +0 -1
  188. data/lib/graphql/types/relay/node_field.rb +43 -0
  189. data/lib/graphql/types/relay/nodes_field.rb +45 -0
  190. data/lib/graphql/types/relay.rb +2 -0
  191. data/lib/graphql/unauthorized_error.rb +4 -0
  192. data/lib/graphql/unauthorized_field_error.rb +23 -0
  193. data/lib/graphql/upgrader/member.rb +5 -0
  194. data/lib/graphql/version.rb +1 -1
  195. data/lib/graphql.rb +6 -1
  196. data/readme.md +7 -7
  197. data/spec/dummy/Gemfile +1 -1
  198. data/spec/dummy/Gemfile.lock +157 -0
  199. data/spec/dummy/app/channels/graphql_channel.rb +22 -11
  200. data/spec/dummy/config/locales/en.yml +1 -1
  201. data/spec/dummy/log/test.log +199 -0
  202. data/spec/dummy/test/test_helper.rb +1 -0
  203. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/4w/4wzXRZrAkwKdgYaSE0pid5eB-fer8vSfSku_NPg4rMA.cache +0 -0
  204. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/7I/7IHVBiJT06QSpgLpLoJIxboQ0B-D_tMTxsvoezBTV3Q.cache +1 -0
  205. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/8w/8wY_SKagj8wHuwGNAAf6JnQ8joMbC6cEYpHrTAI8Urc.cache +1 -0
  206. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/AK/AKzz1u6bGb4auXcrObA_g5LL-oV0ejNGa448AgAi_WQ.cache +1 -0
  207. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/ET/ETW4uxvaYpruL8y6_ZptUH82ZowMaHIqvg5WexBFdEM.cache +3 -0
  208. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/F1/F1TWpjjyA56k9Z90n5B3xRn7DUdGjX73QCkYC6k07JQ.cache +0 -0
  209. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/F8/F8MUNRzORGFgr329fNM0xLaoWCXdv3BIalT7dsvLfjs.cache +2 -0
  210. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/KB/KB07ZaKNC5uXJ7TjLi-WqnY6g7dq8wWp_8N3HNjBNxg.cache +2 -0
  211. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Ms/MsKSimH_UCB-H1tLvDABDHuvGciuoW6kVqQWDrXU5FQ.cache +0 -0
  212. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Mt/Mtci-Kim50aPOmeClD4AIicKn1d1WJ0n454IjSd94sk.cache +0 -0
  213. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/QH/QHt3Tc1Y6M66Oo_pDuMyWrQNs4Pp3SMeZR5K1wJj2Ts.cache +1 -0
  214. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/XU/XU4k1OXnfMils5SrirorPvDSyDSqiOWLZNtmAH1HH8k.cache +0 -0
  215. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/ZI/ZIof7mZxWWCnraIFOCuV6a8QRWzKJXJnx2Xd7C0ZyX0.cache +1 -0
  216. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/cG/cGc_puuPS5pZKgUcy1Y_i1L6jl5UtsiIrMH59rTzR6c.cache +3 -0
  217. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/df/dfro_B6bx3KP1Go-7jEOqqZ2j4hVRseXIc3es9PKQno.cache +1 -0
  218. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/jO/jO1DfbqnG0mTULsjJJANc3fefrG2zt7DIMmcptMT628.cache +1 -0
  219. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/pE/pE7gO6pQ-z187Swb4hT554wmqsq-cNzgPWLrCz-LQQQ.cache +0 -0
  220. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/r9/r9iU1l58a6rxkZSW5RSC52_tD-_UQuHxoMVnkfJ7Mhs.cache +1 -0
  221. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/xi/xitPPFfPIyDMpaznV0sBBcw8eSCV8PJcLLWin78sCgE.cache +0 -0
  222. data/spec/dummy/tmp/screenshots/failures_test_it_handles_subscriptions.png +0 -0
  223. data/spec/graphql/analysis/analyze_query_spec.rb +1 -1
  224. data/spec/graphql/analysis/ast/field_usage_spec.rb +51 -0
  225. data/spec/graphql/analysis/ast/max_query_complexity_spec.rb +120 -0
  226. data/spec/graphql/analysis/ast/max_query_depth_spec.rb +114 -0
  227. data/spec/graphql/analysis/ast/query_complexity_spec.rb +299 -0
  228. data/spec/graphql/analysis/ast/query_depth_spec.rb +108 -0
  229. data/spec/graphql/analysis/ast_spec.rb +269 -0
  230. data/spec/graphql/authorization_spec.rb +120 -23
  231. data/spec/graphql/base_type_spec.rb +6 -4
  232. data/spec/graphql/enum_type_spec.rb +6 -1
  233. data/spec/graphql/execution/execute_spec.rb +9 -9
  234. data/spec/graphql/execution/instrumentation_spec.rb +19 -0
  235. data/spec/graphql/execution/interpreter_spec.rb +485 -0
  236. data/spec/graphql/execution/lazy_spec.rb +67 -1
  237. data/spec/graphql/execution/lookahead_spec.rb +363 -0
  238. data/spec/graphql/execution/multiplex_spec.rb +31 -3
  239. data/spec/graphql/execution/typecast_spec.rb +20 -20
  240. data/spec/graphql/execution_error_spec.rb +110 -96
  241. data/spec/graphql/field_spec.rb +1 -1
  242. data/spec/graphql/input_object_type_spec.rb +13 -352
  243. data/spec/graphql/int_type_spec.rb +19 -0
  244. data/spec/graphql/interface_type_spec.rb +4 -4
  245. data/spec/graphql/internal_representation/rewrite_spec.rb +2 -0
  246. data/spec/graphql/introspection/input_value_type_spec.rb +1 -1
  247. data/spec/graphql/introspection/type_type_spec.rb +1 -2
  248. data/spec/graphql/language/document_from_schema_definition_spec.rb +2 -2
  249. data/spec/graphql/language/lexer_spec.rb +72 -3
  250. data/spec/graphql/language/nodes_spec.rb +20 -0
  251. data/spec/graphql/language/printer_spec.rb +18 -6
  252. data/spec/graphql/language/visitor_spec.rb +320 -14
  253. data/spec/graphql/non_null_type_spec.rb +1 -1
  254. data/spec/graphql/object_type_spec.rb +32 -27
  255. data/spec/graphql/query/arguments_spec.rb +21 -0
  256. data/spec/graphql/query/context_spec.rb +28 -0
  257. data/spec/graphql/query/executor_spec.rb +40 -36
  258. data/spec/graphql/query_spec.rb +12 -6
  259. data/spec/graphql/schema/argument_spec.rb +35 -1
  260. data/spec/graphql/schema/build_from_definition_spec.rb +144 -29
  261. data/spec/graphql/schema/catchall_middleware_spec.rb +16 -15
  262. data/spec/graphql/schema/directive/feature_spec.rb +81 -0
  263. data/spec/graphql/schema/directive/transform_spec.rb +39 -0
  264. data/spec/graphql/schema/enum_spec.rb +12 -3
  265. data/spec/graphql/schema/enum_value_spec.rb +11 -0
  266. data/spec/graphql/schema/field_extension_spec.rb +115 -0
  267. data/spec/graphql/schema/field_spec.rb +47 -7
  268. data/spec/graphql/schema/input_object_spec.rb +95 -0
  269. data/spec/graphql/schema/instrumentation_spec.rb +3 -0
  270. data/spec/graphql/schema/interface_spec.rb +8 -2
  271. data/spec/graphql/schema/introspection_system_spec.rb +9 -1
  272. data/spec/graphql/schema/loader_spec.rb +5 -0
  273. data/spec/graphql/schema/member/accepts_definition_spec.rb +4 -0
  274. data/spec/graphql/schema/member/build_type_spec.rb +46 -0
  275. data/spec/graphql/schema/member/scoped_spec.rb +19 -3
  276. data/spec/graphql/schema/mutation_spec.rb +5 -3
  277. data/spec/graphql/schema/object_spec.rb +9 -1
  278. data/spec/graphql/schema/printer_spec.rb +255 -93
  279. data/spec/graphql/schema/relay_classic_mutation_spec.rb +133 -0
  280. data/spec/graphql/schema/resolver_spec.rb +173 -9
  281. data/spec/graphql/schema/scalar_spec.rb +6 -0
  282. data/spec/graphql/schema/subscription_spec.rb +416 -0
  283. data/spec/graphql/schema/traversal_spec.rb +10 -10
  284. data/spec/graphql/schema/type_expression_spec.rb +2 -2
  285. data/spec/graphql/schema/union_spec.rb +7 -0
  286. data/spec/graphql/schema/validation_spec.rb +1 -1
  287. data/spec/graphql/schema/warden_spec.rb +145 -88
  288. data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +213 -73
  289. data/spec/graphql/static_validation/rules/argument_names_are_unique_spec.rb +2 -2
  290. data/spec/graphql/static_validation/rules/arguments_are_defined_spec.rb +72 -29
  291. data/spec/graphql/static_validation/rules/directives_are_defined_spec.rb +4 -2
  292. data/spec/graphql/static_validation/rules/directives_are_in_valid_locations_spec.rb +4 -2
  293. data/spec/graphql/static_validation/rules/fields_are_defined_on_type_spec.rb +10 -5
  294. data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +10 -5
  295. data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +131 -5
  296. data/spec/graphql/static_validation/rules/fragment_names_are_unique_spec.rb +2 -1
  297. data/spec/graphql/static_validation/rules/fragment_spreads_are_possible_spec.rb +6 -3
  298. data/spec/graphql/static_validation/rules/fragment_types_exist_spec.rb +4 -2
  299. data/spec/graphql/static_validation/rules/fragments_are_finite_spec.rb +4 -2
  300. data/spec/graphql/static_validation/rules/fragments_are_named_spec.rb +2 -1
  301. data/spec/graphql/static_validation/rules/fragments_are_on_composite_types_spec.rb +6 -3
  302. data/spec/graphql/static_validation/rules/fragments_are_used_spec.rb +22 -2
  303. data/spec/graphql/static_validation/rules/mutation_root_exists_spec.rb +2 -1
  304. data/spec/graphql/static_validation/rules/operation_names_are_valid_spec.rb +6 -3
  305. data/spec/graphql/static_validation/rules/required_arguments_are_present_spec.rb +13 -4
  306. data/spec/graphql/static_validation/rules/required_input_object_attributes_are_present_spec.rb +58 -0
  307. data/spec/graphql/static_validation/rules/subscription_root_exists_spec.rb +2 -1
  308. data/spec/graphql/static_validation/rules/unique_directives_per_location_spec.rb +14 -7
  309. data/spec/graphql/static_validation/rules/variable_default_values_are_correctly_typed_spec.rb +14 -7
  310. data/spec/graphql/static_validation/rules/variable_usages_are_allowed_spec.rb +8 -4
  311. data/spec/graphql/static_validation/rules/variables_are_input_types_spec.rb +8 -4
  312. data/spec/graphql/static_validation/rules/variables_are_used_and_defined_spec.rb +23 -3
  313. data/spec/graphql/static_validation/type_stack_spec.rb +10 -19
  314. data/spec/graphql/static_validation/validator_spec.rb +50 -2
  315. data/spec/graphql/subscriptions_spec.rb +27 -16
  316. data/spec/graphql/tracing/new_relic_tracing_spec.rb +16 -0
  317. data/spec/graphql/tracing/platform_tracing_spec.rb +59 -37
  318. data/spec/graphql/tracing/prometheus_tracing_spec.rb +3 -0
  319. data/spec/graphql/tracing/skylight_tracing_spec.rb +16 -0
  320. data/spec/graphql/types/iso_8601_date_time_spec.rb +29 -2
  321. data/spec/graphql/union_type_spec.rb +2 -2
  322. data/spec/graphql/upgrader/member_spec.rb +67 -0
  323. data/spec/{graphql → integration/mongoid/graphql}/relay/mongo_relation_connection_spec.rb +11 -22
  324. data/spec/integration/mongoid/spec_helper.rb +2 -0
  325. data/spec/{support → integration/mongoid}/star_trek/data.rb +0 -0
  326. data/spec/{support → integration/mongoid}/star_trek/schema.rb +56 -34
  327. data/spec/{support/star_wars → integration/rails}/data.rb +1 -0
  328. data/spec/{support → integration/rails/generators}/base_generator_test.rb +0 -0
  329. data/spec/{generators → integration/rails/generators}/graphql/enum_generator_spec.rb +0 -0
  330. data/spec/{generators → integration/rails/generators}/graphql/install_generator_spec.rb +1 -1
  331. data/spec/{generators → integration/rails/generators}/graphql/interface_generator_spec.rb +0 -0
  332. data/spec/{generators → integration/rails/generators}/graphql/loader_generator_spec.rb +0 -0
  333. data/spec/{generators → integration/rails/generators}/graphql/mutation_generator_spec.rb +0 -0
  334. data/spec/{generators → integration/rails/generators}/graphql/object_generator_spec.rb +0 -0
  335. data/spec/integration/rails/generators/graphql/scalar_generator_spec.rb +28 -0
  336. data/spec/{generators → integration/rails/generators}/graphql/union_generator_spec.rb +0 -0
  337. data/spec/integration/rails/graphql/input_object_type_spec.rb +364 -0
  338. data/spec/{graphql → integration/rails/graphql}/query/variables_spec.rb +7 -7
  339. data/spec/{graphql → integration/rails/graphql}/relay/array_connection_spec.rb +9 -9
  340. data/spec/{graphql → integration/rails/graphql}/relay/base_connection_spec.rb +11 -3
  341. data/spec/{graphql → integration/rails/graphql}/relay/connection_instrumentation_spec.rb +19 -22
  342. data/spec/{graphql → integration/rails/graphql}/relay/connection_resolve_spec.rb +16 -0
  343. data/spec/{graphql → integration/rails/graphql}/relay/connection_type_spec.rb +0 -0
  344. data/spec/{graphql → integration/rails/graphql}/relay/edge_spec.rb +0 -0
  345. data/spec/{graphql → integration/rails/graphql}/relay/mutation_spec.rb +48 -0
  346. data/spec/{graphql → integration/rails/graphql}/relay/node_spec.rb +0 -0
  347. data/spec/{graphql → integration/rails/graphql}/relay/page_info_spec.rb +22 -22
  348. data/spec/{graphql → integration/rails/graphql}/relay/range_add_spec.rb +4 -4
  349. data/spec/{graphql → integration/rails/graphql}/relay/relation_connection_spec.rb +56 -27
  350. data/spec/{graphql → integration/rails/graphql}/schema_spec.rb +15 -11
  351. data/spec/{graphql → integration/rails/graphql}/tracing/active_support_notifications_tracing_spec.rb +16 -9
  352. data/spec/integration/rails/spec_helper.rb +25 -0
  353. data/spec/integration/tmp/app/graphql/types/family_type.rb +9 -0
  354. data/spec/spec_helper.rb +23 -39
  355. data/spec/support/dummy/data.rb +20 -17
  356. data/spec/support/dummy/schema.rb +315 -305
  357. data/spec/support/error_bubbling_helpers.rb +23 -0
  358. data/spec/support/jazz.rb +213 -46
  359. data/spec/support/lazy_helpers.rb +69 -27
  360. data/spec/support/new_relic.rb +3 -0
  361. data/spec/support/skylight.rb +3 -0
  362. data/spec/support/star_wars/schema.rb +131 -81
  363. data/spec/support/static_validation_helpers.rb +9 -5
  364. metadata +418 -261
  365. data/lib/graphql/language/comments.rb +0 -45
  366. data/lib/graphql/static_validation/arguments_validator.rb +0 -50
  367. data/spec/graphql/schema/member/has_fields_spec.rb +0 -129
  368. data/spec/rails_dependency_sanity_spec.rb +0 -14
@@ -19,28 +19,32 @@ describe GraphQL::StaticValidation::FieldsHaveAppropriateSelections do
19
19
  illegal_selection_error = {
20
20
  "message"=>"Selections can't be made on scalars (field 'id' returns Int but has selections [something, someFields])",
21
21
  "locations"=>[{"line"=>6, "column"=>47}],
22
- "fields"=>["query getCheese", "illegalSelectionCheese", "id"],
22
+ "path"=>["query getCheese", "illegalSelectionCheese", "id"],
23
+ "extensions"=>{"code"=>"selectionMismatch", "nodeName"=>"field 'id'", "typeName"=>"Int"}
23
24
  }
24
25
  assert_includes(errors, illegal_selection_error, "finds illegal selections on scalars")
25
26
 
26
27
  objects_selection_required_error = {
27
28
  "message"=>"Field must have selections (field 'cheese' returns Cheese but has no selections. Did you mean 'cheese { ... }'?)",
28
29
  "locations"=>[{"line"=>4, "column"=>7}],
29
- "fields"=>["query getCheese", "missingFieldsObject"],
30
+ "path"=>["query getCheese", "missingFieldsObject"],
31
+ "extensions"=>{"code"=>"selectionMismatch", "nodeName"=>"field 'cheese'", "typeName"=>"Cheese"}
30
32
  }
31
33
  assert_includes(errors, objects_selection_required_error, "finds objects without selections")
32
34
 
33
35
  interfaces_selection_required_error = {
34
36
  "message"=>"Field must have selections (field 'selfAsEdible' returns Edible but has no selections. Did you mean 'selfAsEdible { ... }'?)",
35
37
  "locations"=>[{"line"=>5, "column"=>47}],
36
- "fields"=>["query getCheese", "missingFieldsInterface", "selfAsEdible"],
38
+ "path"=>["query getCheese", "missingFieldsInterface", "selfAsEdible"],
39
+ "extensions"=>{"code"=>"selectionMismatch", "nodeName"=>"field 'selfAsEdible'", "typeName"=>"Edible"}
37
40
  }
38
41
  assert_includes(errors, interfaces_selection_required_error, "finds interfaces without selections")
39
42
 
40
43
  incorrect_fragment_error = {
41
44
  "message"=>"Selections can't be made on scalars (field 'flavor' returns String but has inline fragments [String])",
42
45
  "locations"=>[{"line"=>7, "column"=>48}],
43
- "fields"=>["query getCheese", "incorrectFragmentSpread", "flavor"],
46
+ "path"=>["query getCheese", "incorrectFragmentSpread", "flavor"],
47
+ "extensions"=>{"code"=>"selectionMismatch", "nodeName"=>"field 'flavor'", "typeName"=>"String"}
44
48
  }
45
49
  assert_includes(errors, incorrect_fragment_error, "finds scalar fields with selections")
46
50
  end
@@ -53,7 +57,8 @@ describe GraphQL::StaticValidation::FieldsHaveAppropriateSelections do
53
57
  selections_required_error = {
54
58
  "message"=> "Field must have selections (anonymous query returns Query but has no selections. Did you mean ' { ... }'?)",
55
59
  "locations"=>[{"line"=>1, "column"=>1}],
56
- "fields"=>["query"]
60
+ "path"=>["query"],
61
+ "extensions"=>{"code"=>"selectionMismatch", "nodeName"=>"anonymous query", "typeName"=>"Query"}
57
62
  }
58
63
  assert_includes(errors, selections_required_error)
59
64
  end
@@ -39,13 +39,18 @@ describe GraphQL::StaticValidation::FieldsWillMerge do
39
39
  species: PetSpecies!
40
40
  }
41
41
 
42
+ interface Mammal {
43
+ name(surname: Boolean = false): String!
44
+ nickname: String
45
+ }
46
+
42
47
  interface Pet {
43
48
  name(surname: Boolean = false): String!
44
49
  nickname: String
45
50
  toys: [Toy!]!
46
51
  }
47
52
 
48
- type Dog implements Pet {
53
+ type Dog implements Pet & Mammal {
49
54
  name(surname: Boolean = false): String!
50
55
  nickname: String
51
56
  doesKnowCommand(dogCommand: PetCommand): Boolean!
@@ -53,7 +58,7 @@ describe GraphQL::StaticValidation::FieldsWillMerge do
53
58
  toys: [Toy!]!
54
59
  }
55
60
 
56
- type Cat implements Pet {
61
+ type Cat implements Pet & Mammal {
57
62
  name(surname: Boolean = false): String!
58
63
  nickname: String
59
64
  doesKnowCommand(catCommand: PetCommand): Boolean!
@@ -348,12 +353,13 @@ describe GraphQL::StaticValidation::FieldsWillMerge do
348
353
 
349
354
  it "fails rule" do
350
355
  assert_equal [
351
- "Field 'name' has a field conflict: name or nickname?",
352
356
  "Field 'x' has a field conflict: name or nickname?",
357
+ "Field 'name' has a field conflict: name or nickname?"
353
358
  ], error_messages
354
359
  end
355
360
  end
356
361
 
362
+
357
363
  describe "deep conflict" do
358
364
  let(:query_string) {%|
359
365
  {
@@ -375,7 +381,8 @@ describe GraphQL::StaticValidation::FieldsWillMerge do
375
381
  {"line"=>4, "column"=>11},
376
382
  {"line"=>8, "column"=>11}
377
383
  ],
378
- "fields"=>[]
384
+ "path"=>[],
385
+ "extensions"=>{"code"=>"fieldConflict", "fieldName"=>"x", "conflicts"=>"name or nickname"}
379
386
  }
380
387
  ]
381
388
  assert_equal expected_errors, errors
@@ -429,6 +436,7 @@ describe GraphQL::StaticValidation::FieldsWillMerge do
429
436
  end
430
437
  end
431
438
 
439
+
432
440
  describe "same aliases allowed on non-overlapping fields" do
433
441
  let(:query_string) {%|
434
442
  {
@@ -448,6 +456,53 @@ describe GraphQL::StaticValidation::FieldsWillMerge do
448
456
  end
449
457
  end
450
458
 
459
+ describe "same aliases not allowed on different interfaces" do
460
+ let(:query_string) {%|
461
+ {
462
+ pet {
463
+ ... on Pet {
464
+ name
465
+ }
466
+ ... on Mammal {
467
+ name: nickname
468
+ }
469
+ }
470
+ }
471
+ |}
472
+
473
+ it "fails rule" do
474
+ assert_equal [
475
+ "Field 'name' has a field conflict: name or nickname?",
476
+ ], error_messages
477
+ end
478
+ end
479
+
480
+ describe "same aliases allowed on different parent interfaces and different concrete types" do
481
+ let(:query_string) {%|
482
+ {
483
+ pet {
484
+ ... on Pet {
485
+ ...X
486
+ }
487
+ ... on Mammal {
488
+ ...Y
489
+ }
490
+ }
491
+ }
492
+
493
+ fragment X on Dog {
494
+ name
495
+ }
496
+ fragment Y on Cat {
497
+ name: nickname
498
+ }
499
+ |}
500
+
501
+ it "passes rule" do
502
+ assert_equal [], errors
503
+ end
504
+ end
505
+
451
506
  describe "allows different args where no conflict is possible" do
452
507
  let(:query_string) {%|
453
508
  {
@@ -473,6 +528,77 @@ describe GraphQL::StaticValidation::FieldsWillMerge do
473
528
  it "passes rule" do
474
529
  assert_equal [], errors
475
530
  end
531
+
532
+ describe "allows different args where no conflict is possible" do
533
+ let(:query_string) {%|
534
+ {
535
+ pet {
536
+ ... on Dog {
537
+ ... on Pet {
538
+ name
539
+ }
540
+ }
541
+ ... on Cat {
542
+ name(surname: true)
543
+ }
544
+ }
545
+ }
546
+ |}
547
+
548
+ it "passes rule" do
549
+ assert_equal [], errors
550
+ end
551
+ end
552
+
553
+ describe "allows different args where no conflict is possible with uneven abstract scoping" do
554
+ let(:query_string) {%|
555
+ {
556
+ pet {
557
+ ... on Pet {
558
+ ... on Dog {
559
+ name
560
+ }
561
+ }
562
+ ... on Cat {
563
+ name(surname: true)
564
+ }
565
+ }
566
+ }
567
+ |}
568
+
569
+ it "passes rule" do
570
+ assert_equal [], errors
571
+ end
572
+ end
573
+ end
574
+
575
+ describe "allows different args where no conflict is possible deep" do
576
+ let(:query_string) {%|
577
+ {
578
+ pet {
579
+ ... on Dog {
580
+ ...X
581
+ }
582
+ }
583
+ pet {
584
+ ... on Cat {
585
+ ...Y
586
+ }
587
+ }
588
+ }
589
+
590
+ fragment X on Pet {
591
+ name(surname: true)
592
+ }
593
+
594
+ fragment Y on Pet {
595
+ name
596
+ }
597
+ |}
598
+
599
+ it "passes rule" do
600
+ assert_equal [], errors
601
+ end
476
602
  end
477
603
 
478
604
  describe "return types must be unambiguous" do
@@ -599,7 +725,7 @@ describe GraphQL::StaticValidation::FieldsWillMerge do
599
725
  }
600
726
  }
601
727
  fragment X on SomeBox {
602
- scalar: deepBox { unreleatedField }
728
+ scalar: deepBox { unrelatedField }
603
729
  }
604
730
  fragment Y on SomeBox {
605
731
  scalar: unrelatedField
@@ -20,7 +20,8 @@ describe GraphQL::StaticValidation::FragmentNamesAreUnique do
20
20
  fragment_def_error = {
21
21
  "message"=>"Fragment name \"frag1\" must be unique",
22
22
  "locations"=>[{"line"=>8, "column"=>5}, {"line"=>9, "column"=>5}],
23
- "fields"=>[],
23
+ "path"=>[],
24
+ "extensions"=>{"code"=>"fragmentNotUnique", "fragmentName"=>"frag1"}
24
25
  }
25
26
  assert_includes(errors, fragment_def_error)
26
27
  end
@@ -31,17 +31,20 @@ describe GraphQL::StaticValidation::FragmentSpreadsArePossible do
31
31
  {
32
32
  "message"=>"Fragment on Milk can't be spread inside Cheese",
33
33
  "locations"=>[{"line"=>6, "column"=>9}],
34
- "fields"=>["query getCheese", "cheese", "... on Milk"],
34
+ "path"=>["query getCheese", "cheese", "... on Milk"],
35
+ "extensions"=>{"code"=>"cannotSpreadFragment", "typeName"=>"Milk", "fragmentName"=>"unknown", "parentName"=>"Cheese"}
35
36
  },
36
37
  {
37
38
  "message"=>"Fragment milkFields on Milk can't be spread inside Cheese",
38
39
  "locations"=>[{"line"=>4, "column"=>9}],
39
- "fields"=>["query getCheese", "cheese", "... milkFields"],
40
+ "path"=>["query getCheese", "cheese", "... milkFields"],
41
+ "extensions"=>{"code"=>"cannotSpreadFragment", "typeName"=>"Milk", "fragmentName"=>" milkFields", "parentName"=>"Cheese"}
40
42
  },
41
43
  {
42
44
  "message"=>"Fragment milkFields on Milk can't be spread inside Cheese",
43
45
  "locations"=>[{"line"=>18, "column"=>7}],
44
- "fields"=>["fragment cheeseFields", "... milkFields"],
46
+ "path"=>["fragment cheeseFields", "... milkFields"],
47
+ "extensions"=>{"code"=>"cannotSpreadFragment", "typeName"=>"Milk", "fragmentName"=>" milkFields", "parentName"=>"Cheese"}
45
48
  }
46
49
  ]
47
50
  assert_equal(expected, errors)
@@ -27,13 +27,15 @@ describe GraphQL::StaticValidation::FragmentTypesExist do
27
27
  inline_fragment_error = {
28
28
  "message"=>"No such type Something, so it can't be a fragment condition",
29
29
  "locations"=>[{"line"=>11, "column"=>5}],
30
- "fields"=>["fragment somethingFields"],
30
+ "path"=>["fragment somethingFields"],
31
+ "extensions"=>{"code"=>"undefinedType", "typeName"=>"Something"}
31
32
  }
32
33
  assert_includes(errors, inline_fragment_error, "on inline fragments")
33
34
  fragment_def_error = {
34
35
  "message"=>"No such type Nothing, so it can't be a fragment condition",
35
36
  "locations"=>[{"line"=>5, "column"=>9}],
36
- "fields"=>["query getCheese", "cheese", "... on Nothing"],
37
+ "path"=>["query getCheese", "cheese", "... on Nothing"],
38
+ "extensions"=>{"code"=>"undefinedType", "typeName"=>"Nothing"}
37
39
  }
38
40
  assert_includes(errors, fragment_def_error, "on fragment definitions")
39
41
  end
@@ -38,12 +38,14 @@ describe GraphQL::StaticValidation::FragmentsAreFinite do
38
38
  {
39
39
  "message"=>"Fragment sourceField contains an infinite loop",
40
40
  "locations"=>[{"line"=>12, "column"=>5}],
41
- "fields"=>["fragment sourceField"],
41
+ "path"=>["fragment sourceField"],
42
+ "extensions"=>{"code"=>"infiniteLoop", "fragmentName"=>"sourceField"}
42
43
  },
43
44
  {
44
45
  "message"=>"Fragment flavorField contains an infinite loop",
45
46
  "locations"=>[{"line"=>17, "column"=>5}],
46
- "fields"=>["fragment flavorField"],
47
+ "path"=>["fragment flavorField"],
48
+ "extensions"=>{"code"=>"infiniteLoop", "fragmentName"=>"flavorField"}
47
49
  }
48
50
  ]
49
51
  assert_equal(expected, errors)
@@ -16,7 +16,8 @@ describe GraphQL::StaticValidation::FragmentTypesExist do
16
16
  fragment_def_error = {
17
17
  "message"=>"Fragment definition has no name",
18
18
  "locations"=>[{"line"=>2, "column"=>5}],
19
- "fields"=>["fragment "],
19
+ "path"=>["fragment "],
20
+ "extensions"=>{"code"=>"anonymousFragment"}
20
21
  }
21
22
  assert_includes(errors, fragment_def_error, "on fragment definitions")
22
23
  end
@@ -35,17 +35,20 @@ describe GraphQL::StaticValidation::FragmentsAreOnCompositeTypes do
35
35
  {
36
36
  "message"=>"Invalid fragment on type Boolean (must be Union, Interface or Object)",
37
37
  "locations"=>[{"line"=>6, "column"=>11}],
38
- "fields"=>["query getCheese", "cheese", "... on Cheese", "... on Boolean"],
38
+ "path"=>["query getCheese", "cheese", "... on Cheese", "... on Boolean"],
39
+ "extensions"=>{"code"=>"fragmentOnNonCompositeType", "typeName"=>"Boolean"}
39
40
  },
40
41
  {
41
42
  "message"=>"Invalid fragment on type DairyProductInput (must be Union, Interface or Object)",
42
43
  "locations"=>[{"line"=>16, "column"=>9}],
43
- "fields"=>["query getCheese", "cheese", "... on DairyProductInput"],
44
+ "path"=>["query getCheese", "cheese", "... on DairyProductInput"],
45
+ "extensions"=>{"code"=>"fragmentOnNonCompositeType", "typeName"=>"DairyProductInput"}
44
46
  },
45
47
  {
46
48
  "message"=>"Invalid fragment on type Int (must be Union, Interface or Object)",
47
49
  "locations"=>[{"line"=>22, "column"=>5}],
48
- "fields"=>["fragment intFields"],
50
+ "path"=>["fragment intFields"],
51
+ "extensions"=>{"code"=>"fragmentOnNonCompositeType", "typeName"=>"Int"}
49
52
  },
50
53
  ]
51
54
  assert_equal(expected, errors)
@@ -17,7 +17,8 @@ describe GraphQL::StaticValidation::FragmentsAreUsed do
17
17
  assert_includes(errors, {
18
18
  "message"=>"Fragment unusedFields was defined, but not used",
19
19
  "locations"=>[{"line"=>8, "column"=>5}],
20
- "fields"=>["fragment unusedFields"],
20
+ "path"=>["fragment unusedFields"],
21
+ "extensions"=>{"code"=>"useAndDefineFragment", "fragmentName"=>"unusedFields"}
21
22
  })
22
23
  end
23
24
 
@@ -25,7 +26,8 @@ describe GraphQL::StaticValidation::FragmentsAreUsed do
25
26
  assert_includes(errors, {
26
27
  "message"=>"Fragment undefinedFields was used, but not defined",
27
28
  "locations"=>[{"line"=>5, "column"=>7}],
28
- "fields"=>["query getCheese", "... undefinedFields"]
29
+ "path"=>["query getCheese", "... undefinedFields"],
30
+ "extensions"=>{"code"=>"useAndDefineFragment", "fragmentName"=>"undefinedFields"}
29
31
  })
30
32
  end
31
33
 
@@ -38,4 +40,22 @@ describe GraphQL::StaticValidation::FragmentsAreUsed do
38
40
  assert_equal({}, result)
39
41
  end
40
42
  end
43
+
44
+ describe "invalid unused fragments" do
45
+ let(:query_string) {"
46
+ query getCheese {
47
+ name
48
+ }
49
+ fragment Invalid on DoesNotExist { fatContent }
50
+ "}
51
+
52
+ it "handles them gracefully" do
53
+ assert_includes(errors, {
54
+ "message"=>"No such type DoesNotExist, so it can't be a fragment condition",
55
+ "locations"=>[{"line"=>5, "column"=>7}],
56
+ "path"=>["fragment Invalid"],
57
+ "extensions"=>{"code"=>"undefinedType", "typeName"=>"DoesNotExist"}
58
+ })
59
+ end
60
+ end
41
61
  end
@@ -31,7 +31,8 @@ describe GraphQL::StaticValidation::MutationRootExists do
31
31
  missing_mutation_root_error = {
32
32
  "message"=>"Schema is not configured for mutations",
33
33
  "locations"=>[{"line"=>2, "column"=>5}],
34
- "fields"=>["mutation addBagel"],
34
+ "path"=>["mutation addBagel"],
35
+ "extensions"=>{"code"=>"missingMutationConfiguration"}
35
36
  }
36
37
  assert_includes(errors, missing_mutation_root_error)
37
38
  end
@@ -25,7 +25,8 @@ describe GraphQL::StaticValidation::OperationNamesAreValid do
25
25
  requires_name_error = {
26
26
  "message"=>"Operation name is required when multiple operations are present",
27
27
  "locations"=>[{"line"=>5, "column"=>5}, {"line"=>9, "column"=>5}],
28
- "fields"=>[],
28
+ "path"=>[],
29
+ "extensions"=>{"code"=>"uniquelyNamedOperations"}
29
30
  }
30
31
  assert_includes(errors, requires_name_error)
31
32
  end
@@ -48,7 +49,8 @@ describe GraphQL::StaticValidation::OperationNamesAreValid do
48
49
  requires_name_error = {
49
50
  "message"=>"Operation name is required when multiple operations are present",
50
51
  "locations"=>[{"line"=>1, "column"=>5}, {"line"=>5, "column"=>5}],
51
- "fields"=>[],
52
+ "path"=>[],
53
+ "extensions"=>{"code"=>"uniquelyNamedOperations"}
52
54
  }
53
55
  assert_includes(errors, requires_name_error)
54
56
  end
@@ -71,7 +73,8 @@ describe GraphQL::StaticValidation::OperationNamesAreValid do
71
73
  name_uniqueness_error = {
72
74
  "message"=>'Operation name "getCheese" must be unique',
73
75
  "locations"=>[{"line"=>1, "column"=>5}, {"line"=>5, "column"=>5}],
74
- "fields"=>[],
76
+ "path"=>[],
77
+ "extensions"=>{"code"=>"uniquelyNamedOperations", "operationName"=>"getCheese"}
75
78
  }
76
79
  assert_includes(errors, name_uniqueness_error)
77
80
  end
@@ -22,21 +22,24 @@ describe GraphQL::StaticValidation::RequiredArgumentsArePresent do
22
22
  query_root_error = {
23
23
  "message"=>"Field 'cheese' is missing required arguments: id",
24
24
  "locations"=>[{"line"=>4, "column"=>7}],
25
- "fields"=>["query getCheese", "cheese"],
25
+ "path"=>["query getCheese", "cheese"],
26
+ "extensions"=>{"code"=>"missingRequiredArguments", "className"=>"Field", "name"=>"cheese", "arguments"=>"id"}
26
27
  }
27
28
  assert_includes(errors, query_root_error)
28
29
 
29
30
  fragment_error = {
30
31
  "message"=>"Field 'similarCheese' is missing required arguments: source",
31
32
  "locations"=>[{"line"=>8, "column"=>7}],
32
- "fields"=>["fragment cheeseFields", "similarCheese"],
33
+ "path"=>["fragment cheeseFields", "similarCheese"],
34
+ "extensions"=>{"code"=>"missingRequiredArguments", "className"=>"Field", "name"=>"similarCheese", "arguments"=>"source"}
33
35
  }
34
36
  assert_includes(errors, fragment_error)
35
37
 
36
38
  directive_error = {
37
39
  "message"=>"Directive 'skip' is missing required arguments: if",
38
40
  "locations"=>[{"line"=>10, "column"=>10}],
39
- "fields"=>["fragment cheeseFields", "id"],
41
+ "path"=>["fragment cheeseFields", "id"],
42
+ "extensions"=>{"code"=>"missingRequiredArguments", "className"=>"Directive", "name"=>"skip", "arguments"=>"if"}
40
43
  }
41
44
  assert_includes(errors, directive_error)
42
45
  end
@@ -55,7 +58,13 @@ describe GraphQL::StaticValidation::RequiredArgumentsArePresent do
55
58
  "locations"=>[
56
59
  {"line"=>3, "column"=>9}
57
60
  ],
58
- "fields"=>["query", "__type"],
61
+ "path"=>["query", "__type"],
62
+ "extensions"=>{
63
+ "code"=>"missingRequiredArguments",
64
+ "className"=>"Field",
65
+ "name"=>"__type",
66
+ "arguments"=>"name"
67
+ }
59
68
  }
60
69
  ]
61
70
  assert_equal(expected_errors, errors)
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+ require "spec_helper"
3
+
4
+ describe GraphQL::StaticValidation::RequiredInputObjectAttributesArePresent do
5
+ include StaticValidationHelpers
6
+ include ErrorBubblingHelpers
7
+
8
+ let(:query_string) {%|
9
+ query getCheese {
10
+ stringCheese: cheese(id: "aasdlkfj") { ...cheeseFields }
11
+ cheese(id: 1) { source @skip(if: "whatever") }
12
+ yakSource: searchDairy(product: [{source: COW, fatContent: 1.1}]) { __typename }
13
+ badSource: searchDairy(product: [{source: 1.1}]) { __typename }
14
+ missingSource: searchDairy(product: [{fatContent: 1.1}]) { __typename }
15
+ listCoerce: cheese(id: 1) { similarCheese(source: YAK) { __typename } }
16
+ missingInputField: searchDairy(product: [{source: YAK, wacky: 1}]) { __typename }
17
+ }
18
+
19
+ fragment cheeseFields on Cheese {
20
+ similarCheese(source: 4.5) { __typename }
21
+ }
22
+ |}
23
+ describe "with error bubbling disabled" do
24
+ missing_required_field_error = {
25
+ "message"=>"Argument 'product' on Field 'missingSource' has an invalid value. Expected type '[DairyProductInput]'.",
26
+ "locations"=>[{"line"=>7, "column"=>7}],
27
+ "path"=>["query getCheese", "missingSource", "product"],
28
+ "extensions"=>{
29
+ "code"=>"argumentLiteralsIncompatible",
30
+ "typeName"=>"Field",
31
+ "argumentName"=>"product",
32
+ },
33
+ }
34
+ missing_source_error = {
35
+ "message"=>"Argument 'source' on InputObject 'DairyProductInput' is required. Expected type DairyAnimal!",
36
+ "locations"=>[{"line"=>7, "column"=>44}],
37
+ "path"=>["query getCheese", "missingSource", "product", "source"],
38
+ "extensions"=>{
39
+ "code"=>"missingRequiredInputObjectAttribute",
40
+ "argumentName"=>"source",
41
+ "argumentType"=>"DairyAnimal!",
42
+ "inputObjectType"=>"DairyProductInput"
43
+ }
44
+ }
45
+ it "finds undefined or missing-required arguments to fields and directives" do
46
+ without_error_bubbling(schema) do
47
+ assert_includes(errors, missing_source_error)
48
+ refute_includes(errors, missing_required_field_error)
49
+ end
50
+ end
51
+ it 'works with error bubbling enabled' do
52
+ with_error_bubbling(schema) do
53
+ assert_includes(errors, missing_required_field_error)
54
+ assert_includes(errors, missing_source_error)
55
+ end
56
+ end
57
+ end
58
+ end
@@ -26,7 +26,8 @@ describe GraphQL::StaticValidation::SubscriptionRootExists do
26
26
  missing_subscription_root_error = {
27
27
  "message"=>"Schema is not configured for subscriptions",
28
28
  "locations"=>[{"line"=>2, "column"=>5}],
29
- "fields"=>["subscription"],
29
+ "path"=>["subscription"],
30
+ "extensions"=>{"code"=>"missingSubscriptionConfiguration"}
30
31
  }
31
32
  assert_includes(errors, missing_subscription_root_error)
32
33
  end
@@ -101,7 +101,8 @@ describe GraphQL::StaticValidation::UniqueDirectivesPerLocation do
101
101
  assert_includes errors, {
102
102
  "message" => 'The directive "A" can only be used once at this location.',
103
103
  "locations" => [{ "line" => 4, "column" => 17 }, { "line" => 4, "column" => 20 }],
104
- "fields" => ["query", "type", "field"],
104
+ "path" => ["query", "type", "field"],
105
+ "extensions" => {"code"=>"directiveNotUniqueForLocation", "directiveName"=>"A"}
105
106
  }
106
107
  end
107
108
  end
@@ -120,13 +121,15 @@ describe GraphQL::StaticValidation::UniqueDirectivesPerLocation do
120
121
  assert_includes errors, {
121
122
  "message" => 'The directive "A" can only be used once at this location.',
122
123
  "locations" => [{ "line" => 4, "column" => 17 }, { "line" => 4, "column" => 20 }],
123
- "fields" => ["query", "type", "field"],
124
+ "path" => ["query", "type", "field"],
125
+ "extensions" => {"code"=>"directiveNotUniqueForLocation", "directiveName"=>"A"}
124
126
  }
125
127
 
126
128
  assert_includes errors, {
127
129
  "message" => 'The directive "A" can only be used once at this location.',
128
130
  "locations" => [{ "line" => 4, "column" => 17 }, { "line" => 4, "column" => 23 }],
129
- "fields" => ["query", "type", "field"],
131
+ "path" => ["query", "type", "field"],
132
+ "extensions" => {"code"=>"directiveNotUniqueForLocation", "directiveName"=>"A"}
130
133
  }
131
134
  end
132
135
  end
@@ -144,13 +147,15 @@ describe GraphQL::StaticValidation::UniqueDirectivesPerLocation do
144
147
  assert_includes errors, {
145
148
  "message" => 'The directive "A" can only be used once at this location.',
146
149
  "locations" => [{ "line" => 4, "column" => 17 }, { "line" => 4, "column" => 23 }],
147
- "fields" => ["query", "type", "field"],
150
+ "path" => ["query", "type", "field"],
151
+ "extensions" => {"code"=>"directiveNotUniqueForLocation", "directiveName"=>"A"}
148
152
  }
149
153
 
150
154
  assert_includes errors, {
151
155
  "message" => 'The directive "B" can only be used once at this location.',
152
156
  "locations" => [{ "line" => 4, "column" => 20 }, { "line" => 4, "column" => 26 }],
153
- "fields" => ["query", "type", "field"],
157
+ "path" => ["query", "type", "field"],
158
+ "extensions" => {"code"=>"directiveNotUniqueForLocation", "directiveName"=>"B"}
154
159
  }
155
160
  end
156
161
  end
@@ -168,13 +173,15 @@ describe GraphQL::StaticValidation::UniqueDirectivesPerLocation do
168
173
  assert_includes errors, {
169
174
  "message" => 'The directive "A" can only be used once at this location.',
170
175
  "locations" => [{ "line" => 3, "column" => 14 }, { "line" => 3, "column" => 17 }],
171
- "fields" => ["query", "type"],
176
+ "path" => ["query", "type"],
177
+ "extensions" => {"code"=>"directiveNotUniqueForLocation", "directiveName"=>"A"}
172
178
  }
173
179
 
174
180
  assert_includes errors, {
175
181
  "message" => 'The directive "A" can only be used once at this location.',
176
182
  "locations" => [{ "line" => 4, "column" => 17 }, { "line" => 4, "column" => 20 }],
177
- "fields" => ["query", "type", "field"],
183
+ "path" => ["query", "type", "field"],
184
+ "extensions" => {"code"=>"directiveNotUniqueForLocation", "directiveName"=>"A"}
178
185
  }
179
186
  end
180
187
  end