github.com/kerryoscer/gqlgen@v0.17.29/codegen/testserver/singlefile/nulls_test.go (about)

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