Skip to content

Commit 72c5221

Browse files
authored
Merge 882ffba into a733377
2 parents a733377 + 882ffba commit 72c5221

File tree

18 files changed

+504
-14
lines changed

18 files changed

+504
-14
lines changed

__tests__/suits/Area.test.tsx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,4 +452,30 @@ describe('test ValidatorProvider', () => {
452452
area.setProps({ errors: ['test error'] });
453453
expect(area.state().errors.length).toBe(1);
454454
});
455+
456+
it('should get other area', async () => {
457+
Validator.extend('test_other_area', (validator: Validator) => ({
458+
passed(): boolean {
459+
return !!validator.area('other');
460+
},
461+
message(): string {
462+
return 'test';
463+
}
464+
}))
465+
466+
const provider = mount<ValidatorProvider, ValidatorProviderProps>(
467+
<ValidatorProvider rules="test_other_area">
468+
<ValidatorArea>
469+
<input name="test" />
470+
</ValidatorArea>
471+
<ValidatorArea>
472+
<input name="other" />
473+
</ValidatorArea>
474+
</ValidatorProvider>
475+
);
476+
477+
await provider.instance().validate();
478+
await tick();
479+
expect(provider.state().valid).toBeTruthy();
480+
})
455481
})

__tests__/suits/rules/length.test.tsx

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import React from 'react';
2+
import { mount } from 'enzyme';
3+
import {
4+
Validator,
5+
ValidatorArea,
6+
IncorrectArgumentTypeError,
7+
ValidatorAreaProps
8+
} from '../../../src';
9+
import tick from '../../common/tick';
10+
import length from '../../../src/rules/length';
11+
12+
describe('test length rule', () => {
13+
beforeEach(() => {
14+
Validator.extend('length', length);
15+
});
16+
17+
it('should always validate inputs and not validate non-inputs', async () => {
18+
const input1 = document.createElement('input');
19+
const input2 = document.createElement('input');
20+
const canvas = document.createElement('canvas');
21+
input1.value = 'foo';
22+
input2.value = 'foobar';
23+
24+
const validator_input_incorrect = new Validator([
25+
input1
26+
],
27+
['length:2'],
28+
'');
29+
30+
const validator_input_correct = new Validator([
31+
input2
32+
],
33+
['length:6'],
34+
'');
35+
36+
const validator_canvas = new Validator([
37+
canvas
38+
],
39+
['length:3'],
40+
'');
41+
42+
const validator_wrong_arg = new Validator([
43+
input1
44+
],
45+
['length:foo'],
46+
'');
47+
48+
await validator_input_incorrect.validate();
49+
expect(validator_input_incorrect.getErrors().length).toBe(1);
50+
51+
await validator_input_correct.validate();
52+
expect(validator_input_correct.getErrors().length).toBe(0);
53+
54+
await validator_canvas.validate();
55+
expect(validator_canvas.getErrors().length).toBe(0);
56+
57+
await expect( validator_wrong_arg.validate()).rejects.toBeInstanceOf(IncorrectArgumentTypeError);
58+
});
59+
60+
it('should validate select', async () => {
61+
const area = mount<ValidatorArea, ValidatorAreaProps>(
62+
<ValidatorArea rules="length:5">
63+
<select name="test">
64+
<option value="Test" selected>Option</option>
65+
</select>
66+
</ValidatorArea>
67+
);
68+
69+
area.find('select').simulate('blur');
70+
await tick();
71+
expect(area.state().errors.length).toBe(1);
72+
});
73+
});
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import React from 'react';
2+
import { mount } from 'enzyme';
3+
import {
4+
Validator,
5+
ValidatorArea,
6+
IncorrectArgumentTypeError,
7+
ValidatorAreaProps,
8+
maxLength
9+
} from '../../../src';
10+
import tick from '../../common/tick';
11+
12+
describe('test max length rule', () => {
13+
beforeEach(() => {
14+
Validator.extend('maxLength', maxLength);
15+
});
16+
17+
it('should always validate inputs and not validate non-inputs', async () => {
18+
const input1 = document.createElement('input');
19+
const input2 = document.createElement('input');
20+
const canvas = document.createElement('canvas');
21+
input1.value = 'foo';
22+
input2.value = 'foobar';
23+
24+
const validator_input_correct = new Validator([
25+
input1
26+
],
27+
['maxLength:6'],
28+
'');
29+
30+
const validator_input_incorrect = new Validator([
31+
input2
32+
],
33+
['maxLength:4'],
34+
'');
35+
36+
const validator_canvas = new Validator([
37+
canvas
38+
],
39+
['maxLength:3'],
40+
'');
41+
42+
const validator_wrong_arg = new Validator([
43+
input1
44+
],
45+
['maxLength:foo'],
46+
'');
47+
48+
await validator_input_incorrect.validate();
49+
expect(validator_input_incorrect.getErrors().length).toBe(1);
50+
51+
await validator_input_correct.validate();
52+
expect(validator_input_correct.getErrors().length).toBe(0);
53+
54+
await validator_canvas.validate();
55+
expect(validator_canvas.getErrors().length).toBe(0);
56+
57+
await expect( validator_wrong_arg.validate()).rejects.toBeInstanceOf(IncorrectArgumentTypeError);
58+
});
59+
60+
it('should validate select', async () => {
61+
const area = mount<ValidatorArea, ValidatorAreaProps>(
62+
<ValidatorArea rules="maxLength:5">
63+
<select name="test">
64+
<option value="Testlong" selected>Option</option>
65+
</select>
66+
</ValidatorArea>
67+
);
68+
69+
area.find('select').simulate('blur');
70+
await tick();
71+
expect(area.state().errors.length).toBe(1);
72+
});
73+
});
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import React from 'react';
2+
import { mount } from 'enzyme';
3+
import {
4+
Validator,
5+
ValidatorArea,
6+
IncorrectArgumentTypeError,
7+
ValidatorAreaProps
8+
} from '../../../src';
9+
import tick from '../../common/tick';
10+
import minLength from '../../../src/rules/minLength';
11+
12+
describe('test min length rule', () => {
13+
beforeEach(() => {
14+
Validator.extend('minLength', minLength);
15+
});
16+
17+
it('should always validate inputs and not validate non-inputs', async () => {
18+
const input = document.createElement('input');
19+
const canvas = document.createElement('canvas');
20+
input.value = 'foo';
21+
22+
const validator_input = new Validator([
23+
input
24+
],
25+
['minLength:4'],
26+
'');
27+
28+
const validator_canvas = new Validator([
29+
canvas
30+
],
31+
['minLength:3'],
32+
'');
33+
34+
const validator_wrong_arg = new Validator([
35+
input
36+
],
37+
['minLength:foo'],
38+
'');
39+
40+
await validator_input.validate();
41+
expect(validator_input.getErrors().length).toBe(1);
42+
43+
await validator_canvas.validate();
44+
expect(validator_canvas.getErrors().length).toBe(0);
45+
46+
await expect( validator_wrong_arg.validate()).rejects.toBeInstanceOf(IncorrectArgumentTypeError);
47+
});
48+
49+
it('should validate select', async () => {
50+
const area = mount<ValidatorArea, ValidatorAreaProps>(
51+
<ValidatorArea rules="minLength:5">
52+
<select name="test">
53+
<option value="Test" selected>Option</option>
54+
</select>
55+
</ValidatorArea>
56+
);
57+
58+
area.find('select').simulate('blur');
59+
await tick();
60+
expect(area.state().errors.length).toBe(1);
61+
});
62+
});

