Skip to content

Commit 4b4f6f8

Browse files
authored
Merge pull request #122 from contentstack/development
Development
2 parents 04bc664 + 3325f95 commit 4b4f6f8

File tree

4 files changed

+658
-31
lines changed

4 files changed

+658
-31
lines changed

.talismanrc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,6 @@ fileignoreconfig:
66
checksum: 34d28e7736ffac2b27d3708b6bca28591f3a930292433001d2397bfdf2d2fd0f
77
- filename: .husky/pre-commit
88
checksum: 5baabd7d2c391648163f9371f0e5e9484f8fb90fa2284cfc378732ec3192c193
9+
- filename: test/request.spec.ts
10+
checksum: 87afd3bb570fd52437404cbe69a39311ad8a8c73bca9d075ecf88652fd3e13f6
911
version: ""

src/lib/retryPolicy/delivery-sdk-handlers.ts

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ const retry = (error: any, config: any, retryCount: number, retryDelay: number,
127127
* @param headers - Response headers from the API
128128
* @returns Delay time in milliseconds
129129
*/
130-
const calculateRateLimitDelay = (headers: any): number => {
130+
export const calculateRateLimitDelay = (headers: any): number => {
131131
// Check for retry-after header (in seconds)
132132
const retryAfter = headers['retry-after'];
133133
if (retryAfter) {
@@ -156,17 +156,6 @@ const calculateRateLimitDelay = (headers: any): number => {
156156
return Math.max(delay + 1000, 1000); // At least 1 second delay
157157
}
158158

159-
// Default fallback delay (60 seconds) if no rate limit reset info is available
160-
return 60000;
161-
};
162-
163-
/**
164-
* Retry request after specified delay
165-
* @param error - The original error object
166-
* @param delay - Delay time in milliseconds
167-
* @param axiosInstance - Axios instance to retry with
168-
* @returns Promise that resolves after the delay and retry
169-
*/
170-
const retryWithDelay = async (error: any, delay: number, axiosInstance: AxiosInstance) => {
171-
return
159+
// Default fallback delay (1 second) if no rate limit reset info is available
160+
return 1000;
172161
};

test/request.spec.ts

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,4 +111,213 @@ describe('Request tests', () => {
111111
expect(mock.history.get[0].url).toBe(livePreviewURL);
112112
expect(result).toEqual(mockResponse);
113113
});
114+
115+
it('should throw error when response has no data property', async () => {
116+
const client = httpClient({});
117+
const mock = new MockAdapter(client as any);
118+
const url = '/your-api-endpoint';
119+
const responseWithoutData = { status: 200, headers: {} }; // Response without data property
120+
121+
// Mock response that returns undefined/empty data
122+
mock.onGet(url).reply(() => [200, undefined, {}]);
123+
124+
await expect(getData(client, url)).rejects.toThrowError();
125+
});
126+
127+
it('should throw error when response is null', async () => {
128+
const client = httpClient({});
129+
const mock = new MockAdapter(client as any);
130+
const url = '/your-api-endpoint';
131+
132+
// Mock response that returns null
133+
mock.onGet(url).reply(() => [200, null]);
134+
135+
await expect(getData(client, url)).rejects.toThrowError();
136+
});
137+
138+
it('should handle live_preview when enable is false', async () => {
139+
const client = httpClient({});
140+
const mock = new MockAdapter(client as any);
141+
const url = '/your-api-endpoint';
142+
const mockResponse = { data: 'mocked' };
143+
144+
client.stackConfig = {
145+
live_preview: {
146+
enable: false, // Disabled
147+
preview_token: 'someToken',
148+
live_preview: 'someHash',
149+
host: 'rest-preview.com',
150+
},
151+
};
152+
153+
mock.onGet(url).reply(200, mockResponse);
154+
155+
const result = await getData(client, url, {});
156+
157+
// Should not modify URL when live preview is disabled
158+
expect(mock.history.get[0].url).toBe(url);
159+
expect(result).toEqual(mockResponse);
160+
});
161+
162+
it('should handle request when stackConfig is undefined', async () => {
163+
const client = httpClient({});
164+
const mock = new MockAdapter(client as any);
165+
const url = '/your-api-endpoint';
166+
const mockResponse = { data: 'mocked' };
167+
168+
// No stackConfig set
169+
client.stackConfig = undefined;
170+
171+
mock.onGet(url).reply(200, mockResponse);
172+
173+
const result = await getData(client, url, {});
174+
expect(result).toEqual(mockResponse);
175+
});
176+
177+
it('should handle request when stackConfig exists but live_preview is undefined', async () => {
178+
const client = httpClient({});
179+
const mock = new MockAdapter(client as any);
180+
const url = '/your-api-endpoint';
181+
const mockResponse = { data: 'mocked' };
182+
183+
client.stackConfig = {
184+
// live_preview not defined
185+
apiKey: 'test-key',
186+
};
187+
188+
mock.onGet(url).reply(200, mockResponse);
189+
190+
const result = await getData(client, url, {});
191+
expect(result).toEqual(mockResponse);
192+
});
193+
194+
it('should set live_preview to "init" when enable is true and no live_preview provided', async () => {
195+
const client = httpClient({});
196+
const mock = new MockAdapter(client as any);
197+
const url = '/your-api-endpoint';
198+
const mockResponse = { data: 'mocked' };
199+
200+
client.stackConfig = {
201+
live_preview: {
202+
enable: true,
203+
preview_token: 'someToken',
204+
// live_preview not provided
205+
},
206+
};
207+
208+
mock.onGet(url).reply(200, mockResponse);
209+
210+
const data: any = {};
211+
const result = await getData(client, url, data);
212+
213+
// Should set live_preview to 'init'
214+
expect(data.live_preview).toBe('init');
215+
expect(result).toEqual(mockResponse);
216+
});
217+
218+
it('should set headers when preview_token is provided', async () => {
219+
const client = httpClient({});
220+
const mock = new MockAdapter(client as any);
221+
const url = '/your-api-endpoint';
222+
const mockResponse = { data: 'mocked' };
223+
224+
client.stackConfig = {
225+
live_preview: {
226+
enable: true,
227+
preview_token: 'test-preview-token',
228+
live_preview: 'init',
229+
},
230+
};
231+
232+
mock.onGet(url).reply(200, mockResponse);
233+
234+
const result = await getData(client, url, {});
235+
236+
// Should set headers
237+
expect(client.defaults.headers.preview_token).toBe('test-preview-token');
238+
expect(client.defaults.headers.live_preview).toBe('init');
239+
expect(result).toEqual(mockResponse);
240+
});
241+
242+
it('should handle live_preview when enable is true but no preview_token', async () => {
243+
const client = httpClient({});
244+
const mock = new MockAdapter(client as any);
245+
const url = '/your-api-endpoint';
246+
const mockResponse = { data: 'mocked' };
247+
248+
client.stackConfig = {
249+
live_preview: {
250+
enable: true,
251+
live_preview: 'init',
252+
// preview_token not provided
253+
},
254+
};
255+
256+
mock.onGet(url).reply(200, mockResponse);
257+
258+
const data: any = {};
259+
const result = await getData(client, url, data);
260+
261+
// Should still set live_preview in data
262+
expect(data.live_preview).toBe('init');
263+
expect(result).toEqual(mockResponse);
264+
});
265+
266+
it('should handle custom error messages when request fails', async () => {
267+
const client = httpClient({});
268+
const mock = new MockAdapter(client as any);
269+
const url = '/your-api-endpoint';
270+
const customError = new Error('Custom network error');
271+
272+
mock.onGet(url).reply(() => {
273+
throw customError;
274+
});
275+
276+
await expect(getData(client, url)).rejects.toThrowError('Custom network error');
277+
});
278+
279+
it('should handle non-Error objects as errors when they have message property', async () => {
280+
const client = httpClient({});
281+
const mock = new MockAdapter(client as any);
282+
const url = '/your-api-endpoint';
283+
const errorObject = { status: 500, message: 'Internal Server Error' };
284+
285+
mock.onGet(url).reply(() => {
286+
throw errorObject;
287+
});
288+
289+
// When error has message property, it uses the message
290+
await expect(getData(client, url)).rejects.toThrowError('Internal Server Error');
291+
});
292+
293+
it('should handle non-Error objects as errors when they have no message property', async () => {
294+
const client = httpClient({});
295+
const mock = new MockAdapter(client as any);
296+
const url = '/your-api-endpoint';
297+
const errorObject = { status: 500, code: 'SERVER_ERROR' };
298+
299+
mock.onGet(url).reply(() => {
300+
throw errorObject;
301+
});
302+
303+
// When error has no message property, it stringifies the object
304+
await expect(getData(client, url)).rejects.toThrowError(JSON.stringify(errorObject));
305+
});
306+
307+
it('should pass data parameter to axios get request', async () => {
308+
const client = httpClient({});
309+
const mock = new MockAdapter(client as any);
310+
const url = '/your-api-endpoint';
311+
const mockResponse = { data: 'mocked' };
312+
const requestData = { params: { limit: 10, skip: 0 } };
313+
314+
mock.onGet(url).reply((config) => {
315+
// Verify that data was passed correctly
316+
expect(config.params).toEqual(requestData.params);
317+
return [200, mockResponse];
318+
});
319+
320+
const result = await getData(client, url, requestData);
321+
expect(result).toEqual(mockResponse);
322+
});
114323
});

0 commit comments

Comments
 (0)