Skip to content

Commit 8d83579

Browse files
authored
async validation rules (#21)
* Draft: async validation rules * Added promisable passed methods. Added active url validation
1 parent 25c017e commit 8d83579

17 files changed

+34766
-15950
lines changed

__tests__/common/tick.ts

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export default (): Promise<void> => {
2+
return new Promise(resolve => {
3+
setTimeout(resolve, 0);
4+
})
5+
}

__tests__/Area.test.tsx renamed to __tests__/suits/Area.test.tsx

+28-14
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,7 @@ import { ValidatorArea, ValidatorAreaProps } from '@/components/ValidatorArea';
55
import ValidatorProvider, { ValidatorProviderProps } from '@/components/ValidatorProvider';
66
import { ProviderScope } from '@/ProviderScope';
77
import required from '@/rules/required';
8-
9-
const tick = () => {
10-
return new Promise(resolve => {
11-
setTimeout(resolve, 0);
12-
})
13-
}
8+
import tick from '../common/tick';
149

1510
describe('test ValidatorProvider', () => {
1611
beforeEach(() => {
@@ -82,14 +77,15 @@ describe('test ValidatorProvider', () => {
8277
expect(area.instance().getInputRefs().length).toBe(4);
8378
});
8479

85-
it('should apply rules on blur', () => {
80+
it('should apply rules on blur', async () => {
8681
const area = mount<ValidatorArea, ValidatorAreaProps>(
8782
<ValidatorArea rules="passes_not">
8883
<input name="test" value="test" />
8984
</ValidatorArea>
9085
);
9186

9287
area.find('input').at(0).simulate('blur');
88+
await tick();
9389
expect(area.state().errors[0]).toBe('Not passed');
9490
});
9591

@@ -107,16 +103,20 @@ describe('test ValidatorProvider', () => {
107103
it('should render error when area dirty', async () => {
108104
const area = mount<ValidatorArea, ValidatorAreaProps>(
109105
<ValidatorArea rules="passes_not">
110-
{({ errors }) => (
111-
<>
112-
<input name="test" value="test" />
113-
{errors.length && <div>{errors[0]}</div>}
114-
</>
115-
)}
106+
{({ errors }) => {
107+
return (
108+
<>
109+
<input name="test" value="test" />
110+
{!!errors.length && <div>{errors[0]}</div>}
111+
</>
112+
);
113+
}}
116114
</ValidatorArea>
117115
);
118116

119117
area.find('input').simulate('blur');
118+
await tick();
119+
area.update();
120120
expect(area.find('div').text()).toBe('Not passed');
121121
})
122122

@@ -288,7 +288,7 @@ describe('test ValidatorProvider', () => {
288288
expect(mockFn).toHaveBeenCalled();
289289
});
290290

291-
it('should use validation name when provided', () => {
291+
it('should use validation name when provided', async () => {
292292
Validator.extend('passes_not', {
293293
passed(): boolean {
294294
return false;
@@ -305,6 +305,20 @@ describe('test ValidatorProvider', () => {
305305
);
306306

307307
area.find('input').at(0).simulate('blur');
308+
await tick();
308309
expect(area.state().errors[0]).toBe('Foo not passed');
309310
});
311+
312+
it('should log error when error occured', async () => {
313+
const logFn = jest.spyOn(console, 'error');
314+
const area = mount(
315+
<ValidatorArea rules="min:foo">
316+
<input name="test" value="test" />
317+
</ValidatorArea>
318+
);
319+
320+
area.find('input').at(0).simulate('blur');
321+
await tick();
322+
expect(logFn).toHaveBeenCalled();
323+
})
310324
})

__tests__/Provider.test.tsx renamed to __tests__/suits/Provider.test.tsx

+1-7
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,7 @@ import { mount } from 'enzyme';
33
import { Validator } from '@/Validator';
44
import ValidatorProvider, { ValidatorProviderProps } from '@/components/ValidatorProvider';
55
import { ValidatorArea } from '@/components/ValidatorArea';
6-
7-
8-
const tick = () => {
9-
return new Promise(resolve => {
10-
setTimeout(resolve, 0);
11-
})
12-
}
6+
import tick from '../common/tick';
137

148
describe('test ValidatorProvider', () => {
159
beforeEach(() => {

__tests__/Validator.test.tsx renamed to __tests__/suits/Validator.test.tsx

+18-25
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Rule } from '../src/Rule';
1+
import { Rule } from '@/Rule';
22
import { Validator } from '@/Validator';
33

44
describe('test validator', () => {
@@ -46,7 +46,7 @@ describe('test validator', () => {
4646
expect(Validator.ruleExists('testRule')).toBeTruthy();
4747
});
4848

49-
it('should validate rules as string', () => {
49+
it('should validate rules as string', async () => {
5050
const input = document.createElement<'input'>('input');
5151
input.value = 'test';
5252

@@ -58,11 +58,11 @@ describe('test validator', () => {
5858
'test'
5959
);
6060

61-
validator.validate();
61+
await validator.validate();
6262
expect(validator.getErrors().length).toBe(2);
6363
});
6464

65-
it('should validate rules as array', () => {
65+
it('should validate rules as array', async (): Promise<void> => {
6666
const input = document.createElement<'input'>('input');
6767
input.value = 'test';
6868
const validator = new Validator(
@@ -73,11 +73,11 @@ describe('test validator', () => {
7373
'test'
7474
);
7575

76-
validator.validate();
76+
await validator.validate();
7777
expect(validator.getErrors().length).toBe(2);
7878
});
7979

80-
it('should validate with parameters', () => {
80+
it('should validate with parameters', async (): Promise<void> => {
8181
const input = document.createElement<'input'>('input');
8282
input.value = 'test';
8383

@@ -89,25 +89,22 @@ describe('test validator', () => {
8989
'test'
9090
);
9191

92-
validator.validate();
92+
await validator.validate();
9393
expect(validator.getErrors()[0]).toBe('Rule params not passed: 1, 2, 3, 4');
9494
});
9595

96-
it('throws an exception when rule is not found', () => {
96+
it('throws an exception when rule is not found', async (): Promise<void> => {
9797
const input = document.createElement<'input'>('input');
9898
input.value = 'test';
99-
const throws = () => {
100-
const validator = new Validator(
101-
[
102-
input
103-
],
104-
['not_existing_rule'],
105-
'test'
106-
);
107-
validator.validate();
108-
}
99+
const validator = new Validator(
100+
[
101+
input
102+
],
103+
['not_existing_rule'],
104+
'test'
105+
);
109106

110-
expect(() => throws()).toThrowError('Validation rule not_existing_rule not found.');
107+
await expect(validator.validate()).rejects.toThrowError('Validation rule not_existing_rule not found.');
111108
});
112109

113110
it('should merge rules', () => {
@@ -130,7 +127,7 @@ describe('test validator', () => {
130127
expect(() => throws()).toThrowError('Areas are only available when validating React components.')
131128
});
132129

133-
it('should be able to check if the value is required', () => {
130+
it('should be able to check if the value is required', async () => {
134131
const input = document.createElement<'input'>('input');
135132
input.value = 'test';
136133
Validator.extend('check_if_required', (validator: Validator) => ({
@@ -150,12 +147,8 @@ describe('test validator', () => {
150147
'test'
151148
);
152149

153-
validator.validate();
150+
await validator.validate();
154151

155152
expect(validator.getErrors()[0]).toBe('Value is false negative required');
156153
})
157-
158-
it('should return empty array when no refs provided', () => {
159-
160-
})
161154
});
+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { Validator } from '@/Validator';
2+
import activeUrl from '@/rules/activeUrl';
3+
import fetchMock from 'jest-fetch-mock';
4+
5+
describe('test activeUrl rule', () => {
6+
beforeEach(() => {
7+
Validator.extend('active_url', activeUrl);
8+
fetchMock.mockResponse((req: Request) => {
9+
if (req.url === 'https://example.com/success') {
10+
return Promise.resolve({ status: 200 });
11+
} else {
12+
return Promise.resolve({ status: 404 });
13+
}
14+
})
15+
});
16+
17+
it('should always validate inputs and not validate non-inputs', async () => {
18+
const input = document.createElement('input');
19+
input.value = 'https://example.com'
20+
const canvas = document.createElement('canvas');
21+
22+
const validator_input = new Validator([
23+
input
24+
],
25+
['active_url'],
26+
'');
27+
28+
const validator_canvas = new Validator([
29+
canvas
30+
],
31+
['active_url'],
32+
'');
33+
34+
await validator_input.validate();
35+
expect(validator_input.getErrors().length).toBe(1);
36+
37+
await validator_canvas.validate();
38+
expect(validator_canvas.getErrors().length).toBe(0);
39+
});
40+
});

__tests__/rules/max.test.tsx renamed to __tests__/suits/rules/max.test.tsx

+10-12
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@ import { mount } from 'enzyme';
33
import max from '@/rules/max';
44
import { Validator } from '@/Validator';
55
import { ValidatorArea, ValidatorAreaProps } from '@/components/ValidatorArea';
6+
import tick from '../../common/tick';
67
import { IncorrectArgumentTypeError } from '@/rules';
78

89
describe('test max rule', () => {
910
beforeEach(() => {
1011
Validator.extend('max', max);
1112
});
1213

13-
it('should always validate inputs and not validate non-inputs', () => {
14+
it('should always validate inputs and not validate non-inputs', async () => {
1415
const input = document.createElement('input');
1516
const meter = document.createElement('meter');
1617
const output = document.createElement('output');
@@ -58,29 +59,25 @@ describe('test max rule', () => {
5859
['max:foo'],
5960
'');
6061

61-
validator_input.validate();
62+
await validator_input.validate();
6263
expect(validator_input.getErrors().length).toBe(1);
6364

64-
validator_meter.validate();
65+
await validator_meter.validate();
6566
expect(validator_meter.getErrors().length).toBe(1);
6667

67-
validator_output.validate();
68+
await validator_output.validate();
6869
expect(validator_output.getErrors().length).toBe(1);
6970

70-
validator_progress.validate();
71+
await validator_progress.validate();
7172
expect(validator_progress.getErrors().length).toBe(1);
7273

73-
validator_canvas.validate();
74+
await validator_canvas.validate();
7475
expect(validator_canvas.getErrors().length).toBe(0);
7576

76-
const throwsInvalidArgument = () => {
77-
validator_wrong_arg.validate();
78-
}
79-
80-
expect(() => throwsInvalidArgument()).toThrowError(IncorrectArgumentTypeError);
77+
await expect( validator_wrong_arg.validate()).rejects.toBeInstanceOf(IncorrectArgumentTypeError);
8178
});
8279

83-
it('should validate select', () => {
80+
it('should validate select', async () => {
8481
const area = mount<ValidatorArea, ValidatorAreaProps>(
8582
<ValidatorArea rules="max:3">
8683
<select name="test">
@@ -90,6 +87,7 @@ describe('test max rule', () => {
9087
);
9188

9289
area.find('select').simulate('blur');
90+
await tick();
9391
expect(area.state().errors.length).toBe(1);
9492
});
9593
});

__tests__/rules/min.test.tsx renamed to __tests__/suits/rules/min.test.tsx

+10-12
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@ import { Validator } from '@/Validator';
33
import { mount } from 'enzyme';
44
import { ValidatorArea, ValidatorAreaProps } from '@/components/ValidatorArea';
55
import React from 'react';
6+
import tick from '../../common/tick';
67
import { IncorrectArgumentTypeError } from '@/rules';
78

89
describe('test min rule', () => {
910
beforeEach(() => {
1011
Validator.extend('min', min);
1112
});
1213

13-
it('should always validate inputs and not validate non-inputs', () => {
14+
it('should always validate inputs and not validate non-inputs', async () => {
1415
const input = document.createElement('input');
1516
const meter = document.createElement('meter');
1617
const output = document.createElement('output');
@@ -58,29 +59,25 @@ describe('test min rule', () => {
5859
['min:foo'],
5960
'');
6061

61-
validator_input.validate();
62+
await validator_input.validate();
6263
expect(validator_input.getErrors().length).toBe(1);
6364

64-
validator_meter.validate();
65+
await validator_meter.validate();
6566
expect(validator_meter.getErrors().length).toBe(1);
6667

67-
validator_output.validate();
68+
await validator_output.validate();
6869
expect(validator_output.getErrors().length).toBe(1);
6970

70-
validator_progress.validate();
71+
await validator_progress.validate();
7172
expect(validator_progress.getErrors().length).toBe(1);
7273

73-
validator_canvas.validate();
74+
await validator_canvas.validate();
7475
expect(validator_canvas.getErrors().length).toBe(0);
7576

76-
const throwsInvalidArgument = () => {
77-
validator_wrong_arg.validate();
78-
}
79-
80-
expect(() => throwsInvalidArgument()).toThrowError(IncorrectArgumentTypeError);
77+
await expect( validator_wrong_arg.validate()).rejects.toBeInstanceOf(IncorrectArgumentTypeError);
8178
});
8279

83-
it('should validate select', () => {
80+
it('should validate select', async () => {
8481
const area = mount<ValidatorArea, ValidatorAreaProps>(
8582
<ValidatorArea rules="min:5">
8683
<select name="test">
@@ -90,6 +87,7 @@ describe('test min rule', () => {
9087
);
9188

9289
area.find('select').simulate('blur');
90+
await tick();
9391
expect(area.state().errors.length).toBe(1);
9492
});
9593
});

0 commit comments

Comments
 (0)