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 }