__tests__/suits/rules/same.test.tsx

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { Validator, ValidatorProviderProps, ValidatorProviderState } from '../../../src';
2+
import React from 'react';
3+
import same from '../../../src/rules/same';
4+
import { mount } from 'enzyme';
5+
import { ValidatorArea, ValidatorProvider } from '../../../src';
6+
import tick from '../../common/tick';
7+
8+
describe('test same rule', () => {
9+
beforeEach(() => {
10+
Validator.extend('same', same);
11+
});
12+
13+
it('should validate true', async () => {
14+
const area = mount<ValidatorProvider, ValidatorProviderProps, ValidatorProviderState>(
15+
<ValidatorProvider>
16+
<ValidatorArea rules="same:bar">
17+
<input value="foo" name="foo" />
18+
</ValidatorArea>
19+
20+
<ValidatorArea validationName="test">
21+
<input value="foo" name="bar" />
22+
</ValidatorArea>
23+
</ValidatorProvider>
24+
);
25+
26+
await area.instance().validate();
27+
await tick();
28+
expect(area.state().valid).toBeTruthy();
29+
});
30+
31+
it('should validate false', async () => {
32+
const area = mount<ValidatorProvider, ValidatorProviderProps, ValidatorProviderState>(
33+
<ValidatorProvider>
34+
<ValidatorArea rules="same:bar">
35+
<input value="foo" name="foo" />
36+
</ValidatorArea>
37+
38+
<ValidatorArea>
39+
<input value="baz" name="bar" />
40+
</ValidatorArea>
41+
</ValidatorProvider>
42+
);
43+
44+
await area.instance().validate();
45+
await tick();
46+
console.log(area.find(ValidatorArea).first().state());
47+
expect(area.state().valid).toBeFalsy();
48+
});
49+
})

