graphql 1.4.5 → 1.5.3

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