graphql 1.9.4 → 1.9.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +5 -5
  2. data/lib/graphql/execution/execute.rb +3 -0
  3. data/lib/graphql/execution/interpreter/runtime.rb +2 -2
  4. data/lib/graphql/execution/lookahead.rb +57 -22
  5. data/lib/graphql/introspection/input_value_type.rb +5 -1
  6. data/lib/graphql/language/parser.rb +57 -54
  7. data/lib/graphql/language/parser.y +12 -9
  8. data/lib/graphql/language/token.rb +1 -1
  9. data/lib/graphql/language/visitor.rb +1 -1
  10. data/lib/graphql/query/arguments.rb +3 -3
  11. data/lib/graphql/query/context.rb +6 -6
  12. data/lib/graphql/query/variable_validation_error.rb +14 -0
  13. data/lib/graphql/schema.rb +2 -2
  14. data/lib/graphql/schema/argument.rb +1 -1
  15. data/lib/graphql/schema/field.rb +6 -3
  16. data/lib/graphql/schema/object.rb +2 -2
  17. data/lib/graphql/schema/relay_classic_mutation.rb +1 -1
  18. data/lib/graphql/schema/rescue_middleware.rb +7 -2
  19. data/lib/graphql/schema/validation.rb +9 -4
  20. data/lib/graphql/static_validation/base_visitor.rb +8 -5
  21. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +3 -1
  22. data/lib/graphql/tracing.rb +3 -3
  23. data/lib/graphql/types.rb +1 -0
  24. data/lib/graphql/types/json.rb +25 -0
  25. data/lib/graphql/types/relay/base_edge.rb +3 -2
  26. data/lib/graphql/unauthorized_field_error.rb +1 -1
  27. data/lib/graphql/version.rb +1 -1
  28. data/spec/dummy/Gemfile.lock +157 -0
  29. data/spec/dummy/log/test.log +199 -0
  30. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/4w/4wzXRZrAkwKdgYaSE0pid5eB-fer8vSfSku_NPg4rMA.cache +0 -0
  31. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/7I/7IHVBiJT06QSpgLpLoJIxboQ0B-D_tMTxsvoezBTV3Q.cache +1 -0
  32. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/8w/8wY_SKagj8wHuwGNAAf6JnQ8joMbC6cEYpHrTAI8Urc.cache +1 -0
  33. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/AK/AKzz1u6bGb4auXcrObA_g5LL-oV0ejNGa448AgAi_WQ.cache +1 -0
  34. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/ET/ETW4uxvaYpruL8y6_ZptUH82ZowMaHIqvg5WexBFdEM.cache +3 -0
  35. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/F1/F1TWpjjyA56k9Z90n5B3xRn7DUdGjX73QCkYC6k07JQ.cache +0 -0
  36. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/F8/F8MUNRzORGFgr329fNM0xLaoWCXdv3BIalT7dsvLfjs.cache +2 -0
  37. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/KB/KB07ZaKNC5uXJ7TjLi-WqnY6g7dq8wWp_8N3HNjBNxg.cache +2 -0
  38. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Ms/MsKSimH_UCB-H1tLvDABDHuvGciuoW6kVqQWDrXU5FQ.cache +0 -0
  39. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Mt/Mtci-Kim50aPOmeClD4AIicKn1d1WJ0n454IjSd94sk.cache +0 -0
  40. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/QH/QHt3Tc1Y6M66Oo_pDuMyWrQNs4Pp3SMeZR5K1wJj2Ts.cache +1 -0
  41. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/XU/XU4k1OXnfMils5SrirorPvDSyDSqiOWLZNtmAH1HH8k.cache +0 -0
  42. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/ZI/ZIof7mZxWWCnraIFOCuV6a8QRWzKJXJnx2Xd7C0ZyX0.cache +1 -0
  43. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/cG/cGc_puuPS5pZKgUcy1Y_i1L6jl5UtsiIrMH59rTzR6c.cache +3 -0
  44. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/df/dfro_B6bx3KP1Go-7jEOqqZ2j4hVRseXIc3es9PKQno.cache +1 -0
  45. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/jO/jO1DfbqnG0mTULsjJJANc3fefrG2zt7DIMmcptMT628.cache +1 -0
  46. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/pE/pE7gO6pQ-z187Swb4hT554wmqsq-cNzgPWLrCz-LQQQ.cache +0 -0
  47. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/r9/r9iU1l58a6rxkZSW5RSC52_tD-_UQuHxoMVnkfJ7Mhs.cache +1 -0
  48. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/xi/xitPPFfPIyDMpaznV0sBBcw8eSCV8PJcLLWin78sCgE.cache +0 -0
  49. data/spec/dummy/tmp/screenshots/failures_test_it_handles_subscriptions.png +0 -0
  50. data/spec/graphql/authorization_spec.rb +47 -14
  51. data/spec/graphql/execution/lookahead_spec.rb +29 -2
  52. data/spec/graphql/function_spec.rb +28 -5
  53. data/spec/graphql/introspection/input_value_type_spec.rb +40 -1
  54. data/spec/graphql/language/parser_spec.rb +8 -0
  55. data/spec/graphql/query/executor_spec.rb +30 -3
  56. data/spec/graphql/schema/object_spec.rb +71 -0
  57. data/spec/graphql/schema/relay_classic_mutation_spec.rb +18 -0
  58. data/spec/graphql/schema/rescue_middleware_spec.rb +14 -0
  59. data/spec/graphql/schema/warden_spec.rb +1 -1
  60. data/spec/graphql/types/relay/base_edge_spec.rb +33 -0
  61. data/spec/integration/rails/graphql/schema_spec.rb +13 -0
  62. data/spec/integration/tmp/app/graphql/types/bird_type.rb +7 -0
  63. data/spec/support/dummy/schema.rb +19 -0
  64. data/spec/support/jazz.rb +16 -14
  65. metadata +57 -7
