graphql 1.7.6 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
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