Skip to content

Commit e03594e

Browse files
Add ValidatorDeclaration tests
Turned out the arg1 and arg2 arguments within ValidatorDeclaration were (of course) overwritten, meaning the value after the first validation cycle was fixed to whatever was returned by the function that time. This is now fixed.
1 parent 4623a02 commit e03594e

File tree

3 files changed

+140
-102
lines changed

3 files changed

+140
-102
lines changed
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
import { FormControl, ValidationErrors, ValidatorFn, AbstractControl } from '@angular/forms';
2+
3+
import { ValidatorDeclaration } from './validator-declaration';
4+
5+
describe('ValidatorDeclaration', () => {
6+
describe('wrappers add a message when invalid', () => {
7+
const message = 'message on error';
8+
const resultKey = 'resultKey';
9+
const wrappedValidatorFn = (control: AbstractControl) => {
10+
const obj: any = {};
11+
obj[resultKey] = true;
12+
return obj;
13+
};
14+
15+
function expectHasMessage(validatorFn: ValidatorFn) {
16+
const formControl = new FormControl('');
17+
18+
let result = validatorFn(formControl);
19+
20+
expect(result).not.toBeNull();
21+
result = <ValidationErrors> result;
22+
expect(result[resultKey].message).toEqual(message);
23+
}
24+
25+
it(`wrapNoArgumentValidator`, () => {
26+
const validator = ValidatorDeclaration.wrapNoArgumentValidator(wrappedValidatorFn, resultKey);
27+
28+
expectHasMessage(validator(message));
29+
});
30+
31+
it(`wrapSingleArgumentValidator`, () => {
32+
const validator = ValidatorDeclaration.wrapSingleArgumentValidator((input: any) => wrappedValidatorFn, resultKey);
33+
34+
expectHasMessage(validator(1, message));
35+
});
36+
37+
it(`wrapTwoArgumentValidator`, () => {
38+
const validator = ValidatorDeclaration.wrapTwoArgumentValidator((input1: any, input2: any) => wrappedValidatorFn, resultKey);
39+
40+
expectHasMessage(validator(1, 2, message));
41+
});
42+
});
43+
44+
describe('wrappers add a dynamic message when invalid', () => {
45+
const message = 'message on error';
46+
const messageFn = () => message;
47+
const resultKey = 'resultKey';
48+
const wrappedValidatorFn = (control: AbstractControl) => {
49+
const obj: any = {};
50+
obj[resultKey] = true;
51+
return obj;
52+
};
53+
54+
function expectHasMessage(validatorFn: ValidatorFn) {
55+
const formControl = new FormControl('');
56+
57+
let result = validatorFn(formControl);
58+
59+
expect(result).not.toBeNull();
60+
result = <ValidationErrors> result;
61+
expect(result[resultKey].message).toEqual(message);
62+
}
63+
64+
it(`wrapNoArgumentValidator`, () => {
65+
const validator = ValidatorDeclaration.wrapNoArgumentValidator(wrappedValidatorFn, resultKey);
66+
67+
expectHasMessage(validator(messageFn));
68+
});
69+
70+
it(`wrapSingleArgumentValidator`, () => {
71+
const validator = ValidatorDeclaration.wrapSingleArgumentValidator((input: any) => wrappedValidatorFn, resultKey);
72+
73+
expectHasMessage(validator(1, messageFn));
74+
});
75+
76+
it(`wrapTwoArgumentValidator`, () => {
77+
const validator = ValidatorDeclaration.wrapTwoArgumentValidator((input1: any, input2: any) => wrappedValidatorFn, resultKey);
78+
79+
expectHasMessage(validator(1, 2, messageFn));
80+
});
81+
});
82+
83+
describe('wrappers get the validation value by calling the input function when specified', () => {
84+
it(`wrapSingleArgumentValidator`, () => {
85+
const spyObj = {
86+
validatorFn: (input1: number) => {
87+
return (control: AbstractControl) => {
88+
expect(input1).toEqual(i);
89+
return {};
90+
};
91+
}
92+
};
93+
94+
spyOn(spyObj, 'validatorFn').and.callThrough();
95+
96+
const validator = ValidatorDeclaration.wrapSingleArgumentValidator(spyObj.validatorFn, 'key');
97+
98+
let i = 0;
99+
const validatorFn = validator(() => i);
100+
const formControl = new FormControl('');
101+
for (; i < 10; i++) {
102+
validatorFn(formControl);
103+
}
104+
105+
expect(spyObj.validatorFn).toHaveBeenCalled();
106+
});
107+
108+
it(`wrapTwoArgumentValidator`, () => {
109+
const spyObj = {
110+
validatorFn: (input1: number, input2: number) => {
111+
return (control: AbstractControl) => {
112+
expect(input1).toEqual(i);
113+
expect(input2).toEqual(j);
114+
return {};
115+
};
116+
}
117+
};
118+
119+
spyOn(spyObj, 'validatorFn').and.callThrough();
120+
121+
const validator = ValidatorDeclaration.wrapTwoArgumentValidator(spyObj.validatorFn, 'key');
122+
123+
let i = 0;
124+
let j = 10;
125+
const validatorFn = validator(() => i, () => j);
126+
const formControl = new FormControl('');
127+
for (; i < 10; i++, j++) {
128+
validatorFn(formControl);
129+
}
130+
131+
expect(spyObj.validatorFn).toHaveBeenCalled();
132+
});
133+
});
134+
});