@@ -12,7 +12,7 @@ module GraphQL
12
12
 
13
13
  def initialize(value:, name:, line:, col:, prev_token:)
14
14
  @name = name
15
- @value = value.freeze
15
+ @value = -value
16
16
  @line = line
17
17
  @col = col
18
18
  @prev_token = prev_token
@@ -24,7 +24,7 @@ module GraphQL
24
24
  # end
25
25
  #
26
26
  # # Initialize a visitor
27
- # visitor = GraphQL::Language::Visitor.new(document, "name")
27
+ # visitor = NameCounter.new(document, "name")
28
28
  # # Run it
29
29
  # visitor.visit
30
30
  # # Check the result
@@ -14,12 +14,12 @@ module GraphQL
14
14
  self.argument_definitions = argument_definitions
15
15
 
16
16
  argument_definitions.each do |_arg_name, arg_definition|
17
- expose_as = arg_definition.expose_as.to_s
18
- expose_as_underscored = GraphQL::Schema::Member::BuildType.underscore(expose_as)
17
+ expose_as = -arg_definition.expose_as.to_s
18
+ expose_as_underscored = -GraphQL::Schema::Member::BuildType.underscore(expose_as)
19
19
  method_names = [expose_as, expose_as_underscored].uniq
20
20
  method_names.each do |method_name|
21
21
  # Don't define a helper method if it would override something.
