graphql 1.4.5 → 1.5.3

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 (139) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/enum_generator.rb +33 -0
  3. data/lib/generators/graphql/function_generator.rb +15 -0
  4. data/lib/generators/graphql/install_generator.rb +118 -0
  5. data/lib/generators/graphql/interface_generator.rb +27 -0
  6. data/lib/generators/graphql/loader_generator.rb +17 -0
  7. data/lib/generators/graphql/mutation_generator.rb +19 -0
  8. data/lib/generators/graphql/object_generator.rb +34 -0
  9. data/lib/generators/graphql/templates/enum.erb +4 -0
  10. data/lib/generators/graphql/templates/function.erb +17 -0
  11. data/lib/generators/graphql/templates/graphql_controller.erb +32 -0
  12. data/lib/generators/graphql/templates/interface.erb +4 -0
  13. data/lib/generators/graphql/templates/loader.erb +15 -0
  14. data/lib/generators/graphql/templates/mutation.erb +12 -0
  15. data/lib/generators/graphql/templates/object.erb +5 -0
  16. data/lib/generators/graphql/templates/query_type.erb +15 -0
  17. data/lib/generators/graphql/templates/schema.erb +34 -0
  18. data/lib/generators/graphql/templates/union.erb +4 -0
  19. data/lib/generators/graphql/type_generator.rb +78 -0
  20. data/lib/generators/graphql/union_generator.rb +33 -0
  21. data/lib/graphql.rb +10 -0
  22. data/lib/graphql/analysis/analyze_query.rb +1 -1
  23. data/lib/graphql/analysis/query_complexity.rb +6 -50
  24. data/lib/graphql/analysis/query_depth.rb +1 -1
  25. data/lib/graphql/argument.rb +21 -0
  26. data/lib/graphql/compatibility/execution_specification/counter_schema.rb +3 -3
  27. data/lib/graphql/define.rb +1 -0
  28. data/lib/graphql/define/assign_argument.rb +3 -19
  29. data/lib/graphql/define/assign_mutation_function.rb +34 -0
  30. data/lib/graphql/define/assign_object_field.rb +26 -14
  31. data/lib/graphql/define/defined_object_proxy.rb +21 -0
  32. data/lib/graphql/define/instance_definable.rb +61 -11
  33. data/lib/graphql/directive.rb +6 -1
  34. data/lib/graphql/execution/directive_checks.rb +1 -0
  35. data/lib/graphql/execution/execute.rb +14 -9
  36. data/lib/graphql/execution/field_result.rb +1 -0
  37. data/lib/graphql/execution/lazy.rb +8 -17
  38. data/lib/graphql/execution/lazy/lazy_method_map.rb +2 -0
  39. data/lib/graphql/execution/lazy/resolve.rb +1 -0
  40. data/lib/graphql/execution/selection_result.rb +1 -0
  41. data/lib/graphql/execution/typecast.rb +39 -26
  42. data/lib/graphql/field.rb +15 -3
  43. data/lib/graphql/field/resolve.rb +3 -3
  44. data/lib/graphql/function.rb +134 -0
  45. data/lib/graphql/id_type.rb +1 -1
  46. data/lib/graphql/input_object_type.rb +1 -1
  47. data/lib/graphql/internal_representation.rb +1 -1
  48. data/lib/graphql/internal_representation/node.rb +35 -107
  49. data/lib/graphql/internal_representation/rewrite.rb +189 -183
  50. data/lib/graphql/internal_representation/visit.rb +38 -0
  51. data/lib/graphql/introspection/input_value_type.rb +10 -1
  52. data/lib/graphql/introspection/schema_type.rb +1 -1
  53. data/lib/graphql/language/lexer.rb +6 -3
  54. data/lib/graphql/language/lexer.rl +6 -3
  55. data/lib/graphql/object_type.rb +53 -13
  56. data/lib/graphql/query.rb +30 -14
  57. data/lib/graphql/query/arguments.rb +2 -0
  58. data/lib/graphql/query/context.rb +2 -2
  59. data/lib/graphql/query/literal_input.rb +9 -0
  60. data/lib/graphql/query/serial_execution/field_resolution.rb +2 -2
  61. data/lib/graphql/query/serial_execution/selection_resolution.rb +1 -1
  62. data/lib/graphql/relay.rb +1 -0
  63. data/lib/graphql/relay/array_connection.rb +1 -1
  64. data/lib/graphql/relay/base_connection.rb +34 -15
  65. data/lib/graphql/relay/connection_resolve.rb +7 -2
  66. data/lib/graphql/relay/mutation.rb +45 -4
  67. data/lib/graphql/relay/node.rb +18 -6
  68. data/lib/graphql/relay/range_add.rb +45 -0
  69. data/lib/graphql/relay/relation_connection.rb +17 -2
  70. data/lib/graphql/runtime_type_error.rb +1 -0
  71. data/lib/graphql/schema.rb +40 -5
  72. data/lib/graphql/schema/base_64_encoder.rb +1 -0
  73. data/lib/graphql/schema/build_from_definition.rb +56 -21
  74. data/lib/graphql/schema/default_parse_error.rb +10 -0
  75. data/lib/graphql/schema/loader.rb +8 -1
  76. data/lib/graphql/schema/null_mask.rb +1 -0
  77. data/lib/graphql/schema/validation.rb +35 -0
  78. data/lib/graphql/static_validation.rb +1 -0
  79. data/lib/graphql/static_validation/all_rules.rb +1 -0
  80. data/lib/graphql/static_validation/arguments_validator.rb +7 -4
  81. data/lib/graphql/static_validation/definition_dependencies.rb +183 -0
  82. data/lib/graphql/static_validation/rules/fields_will_merge.rb +28 -96
  83. data/lib/graphql/static_validation/rules/fragment_names_are_unique.rb +23 -0
  84. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +8 -5
  85. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +6 -31
  86. data/lib/graphql/static_validation/rules/fragments_are_used.rb +11 -41
  87. data/lib/graphql/static_validation/rules/operation_names_are_valid.rb +2 -2
  88. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +19 -7
  89. data/lib/graphql/static_validation/validation_context.rb +22 -1
  90. data/lib/graphql/static_validation/validator.rb +4 -1
  91. data/lib/graphql/string_type.rb +5 -1
  92. data/lib/graphql/version.rb +1 -1
  93. data/readme.md +12 -3
  94. data/spec/generators/graphql/enum_generator_spec.rb +29 -0
  95. data/spec/generators/graphql/function_generator_spec.rb +33 -0
  96. data/spec/generators/graphql/install_generator_spec.rb +185 -0
  97. data/spec/generators/graphql/interface_generator_spec.rb +32 -0
  98. data/spec/generators/graphql/loader_generator_spec.rb +31 -0
  99. data/spec/generators/graphql/mutation_generator_spec.rb +28 -0
  100. data/spec/generators/graphql/object_generator_spec.rb +42 -0
  101. data/spec/generators/graphql/union_generator_spec.rb +50 -0
  102. data/spec/graphql/analysis/query_complexity_spec.rb +2 -1
  103. data/spec/graphql/define/instance_definable_spec.rb +38 -0
  104. data/spec/graphql/directive/skip_directive_spec.rb +1 -0
  105. data/spec/graphql/directive_spec.rb +18 -0
  106. data/spec/graphql/execution/typecast_spec.rb +41 -46
  107. data/spec/graphql/field_spec.rb +1 -1
  108. data/spec/graphql/function_spec.rb +128 -0
  109. data/spec/graphql/internal_representation/rewrite_spec.rb +166 -129
  110. data/spec/graphql/introspection/type_type_spec.rb +1 -1
  111. data/spec/graphql/language/lexer_spec.rb +6 -0
  112. data/spec/graphql/object_type_spec.rb +73 -2
  113. data/spec/graphql/query/arguments_spec.rb +28 -0
  114. data/spec/graphql/query/variables_spec.rb +7 -1
  115. data/spec/graphql/query_spec.rb +30 -0
  116. data/spec/graphql/relay/base_connection_spec.rb +26 -8
  117. data/spec/graphql/relay/connection_resolve_spec.rb +45 -0
  118. data/spec/graphql/relay/connection_type_spec.rb +21 -0
  119. data/spec/graphql/relay/node_spec.rb +30 -2
  120. data/spec/graphql/relay/range_add_spec.rb +113 -0
  121. data/spec/graphql/schema/build_from_definition_spec.rb +114 -0
  122. data/spec/graphql/schema/loader_spec.rb +1 -0
  123. data/spec/graphql/schema/printer_spec.rb +2 -2
  124. data/spec/graphql/schema/validation_spec.rb +80 -11
  125. data/spec/graphql/schema/warden_spec.rb +10 -10
  126. data/spec/graphql/schema_spec.rb +18 -1
  127. data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +16 -0
  128. data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +50 -3
  129. data/spec/graphql/static_validation/rules/fragment_names_are_unique_spec.rb +27 -0
  130. data/spec/graphql/static_validation/rules/fragments_are_finite_spec.rb +57 -0
  131. data/spec/graphql/static_validation/rules/fragments_are_used_spec.rb +1 -1
  132. data/spec/graphql/static_validation/rules/variables_are_input_types_spec.rb +14 -0
  133. data/spec/graphql/string_type_spec.rb +7 -0
  134. data/spec/spec_helper.rb +3 -3
  135. data/spec/support/base_generator_test.rb +7 -0
  136. data/spec/support/dummy/schema.rb +32 -30
  137. data/spec/support/star_wars/schema.rb +81 -23
  138. metadata +98 -20
  139. data/lib/graphql/internal_representation/selection.rb +0 -85
