diff --git a/lib/utils/to-gavel-result.js b/lib/utils/to-gavel-result.js new file mode 100644 index 00000000..80c49240 --- /dev/null +++ b/lib/utils/to-gavel-result.js @@ -0,0 +1,31 @@ +const jsonPointer = require('json-pointer'); + +function splitProperty(property) { + return property.split(/\.|\[|\]/).filter(Boolean); +} + +function reduceProperties(acc, property) { + return acc.concat(splitProperty(property)); +} + +/** + * Converts legacy (Amanda/TV4) error messages + * to the Gavel-compliant structure. + */ +function toGavelResult(legacyErrors) { + return Array.from({ length: legacyErrors.length }, (_, index) => { + const item = legacyErrors[index]; + const propertyPath = item.property.reduce(reduceProperties, []); + const pointer = jsonPointer.compile(propertyPath); + + return { + message: item.message, + location: { + pointer, + property: propertyPath + } + }; + }); +} + +module.exports = toGavelResult; diff --git a/lib/validators/json-schema-legacy.js b/lib/validators/json-schema-legacy.js index baab4ec8..d54dc9ca 100644 --- a/lib/validators/json-schema-legacy.js +++ b/lib/validators/json-schema-legacy.js @@ -4,6 +4,7 @@ const jsonPointer = require('json-pointer'); const { JsonSchemaValidator, META_SCHEMA } = require('./json-schema-next'); const { ValidationErrors } = require('./validation-errors'); +const toGavelResult = require('../utils/to-gavel-result'); /** * Returns a proper article for a given string. @@ -103,12 +104,12 @@ class JsonSchemaLegacy extends JsonSchemaValidator { errors = new ValidationErrors(error); } }); - } catch (error) { + } catch (internalError) { errors = new ValidationErrors({ '0': { property: [], attributeValue: true, - message: `Validator internal error: ${error.message}`, + message: `Validator internal error: ${internalError.message}`, validatorName: 'error' }, length: 1, @@ -116,7 +117,7 @@ class JsonSchemaLegacy extends JsonSchemaValidator { }); } - return this.toGavelResult(errors); + return toGavelResult(errors); } validateUsingTV4(data) { @@ -154,33 +155,7 @@ class JsonSchemaLegacy extends JsonSchemaValidator { } const errors = new ValidationErrors(amandaCompatibleError); - return this.toGavelResult(errors); - } - - /** - * Converts Amanda-like validation result to the - * unified Gavel public validation result. - */ - toGavelResult(amandaLikeResult) { - const results = Array.from( - { length: amandaLikeResult.length }, - (_, index) => { - const item = amandaLikeResult[index]; - const { property, message } = item; - const pathArray = [].concat(property).filter(Boolean); - const pointer = jsonPointer.compile(pathArray); - - return { - message, - location: { - pointer, - property - } - }; - } - ); - - return results; + return toGavelResult(errors); } } diff --git a/test/unit/utils/to-gavel-result.test.js b/test/unit/utils/to-gavel-result.test.js new file mode 100644 index 00000000..69c539e8 --- /dev/null +++ b/test/unit/utils/to-gavel-result.test.js @@ -0,0 +1,87 @@ +const { expect } = require('chai'); +const toGavelResult = require('../../../lib/utils/to-gavel-result'); + +describe('toGavelResult', () => { + // Currently TV4 output is coerced to Amanda format. + // Then Amanda format is coerced to Gavel public API. + describe('given Amanda errors', () => { + let coercedErrors; + + before(() => { + coercedErrors = toGavelResult({ + length: 2, + 0: { + property: ['users', 'username'], + propertyValue: 123, + attributeName: 'type', + attributeValue: 'string', + message: 'Amanda error message' + }, + 1: { + property: ['friends[2]', 'online'], + propertyValue: false, + attributeName: 'type', + attributeValue: 'boolean', + message: 'Arbitrary error message about "online"' + } + }); + }); + + describe('given coerced to Gavel-compliant error', () => { + it('should return 2 errors', () => { + expect(coercedErrors).to.have.lengthOf(2); + }); + + describe('given in-object error', () => { + it('should preserve the original error message', () => { + expect(coercedErrors[0]).to.have.property( + 'message', + 'Amanda error message' + ); + }); + + describe('should produce "location" property', () => { + it('should have "pointer"', () => { + expect(coercedErrors[0]).to.have.nested.property( + 'location.pointer', + '/users/username' + ); + }); + + it('should have "property"', () => { + expect(coercedErrors[0].location.property).to.deep.equal([ + 'users', + 'username' + ]); + }); + }); + }); + + describe('given in-array error', () => { + it('should preserve the original error message', () => { + expect(coercedErrors[1]).to.have.property( + 'message', + 'Arbitrary error message about "online"' + ); + }); + + describe('should produce "location" property', () => { + it('should have "pointer"', () => { + expect(coercedErrors[1]).to.have.nested.property( + 'location.pointer', + '/friends/2/online' + ); + }); + + it('should have "property"', () => { + expect(coercedErrors[1].location.property).to.deep.equal([ + 'friends', + '2', + 'online' + ]); + }); + }); + }); + }); + }); +});