From b9b72413493f131fa4b6fc20f0056126303d49a5 Mon Sep 17 00:00:00 2001 From: Ahmet Tanakol Date: Thu, 12 Apr 2018 21:57:18 +0200 Subject: [PATCH 1/4] add custom error messages for uischema validation --- package-lock.json | 5 ++ package.json | 1 + src/models/ui-metaschema.ts | 109 ++++++++++++++++++++++++++------ src/validation.ts | 7 +- test/uischemaValidation.test.ts | 54 +++++++++++++--- 5 files changed, 145 insertions(+), 31 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8b891f9..8a933f3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -366,6 +366,11 @@ "uri-js": "3.0.2" } }, + "ajv-errors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.0.tgz", + "integrity": "sha1-7PAh+hCP0X37Xms4Py3SM+Mf/Fk=" + }, "ajv-keywords": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.1.0.tgz", diff --git a/package.json b/package.json index e0d83ef..3ccb442 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "json-refs": "^3.0.4", "material-ui-pickers": "1.0.0-rc.9", "react": "16.3.2", + "ajv-errors": "^1.0.0", "react-dom": "^16.3.1", "react-redux": "^5.0.7", "recompose": "^0.27.1", diff --git a/src/models/ui-metaschema.ts b/src/models/ui-metaschema.ts index b2edfa6..4787635 100644 --- a/src/models/ui-metaschema.ts +++ b/src/models/ui-metaschema.ts @@ -71,10 +71,23 @@ export const uiMetaSchema: JsonSchema7 = { '$ref': '#/definitions/rule' } }, - 'required': [ - 'type', - 'scope' - ] + 'required': ['type', 'scope'], + 'additionalProperties': false, + 'errorMessage': { + 'properties': { + 'type': 'type should be equal to one of the allowed values', + 'scope': 'Control scope should match pattern "^#\\/properties\\/{1}"', + 'suggestion': 'Control suggestion should be array', + 'options': 'Control options should be object', + 'label': 'Control label should be string,boolean or label object' + }, + 'required': { + 'scope': 'Control should have an object property "scope"', + 'type': 'Control should have an object property "type"' + }, + 'additionalProperties': 'Control should not have properties ' + + 'other than type,label,scope,options,suggestion and rule' + } }, 'horizontallayout': { 'type': 'object', @@ -92,10 +105,18 @@ export const uiMetaSchema: JsonSchema7 = { '$ref': '#/definitions/rule' } }, - 'required': [ - 'type', - 'elements' - ] + 'required': ['type', 'elements'], + 'additionalProperties': false, + 'errorMessage': { + 'properties': { + 'type': 'type should be equal to one of the allowed values' + }, + 'required': { + 'elements': 'Layout should have an array property "elements"', + 'type': 'Layout should have a string property "type"' + }, + 'additionalProperties': 'Layout should not have properties other than type and elements' + } }, 'verticallayout': { 'type': 'object', @@ -137,7 +158,19 @@ export const uiMetaSchema: JsonSchema7 = { 'required': [ 'type', 'elements' - ] + ], + 'additionalProperties': false, + 'errorMessage': { + 'properties': { + 'type': 'type should be equal to one of the allowed values' + }, + 'required': { + 'elements': 'Categorization should have an array property "elements"', + 'type': 'Categorization should have a string property "type"' + }, + 'additionalProperties': 'Categorization should not have properties ' + + 'other than type and elements' + } }, 'category': { 'type': 'object', @@ -158,10 +191,19 @@ export const uiMetaSchema: JsonSchema7 = { '$ref': '#/definitions/rule' } }, - 'required': [ - 'type', - 'elements' - ] + 'additionalProperties': false, + 'errorMessage': { + 'properties': { + 'type': 'type should be equal to one of the allowed values', + 'label': 'Category label should be string' + }, + 'required': { + 'type': 'Category layout should have a string property "type"', + 'elements': 'Category layout should have an array property "elements"' + }, + 'additionalProperties': 'Category layout should not have properties ' + + 'other than type,elements and label' + } }, 'group': { 'type': 'object', @@ -179,11 +221,21 @@ export const uiMetaSchema: JsonSchema7 = { 'type': 'string' } }, - 'required': [ - 'type', - 'elements', - 'label' - ] + 'required': ['type', 'elements', 'label'], + 'additionalProperties': false, + 'errorMessage': { + 'properties': { + 'type': 'type should be equal to one of the allowed values', + 'label': 'Group label should be string' + }, + 'required': { + 'type': 'Group layout should have a string property "type"', + 'elements': 'Group layout should have an array property "elements"', + 'label': 'Group layout should have a string property "label"' + }, + 'additionalProperties': 'Group layout should not have properties ' + + 'other than type,elements and label' + } }, 'rule': { 'type': 'object', @@ -228,6 +280,12 @@ export const uiMetaSchema: JsonSchema7 = { 'dependencies': { 'effect': ['condition'], 'condition': ['effect'] + }, + 'errorMessage': { + 'dependencies': { + 'effect': 'Condition has to be defined', + 'condition': 'Effect has to be defined' + } } }, 'scope': { @@ -244,5 +302,18 @@ export const uiMetaSchema: JsonSchema7 = { 'required': [ 'elements', 'type' - ] + ], + 'additionalProperties': false, + 'errorMessage': { + 'properties': { + 'type': 'Root type should be equal to one of the allowed values', + 'label': 'Root label should be string' + }, + 'required': { + 'elements': 'Root should have an array property "elements"', + 'type': 'Root should have an object property "type"' + }, + 'additionalProperties': 'Root should not have properties ' + + 'other than type,elements,label and rule' + } }; diff --git a/src/validation.ts b/src/validation.ts index 6b8f062..63246ce 100644 --- a/src/validation.ts +++ b/src/validation.ts @@ -1,19 +1,20 @@ import * as AJV from 'ajv'; import { ErrorObject } from 'ajv'; import { JsonSchema7 } from '@jsonforms/core'; +import AjvErrors = require('ajv-errors'); // tslint:disable-line -const ajv = new AJV({allErrors: true, verbose: true}); +const ajv = new AJV({allErrors: true, verbose: true, jsonPointers: true}); +AjvErrors(ajv); interface ValidationErrors { message: string; schemaPath?: string; } -const extractErrors = (errors: ErrorObject[]): ValidationErrors[] => +const extractErrors = (errors: ErrorObject[]): ValidationErrors[] => errors.map((error: ErrorObject) => { return { message: error.message, - schemaPath: error.schemaPath }; }); diff --git a/test/uischemaValidation.test.ts b/test/uischemaValidation.test.ts index 73e62b9..a06997f 100644 --- a/test/uischemaValidation.test.ts +++ b/test/uischemaValidation.test.ts @@ -175,9 +175,7 @@ test('invalid control element, layout label must be string', () => { elements: [ { type: 'Control', - label: { - label: 'Occupation' - }, + label: ['Occupation'], scope: '#/properties/occupation' } ] @@ -226,12 +224,6 @@ test('invalid vertical layout, missing layout elements', () => { expect(errors).not.toEqual([]); }); -test('invalid layout, empty uischema', () => { - const uischema = {}; - const errors = validator(uischema); - expect(errors).not.toEqual([]); -}); - test('invalid layout type', () => { const uischema = { type: 'TestLayout', @@ -318,6 +310,27 @@ test('invalid control element, options of Control must be type of object', () => expect(errors).not.toEqual([]); }); +test('invalid control element, invalid suggestion type', () => { + const uischema = { + type: 'HorizontalLayout', + elements: [ + { + type: 'Control', + label: 'Occupation', + scope: '#/properties/occupation', + suggestion: { + Accountant: 'Accountant', + Engineer: 'Engineer', + Freelancer: 'Freelancer', + Journalism: 'Journalism' + } + } + ] + }; + const errors = validator(uischema); + expect(errors).not.toEqual([]); +}); + test('invalid rule, missing rule effect', () => { const uischema = { type: 'HorizontalLayout', @@ -470,6 +483,29 @@ test('invalid rule, condition type must be LEAF', () => { expect(errors).not.toEqual([]); }); +test('invalid rule, invalid effect value', () => { + const uischema = { + type: 'HorizontalLayout', + elements: [ + { + type: 'Control', + label: 'Occupation', + scope: '#/properties/occupation', + rule: { + effect: 'Test', + condition: { + type: 'LEAF', + scope: '#/properties/alive', + expectedValue: true + } + } + } + ] + }; + const errors = validator(uischema); + expect(errors).not.toEqual([]); +}); + test('invalid rule, expected value of condition must be string,integer,number or boolean', () => { const uischema = { type: 'HorizontalLayout', From d238b172ede69543a252d279fb3850a39c73f9bb Mon Sep 17 00:00:00 2001 From: Ahmet Tanakol Date: Thu, 26 Apr 2018 11:42:57 +0200 Subject: [PATCH 2/4] add test for custom error message --- src/models/ui-metaschema.ts | 16 +++++++++------- src/validation.ts | 2 +- test/uischemaValidation.test.ts | 15 +++++++++++++++ 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/models/ui-metaschema.ts b/src/models/ui-metaschema.ts index 4787635..9c8a39f 100644 --- a/src/models/ui-metaschema.ts +++ b/src/models/ui-metaschema.ts @@ -1,5 +1,7 @@ import { JsonSchema7 } from '@jsonforms/core'; + export const uiMetaSchema: JsonSchema7 = { + '$schema': 'http://json-schema.org/draft-07/schema', 'type': 'object', '$id': '#root', 'properties': { @@ -277,14 +279,14 @@ export const uiMetaSchema: JsonSchema7 = { ] } }, - 'dependencies': { - 'effect': ['condition'], - 'condition': ['effect'] - }, + 'required': [ + 'effect', + 'condition' + ], 'errorMessage': { - 'dependencies': { - 'effect': 'Condition has to be defined', - 'condition': 'Effect has to be defined' + 'required': { + 'effect': 'Effect has to de defined', + 'condition': 'Condition has to be defined', } } }, diff --git a/src/validation.ts b/src/validation.ts index 63246ce..200784b 100644 --- a/src/validation.ts +++ b/src/validation.ts @@ -1,7 +1,7 @@ import * as AJV from 'ajv'; import { ErrorObject } from 'ajv'; import { JsonSchema7 } from '@jsonforms/core'; -import AjvErrors = require('ajv-errors'); // tslint:disable-line +import * as AjvErrors from 'ajv-errors'; // tslint:disable-line const ajv = new AJV({allErrors: true, verbose: true, jsonPointers: true}); AjvErrors(ajv); diff --git a/test/uischemaValidation.test.ts b/test/uischemaValidation.test.ts index a06997f..a506597 100644 --- a/test/uischemaValidation.test.ts +++ b/test/uischemaValidation.test.ts @@ -595,3 +595,18 @@ test('invalid group layout, Group layout must have label', () => { const errors = validator(uischema); expect(errors).not.toEqual([]); }); + +test('invalid control element, custom error message for missing scope', () => { + const uischema = { + type: 'HorizontalLayout', + elements: [ + { + type: 'Control', + label: 'Occupation', + } + ] + }; + const errors = validator(uischema); + expect(errors).not.toEqual([]); + expect(errors[0].message).toEqual(`Control should have an object property "scope"`); +}); From f85f8aca3ebac8e094684ea9d71c5395ca1ce4f2 Mon Sep 17 00:00:00 2001 From: Ahmet Tanakol Date: Thu, 2 Aug 2018 10:00:31 +0200 Subject: [PATCH 3/4] uischema fixes --- src/models/ui-metaschema.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/models/ui-metaschema.ts b/src/models/ui-metaschema.ts index 9c8a39f..19fb826 100644 --- a/src/models/ui-metaschema.ts +++ b/src/models/ui-metaschema.ts @@ -81,14 +81,14 @@ export const uiMetaSchema: JsonSchema7 = { 'scope': 'Control scope should match pattern "^#\\/properties\\/{1}"', 'suggestion': 'Control suggestion should be array', 'options': 'Control options should be object', - 'label': 'Control label should be string,boolean or label object' + 'label': 'Control label should be string, boolean or label object' }, 'required': { 'scope': 'Control should have an object property "scope"', - 'type': 'Control should have an object property "type"' + 'type': 'Control should have an object property "string"' }, 'additionalProperties': 'Control should not have properties ' + - 'other than type,label,scope,options,suggestion and rule' + 'other than type, label, scope, options, suggestion and rule' } }, 'horizontallayout': { @@ -279,12 +279,12 @@ export const uiMetaSchema: JsonSchema7 = { ] } }, - 'required': [ - 'effect', - 'condition' - ], + 'dependencies': { + 'effect': ['condition'], + 'condition': ['effect'] + }, 'errorMessage': { - 'required': { + 'dependencies': { 'effect': 'Effect has to de defined', 'condition': 'Condition has to be defined', } @@ -313,9 +313,9 @@ export const uiMetaSchema: JsonSchema7 = { }, 'required': { 'elements': 'Root should have an array property "elements"', - 'type': 'Root should have an object property "type"' + 'type': 'Root should have an object property "string"' }, 'additionalProperties': 'Root should not have properties ' + - 'other than type,elements,label and rule' + 'other than type, elements, label and rule' } }; From 5bf4d9a5b614599ccdb1743adba9cb93b2f92455 Mon Sep 17 00:00:00 2001 From: Ahmet Tanakol Date: Fri, 3 Aug 2018 11:25:48 +0200 Subject: [PATCH 4/4] fix error messages for type field --- src/models/ui-metaschema.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/models/ui-metaschema.ts b/src/models/ui-metaschema.ts index 19fb826..1d9883c 100644 --- a/src/models/ui-metaschema.ts +++ b/src/models/ui-metaschema.ts @@ -85,7 +85,7 @@ export const uiMetaSchema: JsonSchema7 = { }, 'required': { 'scope': 'Control should have an object property "scope"', - 'type': 'Control should have an object property "string"' + 'type': 'Control should have a string property "type"' }, 'additionalProperties': 'Control should not have properties ' + 'other than type, label, scope, options, suggestion and rule' @@ -313,7 +313,7 @@ export const uiMetaSchema: JsonSchema7 = { }, 'required': { 'elements': 'Root should have an array property "elements"', - 'type': 'Root should have an object property "string"' + 'type': 'Root should have a string property "type"' }, 'additionalProperties': 'Root should not have properties ' + 'other than type, elements, label and rule'