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
@@ -0,0 +1,364 @@
1
+ # frozen_string_literal: true
2
+ require "spec_helper"
3
+
4
+ describe GraphQL::InputObjectType do
5
+ let(:input_object) { Dummy::DairyProductInput.graphql_definition }
6
+ it "has a description" do
7
+ assert(input_object.description)
8
+ end
9
+
10
+ it "has input fields" do
11
+ assert(input_object.input_fields["fatContent"])
12
+ end
13
+
14
+ describe "on a type unused by the schema" do
15
+ it "has input fields" do
16
+ UnreachedInputType = GraphQL::InputObjectType.define do
17
+ name 'UnreachedInputType'
18
+ description 'An input object type not directly used in the schema.'
19
+
20
+ input_field :field, types.String
21
+ end
22
+ assert(UnreachedInputType.input_fields['field'])
23
+ end
24
+ end
25
+
26
+ describe "input validation" do
27
+ it "Accepts anything that yields key-value pairs to #all?" do
28
+ values_obj = MinimumInputObject.new({"source" => "COW", "fatContent" => 0.4})
29
+ assert input_object.valid_isolated_input?(values_obj)
30
+ end
31
+
32
+ describe "validate_input with non-enumerable input" do
33
+ it "returns a valid result for MinimumInputObject" do
34
+ result = input_object.validate_isolated_input(MinimumInputObject.new({"source" => "COW", "fatContent" => 0.4}))
35
+ assert(result.valid?)
36
+ end
37
+
38
+ it "returns an invalid result for MinimumInvalidInputObject" do
39
+ invalid_input = MinimumInputObject.new({"source" => "KOALA", "fatContent" => 0.4})
40
+ result = input_object.validate_isolated_input(invalid_input)
41
+ assert(!result.valid?)
42
+ end
43
+ end
44
+
45
+ describe "validate_input with null" do
46
+ let(:schema) { GraphQL::Schema.from_definition(%|
47
+ type Query {
48
+ a: Int
49
+ }
50
+
51
+ input ExampleInputObject {
52
+ a: String
53
+ b: Int!
54
+ }
55
+ |) }
56
+ let(:input_type) { schema.types['ExampleInputObject'] }
57
+
58
+ it "returns an invalid result when value is null for non-null argument" do
59
+ invalid_input = MinimumInputObject.new({"a" => "Test", "b" => nil})
60
+ result = input_type.validate_isolated_input(invalid_input)
61
+ assert(!result.valid?)
62
+ end
63
+
64
+ it "returns valid result when value is null for nullable argument" do
65
+ invalid_input = MinimumInputObject.new({"a" => nil, "b" => 1})
66
+ result = input_type.validate_isolated_input(invalid_input)
67
+ assert(result.valid?)
68
+ end
69
+ end
70
+
71
+ describe "validate_input with enumerable input" do
72
+ describe "with good input" do
73
+ let(:input) do
74
+ {
75
+ "source" => "COW",
76
+ "fatContent" => 0.4
77
+ }
78
+ end
79
+ let(:result) { input_object.validate_isolated_input(input) }
80
+
81
+ it "returns a valid result" do
82
+ assert(result.valid?)
83
+ end
84
+ end
85
+
86
+ if ActionPack::VERSION::MAJOR > 3
87
+ describe "with a ActionController::Parameters" do
88
+ let(:input) do
89
+ ActionController::Parameters.new(
90
+ "source" => "COW",
91
+ "fatContent" => 0.4,
92
+ )
93
+ end
94
+ let(:result) { input_object.validate_isolated_input(input) }
95
+
96
+ it "returns a valid result" do
97
+ assert(result.valid?)
98
+ end
99
+ end
100
+ end
101
+
102
+ describe "with bad enum and float" do
103
+ let(:result) { input_object.validate_isolated_input({"source" => "KOALA", "fatContent" => "bad_num"}) }
104
+
105
+ it "returns an invalid result" do
106
+ assert(!result.valid?)
107
+ end
108
+
109
+ it "has problems with correct paths" do
110
+ paths = result.problems.map { |p| p["path"] }
111
+ assert(paths.include?(["source"]))
112
+ assert(paths.include?(["fatContent"]))
113
+ end
114
+
115
+ it "has correct problem explanation" do
116
+ expected = Dummy::DairyAnimal.graphql_definition.validate_isolated_input("KOALA").problems[0]["explanation"]
117
+
118
+ source_problem = result.problems.detect { |p| p["path"] == ["source"] }
119
+ actual = source_problem["explanation"]
120
+
121
+ assert_equal(expected, actual)
122
+ end
123
+ end
124
+
125
+ describe 'with a string as input' do
126
+ let(:result) { input_object.validate_isolated_input("just a string") }
127
+
128
+ it "returns an invalid result" do
129
+ assert(!result.valid?)
130
+ end
131
+
132
+ it "has problem with correct path" do
133
+ paths = result.problems.map { |p| p["path"] }
134
+ assert(paths.include?([]))
135
+ end
136
+
137
+ it "has correct problem explanation" do
138
+ assert(result.problems[0]["explanation"].include?("to be a key, value object"))
139
+ end
140
+ end
141
+
142
+ describe 'with an array as input' do
143
+ let(:result) { input_object.validate_isolated_input(["string array"]) }
144
+
145
+ it "returns an invalid result" do
146
+ assert(!result.valid?)
147
+ end
148
+
149
+ it "has problem with correct path" do
150
+ paths = result.problems.map { |p| p["path"] }
151
+ assert(paths.include?([]))
152
+ end
153
+
154
+ it "has correct problem explanation" do
155
+ assert(result.problems[0]["explanation"].include?("to be a key, value object"))
156
+ end
157
+ end
158
+
159
+ describe 'with a int as input' do
160
+ let(:result) { input_object.validate_isolated_input(10) }
161
+
162
+ it "returns an invalid result" do
163
+ assert(!result.valid?)
164
+ end
165
+
166
+ it "has problem with correct path" do
167
+ paths = result.problems.map { |p| p["path"] }
168
+ assert(paths.include?([]))
169
+ end
170
+
171
+ it "has correct problem explanation" do
172
+ assert(result.problems[0]["explanation"].include?("to be a key, value object"))
173
+ end
174
+ end
175
+
176
+ describe "with extra argument" do
177
+ let(:result) { input_object.validate_isolated_input({"source" => "COW", "fatContent" => 0.4, "isDelicious" => false}) }
178
+
179
+ it "returns an invalid result" do
180
+ assert(!result.valid?)
181
+ end
182
+
183
+ it "has problem with correct path" do
184
+ paths = result.problems.map { |p| p["path"] }
185
+ assert_equal([["isDelicious"]], paths)
186
+ end
187
+
188
+ it "has correct problem explanation" do
189
+ assert(result.problems[0]["explanation"].include?("Field is not defined"))
190
+ end
191
+ end
192
+
193
+ describe "list with one invalid element" do
194
+ let(:list_type) { GraphQL::ListType.new(of_type: Dummy::DairyProductInput.graphql_definition) }
195
+ let(:result) do
196
+ list_type.validate_isolated_input([
197
+ { "source" => "COW", "fatContent" => 0.4 },
198
+ { "source" => "KOALA", "fatContent" => 0.4 }
199
+ ])
200
+ end
201
+
202
+ it "returns an invalid result" do
203
+ assert(!result.valid?)
204
+ end
205
+
206
+ it "has one problem" do
207
+ assert_equal(result.problems.length, 1)
208
+ end
209
+
210
+ it "has problem with correct path" do
211
+ path = result.problems[0]["path"]
212
+ assert_equal(path, [1, "source"])
213
+ end
214
+
215
+ it "has problem with correct explanation" do
216
+ expected = Dummy::DairyAnimal.graphql_definition.validate_isolated_input("KOALA").problems[0]["explanation"]
217
+ actual = result.problems[0]["explanation"]
218
+ assert_equal(expected, actual)
219
+ end
220
+ end
221
+
222
+ describe 'with invalid name' do
223
+ it 'raises the correct error' do
224
+ assert_raises(GraphQL::InvalidNameError) do
225
+ InvalidInputTest = GraphQL::InputObjectType.define do
226
+ name "Some::Invalid Name"
227
+ end
228
+
229
+ # Force evaluation
230
+ InvalidInputTest.name
231
+ end
232
+ end
233
+ end
234
+ end
235
+ end
236
+
237
+ describe "coerce_result" do
238
+ it "omits unspecified arguments" do
239
+ result = input_object.coerce_isolated_result({fatContent: 0.3})
240
+ assert_equal ["fatContent"], result.keys
241
+ assert_equal 0.3, result["fatContent"]
242
+ end
243
+ end
244
+
245
+ describe "coercion of null inputs" do
246
+ let(:schema) { GraphQL::Schema.from_definition(%|
247
+ type Query {
248
+ a: Int
249
+ }
250
+
251
+ input ExampleInputObject {
252
+ a: String
253
+ b: Int!
254
+ c: String = "Default"
255
+ d: Boolean = false
256
+ }
257
+
258
+ input SecondLevelInputObject {
259
+ example: ExampleInputObject = {b: 42, d: true}
260
+ }
261
+ |) }
262
+ let(:input_type) { schema.types['ExampleInputObject'] }
263
+
264
+ it "null values are returned in coerced input" do
265
+ input = MinimumInputObject.new({"a" => "Test", "b" => nil,"c" => "Test"})
266
+ result = input_type.coerce_isolated_input(input)
267
+
268
+ assert_equal 'Test', result['a']
269
+
270
+ assert result.key?('b')
271
+ assert_nil result['b']
272
+
273
+ assert_equal "Test", result['c']
274
+ end
275
+
276
+ it "null values are preserved when argument has a default value" do
277
+ input = MinimumInputObject.new({"a" => "Test", "b" => 1, "c" => nil})
278
+ result = input_type.coerce_isolated_input(input)
279
+
280
+ assert_equal 'Test', result['a']
281
+ assert_equal 1, result['b']
282
+
283
+ assert result.key?('c')
284
+ assert_nil result['c']
285
+ end
286
+
287
+ it "omitted arguments are not returned" do
288
+ input = MinimumInputObject.new({"b" => 1, "c" => "Test"})
289
+ result = input_type.coerce_isolated_input(input)
290
+
291
+ assert !result.key?('a')
292
+ assert_equal 1, result['b']
293
+ assert_equal 'Test', result['c']
294
+ end
295
+
296
+ it "false default values are returned" do
297
+ input = MinimumInputObject.new({"b" => 1})
298
+ result = input_type.coerce_isolated_input(input)
299
+
300
+ assert_equal false, result['d']
301
+ end
302
+
303
+ it "merges defaults of nested input objects" do
304
+ result = schema.types['SecondLevelInputObject'].coerce_isolated_input({})
305
+ assert_equal 42, result['example']['b']
306
+ assert_equal "Default", result['example']['c']
307
+ assert_equal true, result['example']['d']
308
+ end
309
+ end
310
+
311
+ describe "when sent into a query" do
312
+ let(:variables) { {} }
313
+ let(:result) { Dummy::Schema.execute(query_string, variables: variables) }
314
+
315
+ describe "list inputs" do
316
+ let(:variables) { {"search" => [MinimumInputObject.new({"source" => "COW", "fatContent" => 0.4})]} }
317
+ let(:query_string) {%|
318
+ query getCheeses($search: [DairyProductInput]!){
319
+ sheep: searchDairy(product: [{source: SHEEP, fatContent: 0.1}]) {
320
+ ... cheeseFields
321
+ }
322
+ cow: searchDairy(product: $search) {
323
+ ... cheeseFields
324
+ }
325
+ }
326
+
327
+ fragment cheeseFields on Cheese {
328
+ flavor
329
+ }
330
+ |}
331
+
332
+ it "converts items to plain values" do
333
+ sheep_value = result["data"]["sheep"]["flavor"]
334
+ cow_value = result["data"]["cow"]["flavor"]
335
+ assert_equal("Manchego", sheep_value)
336
+ assert_equal("Brie", cow_value)
337
+ end
338
+ end
339
+
340
+ describe "scalar inputs" do
341
+ let(:query_string) {%|
342
+ {
343
+ cheese(id: 1.4) {
344
+ flavor
345
+ }
346
+ }
347
+ |}
348
+
349
+ it "converts them to the correct type" do
350
+ cheese_name = result["data"]["cheese"]["flavor"]
351
+ assert_equal("Brie", cheese_name)
352
+ end
353
+ end
354
+ end
355
+
356
+ describe "#dup" do
357
+ it "shallow-copies internal state" do
358
+ input_object_2 = input_object.dup
359
+ input_object_2.arguments["nonsense"] = GraphQL::Argument.define(name: "int", type: GraphQL::INT_TYPE)
360
+ assert_equal 5, input_object.arguments.size
361
+ assert_equal 6, input_object_2.arguments.size
362
+ end
363
+ end
364
+ end
@@ -69,21 +69,21 @@ describe GraphQL::Query::Variables do
69
69
  it "checks for string matches" do
