@@ -3,6 +3,7 @@ package graphql.schema
33import graphql.AssertException
44import graphql.Directives
55import graphql.ExecutionInput
6+ import graphql.introspection.Introspection.DirectiveLocation
67import graphql.GraphQL
78import graphql.TestUtil
89import graphql.language.Directive
@@ -168,6 +169,83 @@ class GraphQLSchemaTest extends Specification {
168169 schema = schema. transform({ builder -> builder })
169170 then : " all 7 built-in directives are still present"
170171 schema. directives. size() == 7
172+
173+ when : " clearDirectives is called"
174+ schema = basicSchemaBuilder(). clearDirectives(). build()
175+ then : " all 7 built-in directives are still present because ensureBuiltInDirectives re-adds them"
176+ schema. directives. size() == 7
177+
178+ when : " clearDirectives is called and additional directives are added"
179+ schema = basicSchemaBuilder(). clearDirectives()
180+ .additionalDirective(GraphQLDirective . newDirective()
181+ .name(" custom" )
182+ .validLocations(DirectiveLocation . FIELD )
183+ .build())
184+ .build()
185+ then : " all 7 built-in directives are present plus the additional one"
186+ schema. directives. size() == 8
187+ schema. getDirective(" custom" ) != null
188+ }
189+
190+ def " clearDirectives supports replacing non-built-in directives in a schema transform" () {
191+ given : " a schema with a custom directive"
192+ def originalDirective = GraphQLDirective . newDirective()
193+ .name(" custom" )
194+ .description(" v1" )
195+ .validLocations(DirectiveLocation . FIELD )
196+ .build()
197+ def schema = basicSchemaBuilder()
198+ .additionalDirective(originalDirective)
199+ .build()
200+ assert schema. directives. size() == 8
201+
202+ when : " the schema is transformed to replace the custom directive"
203+ def replacementDirective = GraphQLDirective . newDirective()
204+ .name(" custom" )
205+ .description(" v2" )
206+ .validLocations(DirectiveLocation . FIELD )
207+ .build()
208+ def newSchema = schema. transform({ builder ->
209+ def nonBuiltIns = schema. getDirectives(). findAll { ! Directives . isBuiltInDirective(it) }
210+ .collect { it. getName() == " custom" ? replacementDirective : it }
211+ builder. clearDirectives()
212+ .additionalDirectives(new LinkedHashSet<> (nonBuiltIns))
213+ })
214+
215+ then : " all 7 built-in directives are still present"
216+ newSchema. directives. size() == 8
217+ newSchema. getDirective(" include" ) != null
218+ newSchema. getDirective(" skip" ) != null
219+ newSchema. getDirective(" deprecated" ) != null
220+
221+ and : " the custom directive has the updated description"
222+ newSchema. getDirective(" custom" ). description == " v2"
223+ }
224+
225+ def " clearDirectives then adding directives gives expected ordering" () {
226+ given : " a non-standard directive and a customized built-in directive"
227+ def nonStandard = GraphQLDirective . newDirective()
228+ .name(" custom" )
229+ .validLocations(DirectiveLocation . FIELD )
230+ .build()
231+ def skipWithCustomDesc = Directives.SkipDirective . transform({ b ->
232+ b. description(" custom skip description" )
233+ })
234+
235+ when : " clearDirectives is called, then the non-standard directive is added, then the customized built-in is added after it"
236+ def schema = basicSchemaBuilder()
237+ .clearDirectives()
238+ .additionalDirective(nonStandard)
239+ .additionalDirective(skipWithCustomDesc)
240+ .build()
241+
242+ then : " unoverridden built-ins come first (in BUILT_IN_DIRECTIVES order, skip excluded), then user-supplied in insertion order"
243+ def names = schema. directives. collect { it. name }
244+ names == [" include" , " deprecated" , " specifiedBy" , " oneOf" , " defer" ,
245+ " experimental_disableErrorPropagation" , " custom" , " skip" ]
246+
247+ and : " the customized skip directive retains its custom description"
248+ schema. getDirective(" skip" ). description == " custom skip description"
171249 }
172250
173251 def " clear additional types works as expected" () {
0 commit comments