@mimik/api-helper 3.0.0 → 3.0.1

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/README.md CHANGED
@@ -1,3 +1,21 @@
1
+ ## Modules
2
+
3
+ <dl>
4
+ <dt><a href="#module_api-helper">api-helper</a></dt>
5
+ <dd></dd>
6
+ </dl>
7
+
8
+ ## Typedefs
9
+
10
+ <dl>
11
+ <dt><a href="#UUID">UUID</a> : <code>string</code></dt>
12
+ <dd><p>UUID string in RFC 4122 format.</p>
13
+ </dd>
14
+ <dt><a href="#PATH">PATH</a> : <code>string</code></dt>
15
+ <dd><p>File system path string.</p>
16
+ </dd>
17
+ </dl>
18
+
1
19
  <a name="module_api-helper"></a>
2
20
 
3
21
  ## api-helper
@@ -50,7 +68,7 @@ The default formats for validation are: `date`, `time`, `date-time`, `byte`, `uu
50
68
  | securityHandlers | <code>object</code> | List of the security handlers to add for the service. |
51
69
  | extraFormats | <code>object</code> | list of the formats to add for validating properties. |
52
70
  | config | <code>object</code> | Configuration of the service. |
53
- | correlationId | <code>UUID.&lt;string&gt;</code> | CorrelationId when logging activities. |
71
+ | correlationId | [<code>UUID</code>](#UUID) | CorrelationId when logging activities. |
54
72
 
55
73
  <a name="module_api-helper..getAPIFile"></a>
56
74
 
@@ -80,8 +98,8 @@ Gets the API file from swaggerhub and stores it in the given PATH location.
80
98
 
81
99
  | Param | Type | Description |
82
100
  | --- | --- | --- |
83
- | apiFilename | <code>PATH.&lt;string&gt;</code> | Name of the file where the API file will be stored. |
84
- | correlationId | <code>UUID.&lt;string&gt;</code> | CorrelationId when logging activities. |
101
+ | apiFilename | [<code>PATH</code>](#PATH) | Name of the file where the API file will be stored. |
102
+ | correlationId | [<code>UUID</code>](#UUID) | CorrelationId when logging activities. |
85
103
  | options | <code>object</code> | Options associated with the call. Use to pass `metrics` to `rpRetry` and `apiInfo` to access the api file in the api provider. |
86
104
 
87
105
  <a name="module_api-helper..setupServerFiles"></a>
@@ -100,10 +118,10 @@ Setup and validates files for the server
100
118
 
101
119
  | Param | Type | Description |
102
120
  | --- | --- | --- |
103
- | apiFilename | <code>PATH.&lt;string&gt;</code> | Name of the file where the API file will be stored. |
104
- | controllersDirectory | <code>PATH.&lt;string&gt;</code> | Directory to find the controller files. |
105
- | buildDirectory | <code>PATH.&lt;string&gt;</code> | Directory where the register file will be stored. |
106
- | correlationId | <code>UUID.&lt;string&gt;</code> | CorrelationId when logging activities. |
121
+ | apiFilename | [<code>PATH</code>](#PATH) | Name of the file where the API file will be stored. |
122
+ | controllersDirectory | [<code>PATH</code>](#PATH) | Directory to find the controller files. |
123
+ | buildDirectory | [<code>PATH</code>](#PATH) | Directory where the register file will be stored. |
124
+ | correlationId | [<code>UUID</code>](#UUID) | CorrelationId when logging activities. |
107
125
  | options | <code>object</code> | Options associated with the call. Use to pass `metrics` to `rpRetry` and `apiKey` to access private API. |
108
126
 
109
127
  <a name="module_api-helper..securityLib"></a>
@@ -144,7 +162,7 @@ Validates the known SecuritySchemes: `SystemSecurity`, `AdminSecurity`, `UserSec
144
162
  | Param | Type | Description |
145
163
  | --- | --- | --- |
146
164
  | apiDefinition | <code>object</code> | JSON object containing the API definition. |