70
70
  # These get merged into all the values above
71
71
  default_values = {
72
- "originDairy"=>"Sugar Hollow Dairy",
73
- "organic"=>false,
74
- "order_by"=>{"direction"=>"ASC"}
72
+ origin_dairy: "Sugar Hollow Dairy",
73
+ organic: false,
74
+ order_by: { direction: "ASC" },
75
75
  }
76
76
 
77
77
  expected_input_1 = {
78
- "source" => 1,
79
- "fatContent" => 0.99,
78
+ source: 1,
79
+ fat_content: 0.99,
80
80
  }.merge(default_values)
81
81
 
82
82
  assert_equal(expected_input_1, variables["dairy_product_1"].to_h)
83
83
 
84
84
  expected_input_2 = {
85
- "source" => :donkey,
86
- "fatContent" => 0.89,
85
+ source: :donkey,
86
+ fat_content: 0.89,
87
87
  }.merge(default_values)
88
88
  assert_equal(expected_input_2, variables["dairy_product_2"].to_h)
89
89
  end
@@ -43,8 +43,8 @@ describe GraphQL::Relay::ArrayConnection do
43
43
  assert_equal(2, number_of_ships)
44
44
  assert_equal(true, result["data"]["rebels"]["ships"]["pageInfo"]["hasNextPage"])
