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