graphql 1.7.6 → 1.8.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 (289) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/function_generator.rb +1 -1
  3. data/lib/generators/graphql/install_generator.rb +14 -8
  4. data/lib/generators/graphql/loader_generator.rb +1 -1
  5. data/lib/generators/graphql/mutation_generator.rb +6 -1
  6. data/lib/generators/graphql/templates/function.erb +2 -2
  7. data/lib/generators/graphql/templates/loader.erb +2 -2
  8. data/lib/generators/graphql/templates/schema.erb +1 -1
  9. data/lib/graphql/argument.rb +25 -19
  10. data/lib/graphql/backtrace/tracer.rb +16 -22
  11. data/lib/graphql/backtrace.rb +1 -1
  12. data/lib/graphql/backwards_compatibility.rb +2 -3
  13. data/lib/graphql/base_type.rb +31 -31
  14. data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +14 -0
  15. data/lib/graphql/compatibility/query_parser_specification.rb +117 -0
  16. data/lib/graphql/define/assign_object_field.rb +5 -12
  17. data/lib/graphql/deprecated_dsl.rb +42 -0
  18. data/lib/graphql/directive.rb +1 -0
  19. data/lib/graphql/enum_type.rb +3 -1
  20. data/lib/graphql/execution/execute.rb +21 -13
  21. data/lib/graphql/execution/instrumentation.rb +82 -0
  22. data/lib/graphql/execution/lazy/lazy_method_map.rb +1 -1
  23. data/lib/graphql/execution/lazy/resolve.rb +1 -3
  24. data/lib/graphql/execution/multiplex.rb +12 -29
  25. data/lib/graphql/execution.rb +1 -0
  26. data/lib/graphql/field.rb +21 -4
  27. data/lib/graphql/function.rb +14 -0
  28. data/lib/graphql/input_object_type.rb +3 -1
  29. data/lib/graphql/interface_type.rb +5 -3
  30. data/lib/graphql/internal_representation/node.rb +26 -14
  31. data/lib/graphql/internal_representation/visit.rb +3 -6
  32. data/lib/graphql/introspection/base_object.rb +16 -0
  33. data/lib/graphql/introspection/directive_location_enum.rb +11 -7
  34. data/lib/graphql/introspection/directive_type.rb +23 -16
  35. data/lib/graphql/introspection/dynamic_fields.rb +11 -0
  36. data/lib/graphql/introspection/entry_points.rb +29 -0
  37. data/lib/graphql/introspection/enum_value_type.rb +16 -11
  38. data/lib/graphql/introspection/field_type.rb +21 -12
  39. data/lib/graphql/introspection/input_value_type.rb +26 -23
  40. data/lib/graphql/introspection/schema_field.rb +7 -2
  41. data/lib/graphql/introspection/schema_type.rb +36 -22
  42. data/lib/graphql/introspection/type_by_name_field.rb +10 -2
  43. data/lib/graphql/introspection/type_kind_enum.rb +10 -6
  44. data/lib/graphql/introspection/type_type.rb +85 -23
  45. data/lib/graphql/introspection/typename_field.rb +1 -0
  46. data/lib/graphql/introspection.rb +3 -10
  47. data/lib/graphql/language/block_string.rb +47 -0
  48. data/lib/graphql/language/document_from_schema_definition.rb +280 -0
  49. data/lib/graphql/language/generation.rb +3 -182
  50. data/lib/graphql/language/lexer.rb +144 -69
  51. data/lib/graphql/language/lexer.rl +15 -4
  52. data/lib/graphql/language/nodes.rb +141 -78
  53. data/lib/graphql/language/parser.rb +677 -630
  54. data/lib/graphql/language/parser.y +18 -12
  55. data/lib/graphql/language/printer.rb +361 -0
  56. data/lib/graphql/language/token.rb +10 -3
  57. data/lib/graphql/language.rb +3 -0
  58. data/lib/graphql/non_null_type.rb +1 -1
  59. data/lib/graphql/object_type.rb +1 -6
  60. data/lib/graphql/query/arguments.rb +63 -32
  61. data/lib/graphql/query/context.rb +32 -2
  62. data/lib/graphql/query/literal_input.rb +4 -1
  63. data/lib/graphql/query/null_context.rb +1 -1
  64. data/lib/graphql/query/result.rb +1 -1
  65. data/lib/graphql/query/variables.rb +21 -3
  66. data/lib/graphql/query.rb +19 -6
  67. data/lib/graphql/railtie.rb +109 -0
  68. data/lib/graphql/relay/connection_resolve.rb +3 -0
  69. data/lib/graphql/relay/connection_type.rb +5 -3
  70. data/lib/graphql/relay/edge_type.rb +2 -1
  71. data/lib/graphql/relay/global_id_resolve.rb +5 -1
  72. data/lib/graphql/relay/mongo_relation_connection.rb +40 -0
  73. data/lib/graphql/relay/mutation/instrumentation.rb +1 -1
  74. data/lib/graphql/relay/mutation/resolve.rb +5 -1
  75. data/lib/graphql/relay/relation_connection.rb +14 -19
  76. data/lib/graphql/relay/type_extensions.rb +30 -0
  77. data/lib/graphql/relay.rb +2 -0
  78. data/lib/graphql/scalar_type.rb +14 -2
  79. data/lib/graphql/schema/argument.rb +92 -0
  80. data/lib/graphql/schema/build_from_definition.rb +64 -18
  81. data/lib/graphql/schema/enum.rb +85 -0
  82. data/lib/graphql/schema/enum_value.rb +74 -0
  83. data/lib/graphql/schema/field.rb +372 -0
  84. data/lib/graphql/schema/finder.rb +153 -0
  85. data/lib/graphql/schema/input_object.rb +87 -0
  86. data/lib/graphql/schema/interface.rb +105 -0
  87. data/lib/graphql/schema/introspection_system.rb +93 -0
  88. data/lib/graphql/schema/late_bound_type.rb +32 -0
  89. data/lib/graphql/schema/list.rb +32 -0
  90. data/lib/graphql/schema/loader.rb +2 -2
  91. data/lib/graphql/schema/member/accepts_definition.rb +152 -0
  92. data/lib/graphql/schema/member/base_dsl_methods.rb +100 -0
  93. data/lib/graphql/schema/member/build_type.rb +137 -0
  94. data/lib/graphql/schema/member/cached_graphql_definition.rb +26 -0
  95. data/lib/graphql/schema/member/graphql_type_names.rb +21 -0
  96. data/lib/graphql/schema/member/has_arguments.rb +50 -0
  97. data/lib/graphql/schema/member/has_fields.rb +130 -0
  98. data/lib/graphql/schema/member/instrumentation.rb +115 -0
  99. data/lib/graphql/schema/member/type_system_helpers.rb +34 -0
  100. data/lib/graphql/schema/member.rb +28 -0
  101. data/lib/graphql/schema/middleware_chain.rb +5 -1
  102. data/lib/graphql/schema/mutation.rb +138 -0
  103. data/lib/graphql/schema/non_null.rb +38 -0
  104. data/lib/graphql/schema/object.rb +81 -0
  105. data/lib/graphql/schema/printer.rb +33 -266
  106. data/lib/graphql/schema/relay_classic_mutation.rb +87 -0
  107. data/lib/graphql/schema/rescue_middleware.rb +8 -7
  108. data/lib/graphql/schema/resolver.rb +122 -0
  109. data/lib/graphql/schema/scalar.rb +35 -0
  110. data/lib/graphql/schema/traversal.rb +102 -22
  111. data/lib/graphql/schema/union.rb +36 -0
  112. data/lib/graphql/schema/validation.rb +3 -2
  113. data/lib/graphql/schema.rb +381 -12
  114. data/lib/graphql/static_validation/definition_dependencies.rb +1 -1
  115. data/lib/graphql/static_validation/literal_validator.rb +16 -4
  116. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +6 -6
  117. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +5 -1
  118. data/lib/graphql/static_validation/rules/fields_will_merge.rb +15 -8
  119. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +11 -1
  120. data/lib/graphql/static_validation/validation_context.rb +1 -1
  121. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +7 -5
  122. data/lib/graphql/subscriptions/instrumentation.rb +5 -1
  123. data/lib/graphql/subscriptions/serialize.rb +2 -0
  124. data/lib/graphql/subscriptions.rb +90 -16
  125. data/lib/graphql/tracing/data_dog_tracing.rb +49 -0
  126. data/lib/graphql/tracing/new_relic_tracing.rb +26 -0
  127. data/lib/graphql/tracing/platform_tracing.rb +20 -7
  128. data/lib/graphql/tracing/scout_tracing.rb +2 -2
  129. data/lib/graphql/tracing.rb +1 -0
  130. data/lib/graphql/unresolved_type_error.rb +3 -2
  131. data/lib/graphql/upgrader/member.rb +894 -0
  132. data/lib/graphql/upgrader/schema.rb +37 -0
  133. data/lib/graphql/version.rb +1 -1
  134. data/lib/graphql.rb +5 -25
  135. data/readme.md +2 -2
  136. data/spec/dummy/app/channels/graphql_channel.rb +23 -2
  137. data/spec/dummy/log/development.log +239 -0
  138. data/spec/dummy/log/test.log +410 -0
  139. data/spec/dummy/test/system/action_cable_subscription_test.rb +4 -0
  140. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/-x/-xYZjAnuuzgR79fcznLTQtSdh6AARxu8FcQ_J6p7L3U.cache +0 -0
  141. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/13/13HiV12xyoQvT-1L39ZzLwMZxjyaGMiENmfw7f-QTIc.cache +0 -0
  142. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/3W/3Wtf5pCWdqq0AB-iB0Y9uUNrTkruRxIEf1XFn_BETU0.cache +1 -0
  143. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/5i/5iguGafb4hOn8262Kn8Q37ogNN9MxxQKGKNzHAzUcvI.cache +1 -0
  144. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/8m/8mj2T6yy847Mc2Z7k3Xzh8O91hhVJt3NrPe8ASNDlIA.cache +1 -0
  145. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/DT/DTQyMpr4ABZYQetsdRJ5A7S4jf1r3ie4FGOR7GZBNSs.cache +3 -0
  146. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Dq/DqJ5_yJPrP5iLlOQyTQsjAVI5FE5LCVDkED0f7GgsSo.cache +3 -0
  147. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/F8/F8MUNRzORGFgr329fNM0xLaoWCXdv3BIalT7dsvLfjs.cache +0 -0
  148. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/KB/KB07ZaKNC5uXJ7TjLi-WqnY6g7dq8wWp_8N3HNjBNxg.cache +0 -0
  149. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Rw/RwDuCV-XpnCtjNkvhpJfBuxXMk0b5AD3L9eR6M-wcy0.cache +3 -0
  150. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/UL/ULdjhhb0bRuqmaG7XSZlFYzGYCXTDnqZuJBTWRlzqgw.cache +0 -0
  151. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Up/UpPNgh0yYoUsyMDh5zWqe_U6qJIyTC6-dxMMAs1vvlM.cache +1 -0
  152. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Wg/Wguh-szFGTI1gaL6npYwPekMXflugRei7F_mOyRucXg.cache +0 -0
  153. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/X-/X-khLYMA9mqFRPg3zAi86mREDxpKl4bdKYp3uF6WHos.cache +0 -0
  154. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/bi/BIkdhfxsezxM4q-HZ4oCNTq97WEJTigcq0tpX2cDvbY.cache +0 -0
  155. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/ff/FfxmA4CMHQZT7exx0G7NS1Wpcnny0vzp-Jhc2H36bp8.cache +1 -0
  156. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/gE/gEiiG4GZNy_djEjK2pHm_NgA-gyhLZhdQvo0Yt96GqE.cache +0 -0
  157. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/gn/gnA9ZSqpjccNL2m8pe_jBvY6SinXlCzXDWyop83Od8s.cache +1 -0
  158. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/lO/lOAan3cMwCE_Hli6gsDML88xFNfn0nxPmvrSkW7eEOw.cache +1 -0
  159. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/m1/M1pv8MJEPLXGLvS8QxVh3DSO9cI4mRt5FHFWdrvUj6o.cache +2 -0
  160. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/m7/m77qH7ZqH0_0SmwJbiKGDd-aLau1Dav847DC6ge46zY.cache +1 -0
  161. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/sj/sjRjnjRB37lH2vrgtkdJ8Cz84__IJ978IuKTM7HcztI.cache +0 -0
  162. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/um/um1JrirR4hJhK-1rE-HywlyCi5ibgxHVrReiujZBWJM.cache +1 -0
  163. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/v4/v4fwVytD7ITcE0_GDbslZEYud8a5Okm85fV1o7SDl6g.cache +0 -0
  164. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/v_/v_0PAQt0iipQjFP5zjgkkk9Stnpf4VzvnMv67d1Keuw.cache +1 -0
  165. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/wd/wdT9U4MKxe1PyqNjVuCKMpCl3dxGCIRJIlwUTfh2DQU.cache +1 -0
  166. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/xI/xIaxut_fEIhKBDqljTNwYaADK9kj3gG0ESrfHs-5_og.cache +3 -0
  167. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/y0/y0SJOqIx2fn1SKqOkAihsQow0trRJrSIyAswufVuoA8.cache +0 -0
  168. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/zg/zgpzeaX-KZErHyGJ1aBH3ZusweNXMneVZule88XsIJI.cache +1 -0
  169. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/zy/zYFltDy-8VC-uKq2BVEiJJyYXNFvVzAKuMlR3ZIYZsk.cache +0 -0
  170. data/spec/dummy/tmp/screenshots/failures_test_it_handles_subscriptions.png +0 -0
  171. data/spec/fixtures/upgrader/account.original.rb +19 -0
  172. data/spec/fixtures/upgrader/account.transformed.rb +20 -0
  173. data/spec/fixtures/upgrader/blame_range.original.rb +43 -0
  174. data/spec/fixtures/upgrader/blame_range.transformed.rb +30 -0
  175. data/spec/fixtures/upgrader/date_time.original.rb +24 -0
  176. data/spec/fixtures/upgrader/date_time.transformed.rb +23 -0
  177. data/spec/fixtures/upgrader/delete_project.original.rb +28 -0
  178. data/spec/fixtures/upgrader/delete_project.transformed.rb +27 -0
  179. data/spec/fixtures/upgrader/gist_order_field.original.rb +14 -0
  180. data/spec/fixtures/upgrader/gist_order_field.transformed.rb +13 -0
  181. data/spec/fixtures/upgrader/increment_count.original.rb +59 -0
  182. data/spec/fixtures/upgrader/increment_count.transformed.rb +50 -0
  183. data/spec/fixtures/upgrader/photo.original.rb +10 -0
  184. data/spec/fixtures/upgrader/photo.transformed.rb +12 -0
  185. data/spec/fixtures/upgrader/release_order.original.rb +15 -0
  186. data/spec/fixtures/upgrader/release_order.transformed.rb +14 -0
  187. data/spec/fixtures/upgrader/starrable.original.rb +49 -0
  188. data/spec/fixtures/upgrader/starrable.transformed.rb +46 -0
  189. data/spec/fixtures/upgrader/subscribable.original.rb +55 -0
  190. data/spec/fixtures/upgrader/subscribable.transformed.rb +51 -0
  191. data/spec/fixtures/upgrader/type_x.original.rb +65 -0
  192. data/spec/fixtures/upgrader/type_x.transformed.rb +56 -0
  193. data/spec/generators/graphql/function_generator_spec.rb +26 -0
  194. data/spec/generators/graphql/install_generator_spec.rb +1 -1
  195. data/spec/generators/graphql/loader_generator_spec.rb +24 -0
  196. data/spec/graphql/analysis/max_query_complexity_spec.rb +3 -3
  197. data/spec/graphql/analysis/max_query_depth_spec.rb +3 -3
  198. data/spec/graphql/argument_spec.rb +21 -0
  199. data/spec/graphql/backtrace_spec.rb +10 -0
  200. data/spec/graphql/base_type_spec.rb +42 -0
  201. data/spec/graphql/boolean_type_spec.rb +3 -3
  202. data/spec/graphql/directive_spec.rb +3 -1
  203. data/spec/graphql/enum_type_spec.rb +18 -5
  204. data/spec/graphql/execution/execute_spec.rb +4 -4
  205. data/spec/graphql/execution/instrumentation_spec.rb +165 -0
  206. data/spec/graphql/execution/multiplex_spec.rb +2 -2
  207. data/spec/graphql/execution_error_spec.rb +18 -0
  208. data/spec/graphql/float_type_spec.rb +2 -2
  209. data/spec/graphql/id_type_spec.rb +1 -1
  210. data/spec/graphql/input_object_type_spec.rb +15 -2
  211. data/spec/graphql/int_type_spec.rb +2 -2
  212. data/spec/graphql/interface_type_spec.rb +12 -0
  213. data/spec/graphql/internal_representation/rewrite_spec.rb +2 -2
  214. data/spec/graphql/introspection/schema_type_spec.rb +2 -0
  215. data/spec/graphql/language/block_string_spec.rb +70 -0
  216. data/spec/graphql/language/document_from_schema_definition_spec.rb +770 -0
  217. data/spec/graphql/language/generation_spec.rb +21 -186
  218. data/spec/graphql/language/lexer_spec.rb +21 -1
  219. data/spec/graphql/language/nodes_spec.rb +21 -12
  220. data/spec/graphql/language/parser_spec.rb +1 -1
  221. data/spec/graphql/language/printer_spec.rb +203 -0
  222. data/spec/graphql/object_type_spec.rb +22 -0
  223. data/spec/graphql/query/arguments_spec.rb +25 -15
  224. data/spec/graphql/query/context_spec.rb +18 -0
  225. data/spec/graphql/query/executor_spec.rb +2 -1
  226. data/spec/graphql/query/serial_execution/value_resolution_spec.rb +2 -8
  227. data/spec/graphql/query/variables_spec.rb +42 -1
  228. data/spec/graphql/query_spec.rb +31 -5
  229. data/spec/graphql/rake_task_spec.rb +3 -1
  230. data/spec/graphql/relay/base_connection_spec.rb +1 -1
  231. data/spec/graphql/relay/connection_instrumentation_spec.rb +2 -2
  232. data/spec/graphql/relay/connection_resolve_spec.rb +1 -1
  233. data/spec/graphql/relay/connection_type_spec.rb +1 -1
  234. data/spec/graphql/relay/mongo_relation_connection_spec.rb +474 -0
  235. data/spec/graphql/relay/mutation_spec.rb +9 -7
  236. data/spec/graphql/relay/range_add_spec.rb +5 -1
  237. data/spec/graphql/relay/relation_connection_spec.rb +65 -1
  238. data/spec/graphql/schema/argument_spec.rb +87 -0
  239. data/spec/graphql/schema/build_from_definition_spec.rb +89 -5
  240. data/spec/graphql/schema/enum_spec.rb +74 -0
  241. data/spec/graphql/schema/field_spec.rb +225 -0
  242. data/spec/graphql/schema/finder_spec.rb +135 -0
  243. data/spec/graphql/schema/input_object_spec.rb +111 -0
  244. data/spec/graphql/schema/instrumentation_spec.rb +40 -0
  245. data/spec/graphql/schema/interface_spec.rb +185 -0
  246. data/spec/graphql/schema/introspection_system_spec.rb +39 -0
  247. data/spec/graphql/schema/member/accepts_definition_spec.rb +111 -0
  248. data/spec/graphql/schema/member/build_type_spec.rb +17 -0
  249. data/spec/graphql/schema/member/has_fields_spec.rb +129 -0
  250. data/spec/graphql/schema/member/type_system_helpers_spec.rb +63 -0
  251. data/spec/graphql/schema/mutation_spec.rb +148 -0
  252. data/spec/graphql/schema/object_spec.rb +175 -0
  253. data/spec/graphql/schema/printer_spec.rb +111 -15
  254. data/spec/graphql/schema/relay_classic_mutation_spec.rb +38 -0
  255. data/spec/graphql/schema/rescue_middleware_spec.rb +11 -0
  256. data/spec/graphql/schema/resolver_spec.rb +131 -0
  257. data/spec/graphql/schema/scalar_spec.rb +95 -0
  258. data/spec/graphql/schema/traversal_spec.rb +31 -0
  259. data/spec/graphql/schema/union_spec.rb +65 -0
  260. data/spec/graphql/schema/validation_spec.rb +1 -1
  261. data/spec/graphql/schema/warden_spec.rb +11 -11
  262. data/spec/graphql/schema_spec.rb +55 -12
  263. data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +10 -2
  264. data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +2 -2
  265. data/spec/graphql/string_type_spec.rb +3 -3
  266. data/spec/graphql/subscriptions_spec.rb +273 -184
  267. data/spec/graphql/tracing/active_support_notifications_tracing_spec.rb +1 -1
  268. data/spec/graphql/tracing/new_relic_tracing_spec.rb +47 -0
  269. data/spec/graphql/tracing/platform_tracing_spec.rb +60 -1
  270. data/spec/graphql/union_type_spec.rb +1 -1
  271. data/spec/graphql/upgrader/member_spec.rb +516 -0
  272. data/spec/graphql/upgrader/schema_spec.rb +82 -0
  273. data/spec/spec_helper.rb +8 -0
  274. data/spec/support/dummy/schema.rb +53 -24
  275. data/spec/support/jazz.rb +544 -0
  276. data/spec/support/lazy_helpers.rb +21 -23
  277. data/spec/support/new_relic.rb +24 -0
  278. data/spec/support/star_trek/data.rb +109 -0
  279. data/spec/support/star_trek/schema.rb +388 -0
  280. data/spec/support/star_wars/data.rb +6 -7
  281. data/spec/support/star_wars/schema.rb +127 -171
  282. metadata +233 -11
  283. data/lib/graphql/introspection/arguments_field.rb +0 -7
  284. data/lib/graphql/introspection/enum_values_field.rb +0 -18
  285. data/lib/graphql/introspection/fields_field.rb +0 -13
  286. data/lib/graphql/introspection/input_fields_field.rb +0 -12
  287. data/lib/graphql/introspection/interfaces_field.rb +0 -11
  288. data/lib/graphql/introspection/of_type_field.rb +0 -6
  289. data/lib/graphql/introspection/possible_types_field.rb +0 -11