__tests__/suits/utils/utils.test.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { arraysEqual } from '../../../src/common/utils';
2+
3+
describe('utils test', () => {
4+
it('should check if arrays are equal', () => {
5+
expect(arraysEqual(['foo'], ['foo'])).toBeTruthy();
6+
});
7+
8+
it('should check if arrays are not equal', () => {
9+
expect(arraysEqual(['foo'], ['bar'])).toBeFalsy();
10+
});
11+
12+
it('should check if arrays are not equal', () => {
13+
expect(arraysEqual(['foo'], ['foo', 'bar'])).toBeFalsy();
14+
});
15+
});

src/Rule.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ export type RuleObject = {
1717
* Message shown when the rule doesn't pass
1818
*/
1919
message(): string;
20+
/**
21+
* Array of strings to replace the rule args
22+
*/
23+
messageArgs?(): string[];
2024
}
2125

2226
export type Rule = RuleObject | RuleFunction;

src/Validator.ts

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export class Validator {
5858
/**
5959
* Validator area used to access other areas and the provider
6060
*/
61-
private area?: ValidatorArea;
61+
private _area?: ValidatorArea;
6262

6363
/**
6464
* Name used to overwrite name attribute, to allow messages to be more specific
@@ -151,6 +151,17 @@ export class Validator {
151151
return [name, parameters.split(',')];
152152
}
153153

154+
private static parseArgs(rule: RuleObject, args: string[]): string[] {
155+
if (rule.messageArgs) {
156+
return [
157+
...rule.messageArgs(),
158+
...args.slice(rule.messageArgs().length, args.length - 1)
159+
];
160+
}
161+
162+
return args;
163+
}
164+
154165
/**
155166
* Validate a specific rule
156167
*/
@@ -165,7 +176,10 @@ export class Validator {
165176
const passed = await ruleObj.passed(this.elements, ...ruleParameters);
166177

167178
if(!passed) {
168-
this.errors.push(this.localize(ruleObj.message(), ...ruleParameters));
179+
this.errors.push(this.localize(
180+
ruleObj.message(),
181+
Validator.parseArgs(ruleObj, ruleParameters)
182+
));
169183
return false;
170184
}
171185

@@ -192,7 +206,7 @@ export class Validator {
192206
/*
193207
* Get the capitalized, localized message
194208
*/
195-
public localize(message: string, ...ruleArgs: string[]): string {
209+
public localize(message: string, ruleArgs: string[]): string {
196210
return capitalize(this.intl.formatMessage({
197211
id: message,
198212
defaultMessage: message
@@ -213,7 +227,7 @@ export class Validator {
213227
* Sets the current area
214228
*/
215229
public setArea(area: ValidatorArea): Validator {
216-
this.area = area;
230+
this._area = area;
217231

218232
return this;
219233
}
@@ -222,8 +236,8 @@ export class Validator {
222236
* Gets the area where this validator instance is used
223237
*/
224238
public getArea(): ValidatorArea {
225-
if (this.area) {
226-
return this.area;
239+
if (this._area) {
240+
return this._area;
227241
}
228242

229243
throw new Error('Areas are only available when validating React components.');
@@ -236,6 +250,10 @@ export class Validator {
236250
return this.getArea().context.getRefs(name, type);
237251
}
238252

253+
public area(name: string): ValidatorArea | undefined {
254+
return this.getArea().context.getArea(name);
255+
}
256+
239257
/**
240258
* Merges rules from different sources into one array
241259
*/

0 commit comments

Comments
 (0)