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 }
219
View as plain text