22
- if instance_methods.include?(method_name.to_sym)
22
+ if method_defined?(method_name)
23
23
  warn(
24
24
  "Unable to define a helper for argument with name '#{method_name}' "\
25
25
  "as this is a reserved name. If you're using an argument such as "\
@@ -44,11 +44,11 @@ module GraphQL
44
44
  # @api private
45
45
  def spawn_child(key:, irep_node:, object:)
46
46
  FieldResolutionContext.new(
47
- context: @context,
48
- parent: self,
49
- object: object,
50
- key: key,
51
- irep_node: irep_node,
47
+ @context,
48
+ key,
49
+ irep_node,
50
+ self,
51
+ object
52
52
  )
53
53
  end
54
54
 
@@ -203,7 +203,7 @@ module GraphQL
203
203
  attr_reader :irep_node, :field, :parent_type, :query, :schema, :parent, :key, :type
204
204
  alias :selection :irep_node
205
205
 
206
- def initialize(context:, key:, irep_node:, parent:, object:)
206
+ def initialize(context, key, irep_node, parent, object)
207
207
  @context = context
208
208
  @key = key
209
209
  @parent = parent
@@ -9,6 +9,11 @@ module GraphQL
9
9
  @validation_result = validation_result
10
10
 
11
11
  msg = "Variable #{variable_ast.name} of type #{type} was provided invalid value"
12
+
13
+ if problem_fields.any?
14
+ msg += " for #{problem_fields.join(", ")}"
15
+ end
16
+
12
17
  super(msg)
13
18
  self.ast_node = variable_ast
14
19
  end
@@ -25,6 +30,15 @@ module GraphQL
25
30
  end
26
31
  end
27
32
  end
33
+
34
+ private
35
+
36
+ def problem_fields
37
+ @problem_fields ||= @validation_result
38
+ .problems
39
+ .reject { |problem| problem["path"].empty? }
40
+ .map { |problem| "#{problem['path'].join('.')} (#{problem['explanation']})" }
41
+ end
28
42
  end
29
43
  end
30
44
  end
@@ -246,13 +246,13 @@ module GraphQL
246
246
  # Validate a query string according to this schema.
247
247
  # @param string_or_document [String, GraphQL::Language::Nodes::Document]
248
248
  # @return [Array<GraphQL::StaticValidation::Error >]
249
- def validate(string_or_document, rules: nil)
249
+ def validate(string_or_document, rules: nil, context: nil)
250
250
  doc = if string_or_document.is_a?(String)
251
251
  GraphQL.parse(string_or_document)
252
252
  else
253
253
  string_or_document
254
254
  end
255
- query = GraphQL::Query.new(self, document: doc)
255
+ query = GraphQL::Query.new(self, document: doc, context: context)
256
256
  validator_opts = { schema: self }
257
257
  rules && (validator_opts[:rules] = rules)
258
258
  validator = GraphQL::StaticValidation::Validator.new(validator_opts)
@@ -32,7 +32,7 @@ module GraphQL
32
32
  # @param camelize [Boolean] if true, the name will be camelized when building the schema
33
33
  def initialize(arg_name = nil, type_expr = nil, desc = nil, required:, type: nil, name: nil, description: nil, default_value: NO_DEFAULT, as: nil, camelize: true, prepare: nil, owner:, &definition_block)
34
34
  arg_name ||= name
35
- @name = camelize ? Member::BuildType.camelize(arg_name.to_s) : arg_name.to_s
35
+ @name = -(camelize ? Member::BuildType.camelize(arg_name.to_s) : arg_name.to_s)
36
36
  @type_expr = type_expr || type
37
37
  @description = desc || description
38
38
  @null = !required
@@ -130,7 +130,7 @@ module GraphQL
130
130
  # The default was overridden
131
131
  @scope
132
132
  else
133
- @return_type_expr.is_a?(Array) || (@return_type_expr.is_a?(String) && @return_type_expr.include?("[")) || connection?
133
+ @return_type_expr && (@return_type_expr.is_a?(Array) || (@return_type_expr.is_a?(String) && @return_type_expr.include?("[")) || connection?)
134
134
  end
135
135
  end
136
136
 
@@ -173,8 +173,8 @@ module GraphQL
173
173
  raise ArgumentError, "keyword `extras:` may only be used with method-based resolve and class-based field such as mutation class, please remove `field:`, `function:` or `resolve:`"
174
174
  end
175
175
  @original_name = name
176
- @underscored_name = Member::BuildType.underscore(name.to_s)
177
- @name = camelize ? Member::BuildType.camelize(name.to_s) : name.to_s
176
+ @underscored_name = -Member::BuildType.underscore(name.to_s)
177
+ @name = -(camelize ? Member::BuildType.camelize(name.to_s) : name.to_s)
178
178
  @description = description
179
179
  if field.is_a?(GraphQL::Schema::Field)
180
180
  raise ArgumentError, "Instead of passing a field as `field:`, use `add_field(field)` to add an already-defined field."
@@ -504,6 +504,9 @@ module GraphQL
504
504
  err = GraphQL::UnauthorizedFieldError.new(object: application_object, type: object.class, context: ctx, field: self)
505
505
  ctx.schema.unauthorized_field(err)
506
506
  end
507
+ rescue GraphQL::UnauthorizedFieldError => err
508
+ err.field ||= self
509
+ ctx.schema.unauthorized_field(err)
507
510
  rescue GraphQL::UnauthorizedError => err
508
511
  ctx.schema.unauthorized_object(err)
509
512
  end
@@ -37,8 +37,8 @@ module GraphQL
37
37
  def authorized_new(object, context)
38
38
  auth_val = begin
39
39
  authorized?(object, context)
40
- # rescue GraphQL::UnauthorizedError => err
41
- # context.schema.unauthorized_object(err)
40
+ rescue GraphQL::UnauthorizedError => err
41
+ context.schema.unauthorized_object(err)
42
42
  end
43
43
 
44
44
  context.schema.after_lazy(auth_val) do |is_authorized|
@@ -32,7 +32,7 @@ module GraphQL
32
32
  # Without the interpreter, the inputs are unwrapped by an instrumenter.
33
33
  # But when using the interpreter, no instrumenters are applied.
34
34
  if context.interpreter?
35
- input = inputs[:input].to_h
35
+ input = inputs[:input].to_kwargs
36
36
  # Transfer these from the top-level hash to the
37
37
  # shortcutted `input:` object
38
38
  self.class.extras.each do |ext|
@@ -43,8 +43,13 @@ module GraphQL
43
43
  def attempt_rescue(err)
44
44
  rescue_table.each { |klass, handler|
45
45
  if klass.is_a?(Class) && err.is_a?(klass) && handler
46
- message = handler.call(err)
47
- return GraphQL::ExecutionError.new(message)
46
+ result = handler.call(err)
47
+ case result
48
+ when String
49
+ return GraphQL::ExecutionError.new(result)
50
+ when GraphQL::ExecutionError
51
+ return result
52
+ end
48
53
  end
49
54
  }
50
55
 
@@ -12,11 +12,16 @@ module GraphQL
12
12
  # @param object [Object] something to be validated
13
13
  # @return [String, Nil] error message, if there was one
14
14
  def self.validate(object)
15
- rules = RULES.reduce([]) do |memo, (parent_class, validations)|
16
- memo + (object.is_a?(parent_class) ? validations : [])
15
+ RULES.each do |parent_class, validations|
16
+ if object.is_a?(parent_class)
17
+ validations.each do |rule|
18
+ if error = rule.call(object)
19
+ return error
20
+ end
21
+ end
22
+ end
17
23
  end
18
- # Stops after the first error
19
- rules.reduce(nil) { |memo, rule| memo || rule.call(object) }
24
+ nil
20
25
  end
21
26
 
22
27
  module Rules
@@ -146,11 +146,14 @@ module GraphQL
146
146
  end
147
147
 
148
148
  def on_input_object(node, parent)
149
- is_list = @argument_definitions.last&.type&.list? == true
150
-
151
- @path.push(parent.children.index(node)) if is_list
152
- super
153
- @path.pop if is_list
149
+ arg_defn = @argument_definitions.last
150
+ if arg_defn && arg_defn.type.list?
151
+ @path.push(parent.children.index(node))
152
+ super
153
+ @path.pop
154
+ else
155
+ super
156
+ end
154
157
  end
155
158
 
156
159
  # @return [GraphQL::BaseType] The current object type
@@ -26,7 +26,9 @@ module GraphQL
26
26
  # variables = ensure_hash(data["variables"])
27
27
  # operation_name = data["operationName"]
28
28
  # context = {
29
- # current_user: current_user,
29
+ # # Re-implement whatever context methods you need
30
+ # # in this channel or ApplicationCable::Channel
31
+ # # current_user: current_user,
30
32
  # # Make sure the channel is in the context
31
33
  # channel: self,
32
34
  # }
@@ -42,12 +42,12 @@ module GraphQL
42
42
  # execute_multiplex | `{ multiplex: GraphQL::Execution::Multiplex }`
43
43
  # execute_query | `{ query: GraphQL::Query }`
44
44
  # execute_query_lazy | `{ query: GraphQL::Query?, multiplex: GraphQL::Execution::Multiplex? }`
45
- # execute_field | `{ context: GraphQL::Query::Context::FieldResolutionContext?, owner: Class?, field: GraphQL::Schema::Field?, path: Array<String, Integer>?}`
46
- # execute_field_lazy | `{ context: GraphQL::Query::Context::FieldResolutionContext?, owner: Class?, field: GraphQL::Schema::Field?, path: Array<String, Integer>?}`
45
+ # execute_field | `{ context: GraphQL::Query::Context::FieldResolutionContext?, owner: Class?, field: GraphQL::Schema::Field?, query: GraphQL::Query?, path: Array<String, Integer>?}`
46
+ # execute_field_lazy | `{ context: GraphQL::Query::Context::FieldResolutionContext?, owner: Class?, field: GraphQL::Schema::Field?, query: GraphqL::Query?, path: Array<String, Integer>?}`
47
47
  #
48
48
  # Note that `execute_field` and `execute_field_lazy` receive different data in different settings:
49
49
  #
50
- # - When using {GraphQL::Execution::Interpreter}, they receive `{field:, path:}`
50
+ # - When using {GraphQL::Execution::Interpreter}, they receive `{field:, path:, query:}`
51
51
  # - Otherwise, they receive `{context: ...}`
52
52
  #
53
53
  module Tracing
@@ -5,5 +5,6 @@ require "graphql/types/float"
5
5
  require "graphql/types/id"
6
6
  require "graphql/types/int"
7
7
  require "graphql/types/iso_8601_date_time"
8
+ require "graphql/types/json"
8
9
  require "graphql/types/string"
9
10
  require "graphql/types/relay"
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module Types
4
+ # An untyped JSON scalar that maps to Ruby hashes, arrays, strings, integers, floats, booleans and nils.
5
+ # This should be used judiciously because it subverts the GraphQL type system.
6
+ #
7
+ # Use it for fields or arguments as follows:
8
+ #
9
+ # field :template_parameters, GraphQL::Types::JSON, null: false
10
+ #
11
+ # argument :template_parameters, GraphQL::Types::JSON, null: false
12
+ #
13
+ class JSON < GraphQL::Schema::Scalar
14
+ description "Represents untyped JSON"
15
+
16
+ def self.coerce_input(value, _context)
17
+ value
18
+ end
19
+
20
+ def self.coerce_result(value, _context)
21
+ value
22
+ end
23
+ end
24
+ end
25
+ end
@@ -28,14 +28,15 @@ module GraphQL
28
28
  # Get or set the Object type that this edge wraps.
29
29
  #
30
30
  # @param node_type [Class] A `Schema::Object` subclass
31
- def node_type(node_type = nil)
31
+ # @param null [Boolean]
32
+ def node_type(node_type = nil, null: true)
32
33
  if node_type
33
34
  @node_type = node_type
34
35
  wrapped_type_name = node_type.graphql_name
35
36
  # Set this to be named like the node type, but suffixed with `Edge`
36
37
  graphql_name("#{wrapped_type_name}Edge")
37
38
  # Add a default `node` field
38
- field :node, node_type, null: true, description: "The item at the end of the edge."
39
+ field :node, node_type, null: null, description: "The item at the end of the edge."
39
40
  end
40
41
  @node_type
41
42
  end
@@ -2,7 +2,7 @@
2
2
  module GraphQL
3
3
  class UnauthorizedFieldError < GraphQL::UnauthorizedError
4
4
  # @return [Field] the field that failed the authorization check
5
- attr_reader :field
5
+ attr_accessor :field
6
6
 
7
7
  def initialize(message = nil, object: nil, type: nil, context: nil, field: nil)
8
8
  if message.nil? && [field, type].any?(&:nil?)
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- VERSION = "1.9.4"
3
+ VERSION = "1.9.5"
4
4
  end
@@ -0,0 +1,157 @@
1
+ PATH
2
+ remote: /Users/rmosolgo/code/graphql-ruby
3
+ specs:
4
+ graphql (1.9.0.pre2)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ actioncable (5.2.1)
10
+ actionpack (= 5.2.1)
11
+ nio4r (~> 2.0)
12
+ websocket-driver (>= 0.6.1)
13
+ actionmailer (5.2.1)
14
+ actionpack (= 5.2.1)
15
+ actionview (= 5.2.1)
16
+ activejob (= 5.2.1)
17
+ mail (~> 2.5, >= 2.5.4)
18
+ rails-dom-testing (~> 2.0)
19
+ actionpack (5.2.1)
20
+ actionview (= 5.2.1)
21
+ activesupport (= 5.2.1)
22
+ rack (~> 2.0)
23
+ rack-test (>= 0.6.3)
24
+ rails-dom-testing (~> 2.0)
25
+ rails-html-sanitizer (~> 1.0, >= 1.0.2)
26
+ actionview (5.2.1)
27
+ activesupport (= 5.2.1)
28
+ builder (~> 3.1)
29
+ erubi (~> 1.4)
30
+ rails-dom-testing (~> 2.0)
31
+ rails-html-sanitizer (~> 1.0, >= 1.0.3)
32
+ activejob (5.2.1)
33
+ activesupport (= 5.2.1)
34
+ globalid (>= 0.3.6)
35
+ activemodel (5.2.1)
36
+ activesupport (= 5.2.1)
37
+ activerecord (5.2.1)
38
+ activemodel (= 5.2.1)
39
+ activesupport (= 5.2.1)
40
+ arel (>= 9.0)
41
+ activestorage (5.2.1)
42
+ actionpack (= 5.2.1)
43
+ activerecord (= 5.2.1)
44
+ marcel (~> 0.3.1)
45
+ activesupport (5.2.1)
46
+ concurrent-ruby (~> 1.0, >= 1.0.2)
47
+ i18n (>= 0.7, < 2)
48
+ minitest (~> 5.1)
49
+ tzinfo (~> 1.1)
50
+ addressable (2.5.2)
51
+ public_suffix (>= 2.0.2, < 4.0)
52
+ arel (9.0.0)
53
+ builder (3.2.3)
54
+ capybara (3.7.2)
55
+ addressable
56
+ mini_mime (>= 0.1.3)
57
+ nokogiri (~> 1.8)
58
+ rack (>= 1.6.0)
59
+ rack-test (>= 0.6.3)
60
+ xpath (~> 3.1)
61
+ childprocess (0.9.0)
62
+ ffi (~> 1.0, >= 1.0.11)
63
+ concurrent-ruby (1.0.5)
64
+ crass (1.0.4)
65
+ erubi (1.7.1)
66
+ ffi (1.9.25)
67
+ globalid (0.4.1)
68
+ activesupport (>= 4.2.0)
69
+ i18n (1.1.0)
70
+ concurrent-ruby (~> 1.0)
71
+ listen (3.1.5)
72
+ rb-fsevent (~> 0.9, >= 0.9.4)
73
+ rb-inotify (~> 0.9, >= 0.9.7)
74
+ ruby_dep (~> 1.2)
75
+ loofah (2.2.2)
76
+ crass (~> 1.0.2)
77
+ nokogiri (>= 1.5.9)
78
+ mail (2.7.0)
79
+ mini_mime (>= 0.1.1)
80
+ marcel (0.3.3)
81
+ mimemagic (~> 0.3.2)
82
+ method_source (0.9.0)
83
+ mimemagic (0.3.2)
84
+ mini_mime (1.0.1)
85
+ mini_portile2 (2.3.0)
86
+ minitest (5.11.3)
87
+ nio4r (2.3.1)
88
+ nokogiri (1.8.4)
89
+ mini_portile2 (~> 2.3.0)
90
+ public_suffix (3.0.3)
91
+ puma (3.12.0)
92
+ rack (2.0.5)
93
+ rack-test (1.1.0)
94
+ rack (>= 1.0, < 3)
95
+ rails (5.2.1)
96
+ actioncable (= 5.2.1)
97
+ actionmailer (= 5.2.1)
98
+ actionpack (= 5.2.1)
99
+ actionview (= 5.2.1)
100
+ activejob (= 5.2.1)
101
+ activemodel (= 5.2.1)
102
+ activerecord (= 5.2.1)
103
+ activestorage (= 5.2.1)
104
+ activesupport (= 5.2.1)
105
+ bundler (>= 1.3.0)
106
+ railties (= 5.2.1)
107
+ sprockets-rails (>= 2.0.0)
108
+ rails-dom-testing (2.0.3)
109
+ activesupport (>= 4.2.0)
110
+ nokogiri (>= 1.6)
111
+ rails-html-sanitizer (1.0.4)
112
+ loofah (~> 2.2, >= 2.2.2)
113
+ railties (5.2.1)
114
+ actionpack (= 5.2.1)
115
+ activesupport (= 5.2.1)
116
+ method_source
117
+ rake (>= 0.8.7)
118
+ thor (>= 0.19.0, < 2.0)
119
+ rake (12.3.1)
120
+ rb-fsevent (0.10.3)
121
+ rb-inotify (0.9.10)
122
+ ffi (>= 0.5.0, < 2)
123
+ ruby_dep (1.5.0)
124
+ rubyzip (1.2.2)
125
+ selenium-webdriver (3.14.0)
126
+ childprocess (~> 0.5)
127
+ rubyzip (~> 1.2)
128
+ sprockets (3.7.2)
129
+ concurrent-ruby (~> 1.0)
130
+ rack (> 1, < 3)
131
+ sprockets-rails (3.2.1)
132
+ actionpack (>= 4.0)
133
+ activesupport (>= 4.0)
134
+ sprockets (>= 3.0.0)
135
+ thor (0.20.0)
136
+ thread_safe (0.3.6)
137
+ tzinfo (1.2.5)
138
+ thread_safe (~> 0.1)
139
+ websocket-driver (0.7.0)
140
+ websocket-extensions (>= 0.1.0)
141
+ websocket-extensions (0.1.3)
142
+ xpath (3.1.0)
143
+ nokogiri (~> 1.8)
144
+
145
+ PLATFORMS
146
+ ruby
147
+
148
+ DEPENDENCIES
149
+ capybara
150
+ graphql!
151
+ listen
152
+ puma
153
+ rails (~> 5.2.1)
154
+ selenium-webdriver
155
+
156
+ BUNDLED WITH
157
+ 2.0.1