UNPKG

42.6 kBJavaScriptView Raw
1/*****
2 License
3 --------------
4 Copyright © 2017 Bill & Melinda Gates Foundation
5 The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the "License") and you may not use these files except in compliance with the License. You may obtain a copy of the License at
6
7 http://www.apache.org/licenses/LICENSE-2.0
8
9 Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
10
11 Contributors
12 --------------
13 This is the official list of the Mojaloop project contributors for this file.
14 Names of the original copyright holders (individuals or organizations)
15 should be listed with a '*' in the first column. People who have
16 contributed from an organization can be listed under the organization
17 that actually holds the copyright for their contributions (see the
18 Gates Foundation organization for an example). Those individuals should have
19 their names indented and be marked with a '-'. Email address can be added
20 optionally within square brackets <email>.
21
22 * Gates Foundation
23 - Name Surname <name.surname@gatesfoundation.com>
24
25 * ModusBox
26 - Neal Donnan <neal.donnan@modusbox.com>
27 - Juan Correa <juan.correa@modusbox.com>
28 - Miguel de Barros <miguel.debarros@modusbox.com>
29
30 * Crosslake
31 - Lewis Daly <lewisd@crosslaketech.com>
32
33 --------------
34 ******/
35
36'use strict'
37
38const Test = require('tape')
39const Factory = require('../src/factory')
40const Errors = require('../src/enums').FSPIOPErrorCodes
41const ErrorModelTypes = require('../src/enums').MojaloopModelTypes
42const InternalEnums = require('../src/enums').Internal
43
44Test('Factory should', factoryTest => {
45 factoryTest.test('create an FSPIOPError with extensions', function (test) {
46 const fspiopError = Factory.createFSPIOPError(Errors.SERVER_ERROR, 'An error has occurred', { stack: 'Error:...' }, 'dfsp1', [
47 { key: 'testKey', value: 'testValue' }
48 ])
49 test.ok(fspiopError)
50 test.equal(fspiopError.apiErrorCode.code, Errors.SERVER_ERROR.code)
51 test.end()
52 })
53
54 factoryTest.test('create an FSPIOPError with extensions and error object cause', function (test) {
55 const standardError = new Error('Here be dragons!')
56 const fspiopError = Factory.createFSPIOPError(Errors.SERVER_ERROR, 'An error has occurred', standardError, 'dfsp1', [
57 { key: 'testKey', value: 'testValue' }
58 ])
59 test.ok(fspiopError)
60 test.equal(fspiopError.apiErrorCode.code, Errors.SERVER_ERROR.code)
61 test.ok(fspiopError.stack.includes(`\n${standardError.stack}`))
62 test.end()
63 })
64
65 factoryTest.test('create a valid FSPIOPError with specific error above 39 with extensions and error object cause and useDescriptionAsMessage set to false', function (test) {
66 const errorInformation = {
67 code: '3399',
68 errorDescription: 'Internal server error - Test Cause',
69 message: 'Internal server error - Test Cause',
70 extensionList: {
71 extension: [
72 {
73 key: 'test',
74 value: 'test'
75 }
76 ]
77 }
78 }
79 const standardError = new Error('Here be dragons!')
80 const fspiopError = Factory.createFSPIOPError(errorInformation, 'An error has occurred', standardError, 'dfsp1', [
81 { key: 'testKey', value: 'testValue' }
82 ], false)
83 const apiErrorObject = fspiopError.toApiErrorObject()
84 test.ok(fspiopError)
85 test.equal(apiErrorObject.errorInformation.errorCode, errorInformation.code)
86 test.end()
87 })
88
89 factoryTest.test('create an FSPIOPError with toApiErrorObject includeCauseExtension: false, truncateExtensions: true', function (test) {
90 const fspiopError = Factory.createFSPIOPError(Errors.SERVER_ERROR, 'An error has occurred', { stack: 'Error:...' }, 'dfsp1')
91 const apiErrorObject = fspiopError.toApiErrorObject()
92 test.ok(fspiopError)
93 test.equal(apiErrorObject.errorInformation.errorCode, Errors.SERVER_ERROR.code)
94 test.end()
95 })
96
97 factoryTest.test('create an FSPIOPError undefined apiErrorCode extensions with toApiErrorObject includeCauseExtension: false, truncateExtensions: true', function (test) {
98 try {
99 const apiErrorCode = undefined
100 const fspiopError = Factory.createFSPIOPError(apiErrorCode, 'An error has occurred', { stack: 'Error:...' }, 'dfsp1')
101 const apiErrorObject = fspiopError.toApiErrorObject()
102 test.ok(fspiopError)
103 test.equal(apiErrorObject.errorInformation.errorCode, Errors.INTERNAL_SERVER_ERROR.code)
104 test.fail(`We should have thrown an error here as the apiErrorCode is ${apiErrorCode}`)
105 } catch (err) {
106 test.ok(err instanceof Factory.FSPIOPError)
107 test.equal(err.apiErrorCode.code, Errors.INTERNAL_SERVER_ERROR.code)
108 }
109 test.end()
110 })
111
112 factoryTest.test('create an FSPIOPError with empty message with toApiErrorObject includeCauseExtension: false, truncateExtensions: true', function (test) {
113 const fspiopError = Factory.createFSPIOPError(Errors.SERVER_ERROR, '', { stack: 'Error:...' }, 'dfsp1', [
114 { key: 'testKey', value: 'testValue' }
115 ])
116 const fspiopErrorDescription = fspiopError.toApiErrorObject()
117 test.ok(fspiopError)
118 test.equal(fspiopError.apiErrorCode.code, Errors.SERVER_ERROR.code)
119 test.equal(fspiopErrorDescription.errorInformation.errorCode, Errors.SERVER_ERROR.code)
120 test.equal(fspiopErrorDescription.errorInformation.errorDescription, Errors.SERVER_ERROR.message)
121 test.end()
122 })
123
124 factoryTest.test('create an FSPIOPError with null message with toApiErrorObject includeCauseExtension: false, truncateExtensions: true', function (test) {
125 const fspiopError = Factory.createFSPIOPError(Errors.SERVER_ERROR, null, { stack: 'Error:...' }, 'dfsp1', [
126 { key: 'testKey', value: 'testValue' }
127 ])
128 const fspiopErrorDescription = fspiopError.toApiErrorObject()
129 test.ok(fspiopError)
130 test.equal(fspiopError.apiErrorCode.code, Errors.SERVER_ERROR.code)
131 test.equal(fspiopErrorDescription.errorInformation.errorCode, Errors.SERVER_ERROR.code)
132 test.equal(fspiopErrorDescription.errorInformation.errorDescription, Errors.SERVER_ERROR.message)
133 test.end()
134 })
135
136 factoryTest.test('create an FSPIOPError with undefined message with toApiErrorObject includeCauseExtension: false, truncateExtensions: true', function (test) {
137 const fspiopError = Factory.createFSPIOPError(Errors.SERVER_ERROR, undefined, { stack: 'Error:...' }, 'dfsp1', [
138 { key: 'testKey', value: 'testValue' }
139 ])
140 const fspiopErrorDescription = fspiopError.toApiErrorObject()
141 test.ok(fspiopError)
142 test.equal(fspiopError.apiErrorCode.code, Errors.SERVER_ERROR.code)
143 test.equal(fspiopErrorDescription.errorInformation.errorCode, Errors.SERVER_ERROR.code)
144 test.equal(fspiopErrorDescription.errorInformation.errorDescription, Errors.SERVER_ERROR.message)
145 test.end()
146 })
147
148 factoryTest.test('create an FSPIOPError undefined apiErrorCode extensions with toApiErrorObject includeCauseExtension: false, truncateExtensions: true', function (test) {
149 try {
150 const apiErrorCode = { foo: 'bar' }
151 const fspiopError = Factory.createFSPIOPError(apiErrorCode, 'An error has occurred', { stack: 'Error:...' }, 'dfsp1')
152 const apiErrorObject = fspiopError.toApiErrorObject()
153 test.ok(fspiopError)
154 test.equal(apiErrorObject.errorInformation.errorCode, Errors.INTERNAL_SERVER_ERROR.code)
155 test.fail(`We should have thrown an error here as the apiErrorCode is ${apiErrorCode}`)
156 } catch (err) {
157 test.ok(err instanceof Factory.FSPIOPError)
158 test.equal(err.apiErrorCode.code, Errors.INTERNAL_SERVER_ERROR.code)
159 }
160 test.end()
161 })
162
163 factoryTest.test('create an FSPIOPError from a Openapi-backend invalid type error response with toApiErrorObject includeCauseExtension: false, truncateExtensions: true', function (test) {
164 const error = {
165 keyword: 'type',
166 dataPath: '.header[\'content-length\']',
167 schemaPath: '#/properties/header/properties/content-length/type',
168 params: {
169 type: 'number'
170 },
171 message: 'should be number'
172 }
173 const fspiopError = Factory.createFSPIOPErrorFromOpenapiError(error, 'dfsp1')
174 test.ok(fspiopError)
175 test.deepEqual(fspiopError.toApiErrorObject(), {
176 errorInformation: {
177 errorCode: '3101',
178 errorDescription: 'Malformed syntax - .header[\'content-length\'] should be number'
179 }
180 })
181 test.end()
182 })
183
184 factoryTest.test('create an FSPIOPError from a Openapi-backend additional property error response with toApiErrorObject includeCauseExtension: false, truncateExtensions: true', function (test) {
185 const error = {
186 keyword: 'additionalProperties',
187 dataPath: '.requestBody.payee.partyIdInfo',
188 schemaPath: '#/properties/requestBody/properties/payee/properties/partyIdInfo/additionalProperties',
189 params: {
190 additionalProperty: 'fake'
191 },
192 message: 'should NOT have additional properties'
193 }
194 const fspiopError = Factory.createFSPIOPErrorFromOpenapiError(error, 'dfsp1')
195 test.ok(fspiopError)
196 test.deepEqual(fspiopError.toApiErrorObject(), {
197 errorInformation: {
198 errorCode: '3103',
199 errorDescription: 'Too many elements - .requestBody.payee.partyIdInfo should NOT have additional properties'
200 }
201 })
202 test.end()
203 })
204
205 factoryTest.test('create an FSPIOPError from a Openapi-backend required error response with toApiErrorObject includeCauseExtension: false, truncateExtensions: true', function (test) {
206 const error = {
207 keyword: 'required',
208 dataPath: '.requestBody.payee.partyIdInfo',
209 schemaPath: '#/properties/requestBody/properties/payee/properties/partyIdInfo/required',
210 params: {
211 missingProperty: 'partyIdType'
212 },
213 message: 'should have required property \'partyIdType\''
214 }
215 const fspiopError = Factory.createFSPIOPErrorFromOpenapiError(error, 'dfsp1')
216 test.ok(fspiopError)
217 test.deepEqual(fspiopError.toApiErrorObject(), {
218 errorInformation: {
219 errorCode: '3102',
220 errorDescription: 'Missing mandatory element - .requestBody.payee.partyIdInfo should have required property \'partyIdType\''
221 }
222 })
223 test.end()
224 })
225
226 factoryTest.test('create an FSPIOPError from a Openapi-backend generic validation error response with includeCauseExtension: false, truncateExtensions: true', function (test) {
227 const error = {
228 keyword: 'validation',
229 dataPath: '.requestBody.payee.partyIdInfo',
230 schemaPath: '#/properties/requestBody/properties/payee/properties/partyIdInfo/required',
231 params: {
232 missingProperty: 'partyIdType'
233 },
234 message: 'should have required property \'partyIdType\''
235 }
236 const fspiopError = Factory.createFSPIOPErrorFromOpenapiError(error, 'dfsp1')
237 test.ok(fspiopError)
238 test.deepEqual(fspiopError.toApiErrorObject(), {
239 errorInformation: {
240 errorCode: '3100',
241 errorDescription: 'Generic validation error - .requestBody.payee.partyIdInfo should have required property \'partyIdType\''
242 }
243 })
244 test.end()
245 })
246
247 factoryTest.test('create an FSPIOPError from a Openapi-backend generic validation error response not found URI', function (test) {
248 const error = {
249 keyword: 'notFound',
250 dataPath: '/invalidURIandMethod',
251 message: 'Not found'
252 }
253 const fspiopError = Factory.createFSPIOPErrorFromOpenapiError(error, 'dfsp1')
254 test.ok(fspiopError)
255 test.deepEqual(fspiopError.toApiErrorObject(), {
256 errorInformation: {
257 errorCode: '3002',
258 errorDescription: 'Unknown URI - /invalidURIandMethod Not found'
259 }
260 })
261 test.end()
262 })
263
264 factoryTest.test('create an FSPIOPError from a Openapi-backend generic validation error response for invalid method for valid path', function (test) {
265 const error = {
266 keyword: 'methodNotAllowed',
267 dataPath: 'POST /health',
268 message: ''
269 }
270 const fspiopError = Factory.createFSPIOPErrorFromOpenapiError(error, 'dfsp1')
271 test.ok(fspiopError)
272 test.deepEqual(fspiopError.toApiErrorObject(), {
273 errorInformation: {
274 errorCode: '3000',
275 errorDescription: 'Generic client error - Method Not Allowed - POST /health'
276 }
277 })
278 test.end()
279 })
280
281 factoryTest.test('create an FSPIOPError from a Joi error and invalid path parameter response with toApiErrorObject includeCauseExtension: false, truncateExtensions: true', function (test) {
282 const joiError = {
283 type: 'any.allowOnly',
284 context: {
285 label: 'Type'
286 }
287 }
288 const joiResponse = {
289 output: {
290 payload: {
291 validation: {
292 source: 'params'
293 }
294 }
295 }
296 }
297 const fspiopError = Factory.createFSPIOPErrorFromJoiError(joiError, joiResponse, 'dfsp1')
298 test.ok(fspiopError)
299 test.deepEqual(fspiopError.toApiErrorObject(), {
300 errorInformation: {
301 errorCode: '3101',
302 errorDescription: 'Malformed syntax - \'Type\' URI path parameter'
303 }
304 })
305 test.end()
306 })
307
308 factoryTest.test('create an FSPIOPError from a Joi error and missing header response with toApiErrorObject includeCauseExtension: false, truncateExtensions: true', function (test) {
309 const joiError = {
310 type: 'any.required',
311 context: {
312 label: 'content-type'
313 }
314 }
315 const joiResponse = {
316 output: {
317 payload: {
318 validation: {
319 source: 'header'
320 }
321 }
322 }
323 }
324 const fspiopError = Factory.createFSPIOPErrorFromJoiError(joiError, joiResponse, 'dfsp1')
325 test.ok(fspiopError)
326 test.deepEqual(fspiopError.toApiErrorObject(), {
327 errorInformation: {
328 errorCode: '3102',
329 errorDescription: 'Missing mandatory element - \'content-type\' HTTP header'
330 }
331 })
332 test.end()
333 })
334
335 factoryTest.test('create an FSPIOPError from a Joi error with toApiErrorObject includeCauseExtension: false, truncateExtensions: true', function (test) {
336 const joiError = {
337 message: 'Field is required',
338 type: 'any.required',
339 context: {
340 label: 'Field is required'
341 }
342 }
343 const fspiopError = Factory.createFSPIOPErrorFromJoiError(joiError, { stack: 'Stack trace...' }, 'dfsp1')
344 test.ok(fspiopError)
345 test.deepEqual(fspiopError.toApiErrorObject(), {
346 errorInformation: {
347 errorCode: '3102',
348 errorDescription: 'Missing mandatory element - Field is required'
349 }
350 })
351 test.end()
352 })
353
354 factoryTest.test('create an FSPIOPError from a Joi error with toApiErrorObject includeCauseExtension: true, truncateExtensions: false', function (test) {
355 const joiError = {
356 message: 'Field is required',
357 type: 'any.required',
358 context: {
359 label: 'Field is required'
360 }
361 }
362 const fspiopError = Factory.createFSPIOPErrorFromJoiError(joiError, { stack: 'Stack trace...' }, 'dfsp1')
363 test.ok(fspiopError)
364 const options = { includeCauseExtension: true, truncateExtensions: false }
365 test.deepEqual(fspiopError.toApiErrorObject(options), {
366 errorInformation: {
367 errorCode: '3102',
368 errorDescription: 'Missing mandatory element - Field is required',
369 extensionList: {
370 extension: [
371 {
372 key: InternalEnums.FSPIOPError.ExtensionsKeys.cause,
373 value: fspiopError.stack
374 }
375 ]
376 }
377 }
378 })
379 test.end()
380 })
381
382 factoryTest.test('create an FSPIOPError from a Joi error with toApiErrorObject includeCauseExtension: true, truncateExtensions: false', function (test) {
383 const joiError = {
384 message: 'Field is required',
385 type: 'any.required',
386 context: {
387 label: 'Field is required'
388 }
389 }
390 const fspiopError = Factory.createFSPIOPErrorFromJoiError(joiError, { stack: 'Stack trace...' }, 'dfsp1')
391 test.ok(fspiopError)
392 const options = { includeCauseExtension: true, truncateExtensions: false }
393 test.deepEqual(fspiopError.toApiErrorObject(options), {
394 errorInformation: {
395 errorCode: '3102',
396 errorDescription: 'Missing mandatory element - Field is required',
397 extensionList: {
398 extension: [
399 {
400 key: InternalEnums.FSPIOPError.ExtensionsKeys.cause,
401 value: fspiopError.stack
402 }
403 ]
404 }
405 }
406 })
407 test.end()
408 })
409
410 factoryTest.test('create an FSPIOPError from a Joi error with a string cause with toApiErrorObject includeCauseExtension: false, truncateExtensions: true', function (test) {
411 const joiError = {
412 message: 'Field is required',
413 type: 'any.required',
414 context: {
415 label: 'Field is required'
416 }
417 }
418 const fspiopError = Factory.createFSPIOPErrorFromJoiError(joiError, 'Stack trace...', 'dfsp1')
419 test.ok(fspiopError)
420 test.deepEqual(fspiopError.toApiErrorObject(), {
421 errorInformation: {
422 errorCode: '3102',
423 errorDescription: 'Missing mandatory element - Field is required'
424 }
425 })
426 test.end()
427 })
428
429 factoryTest.test('create an FSPIOPError from a Joi error with a string cause with toApiErrorObject includeCauseExtension: true, truncateExtensions: true', function (test) {
430 const joiError = {
431 message: 'Field is required',
432 type: 'any.required',
433 context: {
434 label: 'Field is required'
435 }
436 }
437 const fspiopError = Factory.createFSPIOPErrorFromJoiError(joiError, 'Stack trace...', 'dfsp1')
438 test.ok(fspiopError)
439 const options = { includeCauseExtension: true, truncateExtensions: true }
440 test.deepEqual(fspiopError.toApiErrorObject(options), {
441 errorInformation: {
442 errorCode: '3102',
443 errorDescription: 'Missing mandatory element - Field is required',
444 extensionList: {
445 extension: [
446 {
447 key: InternalEnums.FSPIOPError.ExtensionsKeys.cause,
448 value: fspiopError.stack.substring(ErrorModelTypes.ExtensionValue.constraints.min - 1, ErrorModelTypes.ExtensionValue.constraints.max) // truncate string to match Mojaloop API v1.0 Spec
449 }
450 ]
451 }
452 }
453 })
454 test.end()
455 })
456
457 factoryTest.test('create an FSPIOPError from an unknown Joi error with toApiErrorObject includeCauseExtension: false, truncateExtensions: true', function (test) {
458 const joiError = {
459 message: 'Unknown issue',
460 type: 'unknown',
461 context: {
462 label: 'Unknown issue'
463 }
464 }
465 const fspiopError = Factory.createFSPIOPErrorFromJoiError(joiError)
466 test.ok(fspiopError)
467 test.deepEqual(fspiopError.toApiErrorObject(), {
468 errorInformation: {
469 errorCode: '3100',
470 errorDescription: 'Generic validation error - Unknown issue'
471 }
472 })
473 test.end()
474 })
475
476 factoryTest.test('create an FSPIOPError from an unknown Joi error with toApiErrorObject includeCauseExtension: true, truncateExtensions: true', function (test) {
477 const joiError = {
478 message: 'Unknown issue',
479 type: 'unknown',
480 context: {
481 label: 'Unknown issue'
482 }
483 }
484 const fspiopError = Factory.createFSPIOPErrorFromJoiError(joiError)
485 test.ok(fspiopError)
486 const options = { includeCauseExtension: true, truncateExtensions: true }
487 test.deepEqual(fspiopError.toApiErrorObject(options), {
488 errorInformation: {
489 errorCode: '3100',
490 errorDescription: 'Generic validation error - Unknown issue',
491 extensionList: {
492 extension: [
493 {
494 key: InternalEnums.FSPIOPError.ExtensionsKeys.cause,
495 value: fspiopError.stack.substring(ErrorModelTypes.ExtensionValue.constraints.min - 1, ErrorModelTypes.ExtensionValue.constraints.max) // truncate string to match Mojaloop API v1.0 Spec
496 }
497 ]
498 }
499 }
500 })
501 test.end()
502 })
503
504 factoryTest.test('create an internal server FSPIOPError with toApiErrorObject includeCauseExtension: false, truncateExtensions: true', function (test) {
505 const cause = new Error('Test Cause')
506 const fspiopError = Factory.createInternalServerFSPIOPError('Test Internal Error', cause, 'dfsp1', [
507 { key: 'testKey', value: 'testValue' }
508 ])
509 test.ok(fspiopError)
510 test.ok(fspiopError.toString())
511 test.deepEqual(fspiopError.toApiErrorObject(), {
512 errorInformation: {
513 errorCode: '2001',
514 errorDescription: 'Internal server error - Test Internal Error',
515 extensionList: {
516 extension: [
517 {
518 key: 'testKey',
519 value: 'testValue'
520 }
521 ]
522 }
523 }
524 })
525 test.end()
526 })
527
528 factoryTest.test('create an internal server FSPIOPError with extension containing cause with toApiErrorObject includeCauseExtension: false, truncateExtensions: true', function (test) {
529 const cause = new Error('Test Cause')
530 const fspiopError = Factory.createInternalServerFSPIOPError('Test Internal Error', cause, 'dfsp1', [
531 { key: InternalEnums.FSPIOPError.ExtensionsKeys.cause, value: 'testValue' }
532 ])
533 test.ok(fspiopError)
534 test.ok(fspiopError.toString())
535 test.deepEqual(fspiopError.toApiErrorObject(), {
536 errorInformation: {
537 errorCode: '2001',
538 errorDescription: 'Internal server error - Test Internal Error'
539 /* Issue #1030: the extensionList should be removed when extension array is empty */
540 }
541 })
542 test.end()
543 })
544
545 factoryTest.test('create an internal server FSPIOPError with toApiErrorObject includeCauseExtension: true, truncateExtensions: true', function (test) {
546 const cause = new Error('Test Cause')
547 const fspiopError = Factory.createInternalServerFSPIOPError('Test Internal Error', cause, 'dfsp1', [
548 { key: 'testKey', value: 'testValue' }
549 ])
550 test.ok(fspiopError)
551 test.ok(fspiopError.toString())
552 const options = { includeCauseExtension: true, truncateExtensions: true }
553 test.deepEqual(fspiopError.toApiErrorObject(options), {
554 errorInformation: {
555 errorCode: '2001',
556 errorDescription: 'Internal server error - Test Internal Error',
557 extensionList: {
558 extension: [
559 {
560 key: 'testKey',
561 value: 'testValue'
562 },
563 {
564 key: InternalEnums.FSPIOPError.ExtensionsKeys.cause,
565 value: fspiopError.stack.substring(ErrorModelTypes.ExtensionValue.constraints.min - 1, ErrorModelTypes.ExtensionValue.constraints.max) // truncate string to match Mojaloop API v1.0 Spec
566 }
567 ]
568 }
569 }
570 })
571 test.end()
572 })
573
574 factoryTest.test('create an internal server FSPIOPError with extensionList instead of an extension with toApiErrorObject includeCauseExtension: false, truncateExtensions: true', function (test) {
575 const cause = new Error('Test Cause')
576 const fspiopError = Factory.createInternalServerFSPIOPError('Test Internal Error', cause, 'dfsp1',
577 {
578 extension: [
579 { key: 'testKey1', value: 'testValue1' },
580 { key: 'testKey2', value: 'testValue2' }
581 ]
582 }
583 )
584 test.ok(fspiopError)
585 test.ok(fspiopError.toString())
586 test.deepEqual(fspiopError.toApiErrorObject(), {
587 errorInformation: {
588 errorCode: '2001',
589 errorDescription: 'Internal server error - Test Internal Error',
590 extensionList: {
591 extension: [
592 {
593 key: 'testKey1',
594 value: 'testValue1'
595 },
596 {
597 key: 'testKey2',
598 value: 'testValue2'
599 }
600 ]
601 }
602 }
603 })
604 test.end()
605 })
606
607 factoryTest.test('create an internal server FSPIOPError with extensionList instead of an extension with cause extension with toApiErrorObject includeCauseExtension: true, truncateExtensions: true', function (test) {
608 const cause = new Error('Test Cause')
609 const fspiopError = Factory.createInternalServerFSPIOPError('Test Internal Error', cause, 'dfsp1',
610 {
611 extension: [
612 { key: 'testKey', value: 'testValue' }
613 ]
614 }
615 )
616 test.ok(fspiopError)
617 test.ok(fspiopError.toString())
618 const options = { includeCauseExtension: true, truncateExtensions: true }
619 test.deepEqual(fspiopError.toApiErrorObject(options), {
620 errorInformation: {
621 errorCode: '2001',
622 errorDescription: 'Internal server error - Test Internal Error',
623 extensionList: {
624 extension: [
625 {
626 key: 'testKey',
627 value: 'testValue'
628 },
629 {
630 key: InternalEnums.FSPIOPError.ExtensionsKeys.cause,
631 value: fspiopError.stack.substring(ErrorModelTypes.ExtensionValue.constraints.min - 1, ErrorModelTypes.ExtensionValue.constraints.max) // truncate string to match Mojaloop API v1.0 Spec
632 }
633 ]
634 }
635 }
636 })
637 test.end()
638 })
639
640 factoryTest.test('create an internal server FSPIOPError with an invalid extension', function (test) {
641 const cause = new Error('Test Cause')
642 try {
643 Factory.createInternalServerFSPIOPError('Test Internal Error', cause, 'dfsp1', {})
644 test.fail('expected validation failure due to invalid extension')
645 } catch (err) {
646 test.ok(err instanceof Error)
647 test.deepEqual(err.message, 'FSPIOPError Parameter Validation Failure - extensions is not a list or does not contain an extension list.')
648 }
649 test.end()
650 })
651
652 factoryTest.test('create an FSPIOPError from a ErrorInformation object with toApiErrorObject includeCauseExtension: false, truncateExtensions: true', function (test) {
653 const errorInformation = {
654 errorCode: '2001',
655 errorDescription: 'Internal server error - Test Cause',
656 extensionList: {
657 extension: [
658 {
659 key: 'test',
660 value: 'test'
661 }
662 ]
663 }
664 }
665 const fspiopError = Factory.createFSPIOPErrorFromErrorInformation(errorInformation, errorInformation.errorDescription)
666 test.ok(fspiopError)
667 test.deepEqual(fspiopError.toApiErrorObject(), {
668 errorInformation: {
669 errorCode: '2001',
670 errorDescription: 'Internal server error - Test Cause',
671 extensionList: {
672 extension: [
673 {
674 key: 'test',
675 value: 'test'
676 }
677 ]
678 }
679 }
680 })
681 test.end()
682 })
683
684 factoryTest.test('create an FSPIOPError from a ErrorInformation object with toApiErrorObject includeCauseExtension: true, truncateExtensions: true', function (test) {
685 const errorInformation = {
686 errorCode: '2001',
687 errorDescription: 'Internal server error - Test Cause',
688 extensionList: {
689 extension: [
690 {
691 key: 'test',
692 value: 'test'
693 }
694 ]
695 }
696 }
697 const fspiopError = Factory.createFSPIOPErrorFromErrorInformation(errorInformation, errorInformation.errorDescription)
698 test.ok(fspiopError)
699 const options = { includeCauseExtension: true, truncateExtensions: true }
700 test.deepEqual(fspiopError.toApiErrorObject(options), {
701 errorInformation: {
702 errorCode: '2001',
703 errorDescription: 'Internal server error - Test Cause',
704 extensionList: {
705 extension: [
706 {
707 key: 'test',
708 value: 'test'
709 },
710 {
711 key: InternalEnums.FSPIOPError.ExtensionsKeys.cause,
712 value: fspiopError.stack.substring(ErrorModelTypes.ExtensionValue.constraints.min - 1, ErrorModelTypes.ExtensionValue.constraints.max) // truncate string to match Mojaloop API v1.0 Spec
713 }
714 ]
715 }
716 }
717 })
718 test.end()
719 })
720
721 factoryTest.test('create an FSPIOPError from a ErrorInformation object with toApiErrorObject includeCauseExtension: true, truncateExtensions: true', function (test) {
722 const errorCause = 'FSPIOPError: Internal server error - Test Cause\n at createFSPIOPError (/Users/mdebarros/Documents/ModusDocs/Projects/MojaLoop/git/fork/central-services-error-handling/src/factory.js:142:12)\n at Object.createFSPIOPErrorFromErrorInformation (/Users/mdebarros/Documents/ModusDocs/Projects/MojaLoop/git/fork/central-services-error-handling/src/factory.js:251:10)\n at Test.<anonymous> (/Users/mdebarros/Documents/ModusDocs/Projects/MojaLoop/git/fork/central-services-error-handling/test/factory.test.js:235:33)\n at Test.bound [as _cb] (/Users/mdebarros/Documents/ModusDocs/Projects/MojaLoop/git/fork/central-services-error-handling/node_modules/tape/lib/test.js:77:32)\n at Test.run (/Users/mdebarros/Documents/ModusDocs/Projects/MojaLoop/git/fork/central-services-error-handling/node_modules/tape/lib/test.js:93:10)\n at Test.bound [as run] (/Users/mdebarros/Documents/ModusDocs/Projects/MojaLoop/git/fork/central-services-error-handling/node_modules/tape/lib/test.js:77:32)\n at Test._end (/Users/mdebarros/Documents/ModusDocs/Projects/MojaLoop/git/fork/central-services-error-handling/node_modules/tape/lib/test.js:162:11)\n at Test.bound [as _end] (/Users/mdebarros/Documents/ModusDocs/Projects/MojaLoop/git/fork/central-services-error-handling/node_modules/tape/lib/test.js:77:32)\n at Test.<anonymous> (/Users/mdebarros/Documents/ModusDocs/Projects/MojaLoop/git/fork/central-services-error-handling/node_modules/tape/lib/test.js:161:40)\n at Test.emit (events.js:189:13)\nInternal server error - Test Cause'
723 const errorInformation = {
724 errorCode: '2001',
725 errorDescription: 'Internal server error - Test Cause',
726 extensionList: {
727 extension: [
728 {
729 key: 'test',
730 value: 'test'
731 },
732 {
733 key: InternalEnums.FSPIOPError.ExtensionsKeys.cause,
734 value: errorCause.substring(ErrorModelTypes.ExtensionValue.constraints.min - 1, ErrorModelTypes.ExtensionValue.constraints.max) // truncate string to match Mojaloop API v1.0 Spec
735 }
736 ]
737 }
738 }
739 const fspiopError = Factory.createFSPIOPErrorFromErrorInformation(errorInformation, errorInformation.errorDescription)
740 test.ok(fspiopError)
741 const options = { includeCauseExtension: true, truncateExtensions: true }
742 test.deepEqual(fspiopError.toApiErrorObject(options), {
743 errorInformation: {
744 errorCode: '2001',
745 errorDescription: 'Internal server error - Test Cause',
746 extensionList: {
747 extension: [
748 {
749 key: 'test',
750 value: 'test'
751 },
752 {
753 key: InternalEnums.FSPIOPError.ExtensionsKeys.cause,
754 value: `${fspiopError.stack}\n${errorCause}`.substring(ErrorModelTypes.ExtensionValue.constraints.min - 1, ErrorModelTypes.ExtensionValue.constraints.max) // truncate string to match Mojaloop API v1.0 Spec
755 }
756 ]
757 }
758 }
759 })
760 test.end()
761 })
762
763 factoryTest.test('create an FSPIOPError from a ErrorInformation object with toApiErrorObject includeCauseExtension: true, truncateExtensions: true', function (test) {
764 const errorCause = 'FSPIOPError: Internal server error - Test Cause\n at createFSPIOPError (/Users/mdebarros/Documents/ModusDocs/Projects/MojaLoop/git/fork/central-services-error-handling/src/factory.js:142:12)\n at Object.createFSPIOPErrorFromErrorInformation (/Users/mdebarros/Documents/ModusDocs/Projects/MojaLoop/git/fork/central-services-error-handling/src/factory.js:251:10)\n at Test.<anonymous> (/Users/mdebarros/Documents/ModusDocs/Projects/MojaLoop/git/fork/central-services-error-handling/test/factory.test.js:235:33)\n at Test.bound [as _cb] (/Users/mdebarros/Documents/ModusDocs/Projects/MojaLoop/git/fork/central-services-error-handling/node_modules/tape/lib/test.js:77:32)\n at Test.run (/Users/mdebarros/Documents/ModusDocs/Projects/MojaLoop/git/fork/central-services-error-handling/node_modules/tape/lib/test.js:93:10)\n at Test.bound [as run] (/Users/mdebarros/Documents/ModusDocs/Projects/MojaLoop/git/fork/central-services-error-handling/node_modules/tape/lib/test.js:77:32)\n at Test._end (/Users/mdebarros/Documents/ModusDocs/Projects/MojaLoop/git/fork/central-services-error-handling/node_modules/tape/lib/test.js:162:11)\n at Test.bound [as _end] (/Users/mdebarros/Documents/ModusDocs/Projects/MojaLoop/git/fork/central-services-error-handling/node_modules/tape/lib/test.js:77:32)\n at Test.<anonymous> (/Users/mdebarros/Documents/ModusDocs/Projects/MojaLoop/git/fork/central-services-error-handling/node_modules/tape/lib/test.js:161:40)\n at Test.emit (events.js:189:13)\nInternal server error - Test Cause'
765 const errorInformation = {
766 errorCode: '2001',
767 errorDescription: 'Internal server error - Test Cause',
768 extensionList: {
769 extension: [
770 {
771 key: 'test',
772 value: 'test'
773 },
774 {
775 key: InternalEnums.FSPIOPError.ExtensionsKeys.cause,
776 value: errorCause.substring(ErrorModelTypes.ExtensionValue.constraints.min - 1, ErrorModelTypes.ExtensionValue.constraints.max) // truncate string to match Mojaloop API v1.0 Spec
777 }
778 ]
779 }
780 }
781 const fspiopError = Factory.createFSPIOPErrorFromErrorInformation(errorInformation, errorInformation.errorDescription)
782 test.ok(fspiopError)
783 const options = { includeCauseExtension: true, truncateExtensions: true }
784 test.deepEqual(fspiopError.toApiErrorObject(options), {
785 errorInformation: {
786 errorCode: '2001',
787 errorDescription: 'Internal server error - Test Cause',
788 extensionList: {
789 extension: [
790 {
791 key: 'test',
792 value: 'test'
793 },
794 {
795 key: InternalEnums.FSPIOPError.ExtensionsKeys.cause,
796 value: `${fspiopError.stack}\n${errorCause}`.substring(ErrorModelTypes.ExtensionValue.constraints.min - 1, ErrorModelTypes.ExtensionValue.constraints.max) // truncate string to match Mojaloop API v1.0 Spec
797 }
798 ]
799 }
800 }
801 })
802 test.end()
803 })
804
805 factoryTest.test('create an invalid FSPIOPError from a ErrorInformation object', function (test) {
806 const errorInformation = {
807 errorCode: '9999',
808 errorDescription: 'Internal server error - Test Cause'
809 }
810 try {
811 const fspiopError = Factory.createFSPIOPErrorFromErrorInformation(errorInformation)
812 test.notOk(fspiopError)
813 test.fail('Should have thrown an exception for an invalid error code!')
814 } catch (err) {
815 test.ok(err instanceof Factory.FSPIOPError)
816 test.deepEqual(err.apiErrorCode, Errors.INTERNAL_SERVER_ERROR)
817 }
818 test.end()
819 })
820
821 factoryTest.test('create an FSPIOPError from an ErrorCode with toApiErrorObject includeCauseExtension: false, truncateExtensions: true', function (test) {
822 const errorInformation = {
823 errorCode: '2001',
824 errorDescription: 'Internal server error - Test Cause',
825 extensionList: {
826 extension: [
827 {
828 key: 'test',
829 value: 'test'
830 }
831 ]
832 }
833 }
834 const fspiopError = Factory.createFSPIOPErrorFromErrorCode(errorInformation.errorCode, undefined, errorInformation.errorDescription, null, errorInformation.extensionList)
835 test.ok(fspiopError)
836 test.deepEqual(fspiopError.toApiErrorObject(), {
837 errorInformation: {
838 errorCode: '2001',
839 errorDescription: 'Internal server error',
840 extensionList: {
841 extension: [
842 {
843 key: 'test',
844 value: 'test'
845 }
846 ]
847 }
848 }
849 })
850 test.end()
851 })
852
853 factoryTest.test('create an FSPIOPError from an ErrorCode with toApiErrorObject includeCauseExtension: true, truncateExtensions: true', function (test) {
854 const errorInformation = {
855 errorCode: '2001',
856 errorDescription: 'Internal server error - Test Cause',
857 extensionList: {
858 extension: [
859 {
860 key: 'test',
861 value: 'test'
862 }
863 ]
864 }
865 }
866 const fspiopError = Factory.createFSPIOPErrorFromErrorCode(errorInformation.errorCode, undefined, errorInformation.errorDescription, null, errorInformation.extensionList)
867 test.ok(fspiopError)
868 const options = { includeCauseExtension: true, truncateExtensions: true }
869 test.deepEqual(fspiopError.toApiErrorObject(options), {
870 errorInformation: {
871 errorCode: '2001',
872 errorDescription: 'Internal server error',
873 extensionList: {
874 extension: [
875 {
876 key: 'test',
877 value: 'test'
878 },
879 {
880 key: InternalEnums.FSPIOPError.ExtensionsKeys.cause,
881 value: fspiopError.stack.substring(ErrorModelTypes.ExtensionValue.constraints.min - 1, ErrorModelTypes.ExtensionValue.constraints.max) // truncate string to match Mojaloop API v1.0 Spec
882 }
883 ]
884 }
885 }
886 })
887 test.end()
888 })
889
890 factoryTest.test('create an invalid FSPIOPError from an ErrorCode', function (test) {
891 const errorInformation = {
892 errorCode: '9999',
893 errorDescription: 'Internal server error - Test Cause'
894 }
895 try {
896 const fspiopError = Factory.createFSPIOPErrorFromErrorCode(errorInformation.errorCode)
897 test.notOk(fspiopError)
898 test.fail('Should have thrown an exception for an invalid error code!')
899 } catch (err) {
900 test.ok(err instanceof Factory.FSPIOPError)
901 test.deepEqual(err.apiErrorCode, Errors.INTERNAL_SERVER_ERROR)
902 }
903 test.end()
904 })
905
906 factoryTest.test('reformat an FSPIOPError from a general error with toApiErrorObject includeCauseExtension: true, truncateExtensions: true', function (test) {
907 const cause = new Error('Test Cause')
908 const fspiopError = Factory.reformatFSPIOPError(cause)
909 test.ok(fspiopError)
910 const options = { includeCauseExtension: true, truncateExtensions: true }
911 test.deepEqual(fspiopError.toApiErrorObject(options), {
912 errorInformation: {
913 errorCode: '2001',
914 errorDescription: 'Internal server error - Test Cause',
915 extensionList: {
916 extension: [
917 {
918 key: InternalEnums.FSPIOPError.ExtensionsKeys.cause,
919 value: fspiopError.stack.substring(ErrorModelTypes.ExtensionValue.constraints.min - 1, ErrorModelTypes.ExtensionValue.constraints.max) // truncate string to match Mojaloop API v1.0 Spec
920 }
921 ]
922 }
923 }
924 })
925 test.end()
926 })
927
928 factoryTest.test('reformat an FSPIOPError from another FSPIOPError returning the original error', function (test) {
929 const error = new Error('Invalid format')
930 const cause = Factory.createFSPIOPError(Errors.MALFORMED_SYNTAX, 'Malformed parameter test', error, 'dfsp1')
931 const fspiopError = Factory.reformatFSPIOPError(cause)
932 test.ok(fspiopError)
933 test.deepEqual(fspiopError, cause)
934 test.end()
935 })
936
937 factoryTest.test('validateFSPIOPErrorCode should validate an integer errorCode', function (test) {
938 const errorCode = 2000
939 try {
940 const result = Factory.validateFSPIOPErrorCode(errorCode)
941 test.ok(result)
942 } catch (err) {
943 test.ok(err instanceof Factory.FSPIOPError)
944 test.fail(err)
945 }
946 test.end()
947 })
948
949 factoryTest.test('validateFSPIOPErrorCode should validate an string errorCode', function (test) {
950 const errorCode = `${Errors.INTERNAL_SERVER_ERROR.code}`
951 try {
952 const result = Factory.validateFSPIOPErrorCode(errorCode)
953 test.deepEqual(result, Errors.INTERNAL_SERVER_ERROR)
954 } catch (err) {
955 test.ok(err instanceof Factory.FSPIOPError)
956 test.fail(err)
957 }
958 test.end()
959 })
960
961 factoryTest.test('validateFSPIOPErrorCode should validate an apiErrorCode errorCode enum', function (test) {
962 const errorCode = Errors.INTERNAL_SERVER_ERROR
963 try {
964 const result = Factory.validateFSPIOPErrorCode(errorCode)
965 test.deepEqual(result, Errors.INTERNAL_SERVER_ERROR)
966 } catch (err) {
967 test.ok(err instanceof Factory.FSPIOPError)
968 test.fail(err)
969 }
970 test.end()
971 })
972
973 factoryTest.test('validateFSPIOPErrorCode should validate an invalid apiErrorCode errorCode enum', function (test) {
974 const errorCode = { test }
975 try {
976 const result = Factory.validateFSPIOPErrorCode(errorCode)
977 test.notOk(result)
978 test.fail()
979 } catch (err) {
980 test.ok(err instanceof Factory.FSPIOPError)
981 test.equal(err.apiErrorCode.code, Errors.INTERNAL_SERVER_ERROR.code)
982 test.equal(err.apiErrorCode.message, Errors.INTERNAL_SERVER_ERROR.message)
983 }
984 test.end()
985 })
986
987 factoryTest.test('validateFSPIOPErrorCode should validate an integer errorCode and throw exception', function (test) {
988 const errorCode = 9999
989 try {
990 const result = Factory.validateFSPIOPErrorCode(errorCode)
991 test.notOk(result)
992 test.fail()
993 } catch (err) {
994 test.ok(err instanceof Factory.FSPIOPError)
995 test.equal(err.apiErrorCode.code, Errors.INTERNAL_SERVER_ERROR.code)
996 test.equal(err.apiErrorCode.message, Errors.INTERNAL_SERVER_ERROR.message)
997 }
998 test.end()
999 })
1000
1001 factoryTest.test('create an FSPIOPError from a Joi error for too many elements', function (test) {
1002 const joiError = {
1003 message: 'Too many elements',
1004 type: 'object.allowUnknown',
1005 context: {
1006 label: 'Too many elements 2'
1007 }
1008 }
1009 const fspiopError = Factory.createFSPIOPErrorFromJoiError(joiError, { stack: 'Stack trace...' }, 'dfsp1')
1010 test.ok(fspiopError)
1011 test.deepEqual(fspiopError.toApiErrorObject(), {
1012 errorInformation: {
1013 errorCode: '3103',
1014 errorDescription: 'Too many elements - Too many elements'
1015 }
1016 })
1017 test.end()
1018 })
1019
1020 factoryTest.test('create an FSPIOPError from a Joi error for invalid integer', function (test) {
1021 const joiError = {
1022 message: 'Malformed syntax',
1023 type: 'number.integer',
1024 context: {
1025 label: 'Malformed syntax 2'
1026 }
1027 }
1028 const fspiopError = Factory.createFSPIOPErrorFromJoiError(joiError, { stack: 'Stack trace...' }, 'dfsp1')
1029 test.ok(fspiopError)
1030 test.deepEqual(fspiopError.toApiErrorObject(), {
1031 errorInformation: {
1032 errorCode: '3101',
1033 errorDescription: 'Malformed syntax - Malformed syntax'
1034 }
1035 })
1036 test.end()
1037 })
1038
1039 factoryTest.end()
1040})