...

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

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

     1  package followschema
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"testing"
     7  
     8  	"github.com/stretchr/testify/require"
     9  
    10  	"github.com/99designs/gqlgen/client"
    11  	"github.com/99designs/gqlgen/graphql/handler"
    12  )
    13  
    14  func TestNullBubbling(t *testing.T) {
    15  	resolvers := &Stub{}
    16  	resolvers.QueryResolver.Valid = func(ctx context.Context) (s string, e error) {
    17  		return "Ok", nil
    18  	}
    19  	resolvers.QueryResolver.Invalid = func(ctx context.Context) (s string, e error) {
    20  		return "Ok", errors.New("ERROR")
    21  	}
    22  	resolvers.QueryResolver.Errors = func(ctx context.Context) (errors *Errors, e error) {
    23  		return &Errors{}, nil
    24  	}
    25  	resolvers.QueryResolver.ErrorBubble = func(ctx context.Context) (i *Error, e error) {
    26  		return &Error{ID: "E1234"}, nil
    27  	}
    28  	resolvers.QueryResolver.ErrorBubbleList = func(ctx context.Context) (i []*Error, e error) {
    29  		return []*Error{{ID: "1"}, nil, nil}, nil
    30  	}
    31  	resolvers.QueryResolver.ErrorList = func(ctx context.Context) (i []*Error, e error) {
    32  		return []*Error{nil}, nil
    33  	}
    34  
    35  	c := client.New(handler.NewDefaultServer(NewExecutableSchema(Config{Resolvers: resolvers})))
    36  
    37  	t.Run("when function errors on non required field", func(t *testing.T) {
    38  		var resp struct {
    39  			Valid       string
    40  			ErrorBubble *struct {
    41  				Id                      string
    42  				ErrorOnNonRequiredField *string
    43  			}
    44  		}
    45  		err := c.Post(`query { valid, errorBubble { id, errorOnNonRequiredField } }`, &resp)
    46  
    47  		require.EqualError(t, err, `[{"message":"boom","path":["errorBubble","errorOnNonRequiredField"]}]`)
    48  		require.Equal(t, "E1234", resp.ErrorBubble.Id)
    49  		require.Nil(t, resp.ErrorBubble.ErrorOnNonRequiredField)
    50  		require.Equal(t, "Ok", resp.Valid)
    51  	})
    52  
    53  	t.Run("when function errors", func(t *testing.T) {
    54  		var resp struct {
    55  			Valid       string
    56  			ErrorBubble *struct {
    57  				NilOnRequiredField string
    58  			}
    59  		}
    60  		err := c.Post(`query { valid, errorBubble { id, errorOnRequiredField } }`, &resp)
    61  
    62  		require.EqualError(t, err, `[{"message":"boom","path":["errorBubble","errorOnRequiredField"]}]`)
    63  		require.Nil(t, resp.ErrorBubble)
    64  		require.Equal(t, "Ok", resp.Valid)
    65  	})
    66  
    67  	t.Run("when user returns null on required field", func(t *testing.T) {
    68  		var resp struct {
    69  			Valid       string
    70  			ErrorBubble *struct {
    71  				NilOnRequiredField string
    72  			}
    73  		}
    74  		err := c.Post(`query { valid, errorBubble { id, nilOnRequiredField } }`, &resp)
    75  
    76  		require.EqualError(t, err, `[{"message":"the requested element is null which the schema does not allow","path":["errorBubble","nilOnRequiredField"]}]`)
    77  		require.Nil(t, resp.ErrorBubble)
    78  		require.Equal(t, "Ok", resp.Valid)
    79  	})
    80  
    81  	t.Run("when list element is null", func(t *testing.T) {
    82  		var resp struct {
    83  			Valid     string
    84  			ErrorList []*struct{}
    85  		}
    86  		err := c.Post(`query { valid, errorList { id } }`, &resp)
    87  
    88  		require.Nil(t, err)
    89  		require.Equal(t, len(resp.ErrorList), 1)
    90  		require.Nil(t, resp.ErrorList[0])
    91  		require.Equal(t, "Ok", resp.Valid)
    92  	})
    93  
    94  	t.Run("when non-null list element is null", func(t *testing.T) {
    95  		var resp struct {
    96  			Valid           string
    97  			ErrorBubbleList []*struct{}
    98  		}
    99  		err := c.Post(`query { valid, errorBubbleList { id } }`, &resp)
   100  
   101  		require.Contains(t, err.Error(), `{"message":"the requested element is null which the schema does not allow","path":["errorBubbleList",2]}`)
   102  		require.Contains(t, err.Error(), `{"message":"the requested element is null which the schema does not allow","path":["errorBubbleList",1]}`)
   103  		require.Nil(t, resp.ErrorBubbleList)
   104  		require.Equal(t, "Ok", resp.Valid)
   105  	})
   106  
   107  	t.Run("null args", func(t *testing.T) {
   108  		var resp struct {
   109  			NullableArg *string
   110  		}
   111  		resolvers.QueryResolver.NullableArg = func(ctx context.Context, arg *int) (i *string, e error) {
   112  			v := "Ok"
   113  			return &v, nil
   114  		}
   115  
   116  		err := c.Post(`query { nullableArg(arg: null) }`, &resp)
   117  		require.Nil(t, err)
   118  		require.Equal(t, "Ok", *resp.NullableArg)
   119  	})
   120  
   121  	t.Run("concurrent null detection", func(t *testing.T) {
   122  		var resp interface{}
   123  		resolvers.ErrorsResolver.A = func(ctx context.Context, obj *Errors) (i *Error, e error) { return nil, nil }
   124  		resolvers.ErrorsResolver.B = func(ctx context.Context, obj *Errors) (i *Error, e error) { return nil, nil }
   125  		resolvers.ErrorsResolver.C = func(ctx context.Context, obj *Errors) (i *Error, e error) { return nil, nil }
   126  		resolvers.ErrorsResolver.D = func(ctx context.Context, obj *Errors) (i *Error, e error) { return nil, nil }
   127  		resolvers.ErrorsResolver.E = func(ctx context.Context, obj *Errors) (i *Error, e error) { return nil, nil }
   128  
   129  		err := c.Post(`{ errors {
   130  			a { id },
   131  			b { id },
   132  			c { id },
   133  			d { id },
   134  			e { id },
   135  		} }`, &resp)
   136  
   137  		require.Error(t, err)
   138  		require.Contains(t, err.Error(), "the requested element is null which the schema does not allow")
   139  	})
   140  
   141  	t.Run("when non-nullable field returns content while error occurred", func(t *testing.T) {
   142  		var resp any
   143  		err := c.Post(`query { invalid }`, &resp)
   144  		require.Nil(t, resp)
   145  		require.NotNil(t, err)
   146  		require.Contains(t, err.Error(), `{"message":"ERROR","path":["invalid"]}`)
   147  	})
   148  }
   149  

View as plain text