@@ -103,14 +103,16 @@ describe GraphQL::Relay::Mutation do
103
103
  end
104
104
 
105
105
  it "applies the description to the derived field" do
106
- assert_equal "Add a ship to this faction", StarWars::IntroduceShipMutation.field.description
106
+ field = GraphQL::Schema::Field.from_options(name: "x", **StarWars::IntroduceShipMutation.field_options)
107
+ assert_equal "Add a ship to this faction", field.description
107
108
  end
108
109
 
109
110
  it "inserts itself into the derived objects' metadata" do
110
- assert_equal StarWars::IntroduceShipMutation, StarWars::IntroduceShipMutation.field.mutation
111
- assert_equal StarWars::IntroduceShipMutation, StarWars::IntroduceShipMutation.return_type.mutation
111
+ field = GraphQL::Schema::Field.from_options(name: "x", **StarWars::IntroduceShipMutation.field_options)
112
+ assert_equal StarWars::IntroduceShipMutation, field.mutation
113
+ assert_equal StarWars::IntroduceShipMutation, field.to_graphql.mutation
114
+ assert_equal StarWars::IntroduceShipMutation, StarWars::IntroduceShipMutation.payload_type.mutation
112
115
  assert_equal StarWars::IntroduceShipMutation, StarWars::IntroduceShipMutation.input_type.mutation
