Skip to content

Commit 8b74d25

Browse files
committed
refactor: update validator working. need expect message for each rules
1 parent 6a30f33 commit 8b74d25

7 files changed

+101
-25
lines changed
+4-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
export interface ValuePropertyValidationError {
22
value: unknown;
3-
type: string;
3+
expect: string;
44
}
55
export class PropertyValidationError extends Error {
66
value: unknown;
7-
type: string;
7+
expect: string;
88
constructor(infos: ValuePropertyValidationError) {
9-
super();
9+
super(infos.expect);
1010
this.value = infos.value;
11-
this.type = infos.type;
11+
this.expect = infos.expect;
1212
}
1313
}

src/validation/reporter.spec.ts

+77-9
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,9 @@ describe('Reporter', () => {
88
it('should format a ValidationError to human readable message', () => {
99
const targetProperty = 'targetProperty';
1010
const value = undefined;
11-
const error = new PropertyValidationError({ type: 'string', value });
11+
const error = new PropertyValidationError({ expect: 'message', value });
1212
const message = defaultFormatter({ targetProperty, ...error });
13-
expect(message).toEqual(
14-
`Invalid value ${value} supplied to : [⚠️ Schema With Type] at property ${targetProperty}. Expecting type ${error.type}`
15-
);
13+
expect(message).toEqual(`Invalid value ${value} supplied at property ${targetProperty}. Expecting: ${error.expect}`);
1614
});
1715
});
1816
describe('Validation', () => {
@@ -32,8 +30,8 @@ describe('Reporter', () => {
3230
});
3331
const result = morphism(schema, JSON.parse('{}'));
3432
const errors = reporter.report(result);
35-
const error1 = new PropertyValidationError({ type: 'boolean', value: undefined });
36-
const error2 = new PropertyValidationError({ type: 'number', value: undefined });
33+
const error1 = new PropertyValidationError({ expect: 'value to be typeof boolean', value: undefined });
34+
const error2 = new PropertyValidationError({ expect: 'value to be typeof number', value: undefined });
3735

3836
const message1 = defaultFormatter({ targetProperty: 't1', ...error1 });
3937
const message2 = defaultFormatter({ targetProperty: 't2', ...error2 });
@@ -45,6 +43,14 @@ describe('Reporter', () => {
4543
}
4644
});
4745

46+
it('should throw an exception when trying to use a rule more than once', () => {
47+
expect(() => {
48+
Validation.string()
49+
.max(1)
50+
.max(1);
51+
}).toThrow('Rule max has already been used');
52+
});
53+
4854
describe('string', () => {
4955
it('should report error on string undefined', () => {
5056
interface S {
@@ -56,7 +62,7 @@ describe('Reporter', () => {
5662

5763
const schema = createSchema<T, S>({ t1: { path: 's1', fn: val => val, validation: Validation.string() } });
5864
const result = morphism(schema, JSON.parse('{}'));
59-
const error = new PropertyValidationError({ type: 'string', value: undefined });
65+
const error = new PropertyValidationError({ expect: 'value to be typeof string', value: undefined });
6066
const message = defaultFormatter({ targetProperty: 't1', ...error });
6167
const errors = reporter.report(result);
6268
expect(errors).not.toBeNull();
@@ -65,6 +71,68 @@ describe('Reporter', () => {
6571
expect(errors[0]).toBe(message);
6672
}
6773
});
74+
75+
it('should report error when string max length is not met', () => {
76+
interface S {
77+
s1: string;
78+
}
79+
interface T {
80+
t1: string;
81+
}
82+
83+
const schema = createSchema<T, S>({ t1: { fn: value => value.s1, validation: Validation.string().max(3) } });
84+
const result = morphism(schema, { s1: 'value' });
85+
const error = new PropertyValidationError({ expect: `value to be less or equal than 3`, value: 'value' });
86+
const message = defaultFormatter({ targetProperty: 't1', ...error });
87+
const errors = reporter.report(result);
88+
expect(errors).not.toBeNull();
89+
if (errors) {
90+
expect(errors.length).toEqual(1);
91+
expect(errors[0]).toBe(message);
92+
}
93+
});
94+
95+
it('should report error when string min length is not met', () => {
96+
interface S {
97+
s1: string;
98+
}
99+
interface T {
100+
t1: string;
101+
}
102+
103+
const schema = createSchema<T, S>({ t1: { fn: value => value.s1, validation: Validation.string().min(3) } });
104+
const result = morphism(schema, { s1: 'a' });
105+
const error = new PropertyValidationError({ expect: `value to be greater or equal than 3`, value: 'a' });
106+
const message = defaultFormatter({ targetProperty: 't1', ...error });
107+
const errors = reporter.report(result);
108+
expect(errors).not.toBeNull();
109+
if (errors) {
110+
expect(errors.length).toEqual(1);
111+
expect(errors[0]).toBe(message);
112+
}
113+
});
114+
115+
it('should return the value when the validation pass', () => {
116+
interface S {
117+
s1: string;
118+
}
119+
interface T {
120+
t1: string;
121+
}
122+
123+
const schema = createSchema<T, S>({
124+
t1: {
125+
fn: value => value.s1,
126+
validation: Validation.string()
127+
.min(1)
128+
.max(3)
129+
}
130+
});
131+
const result = morphism(schema, { s1: 'aaa' });
132+
const errors = reporter.report(result);
133+
expect(errors).toBeNull();
134+
expect(result.t1).toBe('aaa');
135+
});
68136
});
69137

70138
describe('number', () => {
@@ -78,7 +146,7 @@ describe('Reporter', () => {
78146

79147
const schema = createSchema<T, S>({ t1: { path: 's1', fn: val => val, validation: Validation.number() } });
80148
const result = morphism(schema, JSON.parse('{}'));
81-
const error = new PropertyValidationError({ type: 'number', value: undefined });
149+
const error = new PropertyValidationError({ expect: 'value to be typeof number', value: undefined });
82150
const message = defaultFormatter({ targetProperty: 't1', ...error });
83151
const errors = reporter.report(result);
84152
expect(errors).not.toBeNull();
@@ -159,7 +227,7 @@ describe('Reporter', () => {
159227

160228
const schema = createSchema<T, S>({ t1: { path: 's1', fn: val => val, validation: Validation.boolean() } });
161229
const result = morphism(schema, JSON.parse('{ "s1": "a value" }'));
162-
const error = new PropertyValidationError({ type: 'boolean', value: 'a value' });
230+
const error = new PropertyValidationError({ expect: 'value to be typeof boolean', value: 'a value' });
163231
const message = defaultFormatter({ targetProperty: 't1', ...error });
164232

165233
const errors = reporter.report(result);

src/validation/reporter.ts

+7-6
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,24 @@
1+
import { PropertyValidationError } from './PropertyValidationError';
2+
13
export const ERRORS = Symbol('errors');
24

3-
export interface ValidationError {
5+
export interface ValidationError extends PropertyValidationError {
46
targetProperty: string;
57
value: unknown;
6-
type: string;
78
}
89

9-
export interface Errors extends Array<ValidationError> {}
10+
export interface ValidationErrors extends Array<ValidationError> {}
1011

1112
export interface Validation {
12-
[ERRORS]: Errors;
13+
[ERRORS]: ValidationErrors;
1314
}
1415

1516
export function targetHasErrors(target: any): target is Validation {
1617
return target && target[ERRORS] && target[ERRORS].length > 0;
1718
}
1819
export function defaultFormatter(error: ValidationError) {
19-
const { value, targetProperty, type } = error;
20-
return `Invalid value ${value} supplied to : [⚠️ Schema With Type] at property ${targetProperty}. Expecting type ${type}`;
20+
const { value, targetProperty, expect } = error;
21+
return `Invalid value ${value} supplied at property ${targetProperty}. Expecting: ${expect}`;
2122
}
2223

2324
/**

src/validation/validators/BaseValidator.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
interface Rule<T> {
1+
export interface Rule<T> {
22
name: string;
3+
expect: string;
34
test: (value: T) => T;
45
}
56

@@ -12,6 +13,7 @@ export abstract class BaseValidator<T = unknown> {
1213
if (this.rules.has(rule.name)) throw new Error(`Rule ${rule.name} has already been used`);
1314
this.rules.set(rule.name, rule);
1415
}
16+
1517
validate(value: T) {
1618
return [...this.rules.values()].reduce((acc, rule) => {
1719
return rule.test(acc);

src/validation/validators/BooleanValidator.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export class BooleanValidator extends BaseValidator<boolean> {
44
constructor() {
55
super({
66
name: 'boolean',
7+
expect: 'value to be typeof boolean',
78
test: function(value) {
89
if (typeof value === 'boolean') {
910
return value;
@@ -12,7 +13,7 @@ export class BooleanValidator extends BaseValidator<boolean> {
1213
} else if (/false/i.test(value)) {
1314
return false;
1415
} else {
15-
throw new PropertyValidationError({ value, type: this.name });
16+
throw new PropertyValidationError({ value, expect: this.expect });
1617
}
1718
}
1819
});

src/validation/validators/NumberValidator.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ export class NumberValidator extends BaseValidator<number> {
44
constructor() {
55
super({
66
name: 'number',
7+
expect: 'value to be typeof number',
78
test: function(value) {
89
const result = +value;
910
if (isNaN(result)) {
10-
throw new PropertyValidationError({ value, type: this.name });
11+
throw new PropertyValidationError({ value, expect: this.expect });
1112
} else {
1213
return result;
1314
}

src/validation/validators/StringValidator.ts

+6-3
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@ export class StringValidator extends BaseValidator<string> {
66
constructor() {
77
super({
88
name: 'string',
9+
expect: `value to be typeof string`,
910
test: function(value) {
1011
const result = value;
1112
if (!isString(result)) {
12-
throw new PropertyValidationError({ value, type: this.name });
13+
throw new PropertyValidationError({ value, expect: this.expect });
1314
}
1415
return result;
1516
}
@@ -19,9 +20,10 @@ export class StringValidator extends BaseValidator<string> {
1920
min(val: number) {
2021
this.addRule({
2122
name: 'min',
23+
expect: `value to be greater or equal than ${val}`,
2224
test: function(value) {
2325
if (value.length < val) {
24-
throw new PropertyValidationError({ value, type: this.name });
26+
throw new PropertyValidationError({ value, expect: this.expect });
2527
}
2628
return value;
2729
}
@@ -31,9 +33,10 @@ export class StringValidator extends BaseValidator<string> {
3133
max(val: number) {
3234
this.addRule({
3335
name: 'max',
36+
expect: `value to be less or equal than ${val}`,
3437
test: function(value) {
3538
if (value.length > val) {
36-
throw new PropertyValidationError({ value, type: this.name });
39+
throw new PropertyValidationError({ value, expect: this.expect });
3740
}
3841
return value;
3942
}

0 commit comments

Comments
 (0)