Skip to content

Commit

Permalink
fix with merge error if errors in key is string
Browse files Browse the repository at this point in the history
  • Loading branch information
Mariusz Przodała committed Feb 23, 2018
2 parents d4b8621 + 8b8d6b6 commit f90cf6a
Show file tree
Hide file tree
Showing 7 changed files with 220 additions and 9 deletions.
2 changes: 1 addition & 1 deletion .babelrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{ "presets": ["es2015"] }
{ "presets": ["es2015", "es2017", "stage-0"] }
12 changes: 11 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "form-schema-validation",
"version": "1.14.0",
"version": "1.14.2",
"description": "Schema for form validation",
"main": "dist/index.js",
"jsnext:main": "src/index.js",
Expand Down Expand Up @@ -37,6 +37,7 @@
"babel-polyfill": "^6.26.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-es2015-native-modules": "^6.9.4",
"babel-preset-es2017": "^6.24.1",
"babel-preset-stage-0": "^6.24.1",
"coveralls": "^2.13.3",
"eslint": "^4.14.0",
Expand Down
14 changes: 8 additions & 6 deletions src/Schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
getFunctionName,
removeFirstKeyIfNumber,
getErrorIndexFromKeys,
mergeErrors,
} from './helpers';
import OneOfTypes from './OneOfTypes';
import SchemaType from './SchemaType';
Expand Down Expand Up @@ -53,7 +54,7 @@ class Schema {
this.errors = {};
this.promises = [];
this.additionalValidators = new Set();
this.messages = messages || defaultMessages;
this.messages = { ...defaultMessages, ...messages };
this.validateKeys = validateKeys;

this.validateTypeString = this.validateTypeString.bind(this);
Expand Down Expand Up @@ -142,13 +143,13 @@ class Schema {
return this.errors;
}

setError(key, message, index) {
setError(key, error, index) {
if (!this.errors[key]) this.errors[key] = [];
if (index > -1) {
this.errors[key][index] = message;
this.errors[key][index] = mergeErrors(this.errors[key][index], error);
return;
}
this.errors[key].push(message);
this.errors[key].push(error);
}

setModelError(path, message) {
Expand All @@ -159,9 +160,10 @@ class Schema {
const field = this.getField(firstKey);
const fieldType = getFieldType(field);
if (fieldType instanceof Schema) {
const virtualSchema = new Schema(fieldType.schema);
const childPath = removeFirstKeyIfNumber(keys).join('.');
fieldType.setModelError(childPath, message);
error = fieldType.errors;
virtualSchema.setModelError(childPath, message);
error = virtualSchema.errors;
}
this.setError(firstKey, error, errorIndex);
}
Expand Down
145 changes: 145 additions & 0 deletions src/Schema.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1116,6 +1116,25 @@ describe('Schema', () => {
});
});

it('should overwrite validation messages', () => {
const errorMessage = 'foo error';
const schema = new Schema({
companyName: {
type: String,
required: true,
},
}, {
validateRequired: () => errorMessage,
});

const testObjectErrors = schema.validate({
companyName: '',
});

expect(testObjectErrors).toEqual({ companyName: [errorMessage] });
expect(Object.keys(schema.messages).length > 1).toEqual(true);
});

it('should return model error if model is undefined', () => {
const schema = new Schema({
companyName: {
Expand Down Expand Up @@ -1666,6 +1685,132 @@ describe('Schema', () => {
],
});
});
it('should merge errors if error is set on the same key and index', () => {
const unitSchema = new Schema({
value: {
type: String,
required: true,
},
unit: {
type: String,
required: true,
},
});
const elementSchema = new Schema({
name: {
type: String,
},
type: {
type: String,
},
height: {
type: unitSchema,
},
weight: {
type: unitSchema,
},
length: {
type: unitSchema,
},
});
const modelSchema = new Schema({
elements: {
type: [elementSchema],
},
});
const data = {
elements: [
{
name: 'test',
type: 'pallet',
height: {
value: '10',
unit: 'm',
},
weight: {
value: '10',
unit: 'm',
},
length: {
value: '10',
unit: 'm',
},
},
{
name: 'test',
type: 'pallet',
height: {
value: '',
unit: 'm',
},
weight: {
value: '10',
unit: 'm',
},
length: {
value: '10',
unit: 'm',
},
},
{
name: 'test1',
type: 'pallet',
height: {
value: '',
unit: 'm',
},
weight: {
value: '',
unit: 'm',
},
length: {
value: '10',
unit: 'm',
},
},
],
};

modelSchema.addValidator((model, schema) => {
if (!model || !Array.isArray(model.elements)) return;
const uniqueNames = new Set();
const errorMsg = 'duplicatedKey';

model.elements.forEach((element, index) => {
if (uniqueNames.has(element.name)) {
schema.setModelError(`elements.${index}.name`, errorMsg);
} else {
uniqueNames.add(element.name);
}
});
});

expect(modelSchema.validate(data)).toEqual({
elements: [
undefined,
{
name: ['duplicatedKey'],
height: [
{
value: ["Field 'value' is required"],
},
],
},
{
height: [
{
value: ["Field 'value' is required"],
},
],
weight: [
{
value: ["Field 'value' is required"],
},
],
},
],
});
});
it('should set error on field (async validation)', () => {
const fooSchema = new Schema({
fooStart: {
Expand Down
19 changes: 19 additions & 0 deletions src/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,22 @@ export const getErrorIndexFromKeys = (keys) => {
}
return -1;
};

export const mergeErrors = (currentErrors = {}, nextErrors = {}) => {
const errors = {};
const errorKeys = new Set();
if (typeof nextErrors === 'string') {
if (!Array.isArray(currentErrors)) {
return [nextErrors];
}
return [...currentErrors, nextErrors];
}
Object.keys(currentErrors).forEach(key => errorKeys.add(key));
Object.keys(nextErrors).forEach(key => errorKeys.add(key));
errorKeys.forEach((key) => {
const current = currentErrors[key] || [];
const next = nextErrors[key] || [];
errors[key] = [...wrapToArray(current, true), ...wrapToArray(next, true)];
});
return errors;
};
34 changes: 34 additions & 0 deletions src/helpers.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
isNaN,
removeFirstKeyIfNumber,
getErrorIndexFromKeys,
mergeErrors,
} from './helpers';

describe('helpers', () => {
Expand Down Expand Up @@ -227,4 +228,37 @@ describe('helpers', () => {
expect(getErrorIndexFromKeys(keys)).toEqual(-1);
});
});
describe('mergeErrors', () => {
it('should return error with 2 keys', () => {
const currentErrors = { foo: ['foo error 1', 'foo error 2'] };
const nextErrors = { bar: ['bar error 1', 'bar error 2'] };
expect(mergeErrors(currentErrors, nextErrors)).toEqual({
foo: ['foo error 1', 'foo error 2'],
bar: ['bar error 1', 'bar error 2'],
});
});
it('should return error with 2 keys', () => {
const currentErrors = { foo: ['foo error 1', 'foo error 2'], bar: ['bar error 3'] };
const nextErrors = { bar: ['bar error 1', 'bar error 2'] };
expect(mergeErrors(currentErrors, nextErrors)).toEqual({
foo: ['foo error 1', 'foo error 2'],
bar: ['bar error 3', 'bar error 1', 'bar error 2'],
});
});
it('should return empty object if errors are undefined', () => {
const currentErrors = undefined;
const nextErrors = undefined;
expect(mergeErrors(currentErrors, nextErrors)).toEqual({});
});
it('should return array with errors if next error is string', () => {
const currentErrors = ['foo error'];
const nextErrors = 'bar error';
expect(mergeErrors(currentErrors, nextErrors)).toEqual(['foo error', 'bar error']);
});
it('should return array with error if next error is string and current error is undefined', () => {
const currentErrors = undefined;
const nextErrors = 'bar error';
expect(mergeErrors(currentErrors, nextErrors)).toEqual(['bar error']);
});
});
});

0 comments on commit f90cf6a

Please sign in to comment.