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
@@ -3,13 +3,14 @@ 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 {
9
10
  stringCheese: cheese(id: "aasdlkfj") { ...cheeseFields }
10
11
  cheese(id: 1) { source @skip(if: "whatever") }
11
12
  yakSource: searchDairy(product: [{source: COW, fatContent: 1.1}]) { __typename }
12
- badSource: searchDairy(product: [{source: 1.1}]) { __typename }
13
+ badSource: searchDairy(product: {source: 1.1}) { __typename }
13
14
  missingSource: searchDairy(product: [{fatContent: 1.1}]) { __typename }
14
15
  listCoerce: cheese(id: 1) { similarCheese(source: YAK) { __typename } }
15
16
  missingInputField: searchDairy(product: [{source: YAK, wacky: 1}]) { __typename }
@@ -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"=>39}],
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"=>39}],
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
@@ -19,7 +19,7 @@ describe GraphQL::StaticValidation::ArgumentNamesAreUnique do
19
19
  error = errors.first
20
20
  assert_equal 'There can be only one argument named "id"', error["message"]
21
21
  assert_equal [{ "line" => 2, "column" => 18}, { "line" => 2, "column" => 25 }], error["locations"]
22
- assert_equal ["query GetStuff", "c1"], error["fields"]
22
+ assert_equal ["query GetStuff", "c1"], error["path"]
23
23
  end
24
24
  end
25
25
 
@@ -38,7 +38,7 @@ describe GraphQL::StaticValidation::ArgumentNamesAreUnique do
38
38
  error = errors.first
39
39
  assert_equal 'There can be only one argument named "if"', error["message"]
40
40
  assert_equal [{ "line" => 2, "column" => 34}, { "line" => 2, "column" => 44 }], error["locations"]
41
- assert_equal ["query GetStuff", "c1"], error["fields"]
41
+ assert_equal ["query GetStuff", "c1"], error["path"]
42
42
  end
43
43
  end
44
44
  end
@@ -3,6 +3,7 @@ require "spec_helper"
3
3
 
4
4
  describe GraphQL::StaticValidation::ArgumentsAreDefined do
5
5
  include StaticValidationHelpers
6
+ include ErrorBubblingHelpers
6
7
 
7
8
  let(:query_string) {"
8
9
  query getCheese {
@@ -17,38 +18,79 @@ describe GraphQL::StaticValidation::ArgumentsAreDefined do
17
18
  }
18
19
  "}
19
20
 
20
- it "finds undefined arguments to fields and directives" do
21
- # There's an extra error here, the unexpected argument on "DairyProductInput"
22
- # triggers _another_ error that the field expected a different type
23
- assert_equal(5, errors.length)
21
+ describe "finds undefined arguments to fields and directives" do
22
+ it "works with error bubbling" do
23
+ with_error_bubbling(Dummy::Schema) do
24
+ # There's an extra error here, the unexpected argument on "DairyProductInput"
25
+ # triggers _another_ error that the field expected a different type
26
+ assert_equal(6, errors.length)
24
27
 
25
- query_root_error = {
26
- "message"=>"Field 'cheese' doesn't accept argument 'silly'",
27
- "locations"=>[{"line"=>4, "column"=>14}],
28
- "fields"=>["query getCheese", "cheese", "silly"],
29
- }
30
- assert_includes(errors, query_root_error)
28
+ query_root_error = {
29
+ "message"=>"Field 'cheese' doesn't accept argument 'silly'",
30
+ "locations"=>[{"line"=>4, "column"=>14}],
31
+ "path"=>["query getCheese", "cheese", "silly"],
32
+ "extensions"=>{
33
+ "code"=>"argumentNotAccepted",
34
+ "name"=>"cheese",
35
+ "typeName"=>"Field",
36
+ "argumentName"=>"silly"
37
+ },
38
+ }
39
+ assert_includes(errors, query_root_error)
31
40
 
32
- input_obj_record = {
33
- "message"=>"InputObject 'DairyProductInput' doesn't accept argument 'wacky'",
34
- "locations"=>[{"line"=>5, "column"=>30}],
35
- "fields"=>["query getCheese", "searchDairy", "product", "wacky"],
36
- }
37
- assert_includes(errors, input_obj_record)
41
+ input_obj_record = {
42
+ "message"=>"InputObject 'DairyProductInput' doesn't accept argument 'wacky'",
43
+ "locations"=>[{"line"=>5, "column"=>30}],
44
+ "path"=>["query getCheese", "searchDairy", "product", "wacky"],
45
+ "extensions"=>{
46
+ "code"=>"argumentNotAccepted",
47
+ "name"=>"DairyProductInput",
48
+ "typeName"=>"InputObject",
49
+ "argumentName"=>"wacky"
50
+ },
51
+ }
52
+ assert_includes(errors, input_obj_record)
38
53
 
39
- fragment_error = {
40
- "message"=>"Field 'similarCheese' doesn't accept argument 'nonsense'",
41
- "locations"=>[{"line"=>9, "column"=>36}],
42
- "fields"=>["fragment cheeseFields", "similarCheese", "nonsense"],
43
- }
44
- assert_includes(errors, fragment_error)
54
+ fragment_error = {
55
+ "message"=>"Field 'similarCheese' doesn't accept argument 'nonsense'",
56
+ "locations"=>[{"line"=>9, "column"=>36}],
57
+ "path"=>["fragment cheeseFields", "similarCheese", "nonsense"],
58
+ "extensions"=>{
59
+ "code"=>"argumentNotAccepted",
60
+ "name"=>"similarCheese",
61
+ "typeName"=>"Field",
62
+ "argumentName"=>"nonsense",
63
+ },
64
+ }
65
+ assert_includes(errors, fragment_error)
45
66
 
46
- directive_error = {
47
- "message"=>"Directive 'skip' doesn't accept argument 'something'",
48
- "locations"=>[{"line"=>10, "column"=>16}],
49
- "fields"=>["fragment cheeseFields", "id", "something"],
50
- }
51
- assert_includes(errors, directive_error)
67
+ directive_error = {
68
+ "message"=>"Directive 'skip' doesn't accept argument 'something'",
69
+ "locations"=>[{"line"=>10, "column"=>16}],
70
+ "path"=>["fragment cheeseFields", "id", "something"],
71
+ "extensions"=>{
72
+ "code"=>"argumentNotAccepted",
73
+ "name"=>"skip",
74
+ "typeName"=>"Directive",
75
+ "argumentName"=>"something",
76
+ },
77
+ }
78
+ assert_includes(errors, directive_error)
79
+ end
80
+ end
81
+
82
+ it "works without error bubbling" do
83
+ without_error_bubbling(Dummy::Schema) do
84
+ assert_equal(5, errors.length)
85
+
86
+ extra_error = {
87
+ "message"=>"Argument 'product' on Field 'searchDairy' has an invalid value. Expected type '[DairyProductInput]'.",
88
+ "locations"=>[{"line"=>5, "column"=>7}],
89
+ "path"=>["query getCheese", "searchDairy", "product"]
90
+ }
91
+ refute_includes(errors, extra_error)
92
+ end
93
+ end
52
94
  end
53
95
 
54
96
  describe "dynamic fields" do
@@ -62,7 +104,8 @@ describe GraphQL::StaticValidation::ArgumentsAreDefined do
62
104
  assert_includes(errors, {
63
105
  "message"=>"Field '__type' doesn't accept argument 'somethingInvalid'",
64
106
  "locations"=>[{"line"=>3, "column"=>16}],
65
- "fields"=>["query", "__type", "somethingInvalid"],
107
+ "path"=>["query", "__type", "somethingInvalid"],
108
+ "extensions"=>{"code"=>"argumentNotAccepted", "name"=>"__type", "typeName"=>"Field", "argumentName"=>"somethingInvalid"}
66
109
  })
67
110
  end
68
111
  end
@@ -20,11 +20,13 @@ describe GraphQL::StaticValidation::DirectivesAreDefined do
20
20
  {
21
21
  "message"=>"Directive @nonsense is not defined",
22
22
  "locations"=>[{"line"=>5, "column"=>16}],
23
- "fields"=>["query getCheese", "okCheese", "source"],
23
+ "path"=>["query getCheese", "okCheese", "source"],
24
+ "extensions"=>{"code"=>"undefinedDirective", "directiveName"=>"nonsense"}
24
25
  }, {
25
26
  "message"=>"Directive @moreNonsense is not defined",
26
27
  "locations"=>[{"line"=>7, "column"=>18}],
27
- "fields"=>["query getCheese", "okCheese", "... on Cheese", "flavor"],
28
+ "path"=>["query getCheese", "okCheese", "... on Cheese", "flavor"],
29
+ "extensions"=>{"code"=>"undefinedDirective", "directiveName"=>"moreNonsense"}
28
30
  }
29
31
  ]
30
32
  assert_equal(expected, errors)
@@ -26,12 +26,14 @@ describe GraphQL::StaticValidation::DirectivesAreInValidLocations do
26
26
  {
27
27
  "message"=> "'@skip' can't be applied to queries (allowed: fields, fragment spreads, inline fragments)",
28
28
  "locations"=>[{"line"=>2, "column"=>21}],
29
- "fields"=>["query getCheese"],
29
+ "path"=>["query getCheese"],
30
+ "extensions"=>{"code"=>"directiveCannotBeApplied", "targetName"=>"queries", "name"=>"skip"}
30
31
  },
31
32
  {
32
33
  "message"=>"'@skip' can't be applied to fragment definitions (allowed: fields, fragment spreads, inline fragments)",
33
34
  "locations"=>[{"line"=>13, "column"=>33}],
34
- "fields"=>["fragment whatever"],
35
+ "path"=>["fragment whatever"],
36
+ "extensions"=>{"code"=>"directiveCannotBeApplied", "targetName"=>"fragment definitions", "name"=>"skip"}
35
37
  },
36
38
  ]
