graphql 0.18.14 → 0.18.15

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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql/analysis/query_complexity.rb +15 -6
  3. data/lib/graphql/analysis/query_depth.rb +11 -10
  4. data/lib/graphql/directive.rb +2 -6
  5. data/lib/graphql/directive/include_directive.rb +0 -4
  6. data/lib/graphql/directive/skip_directive.rb +0 -4
  7. data/lib/graphql/execution/directive_checks.rb +22 -13
  8. data/lib/graphql/execution_error.rb +7 -0
  9. data/lib/graphql/internal_representation/node.rb +20 -2
  10. data/lib/graphql/internal_representation/rewrite.rb +66 -20
  11. data/lib/graphql/language/generation.rb +22 -8
  12. data/lib/graphql/language/nodes.rb +48 -20
  13. data/lib/graphql/language/parser.rb +436 -423
  14. data/lib/graphql/language/parser.y +22 -19
  15. data/lib/graphql/language/parser_tests.rb +131 -2
  16. data/lib/graphql/query/serial_execution/field_resolution.rb +1 -0
  17. data/lib/graphql/query/serial_execution/selection_resolution.rb +1 -1
  18. data/lib/graphql/query/serial_execution/value_resolution.rb +4 -1
  19. data/lib/graphql/schema/printer.rb +1 -1
  20. data/lib/graphql/static_validation/message.rb +1 -1
  21. data/lib/graphql/version.rb +1 -1
  22. data/readme.md +10 -12
  23. data/spec/graphql/directive_spec.rb +139 -1
  24. data/spec/graphql/execution_error_spec.rb +63 -3
  25. data/spec/graphql/introspection/type_type_spec.rb +2 -0
  26. data/spec/graphql/language/generation_spec.rb +55 -7
  27. data/spec/graphql/query/executor_spec.rb +4 -2
  28. data/spec/graphql/schema/catchall_middleware_spec.rb +1 -0
  29. data/spec/graphql/schema/printer_spec.rb +1 -1
  30. data/spec/graphql/schema/timeout_middleware_spec.rb +10 -5
  31. data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +6 -6
  32. data/spec/graphql/static_validation/rules/arguments_are_defined_spec.rb +4 -4
  33. data/spec/graphql/static_validation/rules/directives_are_defined_spec.rb +2 -2
  34. data/spec/graphql/static_validation/rules/directives_are_in_valid_locations_spec.rb +2 -2
  35. data/spec/graphql/static_validation/rules/fields_are_defined_on_type_spec.rb +3 -3
  36. data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +2 -2
  37. data/spec/graphql/static_validation/rules/fragment_spreads_are_possible_spec.rb +3 -3
  38. data/spec/graphql/static_validation/rules/fragment_types_exist_spec.rb +2 -2
  39. data/spec/graphql/static_validation/rules/fragments_are_finite_spec.rb +2 -2
  40. data/spec/graphql/static_validation/rules/fragments_are_named_spec.rb +1 -1
  41. data/spec/graphql/static_validation/rules/fragments_are_on_composite_types_spec.rb +3 -3
  42. data/spec/graphql/static_validation/rules/fragments_are_used_spec.rb +2 -2
  43. data/spec/graphql/static_validation/rules/mutation_root_exists_spec.rb +1 -1
  44. data/spec/graphql/static_validation/rules/required_arguments_are_present_spec.rb +3 -3
  45. data/spec/graphql/static_validation/rules/subscription_root_exists_spec.rb +1 -1
  46. data/spec/graphql/static_validation/rules/variable_default_values_are_correctly_typed_spec.rb +4 -4
  47. data/spec/graphql/static_validation/rules/variable_usages_are_allowed_spec.rb +4 -4
  48. data/spec/graphql/static_validation/rules/variables_are_input_types_spec.rb +3 -3
  49. data/spec/graphql/static_validation/rules/variables_are_used_and_defined_spec.rb +3 -3
  50. data/spec/graphql/static_validation/validator_spec.rb +1 -1
  51. data/spec/support/dairy_app.rb +8 -0
  52. metadata +30 -2
@@ -18,6 +18,28 @@ describe GraphQL::ExecutionError do
18
18
  }
19
19
  flavor
20
20
  }
