-
Notifications
You must be signed in to change notification settings - Fork 577
Expand file tree
/
Copy pathfetch-resource.spec.ts
More file actions
118 lines (96 loc) · 3.58 KB
/
fetch-resource.spec.ts
File metadata and controls
118 lines (96 loc) · 3.58 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
/**
* @jest-environment node
*/
import fetch, { Headers } from 'node-fetch';
import { vi } from 'vitest';
import { fetchResource } from '../feature';
vi.mock('node-fetch', async () => {
const actual = await vi.importActual('node-fetch');
return {
...actual,
default: vi.fn()
};
});
/**
* mock valid response
*/
function mockFetchOnce(data: any = {}, headers: Headers = new Headers()) {
// @ts-expect-error fetch does not have mocked fn
fetch.mockResolvedValueOnce({
headers,
json: async () => data
});
}
/**
* mock error during process
*/
function mockRejectOnce<T extends Error>(error: T) {
// @ts-expect-error fetch does not have mocked fn
fetch.mockRejectedValueOnce(error);
}
describe('fetchResource', () => {
const uri = 'http://hello.world/data.json';
const headers = new Headers({ 'Content-Type': 'application/json' });
afterEach(() => {
vi.clearAllMocks();
});
it('should be called with proper arguments', async () => {
mockFetchOnce({}, new Headers({ 'Content-Type': 'application/json, charset=utf-8' }));
const resource = await fetchResource(uri, headers, 100, 100);
expect(fetch).toHaveBeenCalledWith(uri, expect.anything());
expect(resource.data).toEqual({});
});
it('should throw exception for unsupported media', async () => {
mockFetchOnce();
await expect(() => {
return fetchResource(uri, headers, 100, 100);
}).rejects.toThrowError('Unsupported Media Type');
});
it('should throw exception upon exceeded size', async () => {
mockRejectOnce(new Error('FetchError: content size at https://path/to/resour.ce over limit: 100'));
await expect(() => {
return fetchResource(uri, headers, 100, 100);
}).rejects.toThrowError('Max Content Size Exceeded');
});
it('should handle AbortSignal', async () => {
class TimeoutError extends Error {
constructor() {
super();
this.name = 'TimeoutError';
}
}
mockRejectOnce(new TimeoutError());
await expect(() => {
return fetchResource(uri, headers, 100, 100);
}).rejects.toThrowError('Gateway Timeout');
});
it('should handle size overflow', async () => {
mockRejectOnce(new Error('file is over limit: 100'));
await expect(() => {
return fetchResource(uri, headers, 100, 100);
}).rejects.toThrowError('Max Content Size Exceeded');
});
it('should handle unexpected result', async () => {
// @ts-expect-error fetch does not have mocked fn
fetch.mockRejectedValueOnce({ data: "unexpected exception" });
const fn = () => {
return fetchResource(uri, headers, 100, 100);
};
try {
await fn();
} catch (e: any) {
expect(e.message).toEqual('General Error');
expect(e.status).toEqual(500);
}
});
it('should handle malformed JSON response gracefully', async () => {
// Mock fetch to return a response with invalid JSON
// @ts-expect-error fetch does not have mocked fn
fetch.mockResolvedValueOnce({
headers: new Headers({ 'Content-Type': 'application/json' }),
// Simulate malformed JSON by rejecting during json parsing
json: async () => { throw new SyntaxError('Unexpected token < in JSON at position 0'); }
});
await expect(fetchResource(uri, headers, 100, 100)).rejects.toThrowError('Unsupported Media Type');
});
});