github.com/HaswinVidanage/gqlgen@v0.8.1-0.20220609041233-69528c1bf712/handler/graphql_test.go (about) 1 package handler 2 3 import ( 4 "net/http" 5 "net/http/httptest" 6 "strings" 7 "testing" 8 9 "github.com/stretchr/testify/assert" 10 ) 11 12 func TestHandlerPOST(t *testing.T) { 13 h := GraphQL(&executableSchemaStub{}) 14 15 t.Run("success", func(t *testing.T) { 16 resp := doRequest(h, "POST", "/graphql", `{"query":"{ me { name } }"}`) 17 assert.Equal(t, http.StatusOK, resp.Code) 18 assert.Equal(t, `{"data":{"name":"test"}}`, resp.Body.String()) 19 }) 20 21 t.Run("query caching", func(t *testing.T) { 22 // Run enough unique queries to evict a bunch of them 23 for i := 0; i < 2000; i++ { 24 query := `{"query":"` + strings.Repeat(" ", i) + "{ me { name } }" + `"}` 25 resp := doRequest(h, "POST", "/graphql", query) 26 assert.Equal(t, http.StatusOK, resp.Code) 27 assert.Equal(t, `{"data":{"name":"test"}}`, resp.Body.String()) 28 } 29 30 t.Run("evicted queries run", func(t *testing.T) { 31 query := `{"query":"` + strings.Repeat(" ", 0) + "{ me { name } }" + `"}` 32 resp := doRequest(h, "POST", "/graphql", query) 33 assert.Equal(t, http.StatusOK, resp.Code) 34 assert.Equal(t, `{"data":{"name":"test"}}`, resp.Body.String()) 35 }) 36 37 t.Run("non-evicted queries run", func(t *testing.T) { 38 query := `{"query":"` + strings.Repeat(" ", 1999) + "{ me { name } }" + `"}` 39 resp := doRequest(h, "POST", "/graphql", query) 40 assert.Equal(t, http.StatusOK, resp.Code) 41 assert.Equal(t, `{"data":{"name":"test"}}`, resp.Body.String()) 42 }) 43 }) 44 45 t.Run("decode failure", func(t *testing.T) { 46 resp := doRequest(h, "POST", "/graphql", "notjson") 47 assert.Equal(t, http.StatusBadRequest, resp.Code) 48 assert.Equal(t, resp.Header().Get("Content-Type"), "application/json") 49 assert.Equal(t, `{"errors":[{"message":"json body could not be decoded: invalid character 'o' in literal null (expecting 'u')"}],"data":null}`, resp.Body.String()) 50 }) 51 52 t.Run("parse failure", func(t *testing.T) { 53 resp := doRequest(h, "POST", "/graphql", `{"query": "!"}`) 54 assert.Equal(t, http.StatusUnprocessableEntity, resp.Code) 55 assert.Equal(t, resp.Header().Get("Content-Type"), "application/json") 56 assert.Equal(t, `{"errors":[{"message":"Unexpected !","locations":[{"line":1,"column":1}]}],"data":null}`, resp.Body.String()) 57 }) 58 59 t.Run("validation failure", func(t *testing.T) { 60 resp := doRequest(h, "POST", "/graphql", `{"query": "{ me { title }}"}`) 61 assert.Equal(t, http.StatusUnprocessableEntity, resp.Code) 62 assert.Equal(t, resp.Header().Get("Content-Type"), "application/json") 63 assert.Equal(t, `{"errors":[{"message":"Cannot query field \"title\" on type \"User\".","locations":[{"line":1,"column":8}]}],"data":null}`, resp.Body.String()) 64 }) 65 66 t.Run("invalid variable", func(t *testing.T) { 67 resp := doRequest(h, "POST", "/graphql", `{"query": "query($id:Int!){user(id:$id){name}}","variables":{"id":false}}`) 68 assert.Equal(t, http.StatusUnprocessableEntity, resp.Code) 69 assert.Equal(t, resp.Header().Get("Content-Type"), "application/json") 70 assert.Equal(t, `{"errors":[{"message":"cannot use bool as Int","path":["variable","id"]}],"data":null}`, resp.Body.String()) 71 }) 72 73 t.Run("execution failure", func(t *testing.T) { 74 resp := doRequest(h, "POST", "/graphql", `{"query": "mutation { me { name } }"}`) 75 assert.Equal(t, http.StatusOK, resp.Code) 76 assert.Equal(t, resp.Header().Get("Content-Type"), "application/json") 77 assert.Equal(t, `{"errors":[{"message":"mutations are not supported"}],"data":null}`, resp.Body.String()) 78 }) 79 } 80 81 func TestHandlerGET(t *testing.T) { 82 h := GraphQL(&executableSchemaStub{}) 83 84 t.Run("success", func(t *testing.T) { 85 resp := doRequest(h, "GET", "/graphql?query={me{name}}", ``) 86 assert.Equal(t, http.StatusOK, resp.Code) 87 assert.Equal(t, `{"data":{"name":"test"}}`, resp.Body.String()) 88 }) 89 90 t.Run("decode failure", func(t *testing.T) { 91 resp := doRequest(h, "GET", "/graphql?query=me{id}&variables=notjson", "") 92 assert.Equal(t, http.StatusBadRequest, resp.Code) 93 assert.Equal(t, `{"errors":[{"message":"variables could not be decoded"}],"data":null}`, resp.Body.String()) 94 }) 95 96 t.Run("invalid variable", func(t *testing.T) { 97 resp := doRequest(h, "GET", `/graphql?query=query($id:Int!){user(id:$id){name}}&variables={"id":false}`, "") 98 assert.Equal(t, http.StatusUnprocessableEntity, resp.Code) 99 assert.Equal(t, `{"errors":[{"message":"cannot use bool as Int","path":["variable","id"]}],"data":null}`, resp.Body.String()) 100 }) 101 102 t.Run("parse failure", func(t *testing.T) { 103 resp := doRequest(h, "GET", "/graphql?query=!", "") 104 assert.Equal(t, http.StatusUnprocessableEntity, resp.Code) 105 assert.Equal(t, `{"errors":[{"message":"Unexpected !","locations":[{"line":1,"column":1}]}],"data":null}`, resp.Body.String()) 106 }) 107 108 t.Run("no mutations", func(t *testing.T) { 109 resp := doRequest(h, "GET", "/graphql?query=mutation{me{name}}", "") 110 assert.Equal(t, http.StatusUnprocessableEntity, resp.Code) 111 assert.Equal(t, `{"errors":[{"message":"GET requests only allow query operations"}],"data":null}`, resp.Body.String()) 112 }) 113 } 114 115 func TestHandlerOptions(t *testing.T) { 116 h := GraphQL(&executableSchemaStub{}) 117 118 resp := doRequest(h, "OPTIONS", "/graphql?query={me{name}}", ``) 119 assert.Equal(t, http.StatusOK, resp.Code) 120 assert.Equal(t, "OPTIONS, GET, POST", resp.Header().Get("Allow")) 121 } 122 123 func TestHandlerHead(t *testing.T) { 124 h := GraphQL(&executableSchemaStub{}) 125 126 resp := doRequest(h, "HEAD", "/graphql?query={me{name}}", ``) 127 assert.Equal(t, http.StatusMethodNotAllowed, resp.Code) 128 } 129 130 func doRequest(handler http.Handler, method string, target string, body string) *httptest.ResponseRecorder { 131 r := httptest.NewRequest(method, target, strings.NewReader(body)) 132 w := httptest.NewRecorder() 133 134 handler.ServeHTTP(w, r) 135 return w 136 }