45
45
  assert_equal(false, result["data"]["rebels"]["ships"]["pageInfo"]["hasPreviousPage"])
46
- assert_equal("MQ==", result["data"]["rebels"]["ships"]["pageInfo"]["startCursor"])
47
- assert_equal("Mg==", result["data"]["rebels"]["ships"]["pageInfo"]["endCursor"])
46
+ assert_equal("MQ", result["data"]["rebels"]["ships"]["pageInfo"]["startCursor"])
47
+ assert_equal("Mg", result["data"]["rebels"]["ships"]["pageInfo"]["endCursor"])
48
48
 
49
49
  result = star_wars_query(query_string, "first" => 3)
50
50
  number_of_ships = get_names(result).length
@@ -55,14 +55,14 @@ describe GraphQL::Relay::ArrayConnection do
55
55
  result = star_wars_query(query_string, "first" => 2)
56
56
  assert_equal(true, result["data"]["rebels"]["ships"]["pageInfo"]["hasNextPage"])
57
57
  assert_equal(false, result["data"]["rebels"]["ships"]["pageInfo"]["hasPreviousPage"])
58
- assert_equal("MQ==", result["data"]["rebels"]["ships"]["pageInfo"]["startCursor"])
59
- assert_equal("Mg==", result["data"]["rebels"]["ships"]["pageInfo"]["endCursor"])
58
+ assert_equal("MQ", result["data"]["rebels"]["ships"]["pageInfo"]["startCursor"])
59
+ assert_equal("Mg", result["data"]["rebels"]["ships"]["pageInfo"]["endCursor"])
60
60
 