angular-reactive-validation/src/validator-declaration.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ export class ValidatorDeclaration {
3030

3131
return function (arg1: TInput | (() => TInput), message?: string | ((arg1: TInput) => string)): ValidatorFn {
3232
return function(control: AbstractControl): ValidationErrors | null {
33-
arg1 = ValidatorDeclaration.unwrapArgument(arg1);
33+
const unwrappedArg1 = ValidatorDeclaration.unwrapArgument(arg1);
3434

35-
return ValidatorDeclaration.validateAndSetMessageIfInvalid(control, validatorFactoryFn, resultKey, message, arg1);
35+
return ValidatorDeclaration.validateAndSetMessageIfInvalid(control, validatorFactoryFn, resultKey, message, unwrappedArg1);
3636
};
3737
};
3838
}
@@ -50,10 +50,11 @@ export class ValidatorDeclaration {
5050
message?: string | ((arg1: TInput1, arg2: TInput2) => string)): ValidatorFn {
5151

5252
return function(control: AbstractControl): ValidationErrors | null {
53-
arg1 = ValidatorDeclaration.unwrapArgument(arg1);
54-
arg2 = ValidatorDeclaration.unwrapArgument(arg2);
53+
const unwrappedArg1 = ValidatorDeclaration.unwrapArgument(arg1);
54+
const unwrappedArg2 = ValidatorDeclaration.unwrapArgument(arg2);
5555

56-
return ValidatorDeclaration.validateAndSetMessageIfInvalid(control, validatorFactoryFn, resultKey, message, arg1, arg2);
56+
return ValidatorDeclaration.validateAndSetMessageIfInvalid(control, validatorFactoryFn, resultKey, message,
57+
unwrappedArg1, unwrappedArg2);
5758
};
5859
};
5960
}

angular-reactive-validation/src/validators.spec.ts

Lines changed: 0 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -104,101 +104,4 @@ describe('Validators', () => {
104104
});
105105
});
106106
});
107-
108-
it(`add a message when the validation result is invalid`, () => {
109-
const expectedMessage = 'The FormControl has an invalid value.';
110-
const combinations = [{
111-
validatorFn: Validators.min(0, expectedMessage),
112-
control: new FormControl(-1)
113-
}, {
114-
validatorFn: Validators.max(0, expectedMessage),
115-
control: new FormControl(1)
116-
}, {
117-
validatorFn: Validators.minLength(2, expectedMessage),
118-
control: new FormControl('a')
119-
}, {
120-
validatorFn: Validators.maxLength(2, expectedMessage),
121-
control: new FormControl('abc')
122-
}, {
123-
validatorFn: Validators.pattern(/a/, expectedMessage),
124-
control: new FormControl('b')
125-
}, {
126-
validatorFn: Validators.required(expectedMessage),
127-
control: new FormControl(null)
128-
}, {
129-
validatorFn: Validators.requiredTrue(expectedMessage),
130-
control: new FormControl(false)
131-
}, {
132-
validatorFn: Validators.email(expectedMessage),
133-
control: new FormControl('davidwalschots@[email protected]')
134-
}];
135-
136-
combinations.forEach(combination => {
137-
const result = combination.validatorFn(combination.control);
138-
expect(result).not.toBeNull();
139-
expect((<ValidationErrors>result)[Object.getOwnPropertyNames(result)[0]].message).toEqual(expectedMessage);
140-
});
141-
});
142-
143-
it(`add a dynamic message when the validation result is invalid`, () => {
144-
const combinations = [{
145-
validatorFn: Validators.min(0, min => `The minimum value is: ${min}`),
146-
control: new FormControl(-1),
147-
expectedMessage: 'The minimum value is: 0'
148-
}, {
149-
validatorFn: Validators.max(0, max => `The maximum value is: ${max}`),
150-
control: new FormControl(1),
151-
expectedMessage: 'The maximum value is: 0'
152-
}, {
153-
validatorFn: Validators.minLength(2, minLength => `The minimum length is: ${minLength}`),
154-
control: new FormControl('a'),
155-
expectedMessage: 'The minimum length is: 2'
156-
}, {
157-
validatorFn: Validators.maxLength(2, maxLength => `The maximum length is: ${maxLength}`),
158-
control: new FormControl('abc'),
159-
expectedMessage: 'The maximum length is: 2'
160-
}];
161-
162-
combinations.forEach(combination => {
163-
const result = combination.validatorFn(combination.control);
164-
expect(result).not.toBeNull();
165-
expect((<ValidationErrors>result)[Object.getOwnPropertyNames(result)[0]].message).toEqual(combination.expectedMessage);
166-
});
167-
});
168-
169-
it(`get the validation value by calling the input function when specified`, () => {
170-
const combinations = [{
171-
validatorFn: Validators.min,
172-
fn: () => 100,
173-
control: new FormControl(101)
174-
}, {
175-
validatorFn: Validators.max,
176-
fn: () => 100,
177-
control: new FormControl(99)
178-
}, {
179-
validatorFn: Validators.minLength,
180-
fn: () => 3,
181-
control: new FormControl('abc')
182-
}, {
183-
validatorFn: Validators.maxLength,
184-
fn: () => 5,
185-
control: new FormControl('abcd')
186-
}];
187-
188-
const patternValidator = {
189-
validatorFn: Validators.pattern,
190-
fn: () => /a/,
191-
control: new FormControl('a')
192-
};
193-
194-
combinations.forEach(combination => {
195-
spyOn(combination, 'fn').and.callThrough();
196-
combination.validatorFn(combination.fn, 'test')(combination.control);
197-
expect(combination.fn).toHaveBeenCalled();
198-
});
199-
200-
spyOn(patternValidator, 'fn').and.callThrough();
201-
patternValidator.validatorFn(patternValidator.fn, 'test')(patternValidator.control);
202-
expect(patternValidator.fn).toHaveBeenCalled();
203-
});
204107
});

0 commit comments

Comments
 (0)