github.com/tobiash/gqlgen@v0.5.1/codegen/testserver/generated_test.go (about)

     1  //go:generate rm -f resolver.go
     2  //go:generate gorunpkg github.com/99designs/gqlgen
     3  
     4  package testserver
     5  
     6  import (
     7  	"context"
     8  	"net/http"
     9  	"net/http/httptest"
    10  	"reflect"
    11  	"runtime"
    12  	"testing"
    13  	"time"
    14  
    15  	"github.com/99designs/gqlgen/client"
    16  	"github.com/99designs/gqlgen/handler"
    17  	"github.com/stretchr/testify/require"
    18  )
    19  
    20  func TestGeneratedResolversAreValid(t *testing.T) {
    21  	http.Handle("/query", handler.GraphQL(NewExecutableSchema(Config{
    22  		Resolvers: &Resolver{},
    23  	})))
    24  }
    25  
    26  func TestForcedResolverFieldIsPointer(t *testing.T) {
    27  	field, ok := reflect.TypeOf((*ForcedResolverResolver)(nil)).Elem().MethodByName("Field")
    28  	require.True(t, ok)
    29  	require.Equal(t, "*testserver.Circle", field.Type.Out(0).String())
    30  }
    31  
    32  func TestGeneratedServer(t *testing.T) {
    33  	tickChan := make(chan string, 1)
    34  	srv := httptest.NewServer(handler.GraphQL(NewExecutableSchema(Config{
    35  		Resolvers: &testResolver{tick: tickChan},
    36  	})))
    37  	c := client.New(srv.URL)
    38  
    39  	t.Run("null bubbling", func(t *testing.T) {
    40  		t.Run("when function errors on non required field", func(t *testing.T) {
    41  			var resp struct {
    42  				Valid       string
    43  				ErrorBubble *struct {
    44  					Id                      string
    45  					ErrorOnNonRequiredField *string
    46  				}
    47  			}
    48  			err := c.Post(`query { valid, errorBubble { id, errorOnNonRequiredField } }`, &resp)
    49  
    50  			require.EqualError(t, err, `[{"message":"boom","path":["errorBubble","errorOnNonRequiredField"]}]`)
    51  			require.Equal(t, "E1234", resp.ErrorBubble.Id)
    52  			require.Nil(t, resp.ErrorBubble.ErrorOnNonRequiredField)
    53  			require.Equal(t, "Ok", resp.Valid)
    54  		})
    55  
    56  		t.Run("when function errors", func(t *testing.T) {
    57  			var resp struct {
    58  				Valid       string
    59  				ErrorBubble *struct {
    60  					NilOnRequiredField string
    61  				}
    62  			}
    63  			err := c.Post(`query { valid, errorBubble { id, errorOnRequiredField } }`, &resp)
    64  
    65  			require.EqualError(t, err, `[{"message":"boom","path":["errorBubble","errorOnRequiredField"]}]`)
    66  			require.Nil(t, resp.ErrorBubble)
    67  			require.Equal(t, "Ok", resp.Valid)
    68  		})
    69  
    70  		t.Run("when user returns null on required field", func(t *testing.T) {
    71  			var resp struct {
    72  				Valid       string
    73  				ErrorBubble *struct {
    74  					NilOnRequiredField string
    75  				}
    76  			}
    77  			err := c.Post(`query { valid, errorBubble { id, nilOnRequiredField } }`, &resp)
    78  
    79  			require.EqualError(t, err, `[{"message":"must not be null","path":["errorBubble","nilOnRequiredField"]}]`)
    80  			require.Nil(t, resp.ErrorBubble)
    81  			require.Equal(t, "Ok", resp.Valid)
    82  		})
    83  
    84  	})
    85  
    86  	t.Run("subscriptions", func(t *testing.T) {
    87  		t.Run("wont leak goroutines", func(t *testing.T) {
    88  			initialGoroutineCount := runtime.NumGoroutine()
    89  
    90  			sub := c.Websocket(`subscription { updated }`)
    91  
    92  			tickChan <- "message"
    93  
    94  			var msg struct {
    95  				resp struct {
    96  					Updated string
    97  				}
    98  			}
    99  
   100  			err := sub.Next(&msg.resp)
   101  			require.NoError(t, err)
   102  			require.Equal(t, "message", msg.resp.Updated)
   103  			sub.Close()
   104  
   105  			// need a little bit of time for goroutines to settle
   106  			time.Sleep(200 * time.Millisecond)
   107  
   108  			require.Equal(t, initialGoroutineCount, runtime.NumGoroutine())
   109  		})
   110  	})
   111  }
   112  
   113  type testResolver struct {
   114  	tick chan string
   115  }
   116  
   117  func (r *testResolver) ForcedResolver() ForcedResolverResolver {
   118  	return &forcedResolverResolver{nil}
   119  }
   120  func (r *testResolver) Query() QueryResolver {
   121  	return &testQueryResolver{}
   122  }
   123  
   124  type testQueryResolver struct{ queryResolver }
   125  
   126  func (r *testQueryResolver) ErrorBubble(ctx context.Context) (*Error, error) {
   127  	return &Error{ID: "E1234"}, nil
   128  }
   129  
   130  func (r *testQueryResolver) Valid(ctx context.Context) (string, error) {
   131  	return "Ok", nil
   132  }
   133  
   134  func (r *testResolver) Subscription() SubscriptionResolver {
   135  	return &testSubscriptionResolver{r}
   136  }
   137  
   138  type testSubscriptionResolver struct{ *testResolver }
   139  
   140  func (r *testSubscriptionResolver) Updated(ctx context.Context) (<-chan string, error) {
   141  	res := make(chan string, 1)
   142  
   143  	go func() {
   144  		for {
   145  			select {
   146  			case t := <-r.tick:
   147  				res <- t
   148  			case <-ctx.Done():
   149  				close(res)
   150  				return
   151  			}
   152  		}
   153  	}()
   154  	return res, nil
   155  }