61
61
  result = star_wars_query(query_string, "first" => 100)
62
62
  assert_equal(false, result["data"]["rebels"]["ships"]["pageInfo"]["hasNextPage"])
63
63
  assert_equal(false, result["data"]["rebels"]["ships"]["pageInfo"]["hasPreviousPage"])
64
- assert_equal("MQ==", result["data"]["rebels"]["ships"]["pageInfo"]["startCursor"])
65
- assert_equal("NQ==", result["data"]["rebels"]["ships"]["pageInfo"]["endCursor"])
64
+ assert_equal("MQ", result["data"]["rebels"]["ships"]["pageInfo"]["startCursor"])
65
+ assert_equal("NQ", result["data"]["rebels"]["ships"]["pageInfo"]["endCursor"])
66
66
  end
67
67
 
68
68
  it "provides bidirectional_pagination" do
@@ -166,8 +166,8 @@ describe GraphQL::Relay::ArrayConnection do
166
166
 
167
167
  assert_equal(false, result["data"]["rebels"]["ships"]["pageInfo"]["hasNextPage"])
168
168
  assert_equal(false, result["data"]["rebels"]["ships"]["pageInfo"]["hasPreviousPage"])
169
- assert_equal("MQ==", result["data"]["rebels"]["ships"]["pageInfo"]["startCursor"])
170
- assert_equal("NQ==", result["data"]["rebels"]["ships"]["pageInfo"]["endCursor"])
169
+ assert_equal("MQ", result["data"]["rebels"]["ships"]["pageInfo"]["startCursor"])
170
+ assert_equal("NQ", result["data"]["rebels"]["ships"]["pageInfo"]["endCursor"])
171
171
  assert_equal(5, result["data"]["rebels"]["ships"]["edges"].length)