37
39
  assert_equal(expected, errors)
@@ -31,7 +31,8 @@ describe GraphQL::StaticValidation::FieldsAreDefinedOnType do
31
31
  {
32
32
  "message"=>"Field 'notDefinedField' doesn't exist on type 'Query'",
33
33
  "locations"=>[{"line"=>1, "column"=>18}],
34
- "fields"=>["query getStuff", "notDefinedField"],
34
+ "path"=>["query getStuff", "notDefinedField"],
35
+ "extensions"=>{"code"=>"undefinedField", "typeName"=>"Query", "fieldName"=>"notDefinedField"}
35
36
  }
36
37
  ]
37
38
  assert_equal(expected_errors, errors)
@@ -46,7 +47,8 @@ describe GraphQL::StaticValidation::FieldsAreDefinedOnType do
46
47
  {
47
48
  "message"=>"Field 'amountThatILikeIt' doesn't exist on type 'Edible'",
48
49
  "locations"=>[{"line"=>1, "column"=>35}],
49
- "fields"=>["query getStuff", "favoriteEdible", "amountThatILikeIt"],
50
+ "path"=>["query getStuff", "favoriteEdible", "amountThatILikeIt"],
51
+ "extensions"=>{"code"=>"undefinedField", "typeName"=>"Edible", "fieldName"=>"amountThatILikeIt"}
50
52
  }
