-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtesthelper_test.go
More file actions
193 lines (165 loc) · 5.54 KB
/
Copy pathtesthelper_test.go
File metadata and controls
193 lines (165 loc) · 5.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
package didww
import (
"encoding/json"
"io"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"runtime"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// fixturesDir returns the absolute path to the testdata/fixtures directory.
func fixturesDir() string {
_, filename, _, _ := runtime.Caller(0)
return filepath.Join(filepath.Dir(filename), "testdata", "fixtures")
}
// loadFixture reads a fixture file from the testdata/fixtures directory.
func loadFixture(t *testing.T, path string) []byte {
t.Helper()
fullPath := filepath.Join(fixturesDir(), path)
data, err := os.ReadFile(fullPath)
require.NoError(t, err, "failed to load fixture %s", path)
return data
}
// newTestServer creates an httptest.Server that serves fixture files based on the request path.
// The handler maps URL paths to fixture file paths.
func newTestServer(t *testing.T, routes map[string]testRoute) (*httptest.Server, *Client) {
t.Helper()
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
route, ok := routes[r.Method+" "+r.URL.Path]
if !ok {
// Try without method prefix for simple GET routes
route, ok = routes[r.URL.Path]
}
if !ok {
w.WriteHeader(http.StatusNotFound)
w.Write([]byte(`{"errors":[{"title":"not found","status":"404"}]}`))
return
}
w.Header().Set("Content-Type", "application/vnd.api+json")
w.WriteHeader(route.status)
if route.fixture != "" {
data := loadFixture(t, route.fixture)
w.Write(data)
} else if route.body != "" {
w.Write([]byte(route.body))
}
}))
client, err := NewClient("test-api-key", WithBaseURL(server.URL))
require.NoError(t, err)
t.Cleanup(func() {
server.Close()
})
return server, client
}
// testRoute defines a route for the test server.
type testRoute struct {
status int
fixture string // path to fixture file relative to testdata/fixtures/
body string // raw body to return (used if fixture is empty)
}
// testServerWithClient wraps a test server with an associated client.
type testServerWithClient struct {
server *http.Server
client *Client
}
// newTestServerWithInspector creates a test server that calls an inspector function for each request.
func newTestServerWithInspector(t *testing.T, routes map[string]testRoute, inspector func(r *http.Request)) *testServerWithClient {
t.Helper()
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if inspector != nil {
inspector(r)
}
route, ok := routes[r.Method+" "+r.URL.Path]
if !ok {
route, ok = routes[r.URL.Path]
}
if !ok {
w.WriteHeader(http.StatusNotFound)
w.Write([]byte(`{"errors":[{"title":"not found","status":"404"}]}`))
return
}
w.Header().Set("Content-Type", "application/vnd.api+json")
w.WriteHeader(route.status)
if route.fixture != "" {
data := loadFixture(t, route.fixture)
w.Write(data)
} else if route.body != "" {
w.Write([]byte(route.body))
}
}))
client, err := NewClient("test-api-key", WithBaseURL(server.URL))
require.NoError(t, err)
t.Cleanup(func() {
server.Close()
})
return &testServerWithClient{client: client}
}
// newTestServerWithDynamicPatch creates a test server where PATCH requests are handled
// dynamically based on call count. Other methods use static routes.
func newTestServerWithDynamicPatch(t *testing.T, routes map[string]testRoute, inspector func(r *http.Request), patchRouter func(call int) testRoute) *testServerWithClient {
t.Helper()
var patchCount int
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if inspector != nil {
inspector(r)
}
var route testRoute
var ok bool
if r.Method == http.MethodPatch {
patchCount++
route = patchRouter(patchCount)
ok = true
} else {
route, ok = routes[r.Method+" "+r.URL.Path]
if !ok {
route, ok = routes[r.URL.Path]
}
}
if !ok {
w.WriteHeader(http.StatusNotFound)
w.Write([]byte(`{"errors":[{"title":"not found","status":"404"}]}`))
return
}
w.Header().Set("Content-Type", "application/vnd.api+json")
w.WriteHeader(route.status)
if route.fixture != "" {
data := loadFixture(t, route.fixture)
w.Write(data)
} else if route.body != "" {
w.Write([]byte(route.body))
}
}))
client, err := NewClient("test-api-key", WithBaseURL(server.URL))
require.NoError(t, err)
t.Cleanup(func() {
server.Close()
})
return &testServerWithClient{client: client}
}
// assertRequestJSON compares the actual request body against a fixture file using semantic JSON comparison.
// Key order is ignored; both are normalized to map[string]any before comparison.
func assertRequestJSON(t *testing.T, actual []byte, fixturePath string) {
t.Helper()
expected := loadFixture(t, fixturePath)
var actualObj any
require.NoError(t, json.Unmarshal(actual, &actualObj), "failed to parse actual request body")
var expectedObj any
require.NoError(t, json.Unmarshal(expected, &expectedObj), "failed to parse expected fixture %s", fixturePath)
assert.Equal(t, expectedObj, actualObj, "request body mismatch for fixture %s", fixturePath)
}
// captureRequestBody creates a test server with an inspector that captures the request body.
// Returns the server wrapper and a pointer to the captured body bytes.
func captureRequestBody(t *testing.T, routes map[string]testRoute) (*testServerWithClient, *[]byte) {
t.Helper()
var body []byte
server := newTestServerWithInspector(t, routes, func(r *http.Request) {
if r.Method == http.MethodPatch || r.Method == http.MethodPost {
body, _ = io.ReadAll(r.Body)
}
})
return server, &body
}