172
172
  end
173
173
 
@@ -217,7 +217,7 @@ describe GraphQL::Relay::ArrayConnection do
217
217
  assert_equal(["Yavin", "Echo Base"], get_names(result))
218
218
  assert_equal(false, get_page_info(result)["hasPreviousPage"], "hasPreviousPage is false when last is not specified")
219
219
 
220
- third_cursor = "Mw=="
220
+ third_cursor = "Mw"
221
221
  first_and_second_names = ["Yavin", "Echo Base"]
222
222
  result = star_wars_query(query_string, "last" => 100, "before" => third_cursor)
223
223
  assert_equal(first_and_second_names, get_names(result))
@@ -77,11 +77,11 @@ describe GraphQL::Relay::BaseConnection do
77
77
  assert_equal "Person/1", conn.decode("1/nosreP")
78
78
  end
79
79
 
80
- it "defaults to base64" do
80
+ it "defaults to base64 (urlsafe_base64 without padding)" do
81
81
  conn = GraphQL::Relay::BaseConnection.new([], {}, context: nil)
82
82
 
83
- assert_equal "UGVyc29uLzE=", conn.encode("Person/1")
84
- assert_equal "Person/1", conn.decode("UGVyc29uLzE=")
83
+ assert_equal "UGVyc29uLzE", conn.encode("Person/1")
84
+ assert_equal "Person/1", conn.decode("UGVyc29uLzE=") # can decode with padding
85
85
  end
86
86
 
87
87
  it "handles trimmed base64" do
@@ -89,5 +89,13 @@ describe GraphQL::Relay::BaseConnection do
89
89
 
90
90
  assert_equal "Person/1", conn.decode("UGVyc29uLzE")
91
91
  end
92
+
93
+ it "raises an execution error when an invalid cursor is given" do
94
+ conn = GraphQL::Relay::BaseConnection.new([], {}, context: nil)
95
+
96
+ assert_raises(GraphQL::ExecutionError) do
97
+ conn.decode("0")
98
+ end
99
+ end
92
100
  end
93
101
  end
@@ -11,11 +11,6 @@ describe GraphQL::Relay::ConnectionInstrumentation do
11
11
  assert_equal ["tests"], test_type.fields.keys
12
12
  end
13
13
 
