-
Notifications
You must be signed in to change notification settings - Fork 201
Expand file tree
/
Copy pathfetch.test.ts
More file actions
408 lines (380 loc) · 11.7 KB
/
fetch.test.ts
File metadata and controls
408 lines (380 loc) · 11.7 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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
import process from "node:process";
import { Cacheable } from "cacheable";
import { describe, expect, test } from "vitest";
import {
type FetchOptions,
fetch,
get,
head,
patch,
post,
} from "../src/fetch.js";
const testUrl = process.env.TEST_URL ?? "https://mockhttp.org";
const testTimeout = 10_000; // 10 seconds
describe("Fetch", () => {
test(
"should fetch data successfully",
async () => {
const url = `${testUrl}/get`;
const options: FetchOptions = {
method: "GET",
cache: new Cacheable(),
};
const response = await fetch(url, options);
expect(response).toBeDefined();
},
testTimeout,
);
test(
"should fetch data without method (defaults to GET)",
async () => {
const url = `${testUrl}/get`;
const cache = new Cacheable({ stats: true });
const options: FetchOptions = {
cache,
} as FetchOptions;
const response = await fetch(url, options);
expect(response).toBeDefined();
// Make second request to verify caching with default GET method
const response2 = await fetch(url, options);
expect(response2).toBeDefined();
expect(cache.stats.hits).toBe(1);
},
testTimeout,
);
test(
"should fetch data successfully from cache",
async () => {
const cache = new Cacheable({ stats: true });
const url = `${testUrl}/get`;
const options: FetchOptions = {
method: "GET",
cache,
};
const response = await fetch(url, options);
const response2 = await fetch(url, options);
expect(response).toBeDefined();
expect(response2).toBeDefined();
expect(cache.stats).toBeDefined();
expect(cache.stats.hits).toBe(1);
// Verify that both responses have the same text content
const text1 = await response.text();
const text2 = await response2.text();
expect(text1).toEqual(text2);
},
testTimeout,
);
test(
"should throw an error if cache is not provided",
async () => {
const url = `${testUrl}/get`;
const options: FetchOptions = {
method: "GET",
cache: undefined as unknown as Cacheable, // Force error
};
await expect(fetch(url, options)).rejects.toThrow(
"Fetch options must include a cache instance or options.",
);
},
testTimeout,
);
test(
"should fetch data using get helper",
async () => {
const url = `${testUrl}/get`;
const options = {
cache: new Cacheable(),
};
const result = await get(url, options);
expect(result).toBeDefined();
expect(result.data).toBeDefined();
expect(result.response).toBeDefined();
expect(result.response.status).toBe(200);
},
testTimeout,
);
test(
"should cache data using get helper",
async () => {
const cache = new Cacheable({ stats: true });
const url = `${testUrl}/get`;
const options = {
cache,
};
const result1 = await get(url, options);
const result2 = await get(url, options);
expect(result1).toBeDefined();
expect(result2).toBeDefined();
expect(cache.stats).toBeDefined();
expect(cache.stats.hits).toBe(1);
// Verify that both responses have the same data
expect(result1.data).toEqual(result2.data);
// Verify response objects are valid
expect(result1.response.status).toBe(200);
expect(result2.response.status).toBe(200);
},
testTimeout,
);
test(
"should handle non-JSON response in get helper",
async () => {
const cache = new Cacheable();
// Use mockhttp.org/plain which returns plain text
const url = `${testUrl}/plain`;
const options = {
cache,
};
const result = await get(url, options);
expect(result).toBeDefined();
expect(result.data).toBeDefined();
expect(typeof result.data).toBe("string");
expect(result.data).toBeTruthy(); // Plain text is not empty
expect(result.response).toBeDefined();
expect(result.response.status).toBe(200);
},
testTimeout,
);
test(
"should fetch data using post helper",
async () => {
const url = `${testUrl}/post`;
const data = { test: "data" };
const options = {
cache: new Cacheable(),
};
const result = await post(url, data, options);
expect(result).toBeDefined();
expect(result.data).toBeDefined();
expect(result.response).toBeDefined();
expect(result.response.status).toBe(200);
},
testTimeout,
);
test(
"should not cache data using post helper (POST requests are not cached)",
async () => {
const cache = new Cacheable({ stats: true });
const url = `${testUrl}/post`;
const data = { test: "data" };
const options = {
cache,
};
const result1 = await post(url, data, options);
const result2 = await post(url, data, options);
expect(result1).toBeDefined();
expect(result2).toBeDefined();
expect(cache.stats).toBeDefined();
// POST requests should not be cached, so expect 0 hits
expect(cache.stats.hits).toBe(0);
// Verify response objects are valid
expect(result1.response.status).toBe(200);
expect(result2.response.status).toBe(200);
},
testTimeout,
);
test(
"should fetch data using head helper",
async () => {
const url = `${testUrl}/get`;
const options = {
cache: new Cacheable(),
};
const response = await head(url, options);
expect(response).toBeDefined();
expect(response.status).toBe(200);
// Headers should still be present
expect(response.headers).toBeDefined();
},
testTimeout,
);
test(
"should not cache HEAD requests (HEAD requests are not cached)",
async () => {
const cache = new Cacheable({ stats: true });
const url = `${testUrl}/get`;
const options = {
cache,
};
const response1 = await head(url, options);
const response2 = await head(url, options);
expect(response1).toBeDefined();
expect(response2).toBeDefined();
expect(cache.stats).toBeDefined();
// HEAD requests should not be cached, so expect 0 hits
expect(cache.stats.hits).toBe(0);
// Both responses should have the same status
expect(response1.status).toBe(200);
expect(response2.status).toBe(200);
},
testTimeout,
);
test(
"should handle non-JSON response in post helper",
async () => {
const cache = new Cacheable();
// Use mockhttp.org/plain which now accepts POST and returns plain text
const url = `${testUrl}/plain`;
const data = "test data";
const options = {
cache,
headers: {
"Content-Type": "text/plain",
},
};
const result = await post(url, data, options);
expect(result).toBeDefined();
// The plain endpoint returns text, which should be returned as a string
expect(result.data).toBeDefined();
expect(typeof result.data).toBe("string");
expect(result.data).toBeTruthy(); // Plain text is not empty
expect(result.response).toBeDefined();
expect(result.response.status).toBe(200);
},
testTimeout,
);
test(
"should fetch data using patch helper",
async () => {
const url = `${testUrl}/patch`;
const data = { update: "data" };
const options = {
cache: new Cacheable(),
};
const result = await patch(url, data, options);
expect(result).toBeDefined();
expect(result.data).toBeDefined();
expect(result.response).toBeDefined();
expect(result.response.status).toBe(200);
},
testTimeout,
);
test(
"should not cache data using patch helper (PATCH requests are not cached)",
async () => {
const cache = new Cacheable({ stats: true });
const url = `${testUrl}/patch`;
const data = { update: "data" };
const options = {
cache,
};
const result1 = await patch(url, data, options);
const result2 = await patch(url, data, options);
expect(result1).toBeDefined();
expect(result2).toBeDefined();
expect(cache.stats).toBeDefined();
// PATCH requests should not be cached, so expect 0 hits
expect(cache.stats.hits).toBe(0);
// Verify response objects are valid
expect(result1.response.status).toBe(200);
expect(result2.response.status).toBe(200);
},
testTimeout,
);
test(
"should handle non-JSON response in patch helper",
async () => {
const cache = new Cacheable();
// Use mockhttp.org/plain which now accepts PATCH and returns plain text
const url = `${testUrl}/plain`;
const data = "test data";
const options = {
cache,
headers: {
"Content-Type": "text/plain",
},
};
const result = await patch(url, data, options);
expect(result).toBeDefined();
// The plain endpoint returns text, which should be returned as a string
expect(result.data).toBeDefined();
expect(typeof result.data).toBe("string");
expect(result.data).toBeTruthy(); // Plain text is not empty
expect(result.response).toBeDefined();
expect(result.response.status).toBe(200);
},
testTimeout,
);
test("should handle FormData in post helper", async () => {
const cache = new Cacheable();
const url = `${testUrl}/post`;
const formData = new FormData();
formData.append("test", "data");
// Since the server might not handle FormData properly, we'll just verify it doesn't crash
// The actual FormData handling is covered in the branch coverage
try {
const result = await post(url, formData, { cache });
expect(result).toBeDefined();
} catch (error) {
// If server doesn't accept FormData, that's okay - we're testing the client code
expect(error).toBeDefined();
}
});
test("should handle URLSearchParams in post helper", async () => {
const cache = new Cacheable();
const url = `${testUrl}/post`;
const params = new URLSearchParams();
params.append("key", "value");
// Since the server might not handle URLSearchParams properly, we'll just verify it doesn't crash
try {
const result = await post(url, params, { cache });
expect(result).toBeDefined();
} catch (error) {
// If server doesn't accept URLSearchParams, that's okay - we're testing the client code
expect(error).toBeDefined();
}
});
test("should handle Blob in post helper", async () => {
const cache = new Cacheable();
const url = `${testUrl}/post`;
const blob = new Blob(["test data"], { type: "text/plain" });
// Since the server might not handle Blob properly, we'll just verify it doesn't crash
try {
const result = await post(url, blob, { cache });
expect(result).toBeDefined();
} catch (error) {
// If server doesn't accept Blob, that's okay - we're testing the client code
expect(error).toBeDefined();
}
});
test("should handle FormData in patch helper", async () => {
const cache = new Cacheable();
const url = `${testUrl}/patch`;
const formData = new FormData();
formData.append("test", "data");
// Since the server might not handle FormData properly, we'll just verify it doesn't crash
try {
const result = await patch(url, formData, { cache });
expect(result).toBeDefined();
} catch (error) {
// If server doesn't accept FormData, that's okay - we're testing the client code
expect(error).toBeDefined();
}
});
test("should handle URLSearchParams in patch helper", async () => {
const cache = new Cacheable();
const url = `${testUrl}/patch`;
const params = new URLSearchParams();
params.append("key", "value");
// Since the server might not handle URLSearchParams properly, we'll just verify it doesn't crash
try {
const result = await patch(url, params, { cache });
expect(result).toBeDefined();
} catch (error) {
// If server doesn't accept URLSearchParams, that's okay - we're testing the client code
expect(error).toBeDefined();
}
});
test("should handle Blob in patch helper", async () => {
const cache = new Cacheable();
const url = `${testUrl}/patch`;
const blob = new Blob(["test data"], { type: "text/plain" });
// Since the server might not handle Blob properly, we'll just verify it doesn't crash
try {
const result = await patch(url, blob, { cache });
expect(result).toBeDefined();
} catch (error) {
// If server doesn't accept Blob, that's okay - we're testing the client code
expect(error).toBeDefined();
}
});
});