21
+ allDairy {
22
+ ... on Cheese {
23
+ flavor
24
+ }
25
+ ... on Milk {
26
+ source
27
+ executionError
28
+ }
29
+ }
30
+ dairy {
31
+ milks {
32
+ source
33
+ executionError
34
+ allDairy {
35
+ __typename
36
+ ... on Milk {
37
+ origin
38
+ executionError
39
+ }
40
+ }
41
+ }
42
+ }
21
43
  executionError
22
44
  }
23
45
 
@@ -38,20 +60,58 @@ describe GraphQL::ExecutionError do
38
60
  },
39
61
  "flavor" => "Brie",
40
62
  },
63
+ "allDairy" => [
64
+ { "flavor" => "Brie" },
65
+ { "flavor" => "Gouda" },
66
+ { "flavor" => "Manchego" },
67
+ { "source" => "COW", "executionError" => nil }
68
+ ],
69
+ "dairy" => {
70
+ "milks" => [
71
+ {
72
+ "source" => "COW",
73
+ "executionError" => nil,
74
+ "allDairy" => [
75
+ { "__typename" => "Cheese" },
76
+ { "__typename" => "Cheese" },
77
+ { "__typename" => "Cheese" },
78
+ { "__typename" => "Milk", "origin" => "Antiquity", "executionError" => nil }
79
+ ]
80
+ }
81
+ ]
82
+ },
41
83
  "executionError" => nil,
42
84
  },
43
85
  "errors"=>[
44
86
  {
45
87
  "message"=>"No cheeses are made from Yak milk!",
46
- "locations"=>[{"line"=>5, "column"=>9}]
88
+ "locations"=>[{"line"=>5, "column"=>9}],
89
+ "path"=>["cheese", "error1"]
47
90
  },
48
91
  {
49
92
  "message"=>"No cheeses are made from Yak milk!",
50
- "locations"=>[{"line"=>8, "column"=>9}]
93
+ "locations"=>[{"line"=>8, "column"=>9}],
94
+ "path"=>["cheese", "error2"]
95
+ },
96
+ {
97
+ "message"=>"There was an execution error",
98
+ "locations"=>[{"line"=>22, "column"=>11}],
99
+ "path"=>["allDairy", 3, "executionError"]
100
+ },
101
+ {
102
+ "message"=>"There was an execution error",
103
+ "locations"=>[{"line"=>28, "column"=>11}],
104
+ "path"=>["dairy", "milks", 0, "executionError"]
105
+ },
106
+ {
107
+ "message"=>"There was an execution error",
108
+ "locations"=>[{"line"=>33, "column"=>15}],
109
+ "path"=>["dairy", "milks", 0, "allDairy", 3, "executionError"]
51
110
  },
52
111
  {
53
112
  "message"=>"There was an execution error",
54
- "locations"=>[{"line"=>16, "column"=>7}]
113
+ "locations"=>[{"line"=>38, "column"=>7}],
114
+ "path"=>["executionError"]
55
115
  },
56
116
  ]
57
117
  }
@@ -41,6 +41,8 @@ describe GraphQL::Introspection::TypeType do
41
41
  {"name"=>"LocalProduct"},
42
42
  ],
43
43
  "fields"=>[
44
+ {"type"=>{"name"=>"List", "ofType"=>{"name"=>"DairyProduct"}}},
45
+ {"type"=>{"name"=>"String", "ofType"=>nil}},
44
46
  {"type"=>{"name"=>"Non-Null", "ofType"=>{"name"=>"Float"}}},
45
47
  {"type"=>{"name"=>"List", "ofType"=>{"name"=>"String"}}},
46
48
  {"type"=>{"name"=>"Non-Null", "ofType"=>{"name"=>"ID"}}},
@@ -10,7 +10,7 @@ describe GraphQL::Language::Generation do
10
10
  ...moreNestedFields @skip(if: $skipNested)
11
11
  }
12
12
  ... on OtherType @include(unless: false) {
13
- field(arg: [{ key: "value", anotherKey: 0.9, anotherAnotherKey: WHATEVER }])
13
+ field(arg: [{key: "value", anotherKey: 0.9, anotherAnotherKey: WHATEVER}])
14
14
  anotherField
15
15
  }
