Skip to content

Commit c60893c

Browse files
Merge pull request #148 from contentstack/enh/retry-unit-testcases
chore: Added unit testcases
2 parents 969ccd4 + dfdccc2 commit c60893c

File tree

4 files changed

+470
-0
lines changed

4 files changed

+470
-0
lines changed

test/api-error.spec.ts

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
import { APIError } from '../src/lib/api-error';
2+
3+
describe('APIError', () => {
4+
describe('constructor', () => {
5+
it('should create an APIError with all properties', () => {
6+
const error = new APIError('Test error', 'ERROR_CODE', 404);
7+
8+
expect(error.message).toBe('Test error');
9+
expect(error.error_code).toBe('ERROR_CODE');
10+
expect(error.status).toBe(404);
11+
expect(error.error_message).toBe('Test error');
12+
expect(error.name).toBe('APIError');
13+
expect(error.stack).toBeUndefined();
14+
});
15+
16+
it('should create an APIError with numeric error_code', () => {
17+
const error = new APIError('Test error', 500, 500);
18+
19+
expect(error.error_code).toBe(500);
20+
expect(error.status).toBe(500);
21+
});
22+
});
23+
24+
describe('fromAxiosError', () => {
25+
it('should create APIError from axios error with response data', () => {
26+
const axiosError = {
27+
response: {
28+
data: {
29+
error_message: 'Not Found',
30+
error_code: 404,
31+
},
32+
status: 404,
33+
},
34+
};
35+
36+
const error = APIError.fromAxiosError(axiosError);
37+
38+
expect(error).toBeInstanceOf(APIError);
39+
expect(error.error_message).toBe('Not Found');
40+
expect(error.error_code).toBe(404);
41+
expect(error.status).toBe(404);
42+
});
43+
44+
it('should create APIError from axios error with message but no response', () => {
45+
const axiosError = {
46+
message: 'Network Error',
47+
code: 'ENOTFOUND',
48+
};
49+
50+
const error = APIError.fromAxiosError(axiosError);
51+
52+
expect(error).toBeInstanceOf(APIError);
53+
expect(error.error_message).toBe('Network Error');
54+
expect(error.error_code).toBe('ENOTFOUND');
55+
expect(error.status).toBe(0);
56+
});
57+
58+
it('should create APIError from axios error with message but no code', () => {
59+
const axiosError = {
60+
message: 'Network Error',
61+
};
62+
63+
const error = APIError.fromAxiosError(axiosError);
64+
65+
expect(error).toBeInstanceOf(APIError);
66+
expect(error.error_message).toBe('Network Error');
67+
expect(error.error_code).toBe('NETWORK_ERROR');
68+
expect(error.status).toBe(0);
69+
});
70+
71+
it('should create APIError with default message for unknown errors', () => {
72+
const axiosError = {};
73+
74+
const error = APIError.fromAxiosError(axiosError);
75+
76+
expect(error).toBeInstanceOf(APIError);
77+
expect(error.error_message).toBe('Unknown error occurred');
78+
expect(error.error_code).toBe('UNKNOWN_ERROR');
79+
expect(error.status).toBe(0);
80+
});
81+
82+
it('should handle axios error with response.data but no response.status', () => {
83+
const axiosError = {
84+
response: {
85+
data: {
86+
error_message: 'Server Error',
87+
},
88+
},
89+
};
90+
91+
// This should call fromResponseData, which requires status
92+
// Let's test with a proper status
93+
const axiosErrorWithStatus = {
94+
response: {
95+
data: {
96+
error_message: 'Server Error',
97+
},
98+
status: 500,
99+
},
100+
};
101+
102+
const error = APIError.fromAxiosError(axiosErrorWithStatus);
103+
104+
expect(error).toBeInstanceOf(APIError);
105+
expect(error.error_message).toBe('Server Error');
106+
expect(error.status).toBe(500);
107+
});
108+
});
109+
110+
describe('fromResponseData', () => {
111+
it('should create APIError from response data with error_message', () => {
112+
const responseData = {
113+
error_message: 'Bad Request',
114+
error_code: 400,
115+
};
116+
117+
const error = APIError.fromResponseData(responseData, 400);
118+
119+
expect(error).toBeInstanceOf(APIError);
120+
expect(error.error_message).toBe('Bad Request');
121+
expect(error.error_code).toBe(400);
122+
expect(error.status).toBe(400);
123+
});
124+
125+
it('should create APIError from response data with message fallback', () => {
126+
const responseData = {
127+
message: 'Internal Server Error',
128+
code: 500,
129+
};
130+
131+
const error = APIError.fromResponseData(responseData, 500);
132+
133+
expect(error).toBeInstanceOf(APIError);
134+
expect(error.error_message).toBe('Internal Server Error');
135+
expect(error.error_code).toBe(500);
136+
expect(error.status).toBe(500);
137+
});
138+
139+
it('should create APIError from response data with error fallback', () => {
140+
const responseData = {
141+
error: 'Validation Error',
142+
code: 422,
143+
};
144+
145+
const error = APIError.fromResponseData(responseData, 422);
146+
147+
expect(error).toBeInstanceOf(APIError);
148+
expect(error.error_message).toBe('Validation Error');
149+
expect(error.error_code).toBe(422);
150+
expect(error.status).toBe(422);
151+
});
152+
153+
it('should create APIError from string response data', () => {
154+
const responseData = 'Plain text error message';
155+
156+
const error = APIError.fromResponseData(responseData, 500);
157+
158+
expect(error).toBeInstanceOf(APIError);
159+
expect(error.error_message).toBe('Plain text error message');
160+
expect(error.error_code).toBe(500);
161+
expect(error.status).toBe(500);
162+
});
163+
164+
it('should create APIError with default message when no error fields present', () => {
165+
const responseData = {
166+
someOtherField: 'value',
167+
};
168+
169+
const error = APIError.fromResponseData(responseData, 500);
170+
171+
expect(error).toBeInstanceOf(APIError);
172+
expect(error.error_message).toBe('Request failed');
173+
expect(error.error_code).toBe(500);
174+
expect(error.status).toBe(500);
175+
});
176+
177+
it('should extract error_code from response data', () => {
178+
const responseData = {
179+
error_message: 'Error',
180+
error_code: 999,
181+
};
182+
183+
const error = APIError.fromResponseData(responseData, 500);
184+
185+
expect(error.error_code).toBe(999);
186+
});
187+
188+
it('should extract code from response data when error_code not present', () => {
189+
const responseData = {
190+
error_message: 'Error',
191+
code: 888,
192+
};
193+
194+
const error = APIError.fromResponseData(responseData, 500);
195+
196+
expect(error.error_code).toBe(888);
197+
});
198+
199+
it('should use status as error_code fallback', () => {
200+
const responseData = {
201+
error_message: 'Error',
202+
};
203+
204+
const error = APIError.fromResponseData(responseData, 503);
205+
206+
expect(error.error_code).toBe(503);
207+
});
208+
});
209+
});