113
- assert_equal StarWars::IntroduceShipMutation, StarWars::IntroduceShipMutation.result_class.mutation
114
116
  end
115
117
 
116
118
  describe "return_field ... property:" do
@@ -193,17 +195,17 @@ describe GraphQL::Relay::Mutation do
193
195
  end
194
196
 
195
197
  it "doesn't get a mutation in the metadata" do
196
- assert_equal nil, custom_return_type.mutation
198
+ assert_nil custom_return_type.mutation
197
199
  end
198
200
 
199
201
  it "supports input fields with nil default value" do
200
202
  assert input.arguments['nullDefault'].default_value?
201
- assert_equal nil, input.arguments['nullDefault'].default_value
203
+ assert_nil input.arguments['nullDefault'].default_value
202
204
  end
203
205
 
204
206
  it "supports input fields with no default value" do
205
207
  assert !input.arguments['noDefault'].default_value?
206
- assert_equal nil, input.arguments['noDefault'].default_value
208
+ assert_nil input.arguments['noDefault'].default_value
207
209
  end
208
210
 
209
211
  it "supports input fields with non-nil default value" do
@@ -70,7 +70,11 @@ describe GraphQL::Relay::RangeAdd do
70
70
  field :add_item, add_item.field
71
71
  end
72
72
 