16
16
  ... {
@@ -31,7 +31,7 @@ describe GraphQL::Language::Generation do
31
31
  describe "inputs" do
32
32
  let(:query_string) {%|
33
33
  query {
34
- field(int: 3, float: 4.7e-24, bool: false, string: "☀︎🏆\\n escaped \\" unicode ¶ /", enum: ENUM_NAME, array: [7, 8, 9], object: { a: [1, 2, 3], b: { c: "4" } }, unicode_bom: "\xef\xbb\xbfquery")
34
+ field(int: 3, float: 4.7e-24, bool: false, string: "☀︎🏆\\n escaped \\" unicode ¶ /", enum: ENUM_NAME, array: [7, 8, 9], object: {a: [1, 2, 3], b: {c: "4"}}, unicode_bom: "\xef\xbb\xbfquery")
35
35
  }
36
36
  |}
37
37
 
@@ -41,15 +41,63 @@ describe GraphQL::Language::Generation do
41
41
  end
42
42
 
43
43
  describe "schema" do
44
- let(:query_string) {%|
44
+ # From: https://github.com/graphql/graphql-js/blob/a725499b155285c2e33647a93393c82689b20b0f/src/language/__tests__/schema-kitchen-sink.graphql
45
+ let(:query_string) {<<-schema
45
46
  schema {
46
- query: Query
47
+ query: QueryType
48
+ mutation: MutationType
47
49
  }
48
50
 
49
- type Query {
50
- field: String!
51
+ type Foo implements Bar {
52
+ one: Type
53
+ two(argument: InputType!): Type
54
+ three(argument: InputType, other: String): Int
55
+ four(argument: String = "string"): String
56
+ five(argument: [String] = ["string", "string"]): String
57
+ six(argument: InputType = {key: "value"}): Type
51
58
  }
52
- |}
59
+
60
+ type AnnotatedObject @onObject(arg: "value") {
61
+ annotatedField(arg: Type = "default" @onArg): Type @onField
62
+ }
63
+
64
+ interface Bar {
65
+ one: Type
66
+ four(argument: String = "string"): String
67
+ }
68
+
69
+ interface AnnotatedInterface @onInterface {
70
+ annotatedField(arg: Type @onArg): Type @onField
71
+ }
72
+
73
+ union Feed = Story | Article | Advert
74
+
75
+ union AnnotatedUnion @onUnion = A | B
76
+
77
+ scalar CustomScalar
78
+
79
+ scalar AnnotatedScalar @onScalar
80
+
81
+ enum Site {
82
+ DESKTOP
83
+ MOBILE
84
+ }
85
+
86
+ enum AnnotatedEnum @onEnum {
87
+ ANNOTATED_VALUE @onEnumValue
88
+ OTHER_VALUE
89
+ }
90
+
91
+ input InputType {
92
+ key: String!
93
+ answer: Int = 42
94
+ }
95
+
96
+ input AnnotatedInput @onInputObjectType {
97
+ annotatedField: Type @onField
98
+ }
99
+ schema
100
+ }
53
101
 
54
102
  it "generate" do
55
103
  assert_equal query_string.gsub(/^ /, "").strip, document.to_query_string
@@ -143,7 +143,8 @@ describe GraphQL::Query::Executor do
143
143
  "errors" => [
144
144
  {
145
145
  "message" => "BOOM",
146
- "locations" => [ { "line" => 1, "column" => 28 } ]
146
+ "locations" => [ { "line" => 1, "column" => 28 } ],
147
+ "path" => ["noMilk", "cow", "cantBeNullButRaisesExecutionError"]
147
148
  }
148
149
  ]
149
150
  }
@@ -167,7 +168,8 @@ describe GraphQL::Query::Executor do
167
168
  "errors"=>[
168
169
  {
169
170
  "message"=>"Error was handled!",
170
- "locations" => [{"line"=>1, "column"=>17}]
171
+ "locations" => [{"line"=>1, "column"=>17}],
172
+ "path"=>["noMilk", "error"]
171
173
  }
172
174
  ]
173
175
  }
@@ -22,6 +22,7 @@ describe GraphQL::Schema::CatchallMiddleware do
22
22
  {
23
23
  "message"=>"Internal error",
24
24
  "locations"=>[{"line"=>1, "column"=>17}],
25
+ "path"=>["noMilk", "error"]
25
26
  },
26
27
  ]
27
28
  }