@@ -2,162 +2,196 @@
2
2
  require "spec_helper"
3
3
 
4
4
  describe GraphQL::InternalRepresentation::Rewrite do
5
- let(:validator) { GraphQL::StaticValidation::Validator.new(schema: Dummy::Schema) }
6
- let(:query) { GraphQL::Query.new(Dummy::Schema, query_string) }
7
- let(:rewrite_result) {
8
- validator.validate(query)[:irep]
9
- }
10
- describe "plain queries" do
11
- let(:query_string) {%|
12
- query getCheeses {
13
- cheese1: cheese(id: 1) {
14
- id1: id
15
- id2: id
16
- id3: id
17
- }
18
- cheese2: cheese(id: 2) {
19
- id
20
- }
5
+ let(:schema) {
6
+ GraphQL::Schema.from_definition <<-GRAPHQL
7
+ type Query {
8
+ plant(id: ID!): Plant
21
9
  }
22
- |}
23
10
 
24
- it "produces a tree of nodes" do
25
- op_node = rewrite_result["getCheeses"]
26
-
27
- root_children = op_node.typed_children[Dummy::DairyAppQueryType]
28
- assert_equal 2, root_children.length
29
- assert_equal Dummy::DairyAppQueryType, op_node.return_type
30
- first_field = root_children.values.first
31
- assert_equal 3, first_field.typed_children[Dummy::CheeseType].length
32
- assert_equal Dummy::DairyAppQueryType, first_field.owner_type
33
- assert_equal Dummy::CheeseType, first_field.return_type
34
-
35
- second_field = root_children.values.last
36
- assert_equal 1, second_field.typed_children[Dummy::CheeseType].length
37
- assert_equal Dummy::DairyAppQueryType.get_field("cheese"), second_field.definition
38
- assert_equal Dummy::CheeseType, second_field.return_type
39
- assert second_field.inspect.is_a?(String)
40
- end
41
- end
11
+ union Plant = Grain | Fruit | Vegetable | Nut
42
12
 
43
- describe "dynamic fields" do
44
- let(:query_string) {%|
45
- {
46
- cheese(id: 1) {
47
- typename: __typename
48
- }
49
- }
50
- |}
13
+ interface Tree {
14
+ name: String!
15
+ leafType: LeafType
16
+ habitats: [Habitat]
17
+ }
51
18
 
52
- it "gets dynamic field definitions" do
53
- cheese_field = rewrite_result[nil].typed_children[Dummy::DairyAppQueryType]["cheese"]
54
- typename_field = cheese_field.typed_children[Dummy::CheeseType]["typename"]
55
- assert_equal "__typename", typename_field.definition.name
56
- assert_equal "__typename", typename_field.definition_name
57
- end
58
- end
19
+ enum LeafType {
20
+ NEEDLE
21
+ LEAF
22
+ }
59
23
 
60
- describe "merging fragments" do
61
- let(:query_string) {%|
62
- {
63
- cheese(id: 1) {
64
- id1: id
65
- ... {
66
- id2: id
67
- }
24
+ type Fruit implements Tree {
25
+ name: String!
26
+ color: [Int!]!
27
+ leafType: LeafType
28
+ habitats: [Habitat]
29
+ }
68
30
 
69
- fatContent
70
- ... on Edible {
71
- fatContent
72
- origin
73
- }
31
+ type Vegetable {
32
+ name: String!
33
+ edibleParts: [String!]!
34
+ }
74
35
 
75
- ... cheeseFields
36
+ type Grain {
37
+ name: String!
38
+ }
76
39
 
77
- ... similarCheeseField
78
- }
40
+ type Nut implements Tree {
41
+ name: String!
42
+ diameter: Int!
43
+ leafType: LeafType
44
+ habitats: [Habitat]
45
+ }
79
46
 
80
- cheese2: cheese(id: 2) {
81
- similarCheese(source: COW) {
82
- id
83
- }
84
- ... cheese2Fields
85
- }
47
+ type Habitat {
48
+ residentName: String!
49
+ averageWeight: Int!
50
+ seasons: [String]
86
51
  }
52
+ GRAPHQL
87
53
 
88
- fragment cheeseFields on Cheese {
89
- fatContent
90
- flavor
91
- similarCow: similarCheese(source: COW) {
92
- similarCowSource: source,
93
- id
94
- ... similarCowFields
54
+ }
55
+ let(:validator) { GraphQL::StaticValidation::Validator.new(schema: schema) }
56
+ let(:query) { GraphQL::Query.new(schema, query_string) }
57
+ let(:rewrite_result) {
58
+ res = validator.validate(query)
59
+ res[:errors].any? && raise(res[:errors].map(&:message).join("; "))
60
+ res[:irep]
61
+ }
62
+ # TODO: make sure all rewrite specs are covered
63
+
64
+ describe "building a tree over concrete types with fragments" do
65
+ let(:query_string) {
66
+ <<-GRAPHQL
67
+ query getPlant($id: ID!) {
68
+ plant(id: $id) {
69
+ __typename
70
+ ... on Tree {
71
+ leafType
72
+ habitats {
73
+ averageWeight
74
+ }
75
+ }
76
+ ... on Fruit {
77
+ name
78
+ color
79
+ ... on Tree {
80
+ leafType
81
+ }
82
+ }
83
+ ... on Nut {
84
+ leafType
85
+ ...NutFields
86
+ }
87
+ }
95
88
  }
96
- }
97
89
 
98
- fragment similarCowFields on Cheese {
99
- similarCheese(source: SHEEP) {
100
- source
90
+ fragment NutFields on Nut {
91
+ leafType
92
+ ... TreeFields
101
93
  }
102
- }
103
94
 
104
- fragment similarCheeseField on Cheese {
105
- # deep fragment merge
106
- similarCow: similarCheese(source: COW) {
107
- similarCowSource: source,
108
- fatContent
109
- similarCheese(source: SHEEP) {
110
- flavor
95
+ fragment TreeFields on Tree {
96
+ habitats {
97
+ ... HabitatFields
111
98
  }
112
99
  }
113
- }
114
-
115
- fragment cheese2InnerFields on Cheese {
116
- id
117
- fatContent
118
- }
119
100
 
120
- fragment cheese2Fields on Cheese {
121
- similarCheese(source: COW) {
122
- ... cheese2InnerFields
101
+ fragment HabitatFields on Habitat {
102
+ seasons
123
103
  }
104
+ GRAPHQL
124
105
  }
125
106
 
126
- |}
107
+ it "groups selections by object types which they apply to" do
108
+ doc = rewrite_result["getPlant"]
109
+
110
+ plant_selection = doc.typed_children[schema.types["Query"]]["plant"]
111
+ assert_equal ["Fruit", "Grain", "Nut", "Vegetable"], plant_selection.typed_children.keys.map(&:name).sort
112
+
113
+ fruit_selections = plant_selection.typed_children[schema.types["Fruit"]]
114
+ assert_equal ["__typename", "color", "habitats", "leafType", "name"], fruit_selections.keys.sort
115
+ assert_equal 2, fruit_selections["leafType"].ast_nodes.size
116
+
117
+ nut_selections = plant_selection.typed_children[schema.types["Nut"]]
118
+ # `... on Tree`, `... on Nut`, and `NutFields`, but not `... on Fruit { ... on Tree }`
119
+ assert_equal 3, nut_selections["leafType"].ast_nodes.size
120
+ # Multi-level merging when including fragments:
121
+ habitats_selections = nut_selections["habitats"].typed_children[schema.types["Habitat"]]
122
+ assert_equal ["averageWeight", "seasons"], habitats_selections.keys
123
+ end
124
+ end
125
+
126
+ describe "tracking directives on fragment spreads" do
127
+ let(:query_string) { <<-GRAPHQL
128
+ query getPlant($id: ID!) {
129
+ plant(id: $id) {
130
+ ... on Nut @skip(if: true) {
131
+ leafType
132
+ }
133
+
134
+ ... on Tree {
135
+ leafType @include(if: true)
136
+ }
127
137
 
128
- it "puts all fragment members as children" do
129
- op_node = rewrite_result[nil]
138
+ ... on Nut {
139
+ leafType # no directives
140
+ }
130
141
 
131
- cheese_field = op_node.typed_children[Dummy::DairyAppQueryType]["cheese"]
132
- assert_equal ["id1", "id2", "fatContent", "similarCow", "flavor"], cheese_field.typed_children[Dummy::CheeseType].keys
133
- assert_equal ["fatContent", "origin"], cheese_field.typed_children[Dummy::EdibleInterface].keys
134
- # Merge:
135
- similar_cow_field = cheese_field.typed_children[Dummy::CheeseType]["similarCow"]
136
- assert_equal ["similarCowSource", "fatContent", "similarCheese", "id"], similar_cow_field.typed_children[Dummy::CheeseType].keys
137
- # Deep merge:
138
- similar_sheep_field = similar_cow_field.typed_children[Dummy::CheeseType]["similarCheese"]
139
- assert_equal ["flavor", "source"], similar_sheep_field.typed_children[Dummy::CheeseType].keys
142
+ ... NutFields @include(if: false)
143
+ }
144
+ }
145
+ fragment NutFields on Nut {
146
+ leafType @skip(if: false)
147
+ }
148
+ GRAPHQL
149
+ }
140
150
 
141
- edible_origin_node = cheese_field.typed_children[Dummy::EdibleInterface]["origin"]
142
- assert_equal Dummy::EdibleInterface.get_field("origin"), edible_origin_node.definition
143
- assert_equal Dummy::EdibleInterface, edible_origin_node.owner_type
151
+ it "applies directives from all contexts" do
152
+ doc = rewrite_result["getPlant"]
153
+ plant_selection = doc.typed_children[schema.types["Query"]]["plant"]
154
+ leaf_type_selection = plant_selection.typed_children[schema.types["Nut"]]["leafType"]
155
+ # Only unskipped occurrences in the AST
156
+ assert_equal 2, leaf_type_selection.ast_nodes.size
157
+ end
158
+ end
144
159
 
145
- edible_fat_content_node = cheese_field.typed_children[Dummy::EdibleInterface]["fatContent"]
146
- assert_equal Dummy::EdibleInterface.get_field("fatContent"), edible_fat_content_node.definition
147
- assert_equal Dummy::EdibleInterface, edible_fat_content_node.owner_type
160
+ describe "deep fragment merging" do
161
+ let(:query_string) { <<-GRAPHQL
162
+ {
163
+ plant(id: 1) {
164
+ ...TreeFields
165
+ ...NutFields
166
+ }
167
+ }
148
168
 
149
- cheese_fat_content_node = cheese_field.typed_children[Dummy::CheeseType]["fatContent"]
150
- assert_equal Dummy::CheeseType.get_field("fatContent"), cheese_fat_content_node.definition
151
- assert_equal Dummy::CheeseType, cheese_fat_content_node.owner_type
169
+ fragment TreeFields on Tree {
170
+ habitats {
171
+ seasons
172
+ }
173
+ }
152
174
 
153
- cheese_flavor_node = cheese_field.typed_children[Dummy::CheeseType]["flavor"]
154
- assert_equal Dummy::CheeseType.get_field("flavor"), cheese_flavor_node.definition
155
- assert_equal Dummy::CheeseType, cheese_flavor_node.owner_type
175
+ fragment NutFields on Nut {
176
+ habitats {
177
+ residentName
178
+ ... HabitatFields
179
+ }
180
+ }
156
181
 
182
+ fragment HabitatFields on Habitat {
183
+ averageWeight
184
+ }
185
+ GRAPHQL
186
+ }
157
187
 
158
- # nested spread inside fragment definition:
159
- cheese_2_field = op_node.typed_children[Dummy::DairyAppQueryType]["cheese2"].typed_children[Dummy::CheeseType]["similarCheese"]
160
- assert_equal ["id", "fatContent"], cheese_2_field.typed_children[Dummy::CheeseType].keys
188
+ it "applies spreads to their parents only" do
189
+ doc = rewrite_result[nil]
190
+ plant_selection = doc.typed_children[schema.types["Query"]]["plant"]
191
+ nut_habitat_selections = plant_selection.typed_children[schema.types["Nut"]]["habitats"].typed_children[schema.types["Habitat"]]
192
+ assert_equal ["averageWeight", "residentName", "seasons"], nut_habitat_selections.keys.sort
193
+ fruit_habitat_selections = plant_selection.typed_children[schema.types["Fruit"]]["habitats"].typed_children[schema.types["Habitat"]]
194
+ assert_equal ["seasons"], fruit_habitat_selections.keys
161
195
  end
162
196
  end
163
197
 
@@ -219,11 +253,14 @@ describe GraphQL::InternalRepresentation::Rewrite do
219
253
  assert_equal 3, cheeses.length
220
254
  assert_equal 1, milks.length
221
255
 
256
+ expected_cheese_fields = ["cheeseInlineOrigin", "edibleInlineOrigin", "untypedInlineOrigin", "cheeseFragmentOrigin"]
222
257
  cheeses.each do |cheese|
223
- assert_equal ["cheeseInlineOrigin", "cheeseFragmentOrigin", "edibleInlineOrigin", "untypedInlineOrigin"], cheese["selfAsEdible"].keys
258
+ assert_equal expected_cheese_fields, cheese["selfAsEdible"].keys
224
259
  end
260
+
261
+ expected_milk_fields = ["milkInlineOrigin", "edibleInlineOrigin", "untypedInlineOrigin", "milkFragmentOrigin"]
225
262
  milks.each do |milk|
226
- assert_equal ["milkInlineOrigin", "milkFragmentOrigin", "edibleInlineOrigin", "untypedInlineOrigin"], milk["selfAsEdible"].keys
263
+ assert_equal expected_milk_fields, milk["selfAsEdible"].keys
227
264
  end
228
265
  end
229
266
  end
@@ -52,7 +52,7 @@ describe GraphQL::Introspection::TypeType do
52
52
  {"type"=>{"kind"=>"NON_NULL","name"=>nil, "ofType"=>{"name"=>"ID"}}},
53
53
  {"type"=>{"kind"=>"NON_NULL","name"=>nil, "ofType"=>{"name"=>"String"}}},
54
54
  {"type"=>{"kind"=>"INTERFACE", "name"=>"Edible", "ofType"=>nil}},
55
- {"type"=>{"kind"=>"ENUM","name"=>"DairyAnimal", "ofType"=>nil}},
55
+ {"type"=>{"kind"=>"NON_NULL","name"=>nil,"ofType"=>{"name"=>"DairyAnimal"}}},
56
56
  ]
57
57
  },
58
58
  "dairyAnimal"=>{
@@ -16,6 +16,12 @@ describe GraphQL::Language::Lexer do
16
16
  |}
17
17
  let(:tokens) { subject.tokenize(query_string) }
18
18
 
19
+ it "makes utf-8 comments" do
20
+ tokens = subject.tokenize("# 不要!\n{")
21
+ comment_token = tokens.first.prev_token
22
+ assert_equal "# 不要!", comment_token.to_s
23
+ end
24
+
19
25
  it "keeps track of previous_token" do
20
26
  assert_equal tokens[0], tokens[1].prev_token
21
27
  end
@@ -15,8 +15,19 @@ describe GraphQL::ObjectType do
15
15
  assert_equal(22, type.description.length)
16
16
  end
17
17
 
18
- it "may have interfaces" do
19
- assert_equal([Dummy::EdibleInterface, Dummy::AnimalProductInterface, Dummy::LocalProductInterface], type.interfaces)
18
+ describe "interfaces" do
19
+ it "may have interfaces" do
20
+ assert_equal([Dummy::EdibleInterface, Dummy::AnimalProductInterface, Dummy::LocalProductInterface], type.interfaces)
21
+ end
22
+
23
+ it "raises if the interfaces arent an array" do
24
+ type = GraphQL::ObjectType.define do
25
+ name "InvalidInterfaces"
26
+ interfaces(55)
27
+ end
28
+
29
+ assert_raises(ArgumentError) { type.name }
30
+ end
20
31
  end
21
32
 
22
33
  it "accepts fields definition" do
@@ -25,6 +36,66 @@ describe GraphQL::ObjectType do
25
36
  assert_equal([last_produced_dairy], cow_type.fields)
26
37
  end
27
38
 
39
+ describe "#implements" do
40
+ it "adds an interface" do
41
+ type = GraphQL::ObjectType.define do
42
+ name 'Hello'
43
+ implements Dummy::EdibleInterface
44
+ implements Dummy::AnimalProductInterface
45
+
46
+ field :hello, types.String
47
+ end
48
+
49
+ assert_equal([Dummy::EdibleInterface, Dummy::AnimalProductInterface], type.interfaces)
50
+ end
51
+
52
+ it "adds many interfaces" do
53
+ type = GraphQL::ObjectType.define do
54
+ name 'Hello'
55
+ implements Dummy::EdibleInterface, Dummy::AnimalProductInterface
56
+
57
+ field :hello, types.String
58
+ end
59
+
60
+ assert_equal([Dummy::EdibleInterface, Dummy::AnimalProductInterface], type.interfaces)
61
+ end
62
+
63
+ it "preserves existing interfaces and appends a new one" do
64
+ type = GraphQL::ObjectType.define do
65
+ name 'Hello'
66
+ interfaces [Dummy::EdibleInterface]
67
+ implements Dummy::AnimalProductInterface
68
+
69
+ field :hello, types.String
70
+ end
71
+
72
+ assert_equal([Dummy::EdibleInterface, Dummy::AnimalProductInterface], type.interfaces)
73
+ end
74
+
75
+ it "can be used to inherit fields from the interface" do
76
+ type_1 = GraphQL::ObjectType.define do
77
+ name 'Hello'
78
+ implements Dummy::EdibleInterface
79
+ implements Dummy::AnimalProductInterface
80
+ end
81
+
82
+ type_2 = GraphQL::ObjectType.define do
83
+ name 'Hello'
84
+ implements Dummy::EdibleInterface
85
+ implements Dummy::AnimalProductInterface, inherit: true
86
+ end
87
+
88
+ type_3 = GraphQL::ObjectType.define do
89
+ name 'Hello'
90
+ implements Dummy::EdibleInterface, Dummy::AnimalProductInterface, inherit: true
91
+ end
92
+
93
+ assert_equal [], type_1.all_fields.map(&:name)
94
+ assert_equal ["source"], type_2.all_fields.map(&:name)
95
+ assert_equal ["fatContent", "origin", "selfAsEdible", "source"], type_3.all_fields.map(&:name)
96
+ end
97
+ end
98
+
28
99
  describe '#get_field' do
29
100
  it "exposes fields" do
30
101
  field = type.get_field("id")