@flusys/nestjs-shared 6.0.2 → 6.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/cjs/classes/api-controller.class.spec.js +684 -0
- package/cjs/classes/api-service.class.spec.js +809 -0
- package/cjs/classes/handle-custome-db.spec.js +82 -0
- package/cjs/classes/hybrid-cache.class.spec.js +168 -0
- package/cjs/classes/winston.logger.class.spec.js +330 -0
- package/cjs/decorators/api-response.decorator.spec.js +126 -0
- package/cjs/decorators/current-user.decorator.spec.js +74 -0
- package/cjs/decorators/log-action.decorator.spec.js +353 -0
- package/cjs/decorators/public.decorator.spec.js +50 -0
- package/cjs/decorators/require-permission.decorator.spec.js +147 -0
- package/cjs/exceptions/base-app.exception.spec.js +157 -0
- package/cjs/exceptions/permission.exception.spec.js +82 -0
- package/cjs/filters/global-exception.filter.spec.js +440 -0
- package/cjs/guards/jwt-auth.guard.spec.js +75 -0
- package/cjs/guards/optional-jwt-auth.guard.spec.js +55 -0
- package/cjs/guards/permission.guard.spec.js +358 -0
- package/cjs/interceptors/delete-empty-id-from-body.interceptor.spec.js +107 -0
- package/cjs/interceptors/idempotency.interceptor.spec.js +116 -0
- package/cjs/interceptors/response-meta.interceptor.spec.js +89 -0
- package/cjs/interceptors/set-user-field-on-body.interceptor.spec.js +128 -0
- package/cjs/interceptors/slug.interceptor.spec.js +110 -0
- package/cjs/middlewares/logger.middleware.spec.js +462 -0
- package/cjs/modules/cache/cache.module.spec.js +48 -0
- package/cjs/modules/datasource/multi-tenant-datasource.service.spec.js +381 -0
- package/cjs/modules/utils/utils.service.spec.js +169 -0
- package/cjs/utils/date-time.util.spec.js +84 -0
- package/cjs/utils/html-sanitizer.util.spec.js +76 -0
- package/cjs/utils/permission-cache-key.util.spec.js +88 -0
- package/cjs/utils/query-helpers.util.spec.js +209 -0
- package/cjs/utils/request.util.spec.js +249 -0
- package/cjs/utils/string.util.spec.js +63 -0
- package/fesm/classes/api-controller.class.spec.js +680 -0
- package/fesm/classes/api-service.class.spec.js +805 -0
- package/fesm/classes/handle-custome-db.spec.js +78 -0
- package/fesm/classes/hybrid-cache.class.spec.js +164 -0
- package/fesm/classes/winston.logger.class.spec.js +327 -0
- package/fesm/decorators/api-response.decorator.spec.js +122 -0
- package/fesm/decorators/current-user.decorator.spec.js +73 -0
- package/fesm/decorators/log-action.decorator.spec.js +349 -0
- package/fesm/decorators/public.decorator.spec.js +46 -0
- package/fesm/decorators/require-permission.decorator.spec.js +143 -0
- package/fesm/exceptions/base-app.exception.spec.js +153 -0
- package/fesm/exceptions/permission.exception.spec.js +78 -0
- package/fesm/filters/global-exception.filter.spec.js +436 -0
- package/fesm/guards/jwt-auth.guard.spec.js +71 -0
- package/fesm/guards/optional-jwt-auth.guard.spec.js +51 -0
- package/fesm/guards/permission.guard.spec.js +354 -0
- package/fesm/interceptors/delete-empty-id-from-body.interceptor.spec.js +103 -0
- package/fesm/interceptors/idempotency.interceptor.spec.js +112 -0
- package/fesm/interceptors/response-meta.interceptor.spec.js +85 -0
- package/fesm/interceptors/set-user-field-on-body.interceptor.spec.js +124 -0
- package/fesm/interceptors/slug.interceptor.spec.js +106 -0
- package/fesm/middlewares/logger.middleware.spec.js +459 -0
- package/fesm/modules/cache/cache.module.spec.js +44 -0
- package/fesm/modules/datasource/multi-tenant-datasource.service.spec.js +377 -0
- package/fesm/modules/utils/utils.service.spec.js +165 -0
- package/fesm/utils/date-time.util.spec.js +80 -0
- package/fesm/utils/html-sanitizer.util.spec.js +72 -0
- package/fesm/utils/permission-cache-key.util.spec.js +84 -0
- package/fesm/utils/query-helpers.util.spec.js +205 -0
- package/fesm/utils/request.util.spec.js +245 -0
- package/fesm/utils/string.util.spec.js +59 -0
- package/package.json +2 -2
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
}
|
|
7
|
+
function _ts_metadata(k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
}
|
|
10
|
+
import { Reflector } from '@nestjs/core';
|
|
11
|
+
import { PERMISSIONS_KEY } from '../constants';
|
|
12
|
+
import { RequireAnyPermission, RequirePermission, RequirePermissionLogic } from './require-permission.decorator';
|
|
13
|
+
describe('permission decorators', ()=>{
|
|
14
|
+
const reflector = new Reflector();
|
|
15
|
+
describe('RequirePermission', ()=>{
|
|
16
|
+
it('should set metadata with AND operator for multiple permissions', ()=>{
|
|
17
|
+
let Controller = class Controller {
|
|
18
|
+
handler() {}
|
|
19
|
+
};
|
|
20
|
+
_ts_decorate([
|
|
21
|
+
RequirePermission('user.read', 'user.write'),
|
|
22
|
+
_ts_metadata("design:type", Function),
|
|
23
|
+
_ts_metadata("design:paramtypes", []),
|
|
24
|
+
_ts_metadata("design:returntype", void 0)
|
|
25
|
+
], Controller.prototype, "handler", null);
|
|
26
|
+
const metadata = reflector.get(PERMISSIONS_KEY, Controller.prototype.handler);
|
|
27
|
+
expect(metadata).toEqual({
|
|
28
|
+
permissions: [
|
|
29
|
+
'user.read',
|
|
30
|
+
'user.write'
|
|
31
|
+
],
|
|
32
|
+
operator: 'AND'
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
it('should set metadata for a single permission', ()=>{
|
|
36
|
+
let Controller = class Controller {
|
|
37
|
+
handler() {}
|
|
38
|
+
};
|
|
39
|
+
_ts_decorate([
|
|
40
|
+
RequirePermission('user.read'),
|
|
41
|
+
_ts_metadata("design:type", Function),
|
|
42
|
+
_ts_metadata("design:paramtypes", []),
|
|
43
|
+
_ts_metadata("design:returntype", void 0)
|
|
44
|
+
], Controller.prototype, "handler", null);
|
|
45
|
+
const metadata = reflector.get(PERMISSIONS_KEY, Controller.prototype.handler);
|
|
46
|
+
expect(metadata).toEqual({
|
|
47
|
+
permissions: [
|
|
48
|
+
'user.read'
|
|
49
|
+
],
|
|
50
|
+
operator: 'AND'
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
it('should set metadata with an empty permissions array when called with no args', ()=>{
|
|
54
|
+
let Controller = class Controller {
|
|
55
|
+
handler() {}
|
|
56
|
+
};
|
|
57
|
+
_ts_decorate([
|
|
58
|
+
RequirePermission(),
|
|
59
|
+
_ts_metadata("design:type", Function),
|
|
60
|
+
_ts_metadata("design:paramtypes", []),
|
|
61
|
+
_ts_metadata("design:returntype", void 0)
|
|
62
|
+
], Controller.prototype, "handler", null);
|
|
63
|
+
const metadata = reflector.get(PERMISSIONS_KEY, Controller.prototype.handler);
|
|
64
|
+
expect(metadata).toEqual({
|
|
65
|
+
permissions: [],
|
|
66
|
+
operator: 'AND'
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
describe('RequireAnyPermission', ()=>{
|
|
71
|
+
it('should set metadata with OR operator', ()=>{
|
|
72
|
+
let Controller = class Controller {
|
|
73
|
+
handler() {}
|
|
74
|
+
};
|
|
75
|
+
_ts_decorate([
|
|
76
|
+
RequireAnyPermission('admin', 'manager'),
|
|
77
|
+
_ts_metadata("design:type", Function),
|
|
78
|
+
_ts_metadata("design:paramtypes", []),
|
|
79
|
+
_ts_metadata("design:returntype", void 0)
|
|
80
|
+
], Controller.prototype, "handler", null);
|
|
81
|
+
const metadata = reflector.get(PERMISSIONS_KEY, Controller.prototype.handler);
|
|
82
|
+
expect(metadata).toEqual({
|
|
83
|
+
permissions: [
|
|
84
|
+
'admin',
|
|
85
|
+
'manager'
|
|
86
|
+
],
|
|
87
|
+
operator: 'OR'
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
describe('RequirePermissionLogic', ()=>{
|
|
92
|
+
it('should set metadata with a raw string permission', ()=>{
|
|
93
|
+
let Controller = class Controller {
|
|
94
|
+
handler() {}
|
|
95
|
+
};
|
|
96
|
+
_ts_decorate([
|
|
97
|
+
RequirePermissionLogic('users.read'),
|
|
98
|
+
_ts_metadata("design:type", Function),
|
|
99
|
+
_ts_metadata("design:paramtypes", []),
|
|
100
|
+
_ts_metadata("design:returntype", void 0)
|
|
101
|
+
], Controller.prototype, "handler", null);
|
|
102
|
+
const metadata = reflector.get(PERMISSIONS_KEY, Controller.prototype.handler);
|
|
103
|
+
expect(metadata).toBe('users.read');
|
|
104
|
+
});
|
|
105
|
+
it('should set metadata with a complex logic tree', ()=>{
|
|
106
|
+
const logic = {
|
|
107
|
+
type: 'group',
|
|
108
|
+
operator: 'AND',
|
|
109
|
+
children: [
|
|
110
|
+
{
|
|
111
|
+
type: 'action',
|
|
112
|
+
actionId: 'users.read'
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
type: 'group',
|
|
116
|
+
operator: 'OR',
|
|
117
|
+
children: [
|
|
118
|
+
{
|
|
119
|
+
type: 'action',
|
|
120
|
+
actionId: 'admin'
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
type: 'action',
|
|
124
|
+
actionId: 'manager'
|
|
125
|
+
}
|
|
126
|
+
]
|
|
127
|
+
}
|
|
128
|
+
]
|
|
129
|
+
};
|
|
130
|
+
let Controller = class Controller {
|
|
131
|
+
handler() {}
|
|
132
|
+
};
|
|
133
|
+
_ts_decorate([
|
|
134
|
+
RequirePermissionLogic(logic),
|
|
135
|
+
_ts_metadata("design:type", Function),
|
|
136
|
+
_ts_metadata("design:paramtypes", []),
|
|
137
|
+
_ts_metadata("design:returntype", void 0)
|
|
138
|
+
], Controller.prototype, "handler", null);
|
|
139
|
+
const metadata = reflector.get(PERMISSIONS_KEY, Controller.prototype.handler);
|
|
140
|
+
expect(metadata).toEqual(logic);
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
});
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { HttpStatus } from '@nestjs/common';
|
|
2
|
+
import { ERROR_MESSAGES } from '../constants/message-keys';
|
|
3
|
+
import { BaseAppException, ConflictException, ForbiddenException, InternalServerException, NotFoundException, ServiceUnavailableException, UnauthorizedException, ValidationException } from './base-app.exception';
|
|
4
|
+
describe('BaseAppException', ()=>{
|
|
5
|
+
it('should default status to BAD_REQUEST when not provided', ()=>{
|
|
6
|
+
const exception = new BaseAppException({
|
|
7
|
+
message: 'oops'
|
|
8
|
+
});
|
|
9
|
+
expect(exception.getStatus()).toBe(HttpStatus.BAD_REQUEST);
|
|
10
|
+
});
|
|
11
|
+
it('should default messageKey to ERROR_MESSAGES.GENERIC when not provided', ()=>{
|
|
12
|
+
const exception = new BaseAppException({
|
|
13
|
+
message: 'oops'
|
|
14
|
+
});
|
|
15
|
+
expect(exception.messageKey).toBe(ERROR_MESSAGES.GENERIC);
|
|
16
|
+
});
|
|
17
|
+
it('should use the provided status, messageKey, messageVariables, errors, and metadata', ()=>{
|
|
18
|
+
const errors = [
|
|
19
|
+
{
|
|
20
|
+
field: 'name',
|
|
21
|
+
message: 'required'
|
|
22
|
+
}
|
|
23
|
+
];
|
|
24
|
+
const exception = new BaseAppException({
|
|
25
|
+
message: 'Invalid',
|
|
26
|
+
messageKey: 'custom.key',
|
|
27
|
+
messageVariables: {
|
|
28
|
+
foo: 'bar'
|
|
29
|
+
},
|
|
30
|
+
status: HttpStatus.UNPROCESSABLE_ENTITY,
|
|
31
|
+
errors,
|
|
32
|
+
metadata: {
|
|
33
|
+
extra: true
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
expect(exception.getStatus()).toBe(HttpStatus.UNPROCESSABLE_ENTITY);
|
|
37
|
+
expect(exception.messageKey).toBe('custom.key');
|
|
38
|
+
expect(exception.messageVariables).toEqual({
|
|
39
|
+
foo: 'bar'
|
|
40
|
+
});
|
|
41
|
+
expect(exception.errors).toEqual(errors);
|
|
42
|
+
expect(exception.metadata).toEqual({
|
|
43
|
+
extra: true
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
it('should build an HttpException response body with success:false', ()=>{
|
|
47
|
+
const exception = new BaseAppException({
|
|
48
|
+
message: 'oops',
|
|
49
|
+
messageKey: 'k'
|
|
50
|
+
});
|
|
51
|
+
expect(exception.getResponse()).toEqual({
|
|
52
|
+
success: false,
|
|
53
|
+
message: 'oops',
|
|
54
|
+
messageKey: 'k',
|
|
55
|
+
messageVariables: undefined,
|
|
56
|
+
errors: undefined
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
describe('NotFoundException', ()=>{
|
|
60
|
+
it('should build a message with id when id is provided', ()=>{
|
|
61
|
+
const exception = new NotFoundException('User', 'uuid-1');
|
|
62
|
+
expect(exception.getStatus()).toBe(HttpStatus.NOT_FOUND);
|
|
63
|
+
expect(exception.message).toBe('User with id "uuid-1" not found');
|
|
64
|
+
expect(exception.messageKey).toBe(ERROR_MESSAGES.NOT_FOUND);
|
|
65
|
+
expect(exception.metadata).toEqual({
|
|
66
|
+
entity: 'User',
|
|
67
|
+
id: 'uuid-1'
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
it('should build a message without id when id is omitted', ()=>{
|
|
71
|
+
const exception = new NotFoundException('User');
|
|
72
|
+
expect(exception.message).toBe('User not found');
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
describe('ValidationException', ()=>{
|
|
76
|
+
it('should carry the validation errors and BAD_REQUEST status', ()=>{
|
|
77
|
+
const errors = [
|
|
78
|
+
{
|
|
79
|
+
field: 'email',
|
|
80
|
+
message: 'invalid format'
|
|
81
|
+
}
|
|
82
|
+
];
|
|
83
|
+
const exception = new ValidationException(errors);
|
|
84
|
+
expect(exception.getStatus()).toBe(HttpStatus.BAD_REQUEST);
|
|
85
|
+
expect(exception.messageKey).toBe(ERROR_MESSAGES.VALIDATION);
|
|
86
|
+
expect(exception.errors).toEqual(errors);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
describe('UnauthorizedException', ()=>{
|
|
90
|
+
it('should use the default message when none is provided', ()=>{
|
|
91
|
+
const exception = new UnauthorizedException();
|
|
92
|
+
expect(exception.getStatus()).toBe(HttpStatus.UNAUTHORIZED);
|
|
93
|
+
expect(exception.message).toBe('Unauthorized access');
|
|
94
|
+
expect(exception.messageKey).toBe(ERROR_MESSAGES.UNAUTHORIZED);
|
|
95
|
+
});
|
|
96
|
+
it('should use a custom message when provided', ()=>{
|
|
97
|
+
const exception = new UnauthorizedException('Custom message');
|
|
98
|
+
expect(exception.message).toBe('Custom message');
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
describe('ForbiddenException', ()=>{
|
|
102
|
+
it('should default to "Access forbidden"', ()=>{
|
|
103
|
+
const exception = new ForbiddenException();
|
|
104
|
+
expect(exception.getStatus()).toBe(HttpStatus.FORBIDDEN);
|
|
105
|
+
expect(exception.message).toBe('Access forbidden');
|
|
106
|
+
expect(exception.messageKey).toBe(ERROR_MESSAGES.FORBIDDEN);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
describe('ConflictException', ()=>{
|
|
110
|
+
it('should include the field in the message and metadata when provided', ()=>{
|
|
111
|
+
const exception = new ConflictException('User', 'email');
|
|
112
|
+
expect(exception.getStatus()).toBe(HttpStatus.CONFLICT);
|
|
113
|
+
expect(exception.message).toBe('User with this email already exists');
|
|
114
|
+
expect(exception.messageVariables).toEqual({
|
|
115
|
+
entity: 'User',
|
|
116
|
+
field: 'email'
|
|
117
|
+
});
|
|
118
|
+
expect(exception.metadata).toEqual({
|
|
119
|
+
entity: 'User',
|
|
120
|
+
field: 'email'
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
it('should omit the field when not provided', ()=>{
|
|
124
|
+
const exception = new ConflictException('User');
|
|
125
|
+
expect(exception.message).toBe('User already exists');
|
|
126
|
+
expect(exception.messageVariables).toEqual({
|
|
127
|
+
entity: 'User'
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
describe('InternalServerException', ()=>{
|
|
132
|
+
it('should default to "Internal server error"', ()=>{
|
|
133
|
+
const exception = new InternalServerException();
|
|
134
|
+
expect(exception.getStatus()).toBe(HttpStatus.INTERNAL_SERVER_ERROR);
|
|
135
|
+
expect(exception.message).toBe('Internal server error');
|
|
136
|
+
expect(exception.messageKey).toBe(ERROR_MESSAGES.INTERNAL);
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
describe('ServiceUnavailableException', ()=>{
|
|
140
|
+
it('should build a message including the service name', ()=>{
|
|
141
|
+
const exception = new ServiceUnavailableException('Email');
|
|
142
|
+
expect(exception.getStatus()).toBe(HttpStatus.SERVICE_UNAVAILABLE);
|
|
143
|
+
expect(exception.message).toBe('Email is temporarily unavailable');
|
|
144
|
+
expect(exception.messageKey).toBe(ERROR_MESSAGES.SERVICE_UNAVAILABLE);
|
|
145
|
+
expect(exception.messageVariables).toEqual({
|
|
146
|
+
service: 'Email'
|
|
147
|
+
});
|
|
148
|
+
expect(exception.metadata).toEqual({
|
|
149
|
+
service: 'Email'
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
});
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { ForbiddenException, InternalServerErrorException } from '@nestjs/common';
|
|
2
|
+
import { ERROR_MESSAGES } from '../constants/message-keys';
|
|
3
|
+
import { InsufficientPermissionsException, NoPermissionsFoundException, PermissionSystemUnavailableException } from './permission.exception';
|
|
4
|
+
describe('permission exceptions', ()=>{
|
|
5
|
+
describe('PermissionSystemUnavailableException', ()=>{
|
|
6
|
+
it('should be an InternalServerErrorException with the expected response body', ()=>{
|
|
7
|
+
const exception = new PermissionSystemUnavailableException();
|
|
8
|
+
expect(exception).toBeInstanceOf(InternalServerErrorException);
|
|
9
|
+
expect(exception.getResponse()).toMatchObject({
|
|
10
|
+
success: false,
|
|
11
|
+
message: 'Permission system temporarily unavailable',
|
|
12
|
+
messageKey: ERROR_MESSAGES.PERMISSION_SYSTEM_UNAVAILABLE
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
describe('InsufficientPermissionsException', ()=>{
|
|
17
|
+
it('should default to AND operator and matching messageKey', ()=>{
|
|
18
|
+
const exception = new InsufficientPermissionsException([
|
|
19
|
+
'user.create',
|
|
20
|
+
'user.update'
|
|
21
|
+
]);
|
|
22
|
+
expect(exception).toBeInstanceOf(ForbiddenException);
|
|
23
|
+
expect(exception.getResponse()).toMatchObject({
|
|
24
|
+
success: false,
|
|
25
|
+
message: 'Insufficient permissions',
|
|
26
|
+
messageKey: ERROR_MESSAGES.INSUFFICIENT_PERMISSIONS,
|
|
27
|
+
messageVariables: {
|
|
28
|
+
permissions: 'user.create, user.update'
|
|
29
|
+
},
|
|
30
|
+
missingPermissions: [
|
|
31
|
+
'user.create',
|
|
32
|
+
'user.update'
|
|
33
|
+
],
|
|
34
|
+
operator: 'AND'
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
it('should use the OR messageKey when operator is OR', ()=>{
|
|
38
|
+
const exception = new InsufficientPermissionsException([
|
|
39
|
+
'admin',
|
|
40
|
+
'manager'
|
|
41
|
+
], 'OR');
|
|
42
|
+
expect(exception.getResponse()).toMatchObject({
|
|
43
|
+
messageKey: ERROR_MESSAGES.INSUFFICIENT_PERMISSIONS_OR,
|
|
44
|
+
operator: 'OR'
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
it('should join a single missing permission without a separator', ()=>{
|
|
48
|
+
const exception = new InsufficientPermissionsException([
|
|
49
|
+
'user.create'
|
|
50
|
+
]);
|
|
51
|
+
expect(exception.getResponse()).toMatchObject({
|
|
52
|
+
messageVariables: {
|
|
53
|
+
permissions: 'user.create'
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
it('should handle an empty missing-permissions list', ()=>{
|
|
58
|
+
const exception = new InsufficientPermissionsException([]);
|
|
59
|
+
expect(exception.getResponse()).toMatchObject({
|
|
60
|
+
messageVariables: {
|
|
61
|
+
permissions: ''
|
|
62
|
+
},
|
|
63
|
+
missingPermissions: []
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
describe('NoPermissionsFoundException', ()=>{
|
|
68
|
+
it('should be a ForbiddenException with the expected response body', ()=>{
|
|
69
|
+
const exception = new NoPermissionsFoundException();
|
|
70
|
+
expect(exception).toBeInstanceOf(ForbiddenException);
|
|
71
|
+
expect(exception.getResponse()).toMatchObject({
|
|
72
|
+
success: false,
|
|
73
|
+
message: 'No permissions found',
|
|
74
|
+
messageKey: ERROR_MESSAGES.NO_PERMISSIONS_FOUND
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
});
|