@vida-global/core 1.3.3 → 1.4.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.
- package/lib/logger/index.js +4 -1
- package/lib/server/README.md +30 -8
- package/lib/server/serverController.js +108 -34
- package/package.json +2 -2
- package/test/server/serverController.test.js +65 -72
package/lib/logger/index.js
CHANGED
package/lib/server/README.md
CHANGED
|
@@ -118,9 +118,34 @@ Additional options can be passed to `toApiResponse` by explicitly calling `rende
|
|
|
118
118
|
await this.render(response, {includeTitle: true});
|
|
119
119
|
```
|
|
120
120
|
|
|
121
|
+
### Other Status Codes
|
|
122
|
+
There is no need to set `statusCode` directly as there are helper methods for all statuses.
|
|
123
|
+
```
|
|
124
|
+
201 - this.renderCreationSuccessful
|
|
125
|
+
202 - this.renderAccepted
|
|
126
|
+
204 - this.renderNoConent
|
|
127
|
+
301 - this.renderMovedPermanently
|
|
128
|
+
302 - this.renderFound
|
|
129
|
+
304 - this.renderNotModified
|
|
130
|
+
307 - this.renderTemporaryRedirect
|
|
131
|
+
308 - this.renderPermanentRedirect
|
|
132
|
+
401 - this.renderUnauthorizedResponse
|
|
133
|
+
402 - this.renderPaymentRequired
|
|
134
|
+
403 - this.renderForbiddenResponse
|
|
135
|
+
404 - this.renderNotFoundResponse
|
|
136
|
+
405 - this.renderMethodNotAllowed
|
|
137
|
+
408 - this.renderRequestTimeout
|
|
138
|
+
409 - this.renderConflictResponse
|
|
139
|
+
410 - this.renderGone
|
|
140
|
+
413 - this.renderContentTooLarge
|
|
141
|
+
415 - this.renderUnsupportedMediaType
|
|
142
|
+
422 - this.renderUnprocessableContent
|
|
143
|
+
423 - this.renderLocked
|
|
144
|
+
429 - this.renderTooManyRequests
|
|
145
|
+
```
|
|
146
|
+
|
|
121
147
|
|
|
122
148
|
## Error handling
|
|
123
|
-
There is no need to set `statusCode` directly as there are helper methods for all statuses.
|
|
124
149
|
HTTP 400
|
|
125
150
|
```
|
|
126
151
|
await this.renderErrors("Something bad happened", {password: ['must be > 8 characters', 'must include numbers']})
|
|
@@ -134,19 +159,16 @@ await this.renderErrors({password: ['must be > 8 characters', 'must include numb
|
|
|
134
159
|
```
|
|
135
160
|
HTTP 401
|
|
136
161
|
```
|
|
137
|
-
await this.
|
|
162
|
+
await this.renderUnauthorized("Nope")
|
|
138
163
|
// renders {data: {message: "Nope"}, status: "unauthorized"}
|
|
139
164
|
```
|
|
140
165
|
HTTP 403
|
|
141
166
|
```
|
|
142
|
-
await this.
|
|
167
|
+
await this.renderForbidden("You shall not pass")
|
|
143
168
|
// renders {data: {message: "You shall not pass"}, status: "forbidden"}
|
|
144
169
|
```
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
await this.renderNotFoundResponse("Whoops")
|
|
148
|
-
// renders {data: {message: "Whoops"}, status: "not found"}
|
|
149
|
-
```
|
|
170
|
+
* _Other statuses detailed above._
|
|
171
|
+
|
|
150
172
|
Throwing any of `this.Errors.Authorization(msg)`, `this.Errors.Forbidden(msg)`, `this.Errors.NotFound(msg)`, `this.Errors.Validation(msg, errors)` from anywhere in the code will trigger the corresponding error handler. All other errors will generate a 500 error.
|
|
151
173
|
|
|
152
174
|
|
|
@@ -28,6 +28,7 @@ class VidaServerController {
|
|
|
28
28
|
this.#response = response;
|
|
29
29
|
|
|
30
30
|
this.#applyCallbacks();
|
|
31
|
+
this.#setupStatusRenderers();
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
|
|
@@ -121,13 +122,13 @@ class VidaServerController {
|
|
|
121
122
|
|
|
122
123
|
async #handleError(err) {
|
|
123
124
|
if (err instanceof AuthorizationError) {
|
|
124
|
-
await this.
|
|
125
|
+
await this.renderUnauthorized(err.message);
|
|
125
126
|
|
|
126
127
|
} else if (err instanceof ForbiddenError) {
|
|
127
|
-
await this.
|
|
128
|
+
await this.renderForbidden(err.message);
|
|
128
129
|
|
|
129
130
|
} else if (err instanceof NotFoundError) {
|
|
130
|
-
await this.
|
|
131
|
+
await this.renderNotFound(err.message);
|
|
131
132
|
|
|
132
133
|
} else if (err instanceof ValidationError) {
|
|
133
134
|
await this.renderErrors(err.message, err.fields);
|
|
@@ -140,7 +141,7 @@ class VidaServerController {
|
|
|
140
141
|
} else {
|
|
141
142
|
message = err.message;
|
|
142
143
|
}
|
|
143
|
-
await this.
|
|
144
|
+
await this.renderServerError(message);
|
|
144
145
|
}
|
|
145
146
|
}
|
|
146
147
|
|
|
@@ -186,33 +187,14 @@ class VidaServerController {
|
|
|
186
187
|
}
|
|
187
188
|
|
|
188
189
|
|
|
189
|
-
async
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
async renderForbiddenResponse(message=null) {
|
|
195
|
-
return await this.#renderError(403, message);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
async renderNotFoundResponse(message=null) {
|
|
200
|
-
return await this.#renderError(404, message);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
async renderServerErrorResponse(message=null) {
|
|
190
|
+
async renderServerError(message=null) {
|
|
191
|
+
if (process.env.NODE_ENV != 'development') {
|
|
192
|
+
message = null;
|
|
193
|
+
}
|
|
205
194
|
return await this.#renderError(500, message);
|
|
206
195
|
}
|
|
207
196
|
|
|
208
197
|
|
|
209
|
-
async #renderError(statusCode, message) {
|
|
210
|
-
this.statusCode = statusCode;
|
|
211
|
-
const body = {errors: {message: message || null}};
|
|
212
|
-
return await this.render(body);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
|
|
216
198
|
formatJSONBody(body, errors, options) {
|
|
217
199
|
if (options.standardize === false) return body;
|
|
218
200
|
|
|
@@ -253,26 +235,118 @@ class VidaServerController {
|
|
|
253
235
|
switch(this.statusCode) {
|
|
254
236
|
case 200:
|
|
255
237
|
return 'ok';
|
|
238
|
+
case 201:
|
|
239
|
+
return 'created';
|
|
240
|
+
case 202:
|
|
241
|
+
return 'accepted';
|
|
242
|
+
case 204:
|
|
243
|
+
return 'no content';
|
|
244
|
+
case 301:
|
|
245
|
+
return 'moved permanently';
|
|
246
|
+
case 302:
|
|
247
|
+
return 'found';
|
|
248
|
+
case 304:
|
|
249
|
+
return 'not modified';
|
|
250
|
+
case 307:
|
|
251
|
+
return 'temporary redirect';
|
|
252
|
+
case 308:
|
|
253
|
+
return 'permanent redirect';
|
|
256
254
|
case 400:
|
|
257
255
|
return 'bad request'
|
|
258
256
|
case 401:
|
|
259
257
|
return 'unauthorized';
|
|
258
|
+
case 402:
|
|
259
|
+
return 'payment required';
|
|
260
260
|
case 403:
|
|
261
261
|
return 'forbidden';
|
|
262
262
|
case 404:
|
|
263
263
|
return 'not found';
|
|
264
|
+
case 405:
|
|
265
|
+
return 'method not allowed';
|
|
266
|
+
case 408:
|
|
267
|
+
return 'request timeout';
|
|
268
|
+
case 409:
|
|
269
|
+
return 'conflict';
|
|
270
|
+
case 410:
|
|
271
|
+
return 'gone';
|
|
272
|
+
case 413:
|
|
273
|
+
return 'content too large';
|
|
274
|
+
case 415:
|
|
275
|
+
return 'unsupported media type';
|
|
276
|
+
case 422:
|
|
277
|
+
return 'unprocessable content';
|
|
278
|
+
case 423:
|
|
279
|
+
return 'locked';
|
|
280
|
+
case 429:
|
|
281
|
+
return 'too many requests';
|
|
264
282
|
case 500:
|
|
265
283
|
return 'server error';
|
|
266
284
|
}
|
|
267
285
|
}
|
|
268
286
|
|
|
269
287
|
|
|
288
|
+
#setupStatusRenderers() {
|
|
289
|
+
const errorStatuses = {
|
|
290
|
+
Unauthorized: 401,
|
|
291
|
+
PaymentRequired: 402,
|
|
292
|
+
Forbidden: 403,
|
|
293
|
+
NotFound: 404,
|
|
294
|
+
MethodNotAllowed: 405,
|
|
295
|
+
RequestTimeout: 408,
|
|
296
|
+
Conflict: 409,
|
|
297
|
+
Gone: 410,
|
|
298
|
+
ContentTooLarge: 413,
|
|
299
|
+
UnsupportedMediaType: 415,
|
|
300
|
+
UnprocessableContent: 422,
|
|
301
|
+
Locked: 423,
|
|
302
|
+
TooManyRequests: 429,
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const successStatuses = {
|
|
306
|
+
CreationSuccessful: 201,
|
|
307
|
+
Accepted: 202,
|
|
308
|
+
NoConent: 204,
|
|
309
|
+
MovedPermanently: 301,
|
|
310
|
+
Found: 302,
|
|
311
|
+
NotModified: 304,
|
|
312
|
+
TemporaryRedirect: 307,
|
|
313
|
+
PermanentRedirect: 308,
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
for (const [method, statusCode] of Object.entries(errorStatuses)) {
|
|
317
|
+
this[`render${method}`] = async function(message=null) {
|
|
318
|
+
return await this.#renderError(statusCode, message);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
for (const [method, statusCode] of Object.entries(successStatuses)) {
|
|
323
|
+
this[`render${method}`] = async function(message=null) {
|
|
324
|
+
return await this.#renderSuccess(statusCode, message);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
async #renderError(statusCode, message) {
|
|
331
|
+
this.statusCode = statusCode;
|
|
332
|
+
const body = {errors: {message: message || null}};
|
|
333
|
+
return await this.render(body);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
async #renderSuccess(statusCode, body) {
|
|
338
|
+
this.statusCode = statusCode;
|
|
339
|
+
return await this.render(body);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
|
|
270
343
|
/***********************************************************************************************
|
|
271
344
|
* HELPERS
|
|
272
345
|
***********************************************************************************************/
|
|
273
346
|
static autoLoadHelpers() {
|
|
274
|
-
const { InstanceMethods, Accessors } = this._autoLoadModule(this.autoLoadHelperPath);
|
|
347
|
+
const { StaticMethods, InstanceMethods, Accessors } = this._autoLoadModule(this.autoLoadHelperPath);
|
|
275
348
|
|
|
349
|
+
if (StaticMethods) Object.assign(this, StaticMethods);
|
|
276
350
|
if (InstanceMethods) Object.assign(this.prototype, InstanceMethods);
|
|
277
351
|
|
|
278
352
|
if (Accessors) {
|
|
@@ -385,10 +459,10 @@ class VidaServerController {
|
|
|
385
459
|
/***********************************************************************************************
|
|
386
460
|
* VALIDATIONS
|
|
387
461
|
***********************************************************************************************/
|
|
388
|
-
validateParameters(validations) {
|
|
462
|
+
async validateParameters(validations) {
|
|
389
463
|
const errors = {};
|
|
390
464
|
for (const [parameterName, parameterValidations] of Object.entries(validations)) {
|
|
391
|
-
const parameterErrors = this.validateParameter(this.params[parameterName], parameterValidations);
|
|
465
|
+
const parameterErrors = await this.validateParameter(this.params[parameterName], parameterValidations);
|
|
392
466
|
if (parameterErrors.length) errors[parameterName] = parameterErrors;
|
|
393
467
|
}
|
|
394
468
|
|
|
@@ -396,7 +470,7 @@ class VidaServerController {
|
|
|
396
470
|
}
|
|
397
471
|
|
|
398
472
|
|
|
399
|
-
validateParameter(value, parameterValidations) {
|
|
473
|
+
async validateParameter(value, parameterValidations) {
|
|
400
474
|
const errors = [];
|
|
401
475
|
|
|
402
476
|
if (parameterValidations?.optional && value === undefined) return errors;
|
|
@@ -404,7 +478,7 @@ class VidaServerController {
|
|
|
404
478
|
for (const [validationType, validationOptions] of Object.entries(parameterValidations)) {
|
|
405
479
|
const validationMethod = `validate${camelize(validationType)}`;
|
|
406
480
|
if (!this[validationMethod]) continue;
|
|
407
|
-
const error = this[validationMethod](value, validationOptions);
|
|
481
|
+
const error = await this[validationMethod](value, validationOptions);
|
|
408
482
|
if (error) errors.push(error);
|
|
409
483
|
}
|
|
410
484
|
|
|
@@ -457,8 +531,8 @@ class VidaServerController {
|
|
|
457
531
|
}
|
|
458
532
|
|
|
459
533
|
|
|
460
|
-
validateFunction(value, fnc) {
|
|
461
|
-
const error = fnc(value);
|
|
534
|
+
async validateFunction(value, fnc) {
|
|
535
|
+
const error = await fnc.call(this, value);
|
|
462
536
|
if (error) return error;
|
|
463
537
|
}
|
|
464
538
|
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vida-global/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Core libraries for supporting Vida development",
|
|
5
5
|
"author": "",
|
|
6
6
|
"license": "ISC",
|
|
7
7
|
"main": "index.js",
|
|
8
8
|
"scripts": {
|
|
9
|
-
"test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules node_modules/jest/bin/jest.js",
|
|
9
|
+
"test": "LOG_LEVEL=test NODE_NO_WARNINGS=1 node --experimental-vm-modules node_modules/jest/bin/jest.js",
|
|
10
10
|
"release": "node node_modules/@vida-global/release/scripts/release.js",
|
|
11
11
|
"develop": "node node_modules/@vida-global/release/scripts/release.js develop"
|
|
12
12
|
},
|
|
@@ -155,8 +155,8 @@ describe('VidaServerController', () => {
|
|
|
155
155
|
[paramName2]: {[validationType1]: options2}
|
|
156
156
|
};
|
|
157
157
|
|
|
158
|
-
it ('runs validation checkers based on inputs', () => {
|
|
159
|
-
controller.validateParameters(validations);
|
|
158
|
+
it ('runs validation checkers based on inputs', async () => {
|
|
159
|
+
await controller.validateParameters(validations);
|
|
160
160
|
expect(validator1).toHaveBeenCalledTimes(2);
|
|
161
161
|
expect(validator1).toHaveBeenCalledWith(value1, options1);
|
|
162
162
|
expect(validator1).toHaveBeenCalledWith(value2, options2);
|
|
@@ -165,52 +165,44 @@ describe('VidaServerController', () => {
|
|
|
165
165
|
expect(validator2).toHaveBeenCalledWith(value1, options2);
|
|
166
166
|
});
|
|
167
167
|
|
|
168
|
-
it ('throws a `ValidationError` when there\'s an error', () => {
|
|
168
|
+
it ('throws a `ValidationError` when there\'s an error', async () => {
|
|
169
169
|
validator1.mockImplementation(() => error1);
|
|
170
|
-
expect(()
|
|
171
|
-
controller.validateParameters(validations);
|
|
172
|
-
}).toThrow(Errors.ValidationError);
|
|
170
|
+
await expect(controller.validateParameters(validations)).rejects.toThrow();
|
|
173
171
|
});
|
|
174
172
|
|
|
175
|
-
it ('throws a `ValidationError` when there are multiple errors', () => {
|
|
173
|
+
it ('throws a `ValidationError` when there are multiple errors', async () => {
|
|
176
174
|
validator1.mockImplementation(() => error1);
|
|
177
175
|
validator2.mockImplementation(() => error2);
|
|
178
176
|
|
|
179
|
-
expect(()
|
|
180
|
-
controller.validateParameters(validations);
|
|
181
|
-
}).toThrow(Errors.ValidationError);
|
|
177
|
+
await expect(controller.validateParameters(validations)).rejects.toThrow(Errors.ValidationError);
|
|
182
178
|
});
|
|
183
179
|
|
|
184
|
-
it ('sets nothing when there is no error', () => {
|
|
185
|
-
controller.validateParameters(validations);
|
|
180
|
+
it ('sets nothing when there is no error', async () => {
|
|
181
|
+
await controller.validateParameters(validations);
|
|
186
182
|
expect(controller.render).toHaveBeenCalledTimes(0);
|
|
187
183
|
expect(response.statusCode).toEqual(200);
|
|
188
184
|
});
|
|
189
185
|
|
|
190
|
-
it ('ignores details where there is no validator', () => {
|
|
186
|
+
it ('ignores details where there is no validator', async () => {
|
|
191
187
|
const validations = {
|
|
192
188
|
[paramName2]: {[validationType1]: options2, 'foo': true}
|
|
193
189
|
};
|
|
194
|
-
controller.validateParameters(validations);
|
|
190
|
+
await controller.validateParameters(validations);
|
|
195
191
|
|
|
196
192
|
expect(validator1).toHaveBeenCalledTimes(1);
|
|
197
193
|
expect(validator1).toHaveBeenCalledWith(value2, options2);
|
|
198
194
|
});
|
|
199
195
|
|
|
200
|
-
it ('does not error when optional parameters are not included', () => {
|
|
196
|
+
it ('does not error when optional parameters are not included', async () => {
|
|
201
197
|
const validations = {foo: {isString: true, optional: true}};
|
|
202
|
-
expect(()
|
|
203
|
-
controller.validateParameters(validations);
|
|
204
|
-
}).not.toThrow();
|
|
198
|
+
expect(controller.validateParameters(validations)).resolves.not.toThrow();
|
|
205
199
|
});
|
|
206
200
|
|
|
207
|
-
it ('does error when optional parameters are invalid', () => {
|
|
201
|
+
it ('does error when optional parameters are invalid', async () => {
|
|
208
202
|
const validations = {foo: {isString: {length: {gte: 2}}, optional: true}};
|
|
209
203
|
params.foo = '';
|
|
210
204
|
|
|
211
|
-
expect(()
|
|
212
|
-
controller.validateParameters(validations);
|
|
213
|
-
}).toThrow(Errors.ValidationError);
|
|
205
|
+
await expect(controller.validateParameters(validations)).rejects.toThrow(Errors.ValidationError);
|
|
214
206
|
|
|
215
207
|
delete params.foo;
|
|
216
208
|
});
|
|
@@ -458,13 +450,13 @@ describe('VidaServerController', () => {
|
|
|
458
450
|
const error = TestHelpers.Faker.Text.randomString();
|
|
459
451
|
const validator = (value) => value == correctValue ? undefined : error;
|
|
460
452
|
|
|
461
|
-
it ('returns undefiend when passed a valid value', () => {
|
|
462
|
-
const result = controller.validateFunction(correctValue, validator);
|
|
453
|
+
it ('returns undefiend when passed a valid value', async () => {
|
|
454
|
+
const result = await controller.validateFunction(correctValue, validator);
|
|
463
455
|
expect(result).toBe(undefined);
|
|
464
456
|
});
|
|
465
457
|
|
|
466
|
-
it ('returns an error when the function returns an error', () => {
|
|
467
|
-
const result = controller.validateFunction(Math.random(), validator);
|
|
458
|
+
it ('returns an error when the function returns an error', async () => {
|
|
459
|
+
const result = await controller.validateFunction(Math.random(), validator);
|
|
468
460
|
expect(result).toBe(error);
|
|
469
461
|
});
|
|
470
462
|
});
|
|
@@ -472,10 +464,10 @@ describe('VidaServerController', () => {
|
|
|
472
464
|
|
|
473
465
|
describe('#performRequest', () => {
|
|
474
466
|
const errorHandlers = [
|
|
475
|
-
['
|
|
476
|
-
['
|
|
477
|
-
['
|
|
478
|
-
['renderErrors',
|
|
467
|
+
['renderUnauthorized', 'AuthorizationError'],
|
|
468
|
+
['renderForbidden', 'ForbiddenError'],
|
|
469
|
+
['renderNotFound', 'NotFoundError'],
|
|
470
|
+
['renderErrors', 'ValidationError'],
|
|
479
471
|
]
|
|
480
472
|
|
|
481
473
|
it.each(errorHandlers)('calls %s when %s is thrown', async (handlerName, errorClsName) => {
|
|
@@ -505,7 +497,7 @@ describe('VidaServerController', () => {
|
|
|
505
497
|
await controller.performRequest('testAction');
|
|
506
498
|
|
|
507
499
|
expect(controller.statusCode).toEqual(500);
|
|
508
|
-
expect(controller.render).toHaveBeenCalledWith({errors: {
|
|
500
|
+
expect(controller.render).toHaveBeenCalledWith({errors: {message: null}});
|
|
509
501
|
});
|
|
510
502
|
});
|
|
511
503
|
|
|
@@ -519,7 +511,6 @@ describe('VidaServerController', () => {
|
|
|
519
511
|
controller.render = jest.fn();
|
|
520
512
|
});
|
|
521
513
|
|
|
522
|
-
|
|
523
514
|
describe('#renderErrors', () => {
|
|
524
515
|
it ('returns a 400 response', async () => {
|
|
525
516
|
await controller.renderErrors();
|
|
@@ -576,64 +567,66 @@ describe('VidaServerController', () => {
|
|
|
576
567
|
});
|
|
577
568
|
});
|
|
578
569
|
|
|
579
|
-
|
|
580
|
-
describe('#renderUnauthorizedResponse', () => {
|
|
581
|
-
it ('returns a 401 response', async () => {
|
|
582
|
-
await controller.renderUnauthorizedResponse();
|
|
583
|
-
expect(response.statusCode).toBe(401);
|
|
584
|
-
})
|
|
585
|
-
|
|
586
|
-
it ('includes a blank message by default', async () => {
|
|
587
|
-
await controller.renderUnauthorizedResponse();
|
|
588
|
-
expect(controller.render).toHaveBeenCalledTimes(1);
|
|
589
|
-
expect(controller.render).toHaveBeenCalledWith({errors: {message: null}});
|
|
590
|
-
})
|
|
591
570
|
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
571
|
+
const successHandlers = [
|
|
572
|
+
['renderCreationSuccessful', 201],
|
|
573
|
+
['renderAccepted', 202],
|
|
574
|
+
['renderNoConent', 204],
|
|
575
|
+
['renderMovedPermanently', 301],
|
|
576
|
+
['renderFound', 302],
|
|
577
|
+
['renderNotModified', 304],
|
|
578
|
+
['renderTemporaryRedirect', 307],
|
|
579
|
+
['renderPermanentRedirect', 308],
|
|
580
|
+
]
|
|
581
|
+
describe.each(successHandlers)('#%s', (handlerName, statusCode) => {
|
|
582
|
+
it (`returns a ${statusCode} response`, async () => {
|
|
583
|
+
await (controller[handlerName]());
|
|
584
|
+
expect(response.statusCode).toBe(statusCode);
|
|
605
585
|
})
|
|
606
586
|
|
|
607
|
-
it ('includes
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
587
|
+
it ('includes the provided body', async () => {
|
|
588
|
+
const key = TestHelpers.Faker.Text.randomString();
|
|
589
|
+
const value = TestHelpers.Faker.Text.randomString();
|
|
590
|
+
const body = {[key]: value};
|
|
591
|
+
await (controller[handlerName](body));
|
|
612
592
|
|
|
613
|
-
it ('includes a provided message', async () => {
|
|
614
|
-
const msg = TestHelpers.Faker.Text.randomString();
|
|
615
|
-
await controller.renderForbiddenResponse(msg);
|
|
616
593
|
expect(controller.render).toHaveBeenCalledTimes(1);
|
|
617
|
-
expect(controller.render).toHaveBeenCalledWith(
|
|
594
|
+
expect(controller.render).toHaveBeenCalledWith(body);
|
|
618
595
|
});
|
|
619
596
|
});
|
|
620
597
|
|
|
598
|
+
|
|
599
|
+
const errorHandlers = [
|
|
600
|
+
['renderUnauthorized', 401],
|
|
601
|
+
['renderPaymentRequired', 402],
|
|
602
|
+
['renderForbidden', 403],
|
|
603
|
+
['renderNotFound', 404],
|
|
604
|
+
['renderMethodNotAllowed', 405],
|
|
605
|
+
['renderRequestTimeout', 408],
|
|
606
|
+
['renderConflict', 409],
|
|
607
|
+
['renderGone', 410],
|
|
608
|
+
['renderContentTooLarge', 413],
|
|
609
|
+
['renderUnsupportedMediaType', 415],
|
|
610
|
+
['renderUnprocessableContent', 422],
|
|
611
|
+
['renderLocked', 423],
|
|
612
|
+
['renderTooManyRequests', 429],
|
|
613
|
+
]
|
|
621
614
|
|
|
622
|
-
describe('
|
|
623
|
-
it (
|
|
624
|
-
await controller
|
|
625
|
-
expect(response.statusCode).toBe(
|
|
615
|
+
describe.each(errorHandlers)('#%s', (handlerName, statusCode) => {
|
|
616
|
+
it (`returns a ${statusCode} response`, async () => {
|
|
617
|
+
await (controller[handlerName]());
|
|
618
|
+
expect(response.statusCode).toBe(statusCode);
|
|
626
619
|
})
|
|
627
620
|
|
|
628
621
|
it ('includes a blank message by default', async () => {
|
|
629
|
-
await controller
|
|
622
|
+
await controller[handlerName]();
|
|
630
623
|
expect(controller.render).toHaveBeenCalledTimes(1);
|
|
631
624
|
expect(controller.render).toHaveBeenCalledWith({errors: {message: null}});
|
|
632
625
|
})
|
|
633
626
|
|
|
634
627
|
it ('includes a provided message', async () => {
|
|
635
628
|
const msg = TestHelpers.Faker.Text.randomString();
|
|
636
|
-
await controller
|
|
629
|
+
await controller[handlerName](msg);
|
|
637
630
|
expect(controller.render).toHaveBeenCalledTimes(1);
|
|
638
631
|
expect(controller.render).toHaveBeenCalledWith({errors: {message: msg}});
|
|
639
632
|
});
|