@@ -176,7 +176,7 @@ type Post {
176
176
  }
177
177
 
178
178
  type Query {
179
- post(id: ID!, varied: Varied = { id: \"123\", int: 234, float: 2.3, enum: FOO, sub: [{ string: \"str\" }] }): Post
179
+ post(id: ID!, varied: Varied = {id: \"123\", int: 234, float: 2.3, enum: FOO, sub: [{string: \"str\"}]}): Post
180
180
  }
181
181
 
182
182
  input Sub {
@@ -64,11 +64,13 @@ describe GraphQL::Schema::TimeoutMiddleware do
64
64
  expected_errors = [
65
65
  {
66
66
  "message"=>"Timeout on Query.sleepFor",
67
- "locations"=>[{"line"=>6, "column"=>9}]
67
+ "locations"=>[{"line"=>6, "column"=>9}],
68
+ "path"=>["d"]
68
69
  },
69
70
  {
70
71
  "message"=>"Timeout on Query.sleepFor",
71
- "locations"=>[{"line"=>7, "column"=>9}]
72
+ "locations"=>[{"line"=>7, "column"=>9}],
73
+ "path"=>["e"]
72
74
  },
73
75
  ]
74
76
  assert_equal expected_data, result["data"]
@@ -116,11 +118,13 @@ describe GraphQL::Schema::TimeoutMiddleware do
116
118
  expected_errors = [
117
119
  {
118
120
  "message"=>"Timeout on NestedSleep.seconds",
119
- "locations"=>[{"line"=>10, "column"=>15}]
121
+ "locations"=>[{"line"=>10, "column"=>15}],
122
+ "path"=>["a", "b", "c", "d", "seconds"]
120
123
  },
121
124
  {
122
125
  "message"=>"Timeout on NestedSleep.nestedSleep",
123
- "locations"=>[{"line"=>11, "column"=>15}]
126
+ "locations"=>[{"line"=>11, "column"=>15}],
127
+ "path"=>["a", "b", "c", "d", "e"]
124
128
  },
125
129
  ]
126
130
 
@@ -149,7 +153,8 @@ describe GraphQL::Schema::TimeoutMiddleware do
149
153
  expected_errors = [
150
154
  {
151
155
  "message"=>"Timeout on Query.sleepFor",
152
- "locations"=>[{"line"=>6, "column"=>9}]
156
+ "locations"=>[{"line"=>6, "column"=>9}],
157
+ "path"=>["d"]
153
158
  },
154
159
  ]
155
160
 
@@ -27,42 +27,42 @@ describe GraphQL::StaticValidation::ArgumentLiteralsAreCompatible do
27
27
  query_root_error = {
28
28
  "message"=>"Argument 'id' on Field 'cheese' has an invalid value. Expected type 'Int!'.",
29
29
  "locations"=>[{"line"=>3, "column"=>7}],
30
- "path"=>["query getCheese", "cheese", "id"],
30
+ "fields"=>["query getCheese", "cheese", "id"],
31
31
  }
32
32
  assert_includes(errors, query_root_error)
33
33
 
34
34
  directive_error = {
35
35
  "message"=>"Argument 'if' on Directive 'skip' has an invalid value. Expected type 'Boolean!'.",
36
36
  "locations"=>[{"line"=>4, "column"=>30}],
37
- "path"=>["query getCheese", "cheese", "source", "if"],
37
+ "fields"=>["query getCheese", "cheese", "source", "if"],
38
38
  }
39
39
  assert_includes(errors, directive_error)
40
40
 
41
41
  input_object_error = {
42
42
  "message"=>"Argument 'product' on Field 'badSource' has an invalid value. Expected type '[DairyProductInput]'.",
43
43
  "locations"=>[{"line"=>6, "column"=>7}],
44
- "path"=>["query getCheese", "badSource", "product"],
44
+ "fields"=>["query getCheese", "badSource", "product"],
45
45
  }
46
46
  assert_includes(errors, input_object_error)
47
47
 
48
48
  input_object_field_error = {
49
49
  "message"=>"Argument 'source' on InputObject 'DairyProductInput' has an invalid value. Expected type 'DairyAnimal!'.",
50
50
  "locations"=>[{"line"=>6, "column"=>40}],
51
- "path"=>["query getCheese", "badSource", "product", "source"],
51
+ "fields"=>["query getCheese", "badSource", "product", "source"],
52
52
  }
53
53
  assert_includes(errors, input_object_field_error)
54
54
 
55
55
  missing_required_field_error = {
56
56
  "message"=>"Argument 'product' on Field 'missingSource' has an invalid value. Expected type '[DairyProductInput]'.",
57
57
  "locations"=>[{"line"=>7, "column"=>7}],
58
- "path"=>["query getCheese", "missingSource", "product"],
58
+ "fields"=>["query getCheese", "missingSource", "product"],
59
59
  }
60
60
  assert_includes(errors, missing_required_field_error)
61
61
 
62
62
  fragment_error = {
63
63
  "message"=>"Argument 'source' on Field 'similarCheese' has an invalid value. Expected type '[DairyAnimal!]!'.",
64
64
  "locations"=>[{"line"=>13, "column"=>7}],
65
- "path"=>["fragment cheeseFields", "similarCheese", "source"],
65
+ "fields"=>["fragment cheeseFields", "similarCheese", "source"],
66
66
  }
67
67
  assert_includes(errors, fragment_error)
68
68
  end
@@ -24,28 +24,28 @@ describe GraphQL::StaticValidation::ArgumentsAreDefined do
24
24
  query_root_error = {
25
25
  "message"=>"Field 'cheese' doesn't accept argument 'silly'",
26
26
  "locations"=>[{"line"=>4, "column"=>7}],
27
- "path"=>["query getCheese", "cheese", "silly"],
27
+ "fields"=>["query getCheese", "cheese", "silly"],
28
28
  }
29
29
  assert_includes(errors, query_root_error)
30
30
 
31
31
  input_obj_record = {
32
32
  "message"=>"InputObject 'DairyProductInput' doesn't accept argument 'wacky'",
33
33
  "locations"=>[{"line"=>5, "column"=>29}],
34
- "path"=>["query getCheese", "searchDairy", "product", "wacky"],
34
+ "fields"=>["query getCheese", "searchDairy", "product", "wacky"],
35
35
  }
36
36
  assert_includes(errors, input_obj_record)
37
37
 
38
38
  fragment_error = {
39
39
  "message"=>"Field 'similarCheese' doesn't accept argument 'nonsense'",
40
40
  "locations"=>[{"line"=>9, "column"=>7}],
41
- "path"=>["fragment cheeseFields", "similarCheese", "nonsense"],
41
+ "fields"=>["fragment cheeseFields", "similarCheese", "nonsense"],
42
42
  }
43
43
  assert_includes(errors, fragment_error)
44
44
 
45
45
  directive_error = {
46
46
  "message"=>"Directive 'skip' doesn't accept argument 'something'",
47
47
  "locations"=>[{"line"=>10, "column"=>10}],
48
- "path"=>["fragment cheeseFields", "id", "something"],
48
+ "fields"=>["fragment cheeseFields", "id", "something"],
49
49
  }
50
50
  assert_includes(errors, directive_error)
51
51
  end
@@ -23,11 +23,11 @@ describe GraphQL::StaticValidation::DirectivesAreDefined do
23
23
  {
24
24
  "message"=>"Directive @nonsense is not defined",
25
25
  "locations"=>[{"line"=>5, "column"=>16}],
26
- "path"=>["query getCheese", "okCheese", "source"],
26
+ "fields"=>["query getCheese", "okCheese", "source"],
27
27
  }, {
28
28
  "message"=>"Directive @moreNonsense is not defined",
29
29
  "locations"=>[{"line"=>7, "column"=>18}],
30
- "path"=>["query getCheese", "okCheese", "... on Cheese", "flavor"],
30
+ "fields"=>["query getCheese", "okCheese", "... on Cheese", "flavor"],
31
31
  }
32
32
  ]
33
33
  assert_equal(expected, errors)
@@ -27,12 +27,12 @@ describe GraphQL::StaticValidation::DirectivesAreInValidLocations do
27
27
  {
28
28
  "message"=> "'@skip' can't be applied to queries (allowed: fields, fragment spreads, inline fragments)",
29
29
  "locations"=>[{"line"=>2, "column"=>21}],
30
- "path"=>["query getCheese"],
30
+ "fields"=>["query getCheese"],
31
31
  },
32
32
  {
33
33
  "message"=>"'@skip' can't be applied to fragment definitions (allowed: fields, fragment spreads, inline fragments)",
34
34
  "locations"=>[{"line"=>12, "column"=>33}],
35
- "path"=>["fragment whatever"],
35
+ "fields"=>["fragment whatever"],
36
36
  },
37
37
  ]
38
38
  assert_equal(expected, errors)
@@ -34,7 +34,7 @@ describe GraphQL::StaticValidation::FieldsAreDefinedOnType do
34
34
  {
35
35
  "message"=>"Field 'notDefinedField' doesn't exist on type 'Query'",
36
36
  "locations"=>[{"line"=>1, "column"=>18}],
37
- "path"=>["query getStuff", "notDefinedField"],
37
+ "fields"=>["query getStuff", "notDefinedField"],
38
38
  }
39
39
  ]
40
40
  assert_equal(expected_errors, errors)
@@ -49,7 +49,7 @@ describe GraphQL::StaticValidation::FieldsAreDefinedOnType do
49
49
  {
50
50
  "message"=>"Field 'amountThatILikeIt' doesn't exist on type 'Edible'",
51
51
  "locations"=>[{"line"=>1, "column"=>35}],
52
- "path"=>["query getStuff", "favoriteEdible", "amountThatILikeIt"],
52
+ "fields"=>["query getStuff", "favoriteEdible", "amountThatILikeIt"],
53
53
  }
54
54
  ]
55
55
  assert_equal(expected_errors, errors)
@@ -71,7 +71,7 @@ describe GraphQL::StaticValidation::FieldsAreDefinedOnType do
71
71
  "locations"=>[
72
72
  {"line"=>3, "column"=>7}
73
73
  ],
74
- "path"=>["fragment dbFields", "source"],
74
+ "fields"=>["fragment dbFields", "source"],
75
75
  }