test/contentstack-core.spec.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,9 @@ describe('contentstackCore', () => {
150150

151151
describe('config.onError', () => {
152152
it('should call the onError function when an error occurs', async () => {
153+
// Suppress expected console.error from network error
154+
const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation();
155+
153156
const onError = jest.fn();
154157
const options = {
155158
defaultHostname: 'cdn.contentstack.io',
@@ -163,6 +166,8 @@ describe('contentstackCore', () => {
163166
} catch (error: unknown) {
164167
expect(onError).toBeCalledWith(error);
165168
}
169+
170+
consoleErrorSpy.mockRestore();
166171
});
167172

168173
it('should not call the onError function when no error occurs', async () => {

test/request.spec.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,4 +344,34 @@ describe('Request tests', () => {
344344
const result = await getData(client, url, requestData);
345345
expect(result).toEqual(mockResponse);
346346
});
347+
348+
it('should use instance.request when URL length exceeds 2000 characters', async () => {
349+
const client = httpClient({ defaultHostname: 'example.com' });
350+
const url = '/your-api-endpoint';
351+
const mockResponse = { data: 'mocked' };
352+
353+
// Create a very long query parameter that will exceed 2000 characters when combined with baseURL
354+
// baseURL is typically like 'https://example.com:443/v3' (~30 chars), url is '/your-api-endpoint' (~20 chars)
355+
// So we need params that serialize to >1950 chars to exceed 2000 total
356+
const longParam = 'x'.repeat(2000);
357+
const requestData = { params: { longParam, param2: 'y'.repeat(500) } };
358+
359+
// Mock instance.request since that's what gets called for long URLs
360+
const requestSpy = jest.spyOn(client, 'request').mockResolvedValue({ data: mockResponse } as any);
361+
362+
const result = await getData(client, url, requestData);
363+
364+
expect(result).toEqual(mockResponse);
365+
// Verify that request was called (not get) with the full URL
366+
expect(requestSpy).toHaveBeenCalledWith(
367+
expect.objectContaining({
368+
method: 'get',
369+
url: expect.stringMatching(/longParam/),
370+
maxContentLength: Infinity,
371+
maxBodyLength: Infinity,
372+
})
373+
);
374+
375+
requestSpy.mockRestore();
376+
});
347377
});

0 commit comments

Comments
 (0)