73
- GraphQL::Schema.define(query: query, mutation: mutation, cursor_encoder: PassThroughEncoder)
73
+ Class.new(GraphQL::Schema) do
74
+ self.query(query)
75
+ self.mutation(mutation)
76
+ self.cursor_encoder(PassThroughEncoder)
77
+ end
74
78
  }
75
79
 
76
80
 
@@ -74,6 +74,35 @@ describe GraphQL::Relay::RelationConnection do
74
74
  )
75
75
  end
76
76
 
77
+ it "makes one sql query for items and another for count" do
78
+ query_str = <<-GRAPHQL
79
+ {
80
+ empire {
81
+ bases(first: 2) {
82
+ totalCount
83
+ edges {
84
+ cursor
85
+ node {
86
+ name
87
+ }
88
+ }
89
+ }
90
+ }
91
+ }
92
+ GRAPHQL
93
+ io = StringIO.new
94
+ begin
95
+ prev_logger = ActiveRecord::Base.logger
96
+ ActiveRecord::Base.logger = Logger.new(io)
97
+ result = star_wars_query(query_str, "first" => 2)
98
+ ensure
99
+ ActiveRecord::Base.logger = prev_logger
100
+ end
101
+ assert_equal 2, io.string.scan("\n").count, "Two log entries"
102
+ assert_equal 3, result["data"]["empire"]["bases"]["totalCount"]
103
+ assert_equal 2, result["data"]["empire"]["bases"]["edges"].size
104
+ end
105
+
77
106
  it "provides bidirectional_pagination" do