147
- | correlationId | <code>UUID.&lt;string&gt;</code> | CorrelationId when logging activities. |
165
+ | correlationId | [<code>UUID</code>](#UUID) | CorrelationId when logging activities. |
148
166
 
149
167
  <a name="module_api-helper..extractProperties"></a>
150
168
 
@@ -162,7 +180,19 @@ Extracts the properties from API definition and creates a file binding the handl
162
180
  | Param | Type | Description |
163
181
  | --- | --- | --- |
164
182
  | apiDefinition | <code>object</code> | JSON object containing the API definition. |
165
- | controllersDirectory | <code>PATH.&lt;string&gt;</code> | Directory to find the controller files. |
166
- | buildDirectory | <code>PATH.&lt;string&gt;</code> | Directory where the register file will be stored. |
167
- | correlationId | <code>UUID.&lt;string&gt;</code> | CorrelationId when logging activities. |
183
+ | controllersDirectory | [<code>PATH</code>](#PATH) | Directory to find the controller files. |
184
+ | buildDirectory | [<code>PATH</code>](#PATH) | Directory where the register file will be stored. |
185
+ | correlationId | [<code>UUID</code>](#UUID) | CorrelationId when logging activities. |
186
+
187
+ <a name="UUID"></a>
188
+
189
+ ## UUID : <code>string</code>
190
+ UUID string in RFC 4122 format.
191
+
192
+ **Kind**: global typedef
193
+ <a name="PATH"></a>
194
+
195
+ ## PATH : <code>string</code>
196
+ File system path string.
168
197
 
198
+ **Kind**: global typedef
package/index.js CHANGED
@@ -38,6 +38,14 @@ import pathLib from 'path';
38
38
  import { rpRetry } from '@mimik/request-retry';
39
39
  import { saveProperties } from './lib/extract-helper.js';
40
40
  import { securityLib } from './lib/securityHandlers.js';
41
+ /**
42
+ * UUID string in RFC 4122 format.
43
+ * @typedef {string} UUID
44
+ */
45
+ /**
46
+ * File system path string.
47
+ * @typedef {string} PATH
48
+ */
41
49
  /**
42
50
  * @module api-helper
43
51
  * @example
@@ -86,7 +94,7 @@ export { securityLib };
86
94
  * @param {object} securityHandlers - List of the security handlers to add for the service.
87
95
  * @param {object} extraFormats - list of the formats to add for validating properties.
88
96
  * @param {object} config - Configuration of the service.
89
- * @param {UUID.<string>} correlationId - CorrelationId when logging activities.
97
+ * @param {UUID} correlationId - CorrelationId when logging activities.
90
98
  * @return {Promise.<object>} The API file itself.
91
99
  * @throws {Promise} An error is thrown if the initialization failed.
92
100
  *
@@ -238,8 +246,8 @@ const buildProviderRequest = (params, apiInfo, apiFilename) => {
238
246
  * @requires fs
239
247
  * @requires js-yaml
240
248
  * @requires path
241
- * @param {PATH.<string>} apiFilename - Name of the file where the API file will be stored.
242
- * @param {UUID.<string>} correlationId - CorrelationId when logging activities.
249
+ * @param {PATH} apiFilename - Name of the file where the API file will be stored.
250
+ * @param {UUID} correlationId - CorrelationId when logging activities.
243
251
  * @param {object} options - Options associated with the call. Use to pass `metrics` to `rpRetry` and `apiInfo` to access the api file in the api provider.
244
252
  * @return {Promise.<object>} The API file itself.
245
253
  * @throws {Promise} An error is thrown if the apiFilename resolution generates an error or the request to the API provider fails or the file cannot be saved.
@@ -368,7 +376,7 @@ export const getAPIFile = (apiFilename, correlationId, options) => {
368
376
  * @requires @mimik/sumologic-winston-logger
369
377
  * @requires @mimik/response-helper
370
378
  * @param {object} apiDefinition - JSON object containing the API definition.
371
- * @param {UUID.<string>} correlationId - CorrelationId when logging activities.
379
+ * @param {UUID} correlationId - CorrelationId when logging activities.
372
380
  * @return {Array.<string>} An array of the known securitySchemes that are in the API definition.
373
381
  * @throws An error is thrown if a validation fails.
374
382
  */
@@ -398,9 +406,9 @@ export const validateSecuritySchemes = (apiDefinition, correlationId) => {
398
406
  * @requires @mimik/sumologic-winston-logger
399
407
  * @requires fs
400
408
  * @param {object} apiDefinition - JSON object containing the API definition.
401
- * @param {PATH.<string>} controllersDirectory - Directory to find the controller files.
402
- * @param {PATH.<string>} buildDirectory - Directory where the register file will be stored.
403
- * @param {UUID.<string>} correlationId - CorrelationId when logging activities.
409
+ * @param {PATH} controllersDirectory - Directory to find the controller files.
410
+ * @param {PATH} buildDirectory - Directory where the register file will be stored.
411
+ * @param {UUID} correlationId - CorrelationId when logging activities.
404
412
  * @return {void}
405
413
  * @throws An error is thrown for many reasons, like operationId does not exist in controllers, controller does not exist...
406
414
  */
@@ -483,10 +491,10 @@ export const extractProperties = (apiDefinition, controllersDirectory, buildDire
483
491
  * @requires fs
484
492
  * @requires js-yaml
485
493
  * @requires path
486
- * @param {PATH.<string>} apiFilename - Name of the file where the API file will be stored.
487
- * @param {PATH.<string>} controllersDirectory - Directory to find the controller files.
488
- * @param {PATH.<string>} buildDirectory - Directory where the register file will be stored.
489
- * @param {UUID.<string>} correlationId - CorrelationId when logging activities.
494
+ * @param {PATH} apiFilename - Name of the file where the API file will be stored.
495
+ * @param {PATH} controllersDirectory - Directory to find the controller files.
496
+ * @param {PATH} buildDirectory - Directory where the register file will be stored.
497
+ * @param {UUID} correlationId - CorrelationId when logging activities.
490
498
  * @param {object} options - Options associated with the call. Use to pass `metrics` to `rpRetry` and `apiKey` to access private API.
491
499
  * @return {Promise.<object>} The API file, the API filename, the existing known security schemes and the defined security schemes.
492
500
  * @throws {Promise} An error is thrown for many reasons associated with getAPIFile or validateSecuritySchemes or extractProperties.
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@mimik/api-helper",
3
- "version": "3.0.0",
3
+ "version": "3.0.1",
4
4
  "description": "helper for openAPI backend and mimik service",
5
5
  "main": "./index.js",
6
6
  "type": "module",
7
7
  "scripts": {
8
8
  "lint": "eslint . --no-error-on-unmatched-pattern",
9
9
  "docs": "jsdoc2md index.js > README.md",
10
- "test": "mocha test/ --recursive",
10
+ "test": "mocha --reporter mochawesome test/ --recursive",
11
11
  "test-ci": "c8 --reporter=lcov --reporter=text npm test",
12
12
  "prepublishOnly": "npm run docs && npm run lint && npm run test-ci",
13
13
  "commit-ready": "npm run docs && npm run lint && npm run test-ci"
@@ -36,7 +36,7 @@
36
36
  "js-yaml": "4.1.1",
37
37
  "jsonwebtoken": "9.0.3",
38
38
  "openapi-backend": "5.16.1",
39
- "swagger-client": "3.36.2"
39
+ "swagger-client": "3.37.0"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@eslint/js": "9.32.0",
@@ -47,9 +47,10 @@
47
47
  "eslint": "9.32.0",
48
48
  "eslint-plugin-import": "2.32.0",
49
49
  "esmock": "2.7.3",
50
- "globals": "17.3.0",
50
+ "globals": "17.4.0",
51
51
  "husky": "9.1.7",
52
52
  "jsdoc-to-markdown": "9.1.3",
53
- "mocha": "11.7.5"
53
+ "mocha": "11.7.5",
54
+ "mochawesome": "7.1.4"
54
55
  }
55
56
  }
@@ -1,9 +0,0 @@
1
- {
2
- "permissions": {
3
- "allow": [
4
- "Bash(npx mocha:*)",
5
- "Bash(npm test:*)",
6
- "Bash(npx eslint:*)"
7
- ]
8
- }
9
- }
package/.husky/pre-commit DELETED
@@ -1,2 +0,0 @@
1
- #!/bin/sh
2
- npm run commit-ready
package/.husky/pre-push DELETED
@@ -1,2 +0,0 @@
1
- #!/bin/sh
2
- npm run test
package/eslint.config.js DELETED
@@ -1,82 +0,0 @@
1
- import globals from 'globals';
2
- import importPlugin from 'eslint-plugin-import';
3
- import js from '@eslint/js';
4
- import processDoc from '@mimik/eslint-plugin-document-env';
5
- import stylistic from '@stylistic/eslint-plugin';
6
-
7
- const MAX_LENGTH_LINE = 180;
8
- const MAX_FUNCTION_PARAMETERS = 6;
9
- const MAX_LINES_IN_FILES = 600;
10
- const MAX_LINES_IN_FUNCTION = 150;
11
- const MAX_STATEMENTS_IN_FUNCTION = 45;
12
- const MIN_KEYS_IN_OBJECT = 10;
13
- const MAX_COMPLEXITY = 30;
14
- const ECMA_VERSION = 'latest';
15
- const MAX_DEPTH = 6;
16
- const ALLOWED_CONSTANTS = [0, 1, -1];
17
-
18
- export default [
19
- {
20
- ignores: ['mochawesome-report/**', 'node_modules/**', 'dist/**'],
21
- },
22
- importPlugin.flatConfigs.recommended,
23
- stylistic.configs.recommended,
24
- js.configs.all,
25
- {
26
- plugins: {
27
- processDoc,
28
- },
29
- languageOptions: {
30
- ecmaVersion: ECMA_VERSION,
31
- globals: {
32
- ...globals.mocha,
33
- ...globals.nodeBuiltin,
34
- },
35
- sourceType: 'module',
36
- },
37
- rules: {
38
- '@stylistic/brace-style': ['warn', 'stroustrup', { allowSingleLine: true }],
39
- '@stylistic/line-comment-position': ['off'],
40
- '@stylistic/max-len': ['warn', MAX_LENGTH_LINE, { ignoreComments: true, ignoreStrings: true, ignoreRegExpLiterals: true }],
41
- '@stylistic/quotes': ['warn', 'single'],
42
- '@stylistic/semi': ['error', 'always'],
43
- 'capitalized-comments': ['off'],
44
- 'complexity': ['error', MAX_COMPLEXITY],
45
- 'curly': ['off'],
46
- 'id-length': ['error', { exceptions: ['x', 'y', 'z', 'i', 'j', 'k'] }],
47
- 'import/no-extraneous-dependencies': ['error', { devDependencies: true }],
48
- 'import/no-unresolved': ['error', { amd: true, caseSensitiveStrict: true, commonjs: true }],
49
- 'init-declarations': ['off'],
50
- 'linebreak-style': ['off'],
51
- 'max-depth': ['error', MAX_DEPTH],
52
- 'max-len': ['off'],
53
- 'max-lines': ['warn', { max: MAX_LINES_IN_FILES, skipComments: true, skipBlankLines: true }],
54
- 'max-lines-per-function': ['warn', { max: MAX_LINES_IN_FUNCTION, skipComments: true, skipBlankLines: true }],
55
- 'max-params': ['error', MAX_FUNCTION_PARAMETERS],
56
- 'max-statements': ['warn', MAX_STATEMENTS_IN_FUNCTION],
57
- 'no-confusing-arrow': ['off'],
58
- 'no-inline-comments': ['off'],
59
- 'no-magic-numbers': ['error', { ignore: ALLOWED_CONSTANTS, enforceConst: true, detectObjects: true }],
60
- 'no-process-env': ['error'],
61
- 'no-ternary': ['off'],
62
- 'no-undefined': ['off'],
63
- 'one-var': ['error', 'never'],
64
- 'processDoc/validate-document-env': ['error'],
65
- 'quotes': ['off'],
66
- 'sort-imports': ['error', { allowSeparatedGroups: true }],
67
- 'sort-keys': ['error', 'asc', { caseSensitive: true, minKeys: MIN_KEYS_IN_OBJECT, natural: false, allowLineSeparatedGroups: true }],
68
- },
69
- },
70
- {
71
- files: ['test/**/*.js'],
72
- rules: {
73
- 'class-methods-use-this': ['off'],
74
- 'max-classes-per-file': ['off'],
75
- 'max-lines': ['off'],
76
- 'max-lines-per-function': ['off'],
77
- 'max-statements': ['off'],
78
- 'no-empty-function': ['off'],
79
- 'no-magic-numbers': ['off'],
80
- },
81
- },
82
- ];
@@ -1,159 +0,0 @@
1
- import esmock from 'esmock';
2
- import { expect } from 'chai';
3
-
4
- let ajvFormats;
5
- let addedLibFormats;
6
- let addedCustomFormats;
7
-
8
- describe('ajvHelpers', () => {
9
- before(async () => {
10
- const mod = await esmock('../lib/ajvHelpers.js', {
11
- 'ajv-formats': {
12
- default: (ajv, formats) => {
13
- addedLibFormats = formats;
14
- },
15
- },
16
- });
17
-
18
- ({ ajvFormats } = mod);
19
- });
20
-
21
- beforeEach(() => {
22
- addedLibFormats = null;
23
- addedCustomFormats = {};
24
- });
25
-
26
- const createMockAjv = () => ({
27
- addFormat: (name, format) => {
28
- addedCustomFormats[name] = format;
29
- },
30
- });
31
-
32
- describe('with no extra formats', () => {
33
- it('should add default library formats', () => {
34
- const ajv = createMockAjv();
35
- const configurer = ajvFormats();
36
-
37
- configurer(ajv);
38
- expect(addedLibFormats).to.deep.equal(['date', 'time', 'date-time', 'byte', 'uuid', 'uri', 'email', 'ipv4', 'ipv6']);
39
- });
40
-
41
- it('should add built-in semver and ip custom formats', () => {
42
- const ajv = createMockAjv();
43
- const configurer = ajvFormats();
44
-
45
- configurer(ajv);
46
- expect(addedCustomFormats).to.have.property('semver');
47
- expect(addedCustomFormats.semver.type).to.equal('string');
48
- expect(addedCustomFormats).to.have.property('ip');
49
- expect(addedCustomFormats.ip.type).to.equal('string');
50
- });
51
-
52
- it('should return the ajv instance', () => {
53
- const ajv = createMockAjv();
54
- const configurer = ajvFormats();
55
- const result = configurer(ajv);
56
-
57
- expect(result).to.equal(ajv);
58
- });
59
- });
60
-
61
- describe('with null extra formats', () => {
62
- it('should treat null as no extra formats', () => {
63
- const ajv = createMockAjv();
64
- const configurer = ajvFormats(null);
65
-
66
- configurer(ajv);
67
- expect(addedLibFormats).to.deep.equal(['date', 'time', 'date-time', 'byte', 'uuid', 'uri', 'email', 'ipv4', 'ipv6']);
68
- });
69
- });
70
-
71
- describe('with extra library formats (string-only)', () => {
72
- it('should append format names to the library formats list', () => {
73
- const ajv = createMockAjv();
74
- const configurer = ajvFormats({ hostname: {} });
75
-
76
- configurer(ajv);
77
- expect(addedLibFormats).to.include('hostname');
78
- expect(addedLibFormats).to.have.lengthOf(10);
79
- });
80
- });
81
-
82
- describe('with extra custom formats (with type)', () => {
83
- it('should add custom format via ajv.addFormat', () => {
84
- const customFormat = { type: 'string', validate: /^[A-Z]+$/u };
85
- const ajv = createMockAjv();
86
- const configurer = ajvFormats({ uppercase: customFormat });
87
-
88
- configurer(ajv);
89
- expect(addedCustomFormats).to.have.property('uppercase');
90
- expect(addedCustomFormats.uppercase).to.equal(customFormat);
91
- expect(addedLibFormats).to.not.include('uppercase');
92
- });
93
- });
94
-
95
- describe('semver validation', () => {
96
- it('should accept valid semver strings', () => {
97
- const ajv = createMockAjv();
98
-
99
- ajvFormats()(ajv);
100
- const { validate } = addedCustomFormats.semver;
101
-
102
- expect(validate.test('1.0.0')).to.equal(true);
103
- expect(validate.test('0.1.0')).to.equal(true);
104
- expect(validate.test('1.2.3-alpha.1')).to.equal(true);
105
- expect(validate.test('1.2.3+build.123')).to.equal(true);
106
- expect(validate.test('1.2.3-beta+build')).to.equal(true);
107
- });
108
-
109
- it('should reject invalid semver strings', () => {
110
- const ajv = createMockAjv();
111
-
112
- ajvFormats()(ajv);
113
- const { validate } = addedCustomFormats.semver;
114
-
115
- expect(validate.test('1.0')).to.equal(false);
116
- expect(validate.test('abc')).to.equal(false);
117
- expect(validate.test('1.0.0.0')).to.equal(false);
118
- });
119
- });
120
-
121
- describe('ip validation', () => {
122
- it('should accept valid IPv4 addresses', () => {
123
- const ajv = createMockAjv();
124
-
125
- ajvFormats()(ajv);
126
- const { validate } = addedCustomFormats.ip;
127
-
128
- expect(validate.test('192.168.1.1')).to.equal(true);
129
- expect(validate.test('10.0.0.1')).to.equal(true);
130
- expect(validate.test('255.255.255.255')).to.equal(true);
131
- });
132
-
133
- it('should accept valid IPv6 addresses', () => {
134
- const ajv = createMockAjv();
135
-
136
- ajvFormats()(ajv);
137
- const { validate } = addedCustomFormats.ip;
138
-
139
- expect(validate.test('::1')).to.equal(true);
140
- expect(validate.test('2001:0db8:85a3:0000:0000:8a2e:0370:7334')).to.equal(true);
141
- });
142
- });
143
-
144
- describe('DEFAULT_FORMATS isolation', () => {
145
- it('should not mutate DEFAULT_FORMATS between calls', () => {
146
- const ajv1 = createMockAjv();
147
- const ajv2 = createMockAjv();
148
-
149
- ajvFormats({ extra1: {} })(ajv1);
150
- const firstCallLength = addedLibFormats.length;
151
-
152
- ajvFormats()(ajv2);
153
- const secondCallLength = addedLibFormats.length;
154
-
155
- expect(secondCallLength).to.equal(9);
156
- expect(firstCallLength).to.equal(10);
157
- });
158
- });
159
- });
@@ -1,150 +0,0 @@
1
- import { ERROR_CODE } from '@mimik/response-helper';
2
- import esmock from 'esmock';
3
- import { expect } from 'chai';
4
-
5
- let baseHandlers;
6
- let lastRejectArgs;
7
-
8
- describe('baseHandlers', () => {
9
- before(async () => {
10
- const mod = await esmock('../lib/baseHandlers.js', {
11
- '@mimik/swagger-helper': {
12
- rejectRequest: (error, con, res) => {
13
- lastRejectArgs = { error, con, res };
14
- },
15
- },
16
- });
17
-
18
- baseHandlers = mod.default;
19
- });
20
-
21
- beforeEach(() => {
22
- lastRejectArgs = null;
23
- });
24
-
25
- describe('validationFail', () => {
26
- it('should create error with status 400 and call rejectRequest', () => {
27
- const con = { validation: { errors: [{ message: 'bad field' }], warnings: ['warn1'] } };
28
- const req = { method: 'POST', url: '/test' };
29
- const res = {};
30
-
31
- baseHandlers.validationFail(con, req, res);
32
- expect(lastRejectArgs.error.message).to.equal('Failed schema validation');
33
- expect(lastRejectArgs.error.statusCode).to.equal(ERROR_CODE.PARAMETER);
34
- expect(lastRejectArgs.error.info).to.deep.equal({
35
- method: 'POST',
36
- path: '/test',
37
- errors: [{ message: 'bad field' }],
38
- warnings: ['warn1'],
39
- });
40
- expect(lastRejectArgs.con).to.equal(con);
41
- expect(lastRejectArgs.res).to.equal(res);
42
- });
43
-
44
- it('should default warnings to empty array when not present', () => {
45
- const con = { validation: { errors: [] } };
46
- const req = { method: 'GET', url: '/path' };
47
- const res = {};
48
-
49
- baseHandlers.validationFail(con, req, res);
50
- expect(lastRejectArgs.error.info.warnings).to.deep.equal([]);
51
- });
52
- });
53
-
54
- describe('notFound', () => {
55
- it('should create error with status 404 and the path', () => {
56
- const con = {};
57
- const req = { method: 'GET', url: '/unknown' };
58
- const res = {};
59
-
60
- baseHandlers.notFound(con, req, res);
61
- expect(lastRejectArgs.error.message).to.equal('path /unknown not defined in Swagger specification');
62
- expect(lastRejectArgs.error.statusCode).to.equal(ERROR_CODE.NOT_FOUND);
63
- expect(lastRejectArgs.error.info).to.deep.equal({ method: 'GET', path: '/unknown' });
64
- });
65
- });
66
-
67
- describe('unauthorizedHandler', () => {
68
- it('should use default Unauthorized error when no scheme error exists', () => {
69
- const con = { security: { authorized: true, SystemSecurity: {} } };
70
- const req = {};
71
- const res = {};
72
-
73
- baseHandlers.unauthorizedHandler(con, req, res);
74
- expect(lastRejectArgs.error.message).to.equal('Unauthorized');
75
- expect(lastRejectArgs.error.statusCode).to.equal(ERROR_CODE.UNAUTHORIZED);
76
- });
77
-
78
- it('should use scheme error when present', () => {
79
- const schemeError = new Error('token expired');
80
-
81
- schemeError.statusCode = ERROR_CODE.FORBIDDEN;
82
- const con = { security: { authorized: false, SystemSecurity: { error: schemeError } } };
83
- const req = {};
84
- const res = {};
85
-
86
- baseHandlers.unauthorizedHandler(con, req, res);
87
- expect(lastRejectArgs.error).to.equal(schemeError);
88
- expect(lastRejectArgs.error.message).to.equal('token expired');
89
- });
90
-
91
- it('should filter out the authorized key from security schemes', () => {
92
- const schemeError = new Error('forbidden');
93
- const con = { security: { authorized: true, AdminSecurity: { error: schemeError } } };
94
- const req = {};
95
- const res = {};
96
-
97
- baseHandlers.unauthorizedHandler(con, req, res);
98
- expect(lastRejectArgs.error).to.equal(schemeError);
99
- });
100
-
101
- it('should handle scheme with no error property', () => {
102
- const con = { security: { authorized: false, SystemSecurity: null } };
103
- const req = {};
104
- const res = {};
105
-
106
- baseHandlers.unauthorizedHandler(con, req, res);
107
- expect(lastRejectArgs.error.message).to.equal('Unauthorized');
108
- });
109
- });
110
-
111
- describe('notImplemented', () => {
112
- it('should create error with status 501 and include operationId', () => {
113
- const con = { operation: { operationId: 'getUsers' } };
114
- const req = { method: 'GET', url: '/users' };
115
- const res = {};
116
-
117
- baseHandlers.notImplemented(con, req, res);
118
- expect(lastRejectArgs.error.message).to.equal('GET /users defined in Swagger specification, but not implemented');
119
- expect(lastRejectArgs.error.statusCode).to.equal(ERROR_CODE.NOT_IMPLEMENTED);
120
- expect(lastRejectArgs.error.info).to.deep.equal({
121
- method: 'GET',
122
- path: '/users',
123
- operationId: 'getUsers',
124
- });
125
- });
126
- });
127
-
128
- describe('methodNotAllowed', () => {
129
- it('should create error with status 501 for disallowed method', () => {
130
- const con = {};
131
- const req = { method: 'DELETE', url: '/items' };
132
- const res = {};
133
-
134
- baseHandlers.methodNotAllowed(con, req, res);
135
- expect(lastRejectArgs.error.message).to.equal('path /items defined in Swagger specification, but the method DELETE is not defined');
136
- expect(lastRejectArgs.error.statusCode).to.equal(ERROR_CODE.NOT_IMPLEMENTED);
137
- expect(lastRejectArgs.error.info).to.deep.equal({ method: 'DELETE', path: '/items' });
138
- });
139
- });
140
-
141
- describe('exports', () => {
142
- it('should export all five handlers', () => {
143
- expect(baseHandlers).to.have.property('validationFail').that.is.a('function');
144
- expect(baseHandlers).to.have.property('notFound').that.is.a('function');
145
- expect(baseHandlers).to.have.property('unauthorizedHandler').that.is.a('function');
146
- expect(baseHandlers).to.have.property('notImplemented').that.is.a('function');
147
- expect(baseHandlers).to.have.property('methodNotAllowed').that.is.a('function');
148
- });
149
- });
150
- });