Skip to content
This repository was archived by the owner on Nov 27, 2019. It is now read-only.

Commit b4f93a6

Browse files
authored
Merge d238b17 into 5e8d0ca
2 parents 5e8d0ca + d238b17 commit b4f93a6

File tree

5 files changed

+165
-34
lines changed

5 files changed

+165
-34
lines changed

package-lock.json

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"json-refs": "^3.0.4",
1717
"material-ui-pickers": "1.0.0-rc.9",
1818
"react": "16.3.2",
19+
"ajv-errors": "^1.0.0",
1920
"react-dom": "^16.3.1",
2021
"react-redux": "^5.0.7",
2122
"recompose": "^0.27.1",

src/models/ui-metaschema.ts

Lines changed: 95 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { JsonSchema7 } from '@jsonforms/core';
2+
23
export const uiMetaSchema: JsonSchema7 = {
4+
'$schema': 'http://json-schema.org/draft-07/schema',
35
'type': 'object',
46
'$id': '#root',
57
'properties': {
@@ -71,10 +73,23 @@ export const uiMetaSchema: JsonSchema7 = {
7173
'$ref': '#/definitions/rule'
7274
}
7375
},
74-
'required': [
75-
'type',
76-
'scope'
77-
]
76+
'required': ['type', 'scope'],
77+
'additionalProperties': false,
78+
'errorMessage': {
79+
'properties': {
80+
'type': 'type should be equal to one of the allowed values',
81+
'scope': 'Control scope should match pattern "^#\\/properties\\/{1}"',
82+
'suggestion': 'Control suggestion should be array',
83+
'options': 'Control options should be object',
84+
'label': 'Control label should be string,boolean or label object'
85+
},
86+
'required': {
87+
'scope': 'Control should have an object property "scope"',
88+
'type': 'Control should have an object property "type"'
89+
},
90+
'additionalProperties': 'Control should not have properties ' +
91+
'other than type,label,scope,options,suggestion and rule'
92+
}
7893
},
7994
'horizontallayout': {
8095
'type': 'object',
@@ -92,10 +107,18 @@ export const uiMetaSchema: JsonSchema7 = {
92107
'$ref': '#/definitions/rule'
93108
}
94109
},
95-
'required': [
96-
'type',
97-
'elements'
98-
]
110+
'required': ['type', 'elements'],
111+
'additionalProperties': false,
112+
'errorMessage': {
113+
'properties': {
114+
'type': 'type should be equal to one of the allowed values'
115+
},
116+
'required': {
117+
'elements': 'Layout should have an array property "elements"',
118+
'type': 'Layout should have a string property "type"'
119+
},
120+
'additionalProperties': 'Layout should not have properties other than type and elements'
121+
}
99122
},
100123
'verticallayout': {
101124
'type': 'object',
@@ -137,7 +160,19 @@ export const uiMetaSchema: JsonSchema7 = {
137160
'required': [
138161
'type',
139162
'elements'
140-
]
163+
],
164+
'additionalProperties': false,
165+
'errorMessage': {
166+
'properties': {
167+
'type': 'type should be equal to one of the allowed values'
168+
},
169+
'required': {
170+
'elements': 'Categorization should have an array property "elements"',
171+
'type': 'Categorization should have a string property "type"'
172+
},
173+
'additionalProperties': 'Categorization should not have properties ' +
174+
'other than type and elements'
175+
}
141176
},
142177
'category': {
143178
'type': 'object',
@@ -158,10 +193,19 @@ export const uiMetaSchema: JsonSchema7 = {
158193
'$ref': '#/definitions/rule'
159194
}
160195
},
161-
'required': [
162-
'type',
163-
'elements'
164-
]
196+
'additionalProperties': false,
197+
'errorMessage': {
198+
'properties': {
199+
'type': 'type should be equal to one of the allowed values',
200+
'label': 'Category label should be string'
201+
},
202+
'required': {
203+
'type': 'Category layout should have a string property "type"',
204+
'elements': 'Category layout should have an array property "elements"'
205+
},
206+
'additionalProperties': 'Category layout should not have properties ' +
207+
'other than type,elements and label'
208+
}
165209
},
166210
'group': {
167211
'type': 'object',
@@ -179,11 +223,21 @@ export const uiMetaSchema: JsonSchema7 = {
179223
'type': 'string'
180224
}
181225
},
182-
'required': [
183-
'type',
184-
'elements',
185-
'label'
186-
]
226+
'required': ['type', 'elements', 'label'],
227+
'additionalProperties': false,
228+
'errorMessage': {
229+
'properties': {
230+
'type': 'type should be equal to one of the allowed values',
231+
'label': 'Group label should be string'
232+
},
233+
'required': {
234+
'type': 'Group layout should have a string property "type"',
235+
'elements': 'Group layout should have an array property "elements"',
236+
'label': 'Group layout should have a string property "label"'
237+
},
238+
'additionalProperties': 'Group layout should not have properties ' +
239+
'other than type,elements and label'
240+
}
187241
},
188242
'rule': {
189243
'type': 'object',
@@ -225,9 +279,15 @@ export const uiMetaSchema: JsonSchema7 = {
225279
]
226280
}
227281
},
228-
'dependencies': {
229-
'effect': ['condition'],
230-
'condition': ['effect']
282+
'required': [
283+
'effect',
284+
'condition'
285+
],
286+
'errorMessage': {
287+
'required': {
288+
'effect': 'Effect has to de defined',
289+
'condition': 'Condition has to be defined',
290+
}
231291
}
232292
},
233293
'scope': {
@@ -244,5 +304,18 @@ export const uiMetaSchema: JsonSchema7 = {
244304
'required': [
245305
'elements',
246306
'type'
247-
]
307+
],
308+
'additionalProperties': false,
309+
'errorMessage': {
310+
'properties': {
311+
'type': 'Root type should be equal to one of the allowed values',
312+
'label': 'Root label should be string'
313+
},
314+
'required': {
315+
'elements': 'Root should have an array property "elements"',
316+
'type': 'Root should have an object property "type"'
317+
},
318+
'additionalProperties': 'Root should not have properties ' +
319+
'other than type,elements,label and rule'
320+
}
248321
};

