@vida-global/core 2.0.10 → 2.1.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/index.js +2 -0
- package/lib/activeRecord/README.md +1 -1
- package/lib/activeRecord/baseRecord.js +70 -4
- package/lib/cache/index.js +4 -0
- package/lib/cache/memoryCache.js +155 -0
- package/lib/server/README.md +8 -219
- package/lib/server/controllerImporter.js +0 -1
- package/lib/server/controllerMixins/callbacks.js +16 -61
- package/lib/server/controllerMixins/classScopedRegistry.js +48 -0
- package/lib/server/controllerMixins/documentation.js +41 -9
- package/lib/server/controllerMixins/renderer.js +140 -99
- package/lib/server/controllerMixins/validations.js +57 -0
- package/lib/server/doc/callbacks.md +23 -0
- package/lib/server/doc/documentation.md +135 -0
- package/lib/server/doc/renderer.md +115 -0
- package/lib/server/doc/requestDetails.md +52 -0
- package/lib/server/doc/validations.md +40 -0
- package/lib/server/index.js +1 -1
- package/lib/server/openApi/apiDocGenerator.js +426 -0
- package/lib/server/openApi/apiDocsGenerator.js +147 -0
- package/lib/server/openApi/schemaImporter.js +41 -0
- package/lib/server/openApi/schemaRegistry.js +43 -0
- package/lib/server/openApi/schemas.js +97 -0
- package/lib/server/openApi/tagRegistry.js +27 -0
- package/lib/server/server.js +14 -0
- package/lib/server/serverController.js +4 -9
- package/lib/server/statusTexts.js +38 -0
- package/lib/utils/yamlLoader.js +17 -0
- package/package.json +4 -2
- package/test/activeRecord/baseRecord.test.js +101 -0
- package/test/cache/memoryCache.test.js +233 -0
- package/test/server/apiDocGenerator.test.js +743 -0
- package/test/server/controllerMixins/callbacks.test.js +326 -0
- package/test/server/controllerMixins/classScopedRegistry.test.js +95 -0
- package/test/server/controllerMixins/documentation.test.js +168 -0
- package/test/server/controllerMixins/renderer.test.js +734 -0
- package/test/server/controllerMixins/requestDetails.test.js +225 -0
- package/test/server/controllerMixins/routing.test.js +82 -0
- package/test/server/controllerMixins/validations.test.js +509 -0
- package/test/server/openApi/apiDocsGenerator.test.js +306 -0
- package/test/server/openApi/helpers/apiDocsPackageFixture/package.json +5 -0
- package/test/server/openApi/schemaImporter.test.js +54 -0
- package/test/server/openApi/schemaRegistry.test.js +93 -0
- package/test/server/openApi/schemas.test.js +109 -0
- package/test/server/serverController.test.js +8 -867
- package/test/server/statusTexts.test.js +30 -0
- package/test/utils/yamlLoader.test.js +43 -0
- package/lib/server/apiDocsGenerator.js +0 -86
- package/test/server/apiDocsGenerator.test.js +0 -38
|
@@ -1,32 +1,14 @@
|
|
|
1
|
-
const { BarController } = require('./helpers/controllers/barController');
|
|
2
1
|
const { FooController } = require('./helpers/controllers/fooController');
|
|
3
|
-
const { camelize } = require('inflection');
|
|
4
2
|
const Errors = require('../../lib/server/errors');
|
|
5
|
-
const { logger } = require('../../lib/logger');
|
|
6
3
|
const { randomPayload } = require('./helpers/serverController');
|
|
7
4
|
const TestHelpers = require('@vida-global/test-helpers');
|
|
8
5
|
const {
|
|
6
|
+
VidaServerController,
|
|
9
7
|
NoActiveStreamError,
|
|
10
8
|
StreamInProgressError,
|
|
11
|
-
VidaServerController
|
|
12
9
|
} = require('../../lib/server/serverController');
|
|
13
10
|
|
|
14
11
|
describe('VidaServerController', () => {
|
|
15
|
-
describe('.actionNames', () => {
|
|
16
|
-
it ('returns actions based on method names', () => {
|
|
17
|
-
const names = FooController.actionNames;
|
|
18
|
-
const expected = ['postIndex',
|
|
19
|
-
'getFooBar',
|
|
20
|
-
'getBazBan',
|
|
21
|
-
'postFooBar',
|
|
22
|
-
'putFooBar',
|
|
23
|
-
'deleteFooBar',
|
|
24
|
-
'patchFooBar'];
|
|
25
|
-
expect(names).toEqual(expected);
|
|
26
|
-
});
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
|
|
30
12
|
describe('.autoLoadMixins', () => {
|
|
31
13
|
class AutoLoadTestController extends VidaServerController {
|
|
32
14
|
static get mixinDirectory() {
|
|
@@ -78,69 +60,6 @@ describe('VidaServerController', () => {
|
|
|
78
60
|
});
|
|
79
61
|
|
|
80
62
|
|
|
81
|
-
describe('._constructAction', () => {
|
|
82
|
-
class UsersController extends VidaServerController {
|
|
83
|
-
static get routes() {
|
|
84
|
-
return {getBazBan: '/baz/:id/ban'};
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
it ('returns an object with path, method, and action', () => {
|
|
89
|
-
const expected = {
|
|
90
|
-
method: 'GET',
|
|
91
|
-
path: '/users/fooBar',
|
|
92
|
-
action: 'getFooBar'
|
|
93
|
-
}
|
|
94
|
-
expect(UsersController._constructAction('getFooBar', '')).toEqual(expected);
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
it ('uses a blank path for index actions', () => {
|
|
98
|
-
const expected = {
|
|
99
|
-
method: 'POST',
|
|
100
|
-
path: '/users',
|
|
101
|
-
action: 'postIndex'
|
|
102
|
-
}
|
|
103
|
-
expect(UsersController._constructAction('postIndex', '')).toEqual(expected);
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
it ('creates a single resource route for Record', () => {
|
|
107
|
-
const expected = {
|
|
108
|
-
method: 'GET',
|
|
109
|
-
path: '/user/:id',
|
|
110
|
-
action: 'getRecord'
|
|
111
|
-
}
|
|
112
|
-
expect(UsersController._constructAction('getRecord', '')).toEqual(expected);
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
it ('only uses Record when checking for single resource routes', () => {
|
|
116
|
-
const expected = {
|
|
117
|
-
method: 'GET',
|
|
118
|
-
path: '/users/recording',
|
|
119
|
-
action: 'getRecording'
|
|
120
|
-
}
|
|
121
|
-
expect(UsersController._constructAction('getRecording', '')).toEqual(expected);
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
it ('creates a single sub resource route for RecordFoo', () => {
|
|
125
|
-
const expected = {
|
|
126
|
-
method: 'GET',
|
|
127
|
-
path: '/user/:id/foo',
|
|
128
|
-
action: 'getRecordFoo'
|
|
129
|
-
}
|
|
130
|
-
expect(UsersController._constructAction('getRecordFoo', '')).toEqual(expected);
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
it ('uses a custom path when defined', () => {
|
|
134
|
-
const expected = {
|
|
135
|
-
method: 'GET',
|
|
136
|
-
path: '/baz/:id/ban',
|
|
137
|
-
action: 'getBazBan'
|
|
138
|
-
}
|
|
139
|
-
expect(UsersController._constructAction('getBazBan', '')).toEqual(expected);
|
|
140
|
-
});
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
|
|
144
63
|
describe('#hasParam', () => {
|
|
145
64
|
let controller;
|
|
146
65
|
beforeEach(() => {
|
|
@@ -359,452 +278,6 @@ describe('VidaServerController', () => {
|
|
|
359
278
|
});
|
|
360
279
|
|
|
361
280
|
|
|
362
|
-
describe('.validateParameters', () => {
|
|
363
|
-
const paramName1 = TestHelpers.Faker.Text.randomString();
|
|
364
|
-
const paramName2 = TestHelpers.Faker.Text.randomString();
|
|
365
|
-
const value1 = TestHelpers.Faker.Text.randomString();
|
|
366
|
-
const value2 = TestHelpers.Faker.Text.randomString();
|
|
367
|
-
const validationType1 = TestHelpers.Faker.Text.randomString();
|
|
368
|
-
const validationType2 = TestHelpers.Faker.Text.randomString();
|
|
369
|
-
const options1 = [TestHelpers.Faker.Text.randomString()];
|
|
370
|
-
const options2 = [TestHelpers.Faker.Text.randomString()];
|
|
371
|
-
const error1 = TestHelpers.Faker.Text.randomString()
|
|
372
|
-
const error2 = TestHelpers.Faker.Text.randomString()
|
|
373
|
-
|
|
374
|
-
let params;
|
|
375
|
-
let controller;
|
|
376
|
-
let response;
|
|
377
|
-
let validator1;
|
|
378
|
-
let validator2;
|
|
379
|
-
beforeEach(() => {
|
|
380
|
-
params = {[paramName1]: value1, [paramName2]: value2};
|
|
381
|
-
response = {json: jest.fn(), statusCode: 200};
|
|
382
|
-
controller = new FooController({params}, response);
|
|
383
|
-
controller.render = jest.fn();
|
|
384
|
-
validator1 = jest.fn();
|
|
385
|
-
validator2 = jest.fn();
|
|
386
|
-
controller[`validate${camelize(validationType1)}`] = validator1;
|
|
387
|
-
controller[`validate${camelize(validationType2)}`] = validator2;
|
|
388
|
-
});
|
|
389
|
-
|
|
390
|
-
const validations = {
|
|
391
|
-
[paramName1]: {[validationType1]: options1, [validationType2]: options2},
|
|
392
|
-
[paramName2]: {[validationType1]: options2}
|
|
393
|
-
};
|
|
394
|
-
|
|
395
|
-
it ('runs validation checkers based on inputs', async () => {
|
|
396
|
-
await controller.validateParameters(validations);
|
|
397
|
-
expect(validator1).toHaveBeenCalledTimes(2);
|
|
398
|
-
expect(validator1).toHaveBeenCalledWith(value1, options1);
|
|
399
|
-
expect(validator1).toHaveBeenCalledWith(value2, options2);
|
|
400
|
-
|
|
401
|
-
expect(validator2).toHaveBeenCalledTimes(1);
|
|
402
|
-
expect(validator2).toHaveBeenCalledWith(value1, options2);
|
|
403
|
-
});
|
|
404
|
-
|
|
405
|
-
it ('throws a `ValidationError` when there\'s an error', async () => {
|
|
406
|
-
validator1.mockImplementation(() => error1);
|
|
407
|
-
await expect(controller.validateParameters(validations)).rejects.toThrow(Errors.ValidationError);
|
|
408
|
-
});
|
|
409
|
-
|
|
410
|
-
it ('attaches the failing parameter and error message to the ValidationError fields', async () => {
|
|
411
|
-
validator1.mockImplementation(() => error1);
|
|
412
|
-
await expect(controller.validateParameters(validations)).rejects.toMatchObject({
|
|
413
|
-
fields: {[paramName1]: [error1], [paramName2]: [error1]}
|
|
414
|
-
});
|
|
415
|
-
});
|
|
416
|
-
|
|
417
|
-
it ('throws a `ValidationError` when there are multiple errors', async () => {
|
|
418
|
-
validator1.mockImplementation(() => error1);
|
|
419
|
-
validator2.mockImplementation(() => error2);
|
|
420
|
-
|
|
421
|
-
await expect(controller.validateParameters(validations)).rejects.toThrow(Errors.ValidationError);
|
|
422
|
-
});
|
|
423
|
-
|
|
424
|
-
it ('sets nothing when there is no error', async () => {
|
|
425
|
-
await controller.validateParameters(validations);
|
|
426
|
-
expect(controller.render).toHaveBeenCalledTimes(0);
|
|
427
|
-
expect(response.statusCode).toEqual(200);
|
|
428
|
-
});
|
|
429
|
-
|
|
430
|
-
it ('ignores details where there is no validator', async () => {
|
|
431
|
-
const validations = {
|
|
432
|
-
[paramName2]: {[validationType1]: options2, 'foo': true}
|
|
433
|
-
};
|
|
434
|
-
await controller.validateParameters(validations);
|
|
435
|
-
|
|
436
|
-
expect(validator1).toHaveBeenCalledTimes(1);
|
|
437
|
-
expect(validator1).toHaveBeenCalledWith(value2, options2);
|
|
438
|
-
});
|
|
439
|
-
|
|
440
|
-
it ('does not error when optional parameters are not included', async () => {
|
|
441
|
-
const validations = {foo: {isString: true, optional: true}};
|
|
442
|
-
await expect(controller.validateParameters(validations)).resolves.not.toThrow();
|
|
443
|
-
});
|
|
444
|
-
|
|
445
|
-
it ('does error when optional parameters are invalid', async () => {
|
|
446
|
-
const validations = {foo: {isString: {length: {gte: 2}}, optional: true}};
|
|
447
|
-
params.foo = '';
|
|
448
|
-
|
|
449
|
-
await expect(controller.validateParameters(validations)).rejects.toThrow(Errors.ValidationError);
|
|
450
|
-
});
|
|
451
|
-
});
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
describe('.validateAction', () => {
|
|
455
|
-
it ('is a no-op when the controller has no parametersFor<Action> method', async () => {
|
|
456
|
-
class C extends VidaServerController {}
|
|
457
|
-
const controller = new C({}, {});
|
|
458
|
-
controller.validateParameters = jest.fn();
|
|
459
|
-
|
|
460
|
-
await controller.validateAction('getThing');
|
|
461
|
-
expect(controller.validateParameters).not.toHaveBeenCalled();
|
|
462
|
-
});
|
|
463
|
-
|
|
464
|
-
it ('calls validateParameters with the value returned by parametersFor<Action>', async () => {
|
|
465
|
-
const params = {foo: {isString: true}};
|
|
466
|
-
class C extends VidaServerController {
|
|
467
|
-
static parametersForGetThing() { return params; }
|
|
468
|
-
}
|
|
469
|
-
const controller = new C({}, {});
|
|
470
|
-
controller.validateParameters = jest.fn();
|
|
471
|
-
|
|
472
|
-
await controller.validateAction('getThing');
|
|
473
|
-
expect(controller.validateParameters).toHaveBeenCalledTimes(1);
|
|
474
|
-
expect(controller.validateParameters).toHaveBeenCalledWith(params);
|
|
475
|
-
});
|
|
476
|
-
|
|
477
|
-
it ('camelizes the action name when looking up the parametersFor method', async () => {
|
|
478
|
-
const params = {foo: {isString: true}};
|
|
479
|
-
class C extends VidaServerController {
|
|
480
|
-
static parametersForGetFooBar() { return params; }
|
|
481
|
-
}
|
|
482
|
-
const controller = new C({}, {});
|
|
483
|
-
controller.validateParameters = jest.fn();
|
|
484
|
-
|
|
485
|
-
await controller.validateAction('getFooBar');
|
|
486
|
-
expect(controller.validateParameters).toHaveBeenCalledWith(params);
|
|
487
|
-
});
|
|
488
|
-
|
|
489
|
-
it ('propagates ValidationError thrown by validateParameters', async () => {
|
|
490
|
-
class C extends VidaServerController {
|
|
491
|
-
static parametersForGetThing() { return {foo: {isString: true}}; }
|
|
492
|
-
}
|
|
493
|
-
const request = { params: {}, query: {}, body: {foo: 42} };
|
|
494
|
-
const controller = new C(request, {});
|
|
495
|
-
|
|
496
|
-
await expect(controller.validateAction('getThing')).rejects.toThrow(Errors.ValidationError);
|
|
497
|
-
});
|
|
498
|
-
});
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
describe('.parametersForAction', () => {
|
|
502
|
-
it ('returns null when no parametersFor method is defined', () => {
|
|
503
|
-
class C extends VidaServerController {}
|
|
504
|
-
expect(C.parametersForAction('getThing')).toBe(null);
|
|
505
|
-
});
|
|
506
|
-
|
|
507
|
-
it ('returns the value of the matching parametersFor<Action> method', () => {
|
|
508
|
-
const params = {foo: {isString: true}};
|
|
509
|
-
class C extends VidaServerController {
|
|
510
|
-
static parametersForGetThing() { return params; }
|
|
511
|
-
}
|
|
512
|
-
expect(C.parametersForAction('getThing')).toBe(params);
|
|
513
|
-
});
|
|
514
|
-
});
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
describe('.parametersMethodForAction', () => {
|
|
518
|
-
it ('returns the camelized parametersFor<Action> method name', () => {
|
|
519
|
-
class C extends VidaServerController {}
|
|
520
|
-
expect(C.parametersMethodForAction('getFooBar')).toBe('parametersForGetFooBar');
|
|
521
|
-
expect(C.parametersMethodForAction('postIndex')).toBe('parametersForPostIndex');
|
|
522
|
-
});
|
|
523
|
-
});
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
describe('.validatePresence', () => {
|
|
527
|
-
const controller = new FooController({}, {});
|
|
528
|
-
it ('returns undefined when there is a value', () => {
|
|
529
|
-
const result = controller.validatePresence(TestHelpers.Faker.Text.randomString());
|
|
530
|
-
expect(result).toBe(undefined);
|
|
531
|
-
});
|
|
532
|
-
|
|
533
|
-
it ('returns an error when there is no value', () => {
|
|
534
|
-
const result = controller.validatePresence();
|
|
535
|
-
expect(result).toEqual('required');
|
|
536
|
-
});
|
|
537
|
-
});
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
describe('.validateIsInteger', () => {
|
|
541
|
-
const controller = new FooController({}, {});
|
|
542
|
-
it ('returns undefined when there is an integer', () => {
|
|
543
|
-
const val = Math.ceil(Math.random() * 100);
|
|
544
|
-
const result = controller.validateIsInteger(val)
|
|
545
|
-
expect(result).toEqual(undefined);
|
|
546
|
-
});
|
|
547
|
-
|
|
548
|
-
it ('returns undefined when there is an integer string', () => {
|
|
549
|
-
const val = Math.ceil(Math.random() * 100).toString();
|
|
550
|
-
const result = controller.validateIsInteger(val)
|
|
551
|
-
expect(result).toEqual(undefined);
|
|
552
|
-
});
|
|
553
|
-
|
|
554
|
-
it ('returns an error when there is a non integer number', () => {
|
|
555
|
-
const val = Math.random() * 100;
|
|
556
|
-
const result = controller.validateIsInteger(val)
|
|
557
|
-
expect(result).toEqual('must be an integer');
|
|
558
|
-
});
|
|
559
|
-
|
|
560
|
-
it ('returns an error when there is a non integer string', () => {
|
|
561
|
-
// starts with a number because parseFloat converts a string to a float if it starts with a number
|
|
562
|
-
const val = '1' + TestHelpers.Faker.Text.randomString();
|
|
563
|
-
const result = controller.validateIsInteger(val)
|
|
564
|
-
expect(result).toEqual('must be an integer');
|
|
565
|
-
});
|
|
566
|
-
|
|
567
|
-
it ('returns an error when the value is null', () => {
|
|
568
|
-
const result = controller.validateIsInteger(null)
|
|
569
|
-
expect(result).toEqual('must be an integer');
|
|
570
|
-
});
|
|
571
|
-
|
|
572
|
-
it ('returns an error when the value is undefined', () => {
|
|
573
|
-
const result = controller.validateIsInteger(undefined)
|
|
574
|
-
expect(result).toEqual('must be an integer');
|
|
575
|
-
});
|
|
576
|
-
|
|
577
|
-
it ('returns an error when the value is an object', () => {
|
|
578
|
-
const result = controller.validateIsInteger({})
|
|
579
|
-
expect(result).toEqual('must be an integer');
|
|
580
|
-
});
|
|
581
|
-
|
|
582
|
-
it ('returns an error when the number is less than the gte option', () => {
|
|
583
|
-
const result = controller.validateIsInteger(1, {gte: 2});
|
|
584
|
-
expect(result).toEqual('must be greater than or equal to 2');
|
|
585
|
-
});
|
|
586
|
-
|
|
587
|
-
it ('returns undefined when the number is greater than the gte option', () => {
|
|
588
|
-
const result = controller.validateIsInteger(3, {gte: 2});
|
|
589
|
-
expect(result).toEqual(undefined);
|
|
590
|
-
});
|
|
591
|
-
|
|
592
|
-
it ('returns undefined when the number is equal to the gte option', () => {
|
|
593
|
-
const result = controller.validateIsInteger(2, {gte: 2});
|
|
594
|
-
expect(result).toEqual(undefined);
|
|
595
|
-
});
|
|
596
|
-
|
|
597
|
-
it ('returns an error when the number is greater than the lte option', () => {
|
|
598
|
-
const result = controller.validateIsInteger(3, {lte: 2});
|
|
599
|
-
expect(result).toEqual('must be less than or equal to 2');
|
|
600
|
-
});
|
|
601
|
-
|
|
602
|
-
it ('returns undefined when the number is less than the lte option', () => {
|
|
603
|
-
const result = controller.validateIsInteger(1, {lte: 2});
|
|
604
|
-
expect(result).toEqual(undefined);
|
|
605
|
-
});
|
|
606
|
-
|
|
607
|
-
it ('returns undefined when the number is equal to the lte option', () => {
|
|
608
|
-
const result = controller.validateIsInteger(2, {lte: 2});
|
|
609
|
-
expect(result).toEqual(undefined);
|
|
610
|
-
});
|
|
611
|
-
|
|
612
|
-
it ('supports both the lte and gte options', () => {
|
|
613
|
-
let result = controller.validateIsInteger(1, {lte: 2, gte: 0});
|
|
614
|
-
expect(result).toEqual(undefined);
|
|
615
|
-
|
|
616
|
-
result = controller.validateIsInteger(-1, {lte: 2, gte: 0});
|
|
617
|
-
expect(result).toEqual('must be greater than or equal to 0');
|
|
618
|
-
|
|
619
|
-
result = controller.validateIsInteger(3, {lte: 2, gte: 0});
|
|
620
|
-
expect(result).toEqual('must be less than or equal to 2');
|
|
621
|
-
});
|
|
622
|
-
});
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
describe('.validateIsString', () => {
|
|
626
|
-
const controller = new FooController({}, {});
|
|
627
|
-
it ('returns undefined when there is an string', () => {
|
|
628
|
-
const result = controller.validateIsString('')
|
|
629
|
-
expect(result).toEqual(undefined);
|
|
630
|
-
});
|
|
631
|
-
|
|
632
|
-
it ('returns an error when there is a number', () => {
|
|
633
|
-
const result = controller.validateIsString(Math.random());
|
|
634
|
-
expect(result).toEqual('must be a string');
|
|
635
|
-
});
|
|
636
|
-
|
|
637
|
-
it ('returns an error when the value is null', () => {
|
|
638
|
-
const result = controller.validateIsString(null)
|
|
639
|
-
expect(result).toEqual('must be a string');
|
|
640
|
-
});
|
|
641
|
-
|
|
642
|
-
it ('returns an error when the value is undefined', () => {
|
|
643
|
-
const result = controller.validateIsString(undefined)
|
|
644
|
-
expect(result).toEqual('must be a string');
|
|
645
|
-
});
|
|
646
|
-
|
|
647
|
-
it ('returns an error when the value is an object', () => {
|
|
648
|
-
const result = controller.validateIsString({})
|
|
649
|
-
expect(result).toEqual('must be a string');
|
|
650
|
-
});
|
|
651
|
-
|
|
652
|
-
it ('returns an error when the length is fewer than the gte option', () => {
|
|
653
|
-
const result = controller.validateIsString('f', {length: {gte: 2}});
|
|
654
|
-
expect(result).toEqual('must be greater than or equal to 2 characters');
|
|
655
|
-
});
|
|
656
|
-
|
|
657
|
-
it ('returns undefined when the length is greater than the gte option', () => {
|
|
658
|
-
const result = controller.validateIsString('foo', {length: {gte: 2}});
|
|
659
|
-
expect(result).toEqual(undefined);
|
|
660
|
-
});
|
|
661
|
-
|
|
662
|
-
it ('returns undefined when the length is equal to the gte option', () => {
|
|
663
|
-
const result = controller.validateIsString('fo', {length: {gte: 2}});
|
|
664
|
-
expect(result).toEqual(undefined);
|
|
665
|
-
});
|
|
666
|
-
|
|
667
|
-
it ('returns an error when the length is greater than the lte option', () => {
|
|
668
|
-
const result = controller.validateIsString('foo', {length: {lte: 2}});
|
|
669
|
-
expect(result).toEqual('must be fewer than or equal to 2 characters');
|
|
670
|
-
});
|
|
671
|
-
|
|
672
|
-
it ('returns undefined when the length is fewer than the lte option', () => {
|
|
673
|
-
const result = controller.validateIsString('f', {length: {lte: 2}});
|
|
674
|
-
expect(result).toEqual(undefined);
|
|
675
|
-
});
|
|
676
|
-
|
|
677
|
-
it ('returns undefined when the length is equal to the lte option', () => {
|
|
678
|
-
const result = controller.validateIsString('fo', {length: {lte: 2}});
|
|
679
|
-
expect(result).toEqual(undefined);
|
|
680
|
-
});
|
|
681
|
-
|
|
682
|
-
it ('supports both the lte and gte options', () => {
|
|
683
|
-
let result = controller.validateIsString('fo', {length: {lte: 3, gte: 1}});
|
|
684
|
-
expect(result).toEqual(undefined);
|
|
685
|
-
|
|
686
|
-
result = controller.validateIsString('', {length: {lte: 3, gte: 1}});
|
|
687
|
-
expect(result).toEqual('must be greater than or equal to 1 characters');
|
|
688
|
-
|
|
689
|
-
result = controller.validateIsString('foobar', {length: {lte: 3, gte: 1}});
|
|
690
|
-
expect(result).toEqual('must be fewer than or equal to 3 characters');
|
|
691
|
-
});
|
|
692
|
-
|
|
693
|
-
it ('returns undefined when the value matches the pattern', () => {
|
|
694
|
-
const result = controller.validateIsString('foo', {regex: /oo/})
|
|
695
|
-
expect(result).toBe(undefined);
|
|
696
|
-
});
|
|
697
|
-
|
|
698
|
-
it ('returns an error when the value does not match the pattern', () => {
|
|
699
|
-
const result = controller.validateIsString('bar', {regex: /oo/})
|
|
700
|
-
expect(result).toBe(`must match /oo/`);
|
|
701
|
-
});
|
|
702
|
-
});
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
describe('.validateIsDateTime', () => {
|
|
706
|
-
const controller = new FooController({}, {});
|
|
707
|
-
it ('returns undefined when passed a date string of format YYYY-MM-DD', () => {
|
|
708
|
-
const result = controller.validateIsDateTime('2025-12-17');
|
|
709
|
-
expect(result).toBe(undefined);
|
|
710
|
-
});
|
|
711
|
-
|
|
712
|
-
it ('returns undefined when passed a date string of format MM/DD/YY', () => {
|
|
713
|
-
const result = controller.validateIsDateTime('12/17/25');
|
|
714
|
-
expect(result).toBe(undefined);
|
|
715
|
-
});
|
|
716
|
-
|
|
717
|
-
it ('returns undefined when passed a date string of format Month name DD, YYYY', () => {
|
|
718
|
-
const result = controller.validateIsDateTime('December 17, 2025');
|
|
719
|
-
expect(result).toBe(undefined);
|
|
720
|
-
});
|
|
721
|
-
|
|
722
|
-
it ('returns undefined when passed a datetime string of format YYYY-MM-DD HH:MM:SS', () => {
|
|
723
|
-
const result = controller.validateIsDateTime('2025-12-17 01:05:00');
|
|
724
|
-
expect(result).toBe(undefined);
|
|
725
|
-
});
|
|
726
|
-
|
|
727
|
-
it ('returns undefined when passed a datetime string of format MM/DD/YY HH:MM:SS', () => {
|
|
728
|
-
const result = controller.validateIsDateTime('12/17/25 01:05:00');
|
|
729
|
-
expect(result).toBe(undefined);
|
|
730
|
-
});
|
|
731
|
-
|
|
732
|
-
it ('returns undefined when passed a datetime string of format Month name DD, YYYY HH:MM:SS', () => {
|
|
733
|
-
const result = controller.validateIsDateTime('December 17, 2025 01:05:00');
|
|
734
|
-
expect(result).toBe(undefined);
|
|
735
|
-
});
|
|
736
|
-
|
|
737
|
-
it ('returns an error when passed an invalid date', () => {
|
|
738
|
-
const result = controller.validateIsDateTime('foo');
|
|
739
|
-
expect(result).toEqual('invalid date');
|
|
740
|
-
});
|
|
741
|
-
});
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
describe('.validateIsEnum', () => {
|
|
745
|
-
const controller = new FooController({}, {});
|
|
746
|
-
const enums = [Math.random(), Math.random(), Math.random()];
|
|
747
|
-
const error = TestHelpers.Faker.Text.randomString();
|
|
748
|
-
const options = { enums, error }
|
|
749
|
-
it ('returns undefined when passed a valid value', () => {
|
|
750
|
-
const result = controller.validateIsEnum(enums[2], options);
|
|
751
|
-
expect(result).toBe(undefined);
|
|
752
|
-
});
|
|
753
|
-
|
|
754
|
-
it ('returns an error when passed an invalid date', () => {
|
|
755
|
-
const result = controller.validateIsEnum('foo', options);
|
|
756
|
-
expect(result).toBe(error);
|
|
757
|
-
});
|
|
758
|
-
});
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
describe('.validateIsBoolean', () => {
|
|
762
|
-
const controller = new FooController({}, {});
|
|
763
|
-
it ('returns undefined when passed a matching boolean', () => {
|
|
764
|
-
const result1 = controller.validateIsBoolean(true, true);
|
|
765
|
-
const result2 = controller.validateIsBoolean(false, false);
|
|
766
|
-
expect(result1).toBe(undefined);
|
|
767
|
-
expect(result2).toBe(undefined);
|
|
768
|
-
});
|
|
769
|
-
|
|
770
|
-
it ('returns an error when passed an non matching boolean', () => {
|
|
771
|
-
const result1 = controller.validateIsBoolean(true, false);
|
|
772
|
-
const result2 = controller.validateIsBoolean(false, true);
|
|
773
|
-
expect(result1).toBe('must be false');
|
|
774
|
-
expect(result2).toBe('must be true');
|
|
775
|
-
});
|
|
776
|
-
|
|
777
|
-
it ('returns an error when passed an non boolean', () => {
|
|
778
|
-
const result1 = controller.validateIsBoolean('', false);
|
|
779
|
-
const result2 = controller.validateIsBoolean(0, false);
|
|
780
|
-
const result3 = controller.validateIsBoolean('foo', true);
|
|
781
|
-
const result4 = controller.validateIsBoolean(1, true);
|
|
782
|
-
expect(result1).toBe('must be false');
|
|
783
|
-
expect(result2).toBe('must be false');
|
|
784
|
-
expect(result3).toBe('must be true');
|
|
785
|
-
expect(result4).toBe('must be true');
|
|
786
|
-
});
|
|
787
|
-
});
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
describe('.validateFunction', () => {
|
|
791
|
-
const controller = new FooController({}, {});
|
|
792
|
-
const correctValue = Math.random();
|
|
793
|
-
const error = TestHelpers.Faker.Text.randomString();
|
|
794
|
-
const validator = (value) => value == correctValue ? undefined : error;
|
|
795
|
-
|
|
796
|
-
it ('returns undefined when passed a valid value', async () => {
|
|
797
|
-
const result = await controller.validateFunction(correctValue, validator);
|
|
798
|
-
expect(result).toBe(undefined);
|
|
799
|
-
});
|
|
800
|
-
|
|
801
|
-
it ('returns an error when the function returns an error', async () => {
|
|
802
|
-
const result = await controller.validateFunction(Math.random(), validator);
|
|
803
|
-
expect(result).toBe(error);
|
|
804
|
-
});
|
|
805
|
-
});
|
|
806
|
-
|
|
807
|
-
|
|
808
281
|
describe('#performRequest', () => {
|
|
809
282
|
const errorHandlers = [
|
|
810
283
|
['renderUnauthorized', 'AuthorizationError'],
|
|
@@ -865,7 +338,7 @@ describe('VidaServerController', () => {
|
|
|
865
338
|
});
|
|
866
339
|
|
|
867
340
|
it ('awaits render before calling response.end (regression: ERR_HTTP_HEADERS_SENT)', async () => {
|
|
868
|
-
const response = { json: jest.fn(), end: jest.fn(), statusCode: 200 };
|
|
341
|
+
const response = { json: jest.fn(), send: jest.fn(), setHeader: jest.fn(), end: jest.fn(), statusCode: 200 };
|
|
869
342
|
const controller = new FooController({}, response);
|
|
870
343
|
controller.testAction = jest.fn(async () => ({foo: TestHelpers.Faker.Text.randomString()}));
|
|
871
344
|
|
|
@@ -880,266 +353,6 @@ describe('VidaServerController', () => {
|
|
|
880
353
|
});
|
|
881
354
|
|
|
882
355
|
|
|
883
|
-
describe('Rendering', () => {
|
|
884
|
-
let controller;
|
|
885
|
-
let response;
|
|
886
|
-
beforeEach(() => {
|
|
887
|
-
response = {json: jest.fn(), statusCode: 200};
|
|
888
|
-
controller = new FooController({}, response);
|
|
889
|
-
controller.render = jest.fn();
|
|
890
|
-
});
|
|
891
|
-
|
|
892
|
-
describe('#renderErrors', () => {
|
|
893
|
-
it ('returns a 400 response', async () => {
|
|
894
|
-
await controller.renderErrors();
|
|
895
|
-
expect(response.statusCode).toBe(400);
|
|
896
|
-
})
|
|
897
|
-
|
|
898
|
-
it ('includes a blank message and blank fields by default', async () => {
|
|
899
|
-
await controller.renderErrors();
|
|
900
|
-
expect(controller.render).toHaveBeenCalledTimes(1);
|
|
901
|
-
expect(controller.render).toHaveBeenCalledWith({errors: {message: null, fields: {}}});
|
|
902
|
-
})
|
|
903
|
-
|
|
904
|
-
it ('includes a provided message', async () => {
|
|
905
|
-
const msg = TestHelpers.Faker.Text.randomString();
|
|
906
|
-
await controller.renderErrors(msg);
|
|
907
|
-
expect(controller.render).toHaveBeenCalledTimes(1);
|
|
908
|
-
expect(controller.render).toHaveBeenCalledWith({errors: {message: msg, fields: {}}});
|
|
909
|
-
});
|
|
910
|
-
|
|
911
|
-
it ('includes provided field data', async () => {
|
|
912
|
-
const field1 = TestHelpers.Faker.Text.randomString();
|
|
913
|
-
const msg1 = TestHelpers.Faker.Text.randomString();
|
|
914
|
-
const msg2 = TestHelpers.Faker.Text.randomString();
|
|
915
|
-
await controller.renderErrors(null, {[field1]: [msg1, msg2]});
|
|
916
|
-
expect(controller.render).toHaveBeenCalledTimes(1);
|
|
917
|
-
expect(controller.render).toHaveBeenCalledWith({errors: {message: null, fields: {[field1]: [msg1, msg2]}}});
|
|
918
|
-
});
|
|
919
|
-
|
|
920
|
-
it ('includes provided message field data', async () => {
|
|
921
|
-
const field1 = TestHelpers.Faker.Text.randomString();
|
|
922
|
-
const msg1 = TestHelpers.Faker.Text.randomString();
|
|
923
|
-
const msg2 = TestHelpers.Faker.Text.randomString();
|
|
924
|
-
const msg3 = TestHelpers.Faker.Text.randomString();
|
|
925
|
-
await controller.renderErrors(msg1, {[field1]: [msg2, msg3]});
|
|
926
|
-
expect(controller.render).toHaveBeenCalledTimes(1);
|
|
927
|
-
expect(controller.render).toHaveBeenCalledWith({errors: {message: msg1, fields: {[field1]: [msg2, msg3]}}});
|
|
928
|
-
});
|
|
929
|
-
|
|
930
|
-
it ('uses the first parameter as fields if it is an object', async () => {
|
|
931
|
-
const field1 = TestHelpers.Faker.Text.randomString();
|
|
932
|
-
const msg1 = TestHelpers.Faker.Text.randomString();
|
|
933
|
-
const msg2 = TestHelpers.Faker.Text.randomString();
|
|
934
|
-
await controller.renderErrors({[field1]: [msg1, msg2]});
|
|
935
|
-
expect(controller.render).toHaveBeenCalledTimes(1);
|
|
936
|
-
expect(controller.render).toHaveBeenCalledWith({errors: {message: null, fields: {[field1]: [msg1, msg2]}}});
|
|
937
|
-
});
|
|
938
|
-
|
|
939
|
-
it ('converts single field error messages to arrays', async () => {
|
|
940
|
-
const field1 = TestHelpers.Faker.Text.randomString();
|
|
941
|
-
const msg1 = TestHelpers.Faker.Text.randomString();
|
|
942
|
-
await controller.renderErrors({[field1]: msg1});
|
|
943
|
-
expect(controller.render).toHaveBeenCalledTimes(1);
|
|
944
|
-
expect(controller.render).toHaveBeenCalledWith({errors: {message: null, fields: {[field1]: [msg1]}}});
|
|
945
|
-
});
|
|
946
|
-
});
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
const successHandlers = [
|
|
950
|
-
['renderCreationSuccessful', 201],
|
|
951
|
-
['renderAccepted', 202],
|
|
952
|
-
['renderNoConent', 204],
|
|
953
|
-
['renderMovedPermanently', 301],
|
|
954
|
-
['renderFound', 302],
|
|
955
|
-
['renderNotModified', 304],
|
|
956
|
-
['renderTemporaryRedirect', 307],
|
|
957
|
-
['renderPermanentRedirect', 308],
|
|
958
|
-
]
|
|
959
|
-
describe.each(successHandlers)('#%s', (handlerName, statusCode) => {
|
|
960
|
-
it (`returns a ${statusCode} response`, async () => {
|
|
961
|
-
await (controller[handlerName]());
|
|
962
|
-
expect(response.statusCode).toBe(statusCode);
|
|
963
|
-
})
|
|
964
|
-
|
|
965
|
-
it ('includes the provided body', async () => {
|
|
966
|
-
const key = TestHelpers.Faker.Text.randomString();
|
|
967
|
-
const value = TestHelpers.Faker.Text.randomString();
|
|
968
|
-
const body = {[key]: value};
|
|
969
|
-
await (controller[handlerName](body));
|
|
970
|
-
|
|
971
|
-
expect(controller.render).toHaveBeenCalledTimes(1);
|
|
972
|
-
expect(controller.render).toHaveBeenCalledWith(body);
|
|
973
|
-
});
|
|
974
|
-
});
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
const errorHandlers = [
|
|
978
|
-
['renderUnauthorized', 401],
|
|
979
|
-
['renderPaymentRequired', 402],
|
|
980
|
-
['renderForbidden', 403],
|
|
981
|
-
['renderNotFound', 404],
|
|
982
|
-
['renderMethodNotAllowed', 405],
|
|
983
|
-
['renderRequestTimeout', 408],
|
|
984
|
-
['renderConflict', 409],
|
|
985
|
-
['renderGone', 410],
|
|
986
|
-
['renderContentTooLarge', 413],
|
|
987
|
-
['renderUnsupportedMediaType', 415],
|
|
988
|
-
['renderUnprocessableContent', 422],
|
|
989
|
-
['renderLocked', 423],
|
|
990
|
-
['renderTooManyRequests', 429],
|
|
991
|
-
['renderServerError', 500],
|
|
992
|
-
['renderNotImplemented', 501],
|
|
993
|
-
['renderBadGateway', 502],
|
|
994
|
-
['renderServiceUnavailable', 503],
|
|
995
|
-
['renderGatewayTimeout', 504],
|
|
996
|
-
]
|
|
997
|
-
|
|
998
|
-
describe.each(errorHandlers)('#%s', (handlerName, statusCode) => {
|
|
999
|
-
it (`returns a ${statusCode} response`, async () => {
|
|
1000
|
-
await (controller[handlerName]());
|
|
1001
|
-
expect(response.statusCode).toBe(statusCode);
|
|
1002
|
-
})
|
|
1003
|
-
|
|
1004
|
-
it ('includes a blank message by default', async () => {
|
|
1005
|
-
await controller[handlerName]();
|
|
1006
|
-
expect(controller.render).toHaveBeenCalledTimes(1);
|
|
1007
|
-
expect(controller.render).toHaveBeenCalledWith({errors: {message: null}});
|
|
1008
|
-
})
|
|
1009
|
-
|
|
1010
|
-
it ('includes a provided message', async () => {
|
|
1011
|
-
const msg = TestHelpers.Faker.Text.randomString();
|
|
1012
|
-
await controller[handlerName](msg);
|
|
1013
|
-
expect(controller.render).toHaveBeenCalledTimes(1);
|
|
1014
|
-
expect(controller.render).toHaveBeenCalledWith({errors: {message: msg}});
|
|
1015
|
-
});
|
|
1016
|
-
|
|
1017
|
-
it ('includes a provided body and message', async () => {
|
|
1018
|
-
const key = TestHelpers.Faker.Text.randomString();
|
|
1019
|
-
const val = TestHelpers.Faker.Text.randomString();
|
|
1020
|
-
const body = {[key]: val};
|
|
1021
|
-
const msg = TestHelpers.Faker.Text.randomString();
|
|
1022
|
-
const expected = {...body, errors: {message: msg}};
|
|
1023
|
-
await controller[handlerName](msg, body);
|
|
1024
|
-
expect(controller.render).toHaveBeenCalledTimes(1);
|
|
1025
|
-
expect(controller.render).toHaveBeenCalledWith(expected);
|
|
1026
|
-
});
|
|
1027
|
-
});
|
|
1028
|
-
});
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
describe('#render', () => {
|
|
1032
|
-
let response;
|
|
1033
|
-
let controller;
|
|
1034
|
-
beforeEach(() => {
|
|
1035
|
-
response = {json: jest.fn(), send: jest.fn(), statusCode: 200};
|
|
1036
|
-
controller = new FooController({}, response);
|
|
1037
|
-
});
|
|
1038
|
-
|
|
1039
|
-
it ('calls response.send (not response.json) when the body is a string', async () => {
|
|
1040
|
-
const body = TestHelpers.Faker.Text.randomString();
|
|
1041
|
-
await controller.render(body);
|
|
1042
|
-
|
|
1043
|
-
expect(response.send).toHaveBeenCalledTimes(1);
|
|
1044
|
-
expect(response.send).toHaveBeenCalledWith(body);
|
|
1045
|
-
expect(response.json).not.toHaveBeenCalled();
|
|
1046
|
-
});
|
|
1047
|
-
|
|
1048
|
-
it ('marks the controller as rendered after a string render', async () => {
|
|
1049
|
-
await controller.render('hello');
|
|
1050
|
-
expect(controller.rendered).toBe(true);
|
|
1051
|
-
});
|
|
1052
|
-
|
|
1053
|
-
it ('is a no-op when the controller has already been rendered', async () => {
|
|
1054
|
-
controller.markRendered();
|
|
1055
|
-
await controller.render('hello');
|
|
1056
|
-
expect(response.send).not.toHaveBeenCalled();
|
|
1057
|
-
expect(response.json).not.toHaveBeenCalled();
|
|
1058
|
-
});
|
|
1059
|
-
|
|
1060
|
-
it ('is a no-op when the controller is streaming', async () => {
|
|
1061
|
-
controller._isStreaming = true;
|
|
1062
|
-
await controller.render('hello');
|
|
1063
|
-
await controller.render({foo: 'bar'});
|
|
1064
|
-
|
|
1065
|
-
expect(response.send).not.toHaveBeenCalled();
|
|
1066
|
-
expect(response.json).not.toHaveBeenCalled();
|
|
1067
|
-
});
|
|
1068
|
-
|
|
1069
|
-
it ('does not mark the controller as rendered when streaming', async () => {
|
|
1070
|
-
controller._isStreaming = true;
|
|
1071
|
-
await controller.render('hello');
|
|
1072
|
-
expect(controller.rendered).toBe(false);
|
|
1073
|
-
});
|
|
1074
|
-
});
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
describe('#processJSONBody', () => {
|
|
1078
|
-
let controller;
|
|
1079
|
-
beforeEach(() => {
|
|
1080
|
-
controller = new FooController({}, {});
|
|
1081
|
-
});
|
|
1082
|
-
|
|
1083
|
-
it ('returns null when the body is undefined', async () => {
|
|
1084
|
-
expect(await controller.processJSONBody(undefined, {})).toBe(null);
|
|
1085
|
-
});
|
|
1086
|
-
|
|
1087
|
-
it ('returns null when the body is null', async () => {
|
|
1088
|
-
expect(await controller.processJSONBody(null, {})).toBe(null);
|
|
1089
|
-
});
|
|
1090
|
-
|
|
1091
|
-
it ('returns primitives unchanged', async () => {
|
|
1092
|
-
expect(await controller.processJSONBody('hello', {})).toBe('hello');
|
|
1093
|
-
expect(await controller.processJSONBody(42, {})).toBe(42);
|
|
1094
|
-
expect(await controller.processJSONBody(true, {})).toBe(true);
|
|
1095
|
-
});
|
|
1096
|
-
|
|
1097
|
-
it ('returns Date instances as their epoch ms via getTime', async () => {
|
|
1098
|
-
const date = new Date('2020-01-02T03:04:05Z');
|
|
1099
|
-
expect(await controller.processJSONBody(date, {})).toBe(date.getTime());
|
|
1100
|
-
});
|
|
1101
|
-
|
|
1102
|
-
it ('recursively processes Date values inside objects', async () => {
|
|
1103
|
-
const date = new Date('2021-02-03T00:00:00Z');
|
|
1104
|
-
const result = await controller.processJSONBody({createdAt: date, name: 'foo'}, {});
|
|
1105
|
-
expect(result).toEqual({createdAt: date.getTime(), name: 'foo'});
|
|
1106
|
-
});
|
|
1107
|
-
|
|
1108
|
-
it ('recursively processes arrays', async () => {
|
|
1109
|
-
const date = new Date('2022-03-04T00:00:00Z');
|
|
1110
|
-
const result = await controller.processJSONBody([1, date, {ts: date}], {});
|
|
1111
|
-
expect(result).toEqual([1, date.getTime(), {ts: date.getTime()}]);
|
|
1112
|
-
});
|
|
1113
|
-
|
|
1114
|
-
it ('invokes toApiResponse on objects that define it and recurses on the result', async () => {
|
|
1115
|
-
const date = new Date('2023-04-05T00:00:00Z');
|
|
1116
|
-
const apiModel = {
|
|
1117
|
-
async toApiResponse() { return {id: 1, createdAt: date}; }
|
|
1118
|
-
};
|
|
1119
|
-
const result = await controller.processJSONBody(apiModel, {});
|
|
1120
|
-
expect(result).toEqual({id: 1, createdAt: date.getTime()});
|
|
1121
|
-
});
|
|
1122
|
-
|
|
1123
|
-
it ('passes the options argument through to toApiResponse', async () => {
|
|
1124
|
-
const options = {standardize: false, extra: 'flag'};
|
|
1125
|
-
const toApi = jest.fn().mockResolvedValue({});
|
|
1126
|
-
const apiModel = {toApiResponse: toApi};
|
|
1127
|
-
|
|
1128
|
-
await controller.processJSONBody(apiModel, options);
|
|
1129
|
-
expect(toApi).toHaveBeenCalledWith(options);
|
|
1130
|
-
});
|
|
1131
|
-
|
|
1132
|
-
it ('recurses through arrays of objects with toApiResponse', async () => {
|
|
1133
|
-
const apiModels = [
|
|
1134
|
-
{toApiResponse: async () => ({id: 'a'})},
|
|
1135
|
-
{toApiResponse: async () => ({id: 'b'})},
|
|
1136
|
-
];
|
|
1137
|
-
const result = await controller.processJSONBody(apiModels, {});
|
|
1138
|
-
expect(result).toEqual([{id: 'a'}, {id: 'b'}]);
|
|
1139
|
-
});
|
|
1140
|
-
});
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
356
|
describe('Request Properties', () => {
|
|
1144
357
|
let request;
|
|
1145
358
|
let response;
|
|
@@ -1147,83 +360,11 @@ describe('VidaServerController', () => {
|
|
|
1147
360
|
|
|
1148
361
|
beforeEach(() => {
|
|
1149
362
|
request = {headers: randomPayload()};
|
|
1150
|
-
response = {headers: randomPayload(), statusCode: TestHelpers.Faker.Math.randomNumber(), json: jest.fn()};
|
|
363
|
+
response = {headers: randomPayload(), statusCode: TestHelpers.Faker.Math.randomNumber(), json: jest.fn(), send: jest.fn(), setHeader: jest.fn()};
|
|
1151
364
|
request.headers['content-type'] = TestHelpers.Faker.Text.randomString();
|
|
1152
365
|
controller = new FooController(request, response);
|
|
1153
366
|
});
|
|
1154
367
|
|
|
1155
|
-
describe('#requestHeaders', () => {
|
|
1156
|
-
it ('returns a copy of the request headers', () => {
|
|
1157
|
-
expect(controller.requestHeaders).not.toBe(request.headers);
|
|
1158
|
-
expect(JSON.stringify(controller.requestHeaders)).toEqual(JSON.stringify(request.headers));
|
|
1159
|
-
});
|
|
1160
|
-
});
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
describe('#responseHeaders', () => {
|
|
1164
|
-
it ('returns the request headers', () => {
|
|
1165
|
-
expect(controller.responseHeaders).toBe(response.headers);
|
|
1166
|
-
});
|
|
1167
|
-
});
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
describe('#contentType', () => {
|
|
1171
|
-
it ('returns the content-type request header', () => {
|
|
1172
|
-
expect(controller.contentType).toEqual(request.headers['content-type']);
|
|
1173
|
-
});
|
|
1174
|
-
});
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
describe('#userAgent', () => {
|
|
1178
|
-
it ('returns the user-agent request header', () => {
|
|
1179
|
-
const ua = TestHelpers.Faker.Text.randomString();
|
|
1180
|
-
request.headers['user-agent'] = ua;
|
|
1181
|
-
expect(controller.userAgent).toEqual(ua);
|
|
1182
|
-
});
|
|
1183
|
-
});
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
describe('#requestBody', () => {
|
|
1187
|
-
it ('returns the underlying request body', () => {
|
|
1188
|
-
const body = {foo: TestHelpers.Faker.Text.randomString()};
|
|
1189
|
-
request.body = body;
|
|
1190
|
-
expect(controller.requestBody).toBe(body);
|
|
1191
|
-
});
|
|
1192
|
-
});
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
describe('#requestId', () => {
|
|
1196
|
-
it ('returns the request id', () => {
|
|
1197
|
-
request.id = TestHelpers.Faker.Text.randomString();
|
|
1198
|
-
expect(controller.requestId).toEqual(request.id);
|
|
1199
|
-
});
|
|
1200
|
-
});
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
describe('#requestIp', () => {
|
|
1204
|
-
it ('returns the request ip', () => {
|
|
1205
|
-
request.ip = TestHelpers.Faker.Text.randomString();
|
|
1206
|
-
expect(controller.requestIp).toEqual(request.ip);
|
|
1207
|
-
});
|
|
1208
|
-
});
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
describe('#requestMethod', () => {
|
|
1212
|
-
it ('returns the request method', () => {
|
|
1213
|
-
request.method = 'POST';
|
|
1214
|
-
expect(controller.requestMethod).toEqual('POST');
|
|
1215
|
-
});
|
|
1216
|
-
});
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
describe('#url', () => {
|
|
1220
|
-
it ('returns the request originalUrl', () => {
|
|
1221
|
-
request.originalUrl = `/${TestHelpers.Faker.Text.randomString()}`;
|
|
1222
|
-
expect(controller.url).toEqual(request.originalUrl);
|
|
1223
|
-
});
|
|
1224
|
-
});
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
368
|
describe('#logger', () => {
|
|
1228
369
|
it ('returns a child of the passed logger, scoped to the request id', () => {
|
|
1229
370
|
const childLogger = {};
|
|
@@ -1383,7 +524,7 @@ describe('VidaServerController', () => {
|
|
|
1383
524
|
namedBefore() { order.push('before2') }
|
|
1384
525
|
testAction() { order.push('action'); return {} }
|
|
1385
526
|
}
|
|
1386
|
-
const response = { json: jest.fn(), end: jest.fn(), statusCode: 200 };
|
|
527
|
+
const response = { json: jest.fn(), send: jest.fn(), setHeader: jest.fn(), end: jest.fn(), statusCode: 200 };
|
|
1387
528
|
const controller = new C({}, response);
|
|
1388
529
|
|
|
1389
530
|
await controller.performRequest('testAction');
|
|
@@ -1400,7 +541,7 @@ describe('VidaServerController', () => {
|
|
|
1400
541
|
namedAfter() { order.push('after2') }
|
|
1401
542
|
testAction() { order.push('action'); return {} }
|
|
1402
543
|
}
|
|
1403
|
-
const response = { json: jest.fn(), end: jest.fn(), statusCode: 200 };
|
|
544
|
+
const response = { json: jest.fn(), send: jest.fn(), setHeader: jest.fn(), end: jest.fn(), statusCode: 200 };
|
|
1404
545
|
const controller = new C({}, response);
|
|
1405
546
|
|
|
1406
547
|
await controller.performRequest('testAction');
|
|
@@ -1413,7 +554,7 @@ describe('VidaServerController', () => {
|
|
|
1413
554
|
setupCallbacks() { this.beforeCallback(() => false) }
|
|
1414
555
|
}
|
|
1415
556
|
C.prototype.testAction = testAction;
|
|
1416
|
-
const response = { json: jest.fn(), end: jest.fn(), statusCode: 200 };
|
|
557
|
+
const response = { json: jest.fn(), send: jest.fn(), setHeader: jest.fn(), end: jest.fn(), statusCode: 200 };
|
|
1417
558
|
const controller = new C({}, response);
|
|
1418
559
|
|
|
1419
560
|
await controller.performRequest('testAction');
|
|
@@ -1429,7 +570,7 @@ describe('VidaServerController', () => {
|
|
|
1429
570
|
}
|
|
1430
571
|
testAction() { return {} }
|
|
1431
572
|
}
|
|
1432
|
-
const response = { json: jest.fn(), end: jest.fn(), statusCode: 200 };
|
|
573
|
+
const response = { json: jest.fn(), send: jest.fn(), setHeader: jest.fn(), end: jest.fn(), statusCode: 200 };
|
|
1433
574
|
const controller = new C({}, response);
|
|
1434
575
|
|
|
1435
576
|
await controller.performRequest('testAction');
|
|
@@ -1445,7 +586,7 @@ describe('VidaServerController', () => {
|
|
|
1445
586
|
}
|
|
1446
587
|
testAction() { return {} }
|
|
1447
588
|
}
|
|
1448
|
-
const response = { json: jest.fn(), end: jest.fn(), statusCode: 200 };
|
|
589
|
+
const response = { json: jest.fn(), send: jest.fn(), setHeader: jest.fn(), end: jest.fn(), statusCode: 200 };
|
|
1449
590
|
const controller = new C({}, response);
|
|
1450
591
|
|
|
1451
592
|
await controller.performRequest('testAction');
|