14
- it "keeps a reference to the function" do
15
- conn_field = StarWars::Faction.graphql_definition.fields["shipsWithMaxPageSize"]
16
- assert_instance_of StarWars::ShipsWithMaxPageSize, conn_field.function
17
- end
18
-
19
14
  let(:build_schema) {
20
15
  test_type = nil
21
16
 
@@ -58,26 +53,28 @@ describe GraphQL::Relay::ConnectionInstrumentation do
58
53
  assert_instance_of GraphQL::Relay::ConnectionResolve, redefined_connection_field.resolve_proc
59
54
  end
60
55
 
61
- describe "after_built_ins instrumentation" do
62
- it "has access to connection objects" do
63
- query_str = <<-GRAPHQL
64
- {
65
- rebels {
66
- ships {
67
- pageInfo {
68
- __typename
56
+ # field instrumentation doesn't exist here
57
+ if !TESTING_INTERPRETER
58
+ describe "after_built_ins instrumentation" do
59
+ it "has access to connection objects" do
60
+ query_str = <<-GRAPHQL
61
+ {
62
+ rebels {
63
+ ships {
64
+ pageInfo {
65
+ __typename
66
+ }
69
67
  }
70
68
  }
71
69
  }
72
- }
73
- GRAPHQL
74
- ctx = { before_built_ins: [], after_built_ins: [] }
75
- star_wars_query(query_str, {}, context: ctx)
76
- # The second item is different here:
77
- # Before the object is wrapped in a connection, the instrumentation sees `Array`
78
- assert_equal ["StarWars::FactionRecord", "Array", "GraphQL::Relay::ArrayConnection"], ctx[:before_built_ins]
79
- # After the object is wrapped in a connection, it sees the connection object
80
- assert_equal ["StarWars::Faction", "StarWars::ShipConnectionWithParentType", "GraphQL::Types::Relay::PageInfo"], ctx[:after_built_ins]
70
+ GRAPHQL
71
+ ctx = { before_built_ins: [], after_built_ins: [] }
72
+ star_wars_query(query_str, {}, context: ctx)
73
+ # These are data classes, later they're wrapped with type proxies
74
+ assert_equal ["StarWars::FactionRecord", "GraphQL::Relay::ArrayConnection", "GraphQL::Relay::ArrayConnection"], ctx[:before_built_ins]
75
+ # After the object is wrapped in a connection, it sees the connection object
76
+ assert_equal ["StarWars::Faction", "StarWars::ShipConnectionWithParentType", "GraphQL::Types::Relay::PageInfo"], ctx[:after_built_ins]
77
+ end
81
78
  end
82
79
  end
83
80
  end
@@ -53,6 +53,22 @@ describe GraphQL::Relay::ConnectionResolve do
53
53
  end
54
54
  end
55
55
 
56
+ describe "when a resolver is used" do
57
+ it "returns the items with the correct parent" do
58
+ resolver_query_str = <<-GRAPHQL
59
+ {
60
+ rebels {
61
+ shipsByResolver {
62
+ parentClassName
63
+ }
64
+ }
65
+ }
66
+ GRAPHQL
67
+ result = star_wars_query(resolver_query_str)
68
+ assert_equal "StarWars::FactionRecord", result["data"]["rebels"]["shipsByResolver"]["parentClassName"]
69
+ end
70
+ end
71
+
56
72
  describe "when nil is returned" do
57
73
  it "becomes null" do
58
74
  result = star_wars_query(query_string, { "name" => "null" })
@@ -336,4 +336,52 @@ describe GraphQL::Relay::Mutation do
336
336
  assert_equal(expected, result)
337
337
  end
338
338
  end
339
+
340
+ describe 'supports new input object definition with old mutation definition' do
341
+ let(:some_attribute_type) do
342
+ Class.new(GraphQL::Schema::InputObject) do
343
+ graphql_name 'SomeAttribute'
344
+ argument :something, String, required: false
345
+ end
346
+ end
347
+
348
+ let(:do_something_mutation) do
349
+ some_attribute = some_attribute_type
350
+
351
+ GraphQL::Relay::Mutation.define do
352
+ name 'DoSomethingMutation'
353
+ input_field :someAttributes, types[some_attribute.graphql_definition]
354
+
355
+ return_field :anything, types.String
356
+
357
+ resolve ->(_obj, inputs, _ctx) {
358
+ {
359
+ anything: inputs.to_h['someAttributes'][0].class.to_s
360
+ }
361
+ }
362
+ end
363
+ end
364
+
365
+ let(:mutation_type) do
366
+ do_something = do_something_mutation
367
+
368
+ Class.new(GraphQL::Schema::Object) do
369
+ graphql_name 'Mutation'
370
+ field :doSomething, field: do_something.field
371
+ end
372
+ end
373
+
374
+ let(:schema) do
375
+ mutation = mutation_type
376
+
377
+ Class.new(GraphQL::Schema) do
378
+ mutation mutation
379
+ end
380
+ end
381
+
382
+ it 'converts to hash the whole input' do
383
+ result = schema.execute('mutation { doSomething(input: {someAttributes: [{something: "string"}]}) { anything } }')
384
+ assert_equal 'Hash', result['data']['doSomething']['anything']
385
+ end
386
+ end
339
387
  end