51
53
  ]
52
54
  assert_equal(expected_errors, errors)
@@ -67,7 +69,8 @@ describe GraphQL::StaticValidation::FieldsAreDefinedOnType do
67
69
  "locations"=>[
68
70
  {"line"=>3, "column"=>7}
69
71
  ],
70
- "fields"=>["fragment dpFields", "source"],
72
+ "path"=>["fragment dpFields", "source"],
73
+ "extensions"=>{"code"=>"selectionMismatch", "nodeName"=>"DairyProduct"}
71
74
  }
72
75
  ]
73
76
  assert_equal(expected_errors, errors)
@@ -120,7 +123,8 @@ describe GraphQL::StaticValidation::FieldsAreDefinedOnType do
120
123
  "locations"=>[
121
124
  {"line"=>2, "column"=>33}
122
125
  ],
123
- "fields"=>["query", "cheese", "__schema"],
126
+ "path"=>["query", "cheese", "__schema"],
127
+ "extensions"=>{"code"=>"undefinedField", "typeName"=>"Cheese", "fieldName"=>"__schema"}
124
128
  }
125
129
  ]
126
130
  assert_equal(expected_errors, errors)
@@ -151,7 +155,8 @@ describe GraphQL::StaticValidation::FieldsAreDefinedOnType do
151
155
  "locations"=>[
152
156
  {"line"=>2, "column"=>33}
153
157
  ],
154
- "fields"=>["query", "cheese", "__type"],
158
+ "path"=>["query", "cheese", "__type"],
159
+ "extensions"=>{"code"=>"undefinedField", "typeName"=>"Cheese", "fieldName"=>"__type"}
155
160
  }
156
161
  ]
157
162
  assert_equal(expected_errors, errors)