@nextrush/errors 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,458 @@
1
+ /**
2
+ * @nextrush/errors - HTTP Error Tests
3
+ */
4
+
5
+ import { describe, expect, it } from 'vitest';
6
+ import { HttpError } from '../base';
7
+ import {
8
+ BadGatewayError,
9
+ BadRequestError,
10
+ ConflictError,
11
+ ExpectationFailedError,
12
+ FailedDependencyError,
13
+ ForbiddenError,
14
+ GatewayTimeoutError,
15
+ GoneError,
16
+ HttpVersionNotSupportedError,
17
+ ImATeapotError,
18
+ InsufficientStorageError,
19
+ InternalServerError,
20
+ LengthRequiredError,
21
+ LockedError,
22
+ LoopDetectedError,
23
+ MethodNotAllowedError,
24
+ NetworkAuthRequiredError,
25
+ NotAcceptableError,
26
+ NotExtendedError,
27
+ NotFoundError,
28
+ NotImplementedError,
29
+ PayloadTooLargeError,
30
+ PaymentRequiredError,
31
+ PreconditionFailedError,
32
+ PreconditionRequiredError,
33
+ ProxyAuthRequiredError,
34
+ RangeNotSatisfiableError,
35
+ RequestHeaderFieldsTooLargeError,
36
+ RequestTimeoutError,
37
+ ServiceUnavailableError,
38
+ TooEarlyError,
39
+ TooManyRequestsError,
40
+ UnauthorizedError,
41
+ UnavailableForLegalReasonsError,
42
+ UnprocessableEntityError,
43
+ UnsupportedMediaTypeError,
44
+ UpgradeRequiredError,
45
+ UriTooLongError,
46
+ VariantAlsoNegotiatesError,
47
+ } from '../http-errors';
48
+
49
+ describe('4xx Client Errors', () => {
50
+ describe('BadRequestError', () => {
51
+ it('should have status 400', () => {
52
+ const error = new BadRequestError();
53
+ expect(error.status).toBe(400);
54
+ expect(error.code).toBe('BAD_REQUEST');
55
+ expect(error.message).toBe('Bad Request');
56
+ expect(error.expose).toBe(true);
57
+ });
58
+
59
+ it('should accept custom message', () => {
60
+ const error = new BadRequestError('Invalid JSON');
61
+ expect(error.message).toBe('Invalid JSON');
62
+ });
63
+
64
+ it('should accept options', () => {
65
+ const error = new BadRequestError('Invalid', { details: { field: 'name' } });
66
+ expect(error.details).toEqual({ field: 'name' });
67
+ });
68
+ });
69
+
70
+ describe('UnauthorizedError', () => {
71
+ it('should have status 401', () => {
72
+ const error = new UnauthorizedError();
73
+ expect(error.status).toBe(401);
74
+ expect(error.code).toBe('UNAUTHORIZED');
75
+ expect(error.message).toBe('Unauthorized');
76
+ });
77
+ });
78
+
79
+ describe('PaymentRequiredError', () => {
80
+ it('should have status 402', () => {
81
+ const error = new PaymentRequiredError();
82
+ expect(error.status).toBe(402);
83
+ expect(error.code).toBe('PAYMENT_REQUIRED');
84
+ });
85
+ });
86
+
87
+ describe('ForbiddenError', () => {
88
+ it('should have status 403', () => {
89
+ const error = new ForbiddenError();
90
+ expect(error.status).toBe(403);
91
+ expect(error.code).toBe('FORBIDDEN');
92
+ });
93
+
94
+ it('should accept custom message', () => {
95
+ const error = new ForbiddenError('Access denied to this resource');
96
+ expect(error.message).toBe('Access denied to this resource');
97
+ });
98
+ });
99
+
100
+ describe('NotFoundError', () => {
101
+ it('should have status 404', () => {
102
+ const error = new NotFoundError();
103
+ expect(error.status).toBe(404);
104
+ expect(error.code).toBe('NOT_FOUND');
105
+ });
106
+
107
+ it('should accept custom message', () => {
108
+ const error = new NotFoundError('User not found');
109
+ expect(error.message).toBe('User not found');
110
+ });
111
+ });
112
+
113
+ describe('MethodNotAllowedError', () => {
114
+ it('should have status 405', () => {
115
+ const error = new MethodNotAllowedError();
116
+ expect(error.status).toBe(405);
117
+ expect(error.code).toBe('METHOD_NOT_ALLOWED');
118
+ });
119
+
120
+ it('should store allowed methods', () => {
121
+ const error = new MethodNotAllowedError(['GET', 'POST']);
122
+ expect(error.allowedMethods).toEqual(['GET', 'POST']);
123
+ expect(error.details).toEqual({ allowedMethods: ['GET', 'POST'] });
124
+ });
125
+
126
+ it('should accept custom message', () => {
127
+ const error = new MethodNotAllowedError(['GET'], 'Only GET is allowed');
128
+ expect(error.message).toBe('Only GET is allowed');
129
+ });
130
+ });
131
+
132
+ describe('NotAcceptableError', () => {
133
+ it('should have status 406', () => {
134
+ const error = new NotAcceptableError();
135
+ expect(error.status).toBe(406);
136
+ expect(error.code).toBe('NOT_ACCEPTABLE');
137
+ });
138
+ });
139
+
140
+ describe('ProxyAuthRequiredError', () => {
141
+ it('should have status 407', () => {
142
+ const error = new ProxyAuthRequiredError();
143
+ expect(error.status).toBe(407);
144
+ expect(error.code).toBe('PROXY_AUTH_REQUIRED');
145
+ });
146
+ });
147
+
148
+ describe('RequestTimeoutError', () => {
149
+ it('should have status 408', () => {
150
+ const error = new RequestTimeoutError();
151
+ expect(error.status).toBe(408);
152
+ expect(error.code).toBe('REQUEST_TIMEOUT');
153
+ });
154
+ });
155
+
156
+ describe('ConflictError', () => {
157
+ it('should have status 409', () => {
158
+ const error = new ConflictError();
159
+ expect(error.status).toBe(409);
160
+ expect(error.code).toBe('CONFLICT');
161
+ });
162
+
163
+ it('should accept custom message', () => {
164
+ const error = new ConflictError('Resource already exists');
165
+ expect(error.message).toBe('Resource already exists');
166
+ });
167
+ });
168
+
169
+ describe('GoneError', () => {
170
+ it('should have status 410', () => {
171
+ const error = new GoneError();
172
+ expect(error.status).toBe(410);
173
+ expect(error.code).toBe('GONE');
174
+ });
175
+ });
176
+
177
+ describe('LengthRequiredError', () => {
178
+ it('should have status 411', () => {
179
+ const error = new LengthRequiredError();
180
+ expect(error.status).toBe(411);
181
+ expect(error.code).toBe('LENGTH_REQUIRED');
182
+ });
183
+ });
184
+
185
+ describe('PreconditionFailedError', () => {
186
+ it('should have status 412', () => {
187
+ const error = new PreconditionFailedError();
188
+ expect(error.status).toBe(412);
189
+ expect(error.code).toBe('PRECONDITION_FAILED');
190
+ });
191
+ });
192
+
193
+ describe('PayloadTooLargeError', () => {
194
+ it('should have status 413', () => {
195
+ const error = new PayloadTooLargeError();
196
+ expect(error.status).toBe(413);
197
+ expect(error.code).toBe('PAYLOAD_TOO_LARGE');
198
+ });
199
+ });
200
+
201
+ describe('UriTooLongError', () => {
202
+ it('should have status 414', () => {
203
+ const error = new UriTooLongError();
204
+ expect(error.status).toBe(414);
205
+ expect(error.code).toBe('URI_TOO_LONG');
206
+ });
207
+ });
208
+
209
+ describe('UnsupportedMediaTypeError', () => {
210
+ it('should have status 415', () => {
211
+ const error = new UnsupportedMediaTypeError();
212
+ expect(error.status).toBe(415);
213
+ expect(error.code).toBe('UNSUPPORTED_MEDIA_TYPE');
214
+ });
215
+ });
216
+
217
+ describe('RangeNotSatisfiableError', () => {
218
+ it('should have status 416', () => {
219
+ const error = new RangeNotSatisfiableError();
220
+ expect(error.status).toBe(416);
221
+ expect(error.code).toBe('RANGE_NOT_SATISFIABLE');
222
+ });
223
+ });
224
+
225
+ describe('ExpectationFailedError', () => {
226
+ it('should have status 417', () => {
227
+ const error = new ExpectationFailedError();
228
+ expect(error.status).toBe(417);
229
+ expect(error.code).toBe('EXPECTATION_FAILED');
230
+ });
231
+ });
232
+
233
+ describe('ImATeapotError', () => {
234
+ it('should have status 418', () => {
235
+ const error = new ImATeapotError();
236
+ expect(error.status).toBe(418);
237
+ expect(error.code).toBe('IM_A_TEAPOT');
238
+ expect(error.message).toBe("I'm a teapot");
239
+ });
240
+ });
241
+
242
+ describe('UnprocessableEntityError', () => {
243
+ it('should have status 422', () => {
244
+ const error = new UnprocessableEntityError();
245
+ expect(error.status).toBe(422);
246
+ expect(error.code).toBe('UNPROCESSABLE_ENTITY');
247
+ });
248
+ });
249
+
250
+ describe('LockedError', () => {
251
+ it('should have status 423', () => {
252
+ const error = new LockedError();
253
+ expect(error.status).toBe(423);
254
+ expect(error.code).toBe('LOCKED');
255
+ });
256
+ });
257
+
258
+ describe('FailedDependencyError', () => {
259
+ it('should have status 424', () => {
260
+ const error = new FailedDependencyError();
261
+ expect(error.status).toBe(424);
262
+ expect(error.code).toBe('FAILED_DEPENDENCY');
263
+ });
264
+ });
265
+
266
+ describe('TooEarlyError', () => {
267
+ it('should have status 425', () => {
268
+ const error = new TooEarlyError();
269
+ expect(error.status).toBe(425);
270
+ expect(error.code).toBe('TOO_EARLY');
271
+ });
272
+ });
273
+
274
+ describe('UpgradeRequiredError', () => {
275
+ it('should have status 426', () => {
276
+ const error = new UpgradeRequiredError();
277
+ expect(error.status).toBe(426);
278
+ expect(error.code).toBe('UPGRADE_REQUIRED');
279
+ });
280
+ });
281
+
282
+ describe('PreconditionRequiredError', () => {
283
+ it('should have status 428', () => {
284
+ const error = new PreconditionRequiredError();
285
+ expect(error.status).toBe(428);
286
+ expect(error.code).toBe('PRECONDITION_REQUIRED');
287
+ });
288
+ });
289
+
290
+ describe('TooManyRequestsError', () => {
291
+ it('should have status 429', () => {
292
+ const error = new TooManyRequestsError();
293
+ expect(error.status).toBe(429);
294
+ expect(error.code).toBe('TOO_MANY_REQUESTS');
295
+ });
296
+
297
+ it('should store retryAfter', () => {
298
+ const error = new TooManyRequestsError('Rate limited', { retryAfter: 60 });
299
+ expect(error.retryAfter).toBe(60);
300
+ expect(error.details).toEqual({ retryAfter: 60 });
301
+ });
302
+ });
303
+
304
+ describe('RequestHeaderFieldsTooLargeError', () => {
305
+ it('should have status 431', () => {
306
+ const error = new RequestHeaderFieldsTooLargeError();
307
+ expect(error.status).toBe(431);
308
+ expect(error.code).toBe('REQUEST_HEADER_FIELDS_TOO_LARGE');
309
+ });
310
+ });
311
+
312
+ describe('UnavailableForLegalReasonsError', () => {
313
+ it('should have status 451', () => {
314
+ const error = new UnavailableForLegalReasonsError();
315
+ expect(error.status).toBe(451);
316
+ expect(error.code).toBe('UNAVAILABLE_FOR_LEGAL_REASONS');
317
+ });
318
+ });
319
+ });
320
+
321
+ describe('5xx Server Errors', () => {
322
+ describe('InternalServerError', () => {
323
+ it('should have status 500', () => {
324
+ const error = new InternalServerError();
325
+ expect(error.status).toBe(500);
326
+ expect(error.code).toBe('INTERNAL_SERVER_ERROR');
327
+ expect(error.expose).toBe(false);
328
+ });
329
+
330
+ it('should accept custom message', () => {
331
+ const error = new InternalServerError('Database connection failed');
332
+ expect(error.message).toBe('Database connection failed');
333
+ });
334
+ });
335
+
336
+ describe('NotImplementedError', () => {
337
+ it('should have status 501', () => {
338
+ const error = new NotImplementedError();
339
+ expect(error.status).toBe(501);
340
+ expect(error.code).toBe('NOT_IMPLEMENTED');
341
+ expect(error.expose).toBe(false);
342
+ });
343
+ });
344
+
345
+ describe('BadGatewayError', () => {
346
+ it('should have status 502', () => {
347
+ const error = new BadGatewayError();
348
+ expect(error.status).toBe(502);
349
+ expect(error.code).toBe('BAD_GATEWAY');
350
+ expect(error.expose).toBe(false);
351
+ });
352
+ });
353
+
354
+ describe('ServiceUnavailableError', () => {
355
+ it('should have status 503', () => {
356
+ const error = new ServiceUnavailableError();
357
+ expect(error.status).toBe(503);
358
+ expect(error.code).toBe('SERVICE_UNAVAILABLE');
359
+ expect(error.expose).toBe(false);
360
+ });
361
+
362
+ it('should store retryAfter', () => {
363
+ const error = new ServiceUnavailableError('Maintenance', { retryAfter: 3600 });
364
+ expect(error.retryAfter).toBe(3600);
365
+ });
366
+ });
367
+
368
+ describe('GatewayTimeoutError', () => {
369
+ it('should have status 504', () => {
370
+ const error = new GatewayTimeoutError();
371
+ expect(error.status).toBe(504);
372
+ expect(error.code).toBe('GATEWAY_TIMEOUT');
373
+ expect(error.expose).toBe(false);
374
+ });
375
+ });
376
+
377
+ describe('HttpVersionNotSupportedError', () => {
378
+ it('should have status 505', () => {
379
+ const error = new HttpVersionNotSupportedError();
380
+ expect(error.status).toBe(505);
381
+ expect(error.code).toBe('HTTP_VERSION_NOT_SUPPORTED');
382
+ });
383
+ });
384
+
385
+ describe('VariantAlsoNegotiatesError', () => {
386
+ it('should have status 506', () => {
387
+ const error = new VariantAlsoNegotiatesError();
388
+ expect(error.status).toBe(506);
389
+ expect(error.code).toBe('VARIANT_ALSO_NEGOTIATES');
390
+ });
391
+ });
392
+
393
+ describe('InsufficientStorageError', () => {
394
+ it('should have status 507', () => {
395
+ const error = new InsufficientStorageError();
396
+ expect(error.status).toBe(507);
397
+ expect(error.code).toBe('INSUFFICIENT_STORAGE');
398
+ });
399
+ });
400
+
401
+ describe('LoopDetectedError', () => {
402
+ it('should have status 508', () => {
403
+ const error = new LoopDetectedError();
404
+ expect(error.status).toBe(508);
405
+ expect(error.code).toBe('LOOP_DETECTED');
406
+ });
407
+ });
408
+
409
+ describe('NotExtendedError', () => {
410
+ it('should have status 510', () => {
411
+ const error = new NotExtendedError();
412
+ expect(error.status).toBe(510);
413
+ expect(error.code).toBe('NOT_EXTENDED');
414
+ });
415
+ });
416
+
417
+ describe('NetworkAuthRequiredError', () => {
418
+ it('should have status 511', () => {
419
+ const error = new NetworkAuthRequiredError();
420
+ expect(error.status).toBe(511);
421
+ expect(error.code).toBe('NETWORK_AUTH_REQUIRED');
422
+ });
423
+ });
424
+ });
425
+
426
+ describe('Error inheritance', () => {
427
+ it('all 4xx errors should be instanceof HttpError', () => {
428
+ const errors = [
429
+ new BadRequestError(),
430
+ new UnauthorizedError(),
431
+ new ForbiddenError(),
432
+ new NotFoundError(),
433
+ new MethodNotAllowedError(),
434
+ new ConflictError(),
435
+ new TooManyRequestsError(),
436
+ ];
437
+
438
+ for (const error of errors) {
439
+ expect(error).toBeInstanceOf(HttpError);
440
+ expect(error).toBeInstanceOf(Error);
441
+ }
442
+ });
443
+
444
+ it('all 5xx errors should be instanceof HttpError', () => {
445
+ const errors = [
446
+ new InternalServerError(),
447
+ new NotImplementedError(),
448
+ new BadGatewayError(),
449
+ new ServiceUnavailableError(),
450
+ new GatewayTimeoutError(),
451
+ ];
452
+
453
+ for (const error of errors) {
454
+ expect(error).toBeInstanceOf(HttpError);
455
+ expect(error).toBeInstanceOf(Error);
456
+ }
457
+ });
458
+ });