...

Source file src/github.com/99designs/gqlgen/codegen/testserver/followschema/directive_test.go

Documentation: github.com/99designs/gqlgen/codegen/testserver/followschema

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

View as plain text