78
107
  result = star_wars_query(query_string, "first" => 1)
79
108
  last_cursor = get_last_cursor(result)
@@ -88,6 +117,13 @@ describe GraphQL::Relay::RelationConnection do
88
117
  assert_equal true, get_page_info(result)["hasNextPage"]
89
118
  assert_equal true, get_page_info(result)["hasPreviousPage"]
90
119
 
120
+ last_cursor = get_last_cursor(result)
121
+ result = with_bidirectional_pagination {
122
+ star_wars_query(query_string, "last" => 1, "before" => last_cursor)
123
+ }
124
+ assert_equal true, get_page_info(result)["hasNextPage"]
125
+ assert_equal false, get_page_info(result)["hasPreviousPage"]
126
+
91
127
  result = star_wars_query(query_string, "first" => 100)
92
128
  last_cursor = get_last_cursor(result)
93
129
 
@@ -100,7 +136,6 @@ describe GraphQL::Relay::RelationConnection do
100
136
  }
101
137
  assert_equal true, get_page_info(result)["hasNextPage"]
102
138
  assert_equal true, get_page_info(result)["hasPreviousPage"]
103
-
104
139
  end
105
140
 
106
141
  it 'slices the result' do
@@ -564,6 +599,35 @@ describe GraphQL::Relay::RelationConnection do
564
599
  result = star_wars_query(query_string, "last" => 1, "nameIncludes" => "ea", "before" => before)
565
600
  assert_equal(["Death Star"], get_names(result))
566
601
  end
602
+
603
+ it "makes one sql query for items and another for count" do
604
+ query_str = <<-GRAPHQL
605
+ {
606
+ empire {
607
+ basesAsSequelDataset(first: 2) {
608
+ totalCount
609
+ edges {
610
+ cursor
611
+ node {
612
+ name
613
+ }
614
+ }
615
+ }
616
+ }
617
+ }
618
+ GRAPHQL
619
+ result = nil
620
+ io = StringIO.new
621
+ begin
622
+ StarWars::DB.loggers << Logger.new(io)
623
+ result = star_wars_query(query_str, "first" => 2)
624
+ ensure
625
+ StarWars::DB.loggers.pop
626
+ end
627
+ assert_equal 2, io.string.scan("SELECT").count
628
+ assert_equal 3, result["data"]["empire"]["basesAsSequelDataset"]["totalCount"]
629
+ assert_equal 2, result["data"]["empire"]["basesAsSequelDataset"]["edges"].size
630
+ end
567
631
  end
568
632
  end
