github.com/99designs/gqlgen@v0.17.45/client/client_test.go (about) 1 package client_test 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "io" 8 "mime/multipart" 9 "net/http" 10 "net/textproto" 11 "reflect" 12 "testing" 13 "time" 14 15 "github.com/mitchellh/mapstructure" 16 "github.com/stretchr/testify/require" 17 18 "github.com/99designs/gqlgen/client" 19 ) 20 21 func TestClient(t *testing.T) { 22 h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 23 b, err := io.ReadAll(r.Body) 24 if err != nil { 25 panic(err) 26 } 27 require.Equal(t, `{"query":"user(id:$id){name}","variables":{"id":1}}`, string(b)) 28 29 err = json.NewEncoder(w).Encode(map[string]interface{}{ 30 "data": map[string]interface{}{ 31 "name": "bob", 32 }, 33 }) 34 if err != nil { 35 panic(err) 36 } 37 }) 38 39 c := client.New(h) 40 41 var resp struct { 42 Name string 43 } 44 45 c.MustPost("user(id:$id){name}", &resp, client.Var("id", 1)) 46 47 require.Equal(t, "bob", resp.Name) 48 } 49 50 func TestClientMultipartFormData(t *testing.T) { 51 h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 52 bodyBytes, err := io.ReadAll(r.Body) 53 require.NoError(t, err) 54 require.Contains(t, string(bodyBytes), `Content-Disposition: form-data; name="operations"`) 55 require.Contains(t, string(bodyBytes), `{"query":"mutation ($input: Input!) {}","variables":{"file":{}}`) 56 require.Contains(t, string(bodyBytes), `Content-Disposition: form-data; name="map"`) 57 require.Contains(t, string(bodyBytes), `{"0":["variables.file"]}`) 58 require.Contains(t, string(bodyBytes), `Content-Disposition: form-data; name="0"; filename="example.txt"`) 59 require.Contains(t, string(bodyBytes), `Content-Type: text/plain`) 60 require.Contains(t, string(bodyBytes), `Hello World`) 61 62 w.Write([]byte(`{}`)) 63 }) 64 65 c := client.New(h) 66 67 var resp struct{} 68 c.MustPost("{ id }", &resp, 69 func(bd *client.Request) { 70 bodyBuf := &bytes.Buffer{} 71 bodyWriter := multipart.NewWriter(bodyBuf) 72 bodyWriter.WriteField("operations", `{"query":"mutation ($input: Input!) {}","variables":{"file":{}}`) 73 bodyWriter.WriteField("map", `{"0":["variables.file"]}`) 74 75 h := make(textproto.MIMEHeader) 76 h.Set("Content-Disposition", `form-data; name="0"; filename="example.txt"`) 77 h.Set("Content-Type", "text/plain") 78 ff, _ := bodyWriter.CreatePart(h) 79 ff.Write([]byte("Hello World")) 80 bodyWriter.Close() 81 82 bd.HTTP.Body = io.NopCloser(bodyBuf) 83 bd.HTTP.Header.Set("Content-Type", bodyWriter.FormDataContentType()) 84 }, 85 ) 86 } 87 88 func TestAddHeader(t *testing.T) { 89 h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 90 require.Equal(t, "ASDF", r.Header.Get("Test-Key")) 91 92 w.Write([]byte(`{}`)) 93 }) 94 95 c := client.New(h) 96 97 var resp struct{} 98 c.MustPost("{ id }", &resp, 99 client.AddHeader("Test-Key", "ASDF"), 100 ) 101 } 102 103 func TestAddClientHeader(t *testing.T) { 104 h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 105 require.Equal(t, "ASDF", r.Header.Get("Test-Key")) 106 107 w.Write([]byte(`{}`)) 108 }) 109 110 c := client.New(h, client.AddHeader("Test-Key", "ASDF")) 111 112 var resp struct{} 113 c.MustPost("{ id }", &resp) 114 } 115 116 func TestBasicAuth(t *testing.T) { 117 h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 118 user, pass, ok := r.BasicAuth() 119 require.True(t, ok) 120 require.Equal(t, "user", user) 121 require.Equal(t, "pass", pass) 122 123 w.Write([]byte(`{}`)) 124 }) 125 126 c := client.New(h) 127 128 var resp struct{} 129 c.MustPost("{ id }", &resp, 130 client.BasicAuth("user", "pass"), 131 ) 132 } 133 134 func TestAddCookie(t *testing.T) { 135 h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 136 c, err := r.Cookie("foo") 137 require.NoError(t, err) 138 require.Equal(t, "value", c.Value) 139 140 w.Write([]byte(`{}`)) 141 }) 142 143 c := client.New(h) 144 145 var resp struct{} 146 c.MustPost("{ id }", &resp, 147 client.AddCookie(&http.Cookie{Name: "foo", Value: "value"}), 148 ) 149 } 150 151 func TestAddExtensions(t *testing.T) { 152 h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 153 b, err := io.ReadAll(r.Body) 154 if err != nil { 155 panic(err) 156 } 157 require.Equal(t, `{"query":"user(id:1){name}","extensions":{"persistedQuery":{"sha256Hash":"ceec2897e2da519612279e63f24658c3e91194cbb2974744fa9007a7e1e9f9e7","version":1}}}`, string(b)) 158 err = json.NewEncoder(w).Encode(map[string]interface{}{ 159 "data": map[string]interface{}{ 160 "Name": "Bob", 161 }, 162 }) 163 if err != nil { 164 panic(err) 165 } 166 }) 167 168 c := client.New(h) 169 170 var resp struct { 171 Name string 172 } 173 c.MustPost("user(id:1){name}", &resp, 174 client.Extensions(map[string]interface{}{"persistedQuery": map[string]interface{}{"version": 1, "sha256Hash": "ceec2897e2da519612279e63f24658c3e91194cbb2974744fa9007a7e1e9f9e7"}}), 175 ) 176 } 177 178 func TestSetCustomDecodeConfig(t *testing.T) { 179 now := time.Now() 180 181 h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 182 w.WriteHeader(http.StatusOK) 183 w.Header().Set("Content-Type", "application/json") 184 w.Write([]byte(fmt.Sprintf(`{"data": {"created_at":"%s"}}`, now.Format(time.RFC3339)))) 185 }) 186 187 dc := &mapstructure.DecoderConfig{ 188 TagName: "json", 189 ErrorUnused: true, 190 ZeroFields: true, 191 DecodeHook: func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { 192 if t != reflect.TypeOf(time.Time{}) { 193 return data, nil 194 } 195 196 switch f.Kind() { 197 case reflect.String: 198 return time.Parse(time.RFC3339, data.(string)) 199 default: 200 return data, nil 201 } 202 }, 203 } 204 205 c := client.New(h) 206 207 var resp struct { 208 CreatedAt time.Time `json:"created_at"` 209 } 210 211 err := c.Post("user(id: 1) {created_at}", &resp) 212 require.Error(t, err) 213 214 c.SetCustomDecodeConfig(dc) 215 216 c.MustPost("user(id: 1) {created_at}", &resp) 217 require.WithinDuration(t, now, resp.CreatedAt, time.Second) 218 }