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  }