Skip to content

Commit

Permalink
feat: Add custom error message for minlength validation errors. (#212)
Browse files Browse the repository at this point in the history
  • Loading branch information
yeldiRium committed Nov 13, 2020
1 parent e2e9039 commit b7639cd
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 0 deletions.
11 changes: 11 additions & 0 deletions lib/Value.ts
@@ -1,4 +1,5 @@
import Ajv from 'ajv';
import { getByDataPath } from './getByDataPath';
import { JSONSchema7 } from 'json-schema';
import { ValidationError } from './ValidationError';

Expand Down Expand Up @@ -27,6 +28,7 @@ class Value {
}

const error = this.validateInternal.errors![0];
const failingValue = getByDataPath({ object: value, dataPath: error.dataPath });

let updatedPath = `${valueName}${error.dataPath.replace(/\//gu, separator)}`;
let message = 'Validation failed';
Expand All @@ -50,6 +52,15 @@ class Value {
break;
}

case 'minLength': {
const minPropertyLength = (error.params as Ajv.LimitParams).limit;
const actualLength = failingValue.length;

message = `String is too short (${actualLength} chars), minimum ${minPropertyLength}`;

break;
}

default: {
// Intentionally left blank.
}
Expand Down
18 changes: 18 additions & 0 deletions lib/getByDataPath.ts
@@ -0,0 +1,18 @@
const getByDataPath = function ({ object, dataPath }: { object: any; dataPath: string }): any {
const pathSegments = dataPath.split('.');
const nonEmptyPathSegments = pathSegments.filter((segment): boolean => segment !== '');

let value = object;

for (const pathSegment of nonEmptyPathSegments) {
if (value === undefined) {
break;
}

value = value[pathSegment];
}

return value;
};

export { getByDataPath };
17 changes: 17 additions & 0 deletions test/unit/ValueTests.ts
Expand Up @@ -123,6 +123,23 @@ suite('Value', (): void => {
});
}).is.throwing((ex: Error): boolean => ex.message === 'Unexpected additional property: login (at value.login).');
});

test('throws an error if a string undercuts a minimum length.', async (): Promise<void> => {
schema = new Value({
type: 'object',
properties: {
username: { type: 'string', minLength: 4 }
},
required: [ 'username' ],
additionalProperties: false
});

assert.that((): void => {
schema.validate({
username: 'foo'
});
}).is.throwing((ex: Error): boolean => ex.message === 'String is too short (3 chars), minimum 4 (at value.username).');
});
});
});

Expand Down
34 changes: 34 additions & 0 deletions test/unit/getByDataPathTests.ts
@@ -0,0 +1,34 @@
import { assert } from 'assertthat';
import { getByDataPath } from '../../lib/getByDataPath';

suite('getByDataPath', (): void => {
test('traverses an object by following an ajv data path.', async (): Promise<void> => {
const object = {
foo: {
bar: {
baz: 'bam'
}
}
};

const result = getByDataPath({ object, dataPath: '.foo.bar.baz' });

assert.that(result).is.equalTo('bam');
});

test('returns undefined, if the path does not match anything.', async (): Promise<void> => {
const object = {};

const result = getByDataPath({ object, dataPath: '.foo.bar.baz' });

assert.that(result).is.undefined();
});

test('returns undefined, if the object is undefined.', async (): Promise<void> => {
const object = undefined;

const result = getByDataPath({ object, dataPath: '.foo.bar.baz' });

assert.that(result).is.undefined();
});
});

0 comments on commit b7639cd

Please sign in to comment.