github.com/operandinc/gqlgen@v0.16.1/codegen/testserver/followschema/directive_test.go (about) 1 package followschema 2 3 import ( 4 "context" 5 "fmt" 6 "testing" 7 8 "github.com/operandinc/gqlgen/client" 9 "github.com/operandinc/gqlgen/graphql" 10 "github.com/operandinc/gqlgen/graphql/handler" 11 "github.com/stretchr/testify/require" 12 ) 13 14 type ckey string 15 16 func TestDirectives(t *testing.T) { 17 resolvers := &Stub{} 18 ok := "Ok" 19 resolvers.QueryResolver.DirectiveArg = func(ctx context.Context, arg string) (i *string, e error) { 20 return &ok, nil 21 } 22 23 resolvers.QueryResolver.DirectiveInput = func(ctx context.Context, arg InputDirectives) (i *string, e error) { 24 return &ok, nil 25 } 26 27 resolvers.QueryResolver.DirectiveInputNullable = func(ctx context.Context, arg *InputDirectives) (i *string, e error) { 28 return &ok, nil 29 } 30 31 resolvers.QueryResolver.DirectiveNullableArg = func(ctx context.Context, arg *int, arg2 *int, arg3 *string) (*string, error) { 32 return &ok, nil 33 } 34 35 resolvers.QueryResolver.DirectiveInputType = func(ctx context.Context, arg InnerInput) (i *string, e error) { 36 return &ok, nil 37 } 38 39 resolvers.QueryResolver.DirectiveObject = func(ctx context.Context) (*ObjectDirectives, error) { 40 return &ObjectDirectives{ 41 Text: ok, 42 NullableText: &ok, 43 }, nil 44 } 45 46 resolvers.QueryResolver.DirectiveObjectWithCustomGoModel = func(ctx context.Context) (*ObjectDirectivesWithCustomGoModel, error) { 47 return &ObjectDirectivesWithCustomGoModel{ 48 NullableText: ok, 49 }, nil 50 } 51 52 resolvers.QueryResolver.DirectiveField = func(ctx context.Context) (*string, error) { 53 if s, ok := ctx.Value(ckey("request_id")).(*string); ok { 54 return s, nil 55 } 56 57 return nil, nil 58 } 59 60 resolvers.QueryResolver.DirectiveDouble = func(ctx context.Context) (*string, error) { 61 return &ok, nil 62 } 63 64 resolvers.QueryResolver.DirectiveUnimplemented = func(ctx context.Context) (*string, error) { 65 return &ok, nil 66 } 67 68 okchan := func() (<-chan *string, error) { 69 res := make(chan *string, 1) 70 res <- &ok 71 close(res) 72 return res, nil 73 } 74 75 resolvers.SubscriptionResolver.DirectiveArg = func(ctx context.Context, arg string) (strings <-chan *string, e error) { 76 return okchan() 77 } 78 79 resolvers.SubscriptionResolver.DirectiveNullableArg = func(ctx context.Context, arg *int, arg2 *int, arg3 *string) (strings <-chan *string, e error) { 80 return okchan() 81 } 82 83 resolvers.SubscriptionResolver.DirectiveDouble = func(ctx context.Context) (strings <-chan *string, e error) { 84 return okchan() 85 } 86 87 resolvers.SubscriptionResolver.DirectiveUnimplemented = func(ctx context.Context) (<-chan *string, error) { 88 return okchan() 89 } 90 srv := handler.NewDefaultServer(NewExecutableSchema(Config{ 91 Resolvers: resolvers, 92 Directives: DirectiveRoot{ 93 Length: func(ctx context.Context, obj interface{}, next graphql.Resolver, min int, max *int, message *string) (interface{}, error) { 94 e := func(msg string) error { 95 if message == nil { 96 return fmt.Errorf(msg) 97 } 98 return fmt.Errorf(*message) 99 } 100 res, err := next(ctx) 101 if err != nil { 102 return nil, err 103 } 104 105 s := res.(string) 106 if len(s) < min { 107 return nil, e("too short") 108 } 109 if max != nil && len(s) > *max { 110 return nil, e("too long") 111 } 112 return res, nil 113 }, 114 Range: func(ctx context.Context, obj interface{}, next graphql.Resolver, min *int, max *int) (interface{}, error) { 115 res, err := next(ctx) 116 if err != nil { 117 return nil, err 118 } 119 120 switch res := res.(type) { 121 case int: 122 if min != nil && res < *min { 123 return nil, fmt.Errorf("too small") 124 } 125 if max != nil && res > *max { 126 return nil, fmt.Errorf("too large") 127 } 128 return next(ctx) 129 130 case int64: 131 if min != nil && int(res) < *min { 132 return nil, fmt.Errorf("too small") 133 } 134 if max != nil && int(res) > *max { 135 return nil, fmt.Errorf("too large") 136 } 137 return next(ctx) 138 139 case *int: 140 if min != nil && *res < *min { 141 return nil, fmt.Errorf("too small") 142 } 143 if max != nil && *res > *max { 144 return nil, fmt.Errorf("too large") 145 } 146 return next(ctx) 147 } 148 return nil, fmt.Errorf("unsupported type %T", res) 149 }, 150 Custom: func(ctx context.Context, obj interface{}, next graphql.Resolver) (interface{}, error) { 151 return next(ctx) 152 }, 153 Logged: func(ctx context.Context, obj interface{}, next graphql.Resolver, id string) (interface{}, error) { 154 return next(context.WithValue(ctx, ckey("request_id"), &id)) 155 }, 156 ToNull: func(ctx context.Context, obj interface{}, next graphql.Resolver) (interface{}, error) { 157 return nil, nil 158 }, 159 Directive1: func(ctx context.Context, obj interface{}, next graphql.Resolver) (res interface{}, err error) { 160 return next(ctx) 161 }, 162 Directive2: func(ctx context.Context, obj interface{}, next graphql.Resolver) (res interface{}, err error) { 163 return next(ctx) 164 }, 165 Directive3: func(ctx context.Context, obj interface{}, next graphql.Resolver) (res interface{}, err error) { 166 return next(ctx) 167 }, 168 Order1: func(ctx context.Context, obj interface{}, next graphql.Resolver, location string) (res interface{}, err error) { 169 order := []string{location} 170 res, err = next(ctx) 171 od := res.(*ObjectDirectives) 172 od.Order = append(order, od.Order...) 173 return od, err 174 }, 175 Order2: func(ctx context.Context, obj interface{}, next graphql.Resolver, location string) (res interface{}, err error) { 176 order := []string{location} 177 res, err = next(ctx) 178 od := res.(*ObjectDirectives) 179 od.Order = append(order, od.Order...) 180 return od, err 181 }, 182 Unimplemented: nil, 183 }, 184 })) 185 186 srv.AroundFields(func(ctx context.Context, next graphql.Resolver) (res interface{}, err error) { 187 path, _ := ctx.Value(ckey("path")).([]int) 188 return next(context.WithValue(ctx, ckey("path"), append(path, 1))) 189 }) 190 191 srv.AroundFields(func(ctx context.Context, next graphql.Resolver) (res interface{}, err error) { 192 path, _ := ctx.Value(ckey("path")).([]int) 193 return next(context.WithValue(ctx, ckey("path"), append(path, 2))) 194 }) 195 196 c := client.New(srv) 197 198 t.Run("arg directives", func(t *testing.T) { 199 t.Run("when function errors on directives", func(t *testing.T) { 200 var resp struct { 201 DirectiveArg *string 202 } 203 204 err := c.Post(`query { directiveArg(arg: "") }`, &resp) 205 206 require.EqualError(t, err, `[{"message":"invalid length","path":["directiveArg","arg"]}]`) 207 require.Nil(t, resp.DirectiveArg) 208 }) 209 t.Run("when function errors on nullable arg directives", func(t *testing.T) { 210 var resp struct { 211 DirectiveNullableArg *string 212 } 213 214 err := c.Post(`query { directiveNullableArg(arg: -100) }`, &resp) 215 216 require.EqualError(t, err, `[{"message":"too small","path":["directiveNullableArg","arg"]}]`) 217 require.Nil(t, resp.DirectiveNullableArg) 218 }) 219 t.Run("when function success on nullable arg directives", func(t *testing.T) { 220 var resp struct { 221 DirectiveNullableArg *string 222 } 223 224 err := c.Post(`query { directiveNullableArg }`, &resp) 225 226 require.Nil(t, err) 227 require.Equal(t, "Ok", *resp.DirectiveNullableArg) 228 }) 229 t.Run("when function success on valid nullable arg directives", func(t *testing.T) { 230 var resp struct { 231 DirectiveNullableArg *string 232 } 233 234 err := c.Post(`query { directiveNullableArg(arg: 1) }`, &resp) 235 236 require.Nil(t, err) 237 require.Equal(t, "Ok", *resp.DirectiveNullableArg) 238 }) 239 t.Run("when function success", func(t *testing.T) { 240 var resp struct { 241 DirectiveArg *string 242 } 243 244 err := c.Post(`query { directiveArg(arg: "test") }`, &resp) 245 246 require.Nil(t, err) 247 require.Equal(t, "Ok", *resp.DirectiveArg) 248 }) 249 }) 250 t.Run("field definition directives", func(t *testing.T) { 251 resolvers.QueryResolver.DirectiveFieldDef = func(ctx context.Context, ret string) (i string, e error) { 252 return ret, nil 253 } 254 255 t.Run("too short", func(t *testing.T) { 256 var resp struct { 257 DirectiveFieldDef string 258 } 259 260 err := c.Post(`query { directiveFieldDef(ret: "") }`, &resp) 261 262 require.EqualError(t, err, `[{"message":"not valid","path":["directiveFieldDef"]}]`) 263 }) 264 265 t.Run("has 2 directives", func(t *testing.T) { 266 var resp struct { 267 DirectiveDouble string 268 } 269 270 c.MustPost(`query { directiveDouble }`, &resp) 271 272 require.Equal(t, "Ok", resp.DirectiveDouble) 273 }) 274 275 t.Run("directive is not implemented", func(t *testing.T) { 276 var resp struct { 277 DirectiveUnimplemented string 278 } 279 280 err := c.Post(`query { directiveUnimplemented }`, &resp) 281 282 require.EqualError(t, err, `[{"message":"directive unimplemented is not implemented","path":["directiveUnimplemented"]}]`) 283 }) 284 285 t.Run("ok", func(t *testing.T) { 286 var resp struct { 287 DirectiveFieldDef string 288 } 289 290 c.MustPost(`query { directiveFieldDef(ret: "aaa") }`, &resp) 291 292 require.Equal(t, "aaa", resp.DirectiveFieldDef) 293 }) 294 }) 295 t.Run("field directives", func(t *testing.T) { 296 t.Run("add field directive", func(t *testing.T) { 297 var resp struct { 298 DirectiveField string 299 } 300 301 c.MustPost(`query { directiveField@logged(id:"testes_id") }`, &resp) 302 303 require.Equal(t, resp.DirectiveField, `testes_id`) 304 }) 305 t.Run("without field directive", func(t *testing.T) { 306 var resp struct { 307 DirectiveField *string 308 } 309 310 c.MustPost(`query { directiveField }`, &resp) 311 312 require.Nil(t, resp.DirectiveField) 313 }) 314 }) 315 t.Run("input field directives", func(t *testing.T) { 316 t.Run("when function errors on directives", func(t *testing.T) { 317 var resp struct { 318 DirectiveInputNullable *string 319 } 320 321 err := c.Post(`query { directiveInputNullable(arg: {text:"invalid text",inner:{message:"123"}}) }`, &resp) 322 323 require.EqualError(t, err, `[{"message":"not valid","path":["directiveInputNullable","arg","text"]}]`) 324 require.Nil(t, resp.DirectiveInputNullable) 325 }) 326 t.Run("when function errors on inner directives", func(t *testing.T) { 327 var resp struct { 328 DirectiveInputNullable *string 329 } 330 331 err := c.Post(`query { directiveInputNullable(arg: {text:"2",inner:{message:""}}) }`, &resp) 332 333 require.EqualError(t, err, `[{"message":"not valid","path":["directiveInputNullable","arg","inner","message"]}]`) 334 require.Nil(t, resp.DirectiveInputNullable) 335 }) 336 t.Run("when function errors on nullable inner directives", func(t *testing.T) { 337 var resp struct { 338 DirectiveInputNullable *string 339 } 340 341 err := c.Post(`query { directiveInputNullable(arg: {text:"success",inner:{message:"1"},innerNullable:{message:""}}) }`, &resp) 342 343 require.EqualError(t, err, `[{"message":"not valid","path":["directiveInputNullable","arg","innerNullable","message"]}]`) 344 require.Nil(t, resp.DirectiveInputNullable) 345 }) 346 t.Run("when function success", func(t *testing.T) { 347 var resp struct { 348 DirectiveInputNullable *string 349 } 350 351 err := c.Post(`query { directiveInputNullable(arg: {text:"23",inner:{message:"1"}}) }`, &resp) 352 353 require.Nil(t, err) 354 require.Equal(t, "Ok", *resp.DirectiveInputNullable) 355 }) 356 t.Run("when function inner nullable success", func(t *testing.T) { 357 var resp struct { 358 DirectiveInputNullable *string 359 } 360 361 err := c.Post(`query { directiveInputNullable(arg: {text:"23",nullableText:"23",inner:{message:"1"},innerNullable:{message:"success"}}) }`, &resp) 362 363 require.Nil(t, err) 364 require.Equal(t, "Ok", *resp.DirectiveInputNullable) 365 }) 366 t.Run("when arg has directive", func(t *testing.T) { 367 var resp struct { 368 DirectiveInputType *string 369 } 370 371 err := c.Post(`query { directiveInputType(arg: {id: 1}) }`, &resp) 372 373 require.Nil(t, err) 374 require.Equal(t, "Ok", *resp.DirectiveInputType) 375 }) 376 }) 377 t.Run("object field directives", func(t *testing.T) { 378 t.Run("when function success", func(t *testing.T) { 379 var resp struct { 380 DirectiveObject *struct { 381 Text string 382 NullableText *string 383 Order []string 384 } 385 } 386 387 err := c.Post(`query { directiveObject{ text nullableText order} }`, &resp) 388 389 require.Nil(t, err) 390 require.Equal(t, "Ok", resp.DirectiveObject.Text) 391 require.True(t, resp.DirectiveObject.NullableText == nil) 392 require.Equal(t, "Query_field", resp.DirectiveObject.Order[0]) 393 require.Equal(t, "order2_1", resp.DirectiveObject.Order[1]) 394 require.Equal(t, "order1_2", resp.DirectiveObject.Order[2]) 395 require.Equal(t, "order1_1", resp.DirectiveObject.Order[3]) 396 }) 397 t.Run("when directive returns nil & custom go field is not nilable", func(t *testing.T) { 398 var resp struct { 399 DirectiveObjectWithCustomGoModel *struct { 400 NullableText *string 401 } 402 } 403 404 err := c.Post(`query { directiveObjectWithCustomGoModel{ nullableText } }`, &resp) 405 406 require.Nil(t, err) 407 require.True(t, resp.DirectiveObjectWithCustomGoModel.NullableText == nil) 408 }) 409 }) 410 411 t.Run("Subscription directives", func(t *testing.T) { 412 t.Run("arg directives", func(t *testing.T) { 413 t.Run("when function errors on directives", func(t *testing.T) { 414 var resp struct { 415 DirectiveArg *string 416 } 417 418 err := c.WebsocketOnce(`subscription { directiveArg(arg: "") }`, &resp) 419 420 require.EqualError(t, err, `[{"message":"invalid length","path":["directiveArg","arg"]}]`) 421 require.Nil(t, resp.DirectiveArg) 422 }) 423 t.Run("when function errors on nullable arg directives", func(t *testing.T) { 424 var resp struct { 425 DirectiveNullableArg *string 426 } 427 428 err := c.WebsocketOnce(`subscription { directiveNullableArg(arg: -100) }`, &resp) 429 430 require.EqualError(t, err, `[{"message":"too small","path":["directiveNullableArg","arg"]}]`) 431 require.Nil(t, resp.DirectiveNullableArg) 432 }) 433 t.Run("when function success on nullable arg directives", func(t *testing.T) { 434 var resp struct { 435 DirectiveNullableArg *string 436 } 437 438 err := c.WebsocketOnce(`subscription { directiveNullableArg }`, &resp) 439 440 require.Nil(t, err) 441 require.Equal(t, "Ok", *resp.DirectiveNullableArg) 442 }) 443 t.Run("when function success on valid nullable arg directives", func(t *testing.T) { 444 var resp struct { 445 DirectiveNullableArg *string 446 } 447 448 err := c.WebsocketOnce(`subscription { directiveNullableArg(arg: 1) }`, &resp) 449 450 require.Nil(t, err) 451 require.Equal(t, "Ok", *resp.DirectiveNullableArg) 452 }) 453 t.Run("when function success", func(t *testing.T) { 454 var resp struct { 455 DirectiveArg *string 456 } 457 458 err := c.WebsocketOnce(`subscription { directiveArg(arg: "test") }`, &resp) 459 460 require.Nil(t, err) 461 require.Equal(t, "Ok", *resp.DirectiveArg) 462 }) 463 }) 464 }) 465 }