src/validation.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
11
import * as AJV from 'ajv';
22
import { ErrorObject } from 'ajv';
33
import { JsonSchema7 } from '@jsonforms/core';
4+
import * as AjvErrors from 'ajv-errors'; // tslint:disable-line
45

5-
const ajv = new AJV({allErrors: true, verbose: true});
6+
const ajv = new AJV({allErrors: true, verbose: true, jsonPointers: true});
7+
AjvErrors(ajv);
68

79
interface ValidationErrors {
810
message: string;
911
schemaPath?: string;
1012
}
1113

12-
const extractErrors = (errors: ErrorObject[]): ValidationErrors[] =>
14+
const extractErrors = (errors: ErrorObject[]): ValidationErrors[] =>
1315
errors.map((error: ErrorObject) => {
1416
return {
1517
message: error.message,
16-
schemaPath: error.schemaPath
1718
};
1819
});
1920

test/uischemaValidation.test.ts

Lines changed: 60 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -175,9 +175,7 @@ test('invalid control element, layout label must be string', () => {
175175
elements: [
176176
{
177177
type: 'Control',
178-
label: {
179-
label: 'Occupation'
180-
},
178+
label: ['Occupation'],
181179
scope: '#/properties/occupation'
182180
}
183181
]
@@ -226,12 +224,6 @@ test('invalid vertical layout, missing layout elements', () => {
226224
expect(errors).not.toEqual([]);
227225
});
228226

229-
test('invalid layout, empty uischema', () => {
230-
const uischema = {};
231-
const errors = validator(uischema);
232-
expect(errors).not.toEqual([]);
233-
});
234-
235227
test('invalid layout type', () => {
236228
const uischema = {
237229
type: 'TestLayout',
@@ -318,6 +310,27 @@ test('invalid control element, options of Control must be type of object', () =>
318310
expect(errors).not.toEqual([]);
319311
});
320312

313+
test('invalid control element, invalid suggestion type', () => {
314+
const uischema = {
315+
type: 'HorizontalLayout',
316+
elements: [
317+
{
318+
type: 'Control',
319+
label: 'Occupation',
320+
scope: '#/properties/occupation',
321+
suggestion: {
322+
Accountant: 'Accountant',
323+
Engineer: 'Engineer',
324+
Freelancer: 'Freelancer',
325+
Journalism: 'Journalism'
326+
}
327+
}
328+
]
329+
};
330+
const errors = validator(uischema);
331+
expect(errors).not.toEqual([]);
332+
});
333+
321334
test('invalid rule, missing rule effect', () => {
322335
const uischema = {
323336
type: 'HorizontalLayout',
@@ -470,6 +483,29 @@ test('invalid rule, condition type must be LEAF', () => {
470483
expect(errors).not.toEqual([]);
471484
});
472485

486+
test('invalid rule, invalid effect value', () => {
487+
const uischema = {
488+
type: 'HorizontalLayout',
489+
elements: [
490+
{
491+
type: 'Control',
492+
label: 'Occupation',
493+
scope: '#/properties/occupation',
494+
rule: {
495+
effect: 'Test',
496+
condition: {
497+
type: 'LEAF',
498+
scope: '#/properties/alive',
499+
expectedValue: true
500+
}
501+
}
502+
}
503+
]
504+
};
505+
const errors = validator(uischema);
506+
expect(errors).not.toEqual([]);
507+
});
508+
473509
test('invalid rule, expected value of condition must be string,integer,number or boolean', () => {
474510
const uischema = {
475511
type: 'HorizontalLayout',
@@ -559,3 +595,18 @@ test('invalid group layout, Group layout must have label', () => {
559595
const errors = validator(uischema);
560596
expect(errors).not.toEqual([]);
561597
});
598+
599+
test('invalid control element, custom error message for missing scope', () => {
600+
const uischema = {
601+
type: 'HorizontalLayout',
602+
elements: [
603+
{
604+
type: 'Control',
605+
label: 'Occupation',
606+
}
607+
]
608+
};
609+
const errors = validator(uischema);
610+
expect(errors).not.toEqual([]);
611+
expect(errors[0].message).toEqual(`Control should have an object property "scope"`);
612+
});

0 commit comments

Comments
 (0)