76
76
  ]
77
77
  assert_equal(expected_errors, errors)
@@ -19,14 +19,14 @@ describe GraphQL::StaticValidation::FieldsHaveAppropriateSelections do
19
19
  illegal_selection_error = {
20
20
  "message"=>"Selections can't be made on scalars (field 'id' returns Int but has selections [something, someFields])",
21
21
  "locations"=>[{"line"=>5, "column"=>47}],
22
- "path"=>["query getCheese", "illegalSelectionCheese", "id"],
22
+ "fields"=>["query getCheese", "illegalSelectionCheese", "id"],
23
23
  }
24
24
  assert_includes(errors, illegal_selection_error, "finds illegal selections on scalarss")
25
25
 
26
26
  selection_required_error = {
27
27
  "message"=>"Objects must have selections (field 'cheese' returns Cheese but has no selections)",
28
28
  "locations"=>[{"line"=>4, "column"=>7}],
29
- "path"=>["query getCheese", "missingFieldsCheese"],
29
+ "fields"=>["query getCheese", "missingFieldsCheese"],
30
30
  }
31
31
  assert_includes(errors, selection_required_error, "finds objects without selections")
32
32
  end
@@ -32,17 +32,17 @@ describe GraphQL::StaticValidation::FragmentSpreadsArePossible do
32
32
  {
33
33
  "message"=>"Fragment on Milk can't be spread inside Cheese",
34
34
  "locations"=>[{"line"=>6, "column"=>9}],
35
- "path"=>["query getCheese", "cheese", "... on Milk"],
35
+ "fields"=>["query getCheese", "cheese", "... on Milk"],
36
36
  },
37
37
  {
38
38
  "message"=>"Fragment milkFields on Milk can't be spread inside Cheese",
39
39
  "locations"=>[{"line"=>4, "column"=>9}],
40
- "path"=>["query getCheese", "cheese", "... milkFields"],
40
+ "fields"=>["query getCheese", "cheese", "... milkFields"],
41
41
  },
42
42
  {
43
43
  "message"=>"Fragment milkFields on Milk can't be spread inside Cheese",
44
44
  "locations"=>[{"line"=>18, "column"=>7}],
45
- "path"=>["fragment cheeseFields", "... milkFields"],
45
+ "fields"=>["fragment cheeseFields", "... milkFields"],
46
46
  }
47
47
  ]
48
48
  assert_equal(expected, errors)