569
633
 
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+ require "spec_helper"
3
+
4
+ describe GraphQL::Schema::Argument do
5
+ module SchemaArgumentTest
6
+ class Query < GraphQL::Schema::Object
7
+ field :field, String, null: false do
8
+ argument :arg, String, description: "test", required: false
9
+
10
+ argument :arg_with_block, String, required: false do
11
+ description "test"
12
+ end
13
+
14
+ argument :aliased_arg, String, required: false, as: :renamed
15
+ argument :prepared_arg, Int, required: false, prepare: :multiply
16
+ end
17
+
18
+ def field(**args)
19
+ args.inspect
20
+ end
21
+
22
+ def multiply(val)
23
+ context[:multiply_by] * val
24
+ end
25
+ end
26
+
27
+ class Schema < GraphQL::Schema
28
+ query(Query)
29
+ end
30
+ end
31
+
32
+
33
+
34
+ describe "#name" do
35
+ it "reflects camelization" do
36
+ assert_equal "argWithBlock", SchemaArgumentTest::Query.fields["field"].arguments["argWithBlock"].name
37
+ end
38
+ end
39
+
40
+ describe "#type" do
41
+ let(:argument) { SchemaArgumentTest::Query.fields["field"].arguments["arg"] }
42
+ it "returns the type" do
43
+ assert_equal GraphQL::STRING_TYPE, argument.type
44
+ end
45
+ end
46
+
47
+ describe "graphql definition" do
48
+ it "calls block" do
49
+ assert_equal "test", SchemaArgumentTest::Query.fields["field"].arguments["argWithBlock"].description
50
+ end
51
+ end
52
+
53
+ describe "#description" do
54
+ it "sets description" do
55
+ SchemaArgumentTest::Query.fields["field"].arguments["arg"].description "new description"
56
+ assert_equal "new description", SchemaArgumentTest::Query.fields["field"].arguments["arg"].description
57
+ end
58
+
59
+ it "returns description" do
60
+ assert_equal "test", SchemaArgumentTest::Query.fields["field"].arguments["argWithBlock"].description
61
+ end
62
+ end
63
+
64
+ describe "as:" do
65
+ it "uses that Symbol for Ruby kwargs" do
66
+ query_str = <<-GRAPHQL
67
+ { field(aliasedArg: "x") }
68
+ GRAPHQL
69
+
70
+ res = SchemaArgumentTest::Schema.execute(query_str)
71
+ # Make sure it's getting the renamed symbol:
72
+ assert_equal '{:renamed=>"x"}', res["data"]["field"]
73
+ end
74
+ end
75
+
76
+ describe "prepare:" do
77
+ it "calls the method on the field's owner" do
78
+ query_str = <<-GRAPHQL
79
+ { field(preparedArg: 5) }
80
+ GRAPHQL
81
+
82
+ res = SchemaArgumentTest::Schema.execute(query_str, context: {multiply_by: 3})
83
+ # Make sure it's getting the renamed symbol:
84
+ assert_equal '{:prepared_arg=>15}', res["data"]["field"]
85
+ end
86
+ end
87
+ end
@@ -30,6 +30,20 @@ type HelloScalars {
30
30
  build_schema_and_compare_output(schema.chop)
31
31
  end
32
32
 
33
+ it 'can build a schema with default input object values' do
34
+ schema = <<-SCHEMA
35
+ input InputObject {
36
+ a: Int
37
+ }
38
+
39
+ type Query {
40
+ a(input: InputObject = {a: 1}): String
41
+ }
42
+ SCHEMA
43
+
44
+ build_schema_and_compare_output(schema.chop)
45
+ end
46
+
33
47
  it 'can build a schema with directives' do
34
48
  schema = <<-SCHEMA
35
49
  schema {
@@ -118,11 +132,12 @@ type Hello {
118
132
 
119
133
  it 'supports adding directives while maintaining built-in directives' do
120
134
  schema = <<-SCHEMA
121
- schema {
135
+ schema @custom(thing: true) {
122
136
  query: Hello
123
137
  }
124
138
 
125
139
  directive @foo(arg: Int) on FIELD
140
+ directive @custom(thing: Boolean) on SCHEMA
126
141
 
127
142
  type Hello {
128
143
  str: String
@@ -294,7 +309,7 @@ schema {
294
309
  }
295
310
 
296
311
  type Hello {
297
- str(int: Int, bool: Boolean): String
312
+ str(bool: Boolean, int: Int): String
298
313
  }
299
314
  SCHEMA
300
315
 
@@ -491,7 +506,7 @@ type HelloScalars {
491
506
  }
492
507
 
493
508
  type Mutation {
494
- addHelloScalars(str: String, int: Int, bool: Boolean): HelloScalars
509
+ addHelloScalars(bool: Boolean, int: Int, str: String): HelloScalars
495
510
  }
496
511
  SCHEMA
497
512
 
@@ -506,7 +521,7 @@ enum Color {
506
521
  }
507
522
 
508
523
  type Mutation {
509
- hello(str: String, int: Int, color: Color = RED, nullDefault: Int = null): String
524
+ hello(color: Color = RED, int: Int, nullDefault: Int = null, str: String): String
510
525
  }
511
526
 
512
527
  type Query {
@@ -531,7 +546,7 @@ type HelloScalars {
531
546
  }
532
547
 
533
548
  type Subscription {
534
- subscribeHelloScalars(str: String, int: Int, bool: Boolean): HelloScalars
549
+ subscribeHelloScalars(bool: Boolean, int: Int, str: String): HelloScalars
535
550
  }
536
551
  SCHEMA
537
552
 
@@ -589,6 +604,75 @@ type Query {
589
604
 
590
605
  build_schema_and_compare_output(schema.chop)
591
606
  end
607
+
608
+ it 'supports empty types' do
609
+ schema = <<-SCHEMA
610
+ type Query {
611
+ }
612
+ SCHEMA
613
+
614
+ build_schema_and_compare_output(schema.chop)
615
+ end
616
+
617
+ it "tracks original AST node" do
618
+ schema_definition = <<-GRAPHQL
619
+ schema @custom(thing: true) {
620
+ query: Query
621
+ }
622
+
623
+ enum Enum {
624
+ VALUE
625
+ }
626
+
627
+ type Query {
628
+ field(argument: String): String
629
+ deprecatedField(argument: String): String @deprecated(reason: "Test")
630
+ }
631
+
632
+ interface Interface {
633
+ field(argument: String): String
634
+ }
635
+
636
+ union Union = Query
637
+
638
+ scalar Scalar
639
+
640
+ input Input {
641
+ argument: String
642
+ }
643
+
644
+ directive @Directive (
645
+ # Argument
646
+ argument: String
647
+ ) on SCHEMA
648
+
649
+ type Type implements Interface {
650
+ field(argument: String): String
651
+ }
652
+ GRAPHQL
653
+
654
+ schema = GraphQL::Schema.from_definition(schema_definition)
655
+
656
+ assert_equal [1, 1], schema.ast_node.position
657
+ assert_equal [1, 8], schema.ast_node.directives.first.position
658
+ assert_equal [5, 1], schema.types["Enum"].ast_node.position
659
+ assert_equal [6, 3], schema.types["Enum"].values["VALUE"].ast_node.position
660
+ assert_equal [9, 1], schema.types["Query"].ast_node.position
661
+ assert_equal [10, 3], schema.types["Query"].fields["field"].ast_node.position
662
+ assert_equal [10, 9], schema.types["Query"].fields["field"].arguments["argument"].ast_node.position
663
+ assert_equal [11, 45], schema.types["Query"].fields["deprecatedField"].ast_node.directives[0].position
664
+ assert_equal [11, 57], schema.types["Query"].fields["deprecatedField"].ast_node.directives[0].arguments[0].position
665
+ assert_equal [14, 1], schema.types["Interface"].ast_node.position
666
+ assert_equal [15, 3], schema.types["Interface"].fields["field"].ast_node.position
667
+ assert_equal [15, 9], schema.types["Interface"].fields["field"].arguments["argument"].ast_node.position
668
+ assert_equal [18, 1], schema.types["Union"].ast_node.position
669
+ assert_equal [20, 1], schema.types["Scalar"].ast_node.position
670
+ assert_equal [22, 1], schema.types["Input"].ast_node.position
671
+ assert_equal [23, 3], schema.types["Input"].arguments["argument"].ast_node.position
672
+ assert_equal [26, 1], schema.directives["Directive"].ast_node.position
673
+ assert_equal [28, 3], schema.directives["Directive"].arguments["argument"].ast_node.position
674
+ assert_equal [31, 22], schema.types["Type"].ast_node.interfaces[0].position
675
+ end
592
676
  end
593
677
 
594
678
  describe 'Failures' do
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+ require "spec_helper"
3
+
4
+ describe GraphQL::Schema::Enum do
5
+ let(:enum) { Jazz::Family }
6
+ describe "type info" do
7
+ it "tells about the definition" do
8
+ assert_equal "Family", enum.graphql_name
9
+ assert_equal 29, enum.description.length
10
+ assert_equal 6, enum.values.size
11
+ end
12
+
13
+ it "inherits values and description" do
14
+ new_enum = Class.new(enum) do
15
+ value :Nonsense
16
+ value :PERCUSSION, "new description"
17
+ end
18
+
19
+ # Description was inherited
20
+ assert_equal 29, new_enum.description.length
21
+ # values were inherited without modifying the parent
22
+ assert_equal 6, enum.values.size
23
+ assert_equal 7, new_enum.values.size
24
+ perc_value = new_enum.values["PERCUSSION"]
25
+ assert_equal "new description", perc_value.description
26
+ end
27
+
28
+ it "accepts a block" do
29
+ assert_equal "Neither here nor there, really", enum.values["KEYS"].description
30
+ end
31
+
32
+ it "is the #owner of its values" do
33
+ value = enum.values["STRING"]
34
+ assert_equal enum, value.owner
35
+ end
36
+ end
37
+
38
+ it "uses a custom enum value class" do
39
+ enum_type = enum.to_graphql
40
+ value = enum_type.values["STRING"]
41
+ assert_equal 1, value.metadata[:custom_setting]
42
+ end
43
+
44
+ describe ".to_graphql" do
45
+ it "creates an EnumType" do
46
+ enum_type = enum.to_graphql
47
+ assert_equal "Family", enum_type.name
48
+ assert_equal "Groups of musical instruments", enum_type.description
49
+
50
+ string_val = enum_type.values["STRING"]
51
+ didg_val = enum_type.values["DIDGERIDOO"]
52
+ assert_equal "STRING", string_val.name
53
+ assert_equal :str, string_val.value
54
+ assert_equal "DIDGERIDOO", didg_val.name
55
+ assert_equal "Merged into BRASS", didg_val.deprecation_reason
56
+ end
57
+ end
58
+
59
+ describe "in queries" do
60
+ it "works as return values" do
61
+ query_str = "{ instruments { family } }"
62
+ expected_families = ["STRING", "WOODWIND", "BRASS", "KEYS", "KEYS", "PERCUSSION"]
63
+ result = Jazz::Schema.execute(query_str)
64
+ assert_equal expected_families, result["data"]["instruments"].map { |i| i["family"] }
65
+ end
66
+
67
+ it "works as input" do
68
+ query_str = "query($family: Family!) { instruments(family: $family) { name } }"
69
+ expected_names = ["Piano", "Organ"]
70
+ result = Jazz::Schema.execute(query_str, variables: { family: "KEYS" })
71
+ assert_equal expected_names, result["data"]["instruments"].map { |i| i["name"] }
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,225 @@
1
+ # frozen_string_literal: true
2
+ require "spec_helper"
3
+
4
+ describe GraphQL::Schema::Field do
5
+ describe "graphql definition" do
6
+ let(:object_class) { Jazz::Query }
7
+ let(:field) { object_class.fields["inspectInput"] }
8
+
9
+ it "uses the argument class" do
10
+ arg_defn = field.graphql_definition.arguments.values.first
11
+ assert_equal :ok, arg_defn.metadata[:custom]
12
+ end
13
+
14
+ it "attaches itself to its graphql_definition as type_class" do
15
+ assert_equal field, field.graphql_definition.metadata[:type_class]
16
+ end
17
+
18
+ it "camelizes the field name, unless camelize: false" do
19
+ assert_equal 'inspectInput', field.graphql_definition.name
20
+ assert_equal 'inspectInput', field.name
21
+
22
+ underscored_field = GraphQL::Schema::Field.from_options(:underscored_field, String, null: false, camelize: false, owner: nil) do
23
+ argument :underscored_arg, String, required: true, camelize: false
24
+ end
25
+
26
+ assert_equal 'underscored_field', underscored_field.to_graphql.name
27
+ arg_name, arg_defn = underscored_field.to_graphql.arguments.first
28
+ assert_equal 'underscored_arg', arg_name
29
+ assert_equal 'underscored_arg', arg_defn.name
30
+ end
31
+
32
+ it "exposes the method override" do
33
+ object = Class.new(Jazz::BaseObject) do
34
+ field :t, String, method: :tt, null: true
35
+ end
36
+ assert_equal :tt, object.fields["t"].method_sym
37
+ assert_equal "tt", object.fields["t"].method_str
38
+ end
39
+
40
+ it "accepts a block for definition" do
41
+ object = Class.new(Jazz::BaseObject) do
42
+ graphql_name "JustAName"
43
+
44
+ field :test, String, null: true do
45
+ argument :test, String, required: true
46
+ description "A Description."
47
+ end
48
+ end.to_graphql
49
+
50
+ assert_equal "test", object.fields["test"].arguments["test"].name
51
+ assert_equal "A Description.", object.fields["test"].description
52
+ end
53
+
54
+ it "accepts anonymous classes as type" do
55
+ type = Class.new(GraphQL::Schema::Object) do
56
+ graphql_name 'MyType'
57
+ end
58
+ field = GraphQL::Schema::Field.from_options(:my_field, type, owner: nil, null: true)
59
+ assert_equal type.to_graphql, field.to_graphql.type
60
+ end
61
+
62
+ describe "extras" do
63
+ it "can get errors, which adds path" do
64
+ query_str = <<-GRAPHQL
65
+ query {
66
+ find(id: "Musician/Herbie Hancock") {
67
+ ... on Musician {
68
+ addError
69
+ }
70
+ }
71
+ }
72
+ GRAPHQL
73
+
74
+ res = Jazz::Schema.execute(query_str)
75
+ err = res["errors"].first
76
+ assert_equal "this has a path", err["message"]
77
+ assert_equal ["find", "addError"], err["path"]
78
+ assert_equal [{"line"=>4, "column"=>15}], err["locations"]
79
+ end
80
+ end
81
+
82
+ it "is the #owner of its arguments" do
83
+ field = Jazz::Query.fields["find"]
84
+ argument = field.arguments["id"]
85
+ assert_equal field, argument.owner
86
+ end
87
+
88
+ it "has a reference to the object that owns it with #owner" do
89
+ assert_equal Jazz::Query, field.owner
90
+ end
91
+
92
+ describe "type" do
93
+ it "tells the return type" do
94
+ assert_equal "[String!]!", field.type.graphql_definition.to_s
95
+ end
96
+
97
+ it "returns the type class" do
98
+ field = Jazz::Query.fields["nowPlaying"]
99
+ assert_equal Jazz::PerformingAct, field.type.of_type
100
+ end
101
+ end
102
+
103
+ describe "complexity" do
104
+ it "accepts a keyword argument" do
105
+ object = Class.new(Jazz::BaseObject) do
106
+ graphql_name "complexityKeyword"
107
+
108
+ field :complexityTest, String, null: true, complexity: 25
109
+ end.to_graphql
110
+
111
+ assert_equal 25, object.fields["complexityTest"].complexity
112
+ end
113
+
114
+ it "accepts a proc in the definition block" do
115
+ object = Class.new(Jazz::BaseObject) do
116
+ graphql_name "complexityKeyword"
117
+
118
+ field :complexityTest, String, null: true do
119
+ complexity ->(_ctx, _args, _child_complexity) { 52 }
120
+ end
121
+ end.to_graphql
122
+
123
+ assert_equal 52, object.fields["complexityTest"].complexity.call(nil, nil, nil)
124
+ end
125
+
126
+ it "accepts an integer in the definition block" do
127
+ object = Class.new(Jazz::BaseObject) do
128
+ graphql_name "complexityKeyword"
129
+
130
+ field :complexityTest, String, null: true do
131
+ complexity 38
132
+ end
133
+ end.to_graphql
134
+
135
+ assert_equal 38, object.fields["complexityTest"].complexity
136
+ end
137
+
138
+ it 'fails if the complexity is not numeric and not a proc' do
139
+ err = assert_raises(RuntimeError) do
140
+ Class.new(Jazz::BaseObject) do
141
+ graphql_name "complexityKeyword"
142
+
143
+ field :complexityTest, String, null: true do
144
+ complexity 'One hundred and eighty'
145
+ end
146
+ end.to_graphql
147
+ end
148
+
149
+ assert_match /^Invalid complexity:/, err.message
150
+ end
151
+
152
+ it 'fails if the proc does not accept 3 parameters' do
153
+ err = assert_raises(RuntimeError) do
154
+ Class.new(Jazz::BaseObject) do
155
+ graphql_name "complexityKeyword"
156
+
157
+ field :complexityTest, String, null: true do
158
+ complexity ->(one, two) { 52 }
159
+ end
160
+ end.to_graphql
161
+ end
162
+
163
+ assert_match /^A complexity proc should always accept 3 parameters/, err.message
164
+ end
165
+ end
166
+ end
167
+
168
+ describe "build type errors" do
169
+ it "includes the full name" do
170
+ thing = Class.new(GraphQL::Schema::Object) do
171
+ graphql_name "Thing"
172
+ # `Set` is a class but not a GraphQL type
173
+ field :stuff, Set, null: false
174
+ end
175
+
176
+ err = assert_raises ArgumentError do
177
+ thing.fields["stuff"].type
178
+ end
179
+
180
+ assert_includes err.message, "Thing.stuff"
181
+ assert_includes err.message, "Unexpected class/module"
182
+ end
183
+
184
+ it "makes a suggestion when the type is false" do
185
+ thing = Class.new(GraphQL::Schema::Object) do
186
+ graphql_name "Thing"
187
+ # False might come from an invalid `!`
188
+ field :stuff, false, null: false
189
+ end
190
+
191
+ err = assert_raises ArgumentError do
192
+ thing.fields["stuff"].type
193
+ end
194
+
195
+ assert_includes err.message, "Thing.stuff"
196
+ assert_includes err.message, "Received `false` instead of a type, maybe a `!` should be replaced with `null: true` (for fields) or `required: true` (for arguments)"
197
+ end
198
+
199
+ it "makes a suggestion when the type is a GraphQL::Field" do
200
+ err = assert_raises ArgumentError do
201
+ Class.new(GraphQL::Schema::Object) do
202
+ graphql_name "Thing"
203
+ # Previously, field was a valid second argument
204
+ field :stuff, GraphQL::Relay::Node.field, null: false
205
+ end
206
+ end
207
+
208
+ assert_includes err.message, "use the `field:` keyword for this instead"
209
+ end
210
+ end
211
+
212
+ describe "mutation" do
213
+ it "passes when not including extra arguments" do
214
+ mutation_class = Class.new(GraphQL::Schema::Mutation) do
215
+ graphql_name "Thing"
216
+ field :stuff, String, null: false
217
+ end
218
+
219
+ obj = Class.new(GraphQL::Schema::Object) do
220
+ field(:my_field, mutation: mutation_class, null: true)
221
+ end
222
+ assert_equal obj.fields["myField"].mutation, mutation_class
223
+ end
224
+ end
225
+ end