Skip to content

Commit 1a1bd84

Browse files
authored
Merge 1461370 into e8c26a5
2 parents e8c26a5 + 1461370 commit 1a1bd84

File tree

6 files changed

+255
-64
lines changed

6 files changed

+255
-64
lines changed

__tests__/suits/Area.test.tsx

Lines changed: 136 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,30 @@ describe('test ValidatorProvider', () => {
1717
return 'not passed';
1818
}
1919
});
20-
Validator.extend('required', required)
20+
Validator.extend('required', required);
21+
22+
Validator.extend('long_wait', {
23+
async passed(): Promise<boolean> {
24+
return new Promise((resolve: (value: boolean) => void): void => {
25+
setTimeout(() => {
26+
resolve(true);
27+
}, 100);
28+
})
29+
},
30+
message(): string {
31+
return 'test';
32+
}
33+
});
34+
});
35+
36+
afterEach(() => {
37+
jest.useRealTimers();
2138
});
2239

2340
it('should render input', () => {
2441
const area = mount<ValidatorArea, ValidatorAreaProps>(
2542
<ValidatorArea>
26-
<input name="test" />
43+
<input name="test"/>
2744
</ValidatorArea>
2845
);
2946

@@ -34,7 +51,7 @@ describe('test ValidatorProvider', () => {
3451
const area = mount<ValidatorArea, ValidatorAreaProps>(
3552
<ValidatorArea>
3653
{() => (
37-
<input name="test" />
54+
<input name="test"/>
3855
)}
3956
</ValidatorArea>
4057
);
@@ -65,8 +82,8 @@ describe('test ValidatorProvider', () => {
6582
<>
6683
<><input/></>
6784
<div>
68-
<input />
69-
<input />
85+
<input/>
86+
<input/>
7087
<><input/></>
7188
</div>
7289
</>
@@ -80,7 +97,7 @@ describe('test ValidatorProvider', () => {
8097
it('should apply rules on blur', async () => {
8198
const area = mount<ValidatorArea, ValidatorAreaProps>(
8299
<ValidatorArea rules="passes_not">
83-
<input name="test" value="test" />
100+
<input name="test" value="test"/>
84101
</ValidatorArea>
85102
);
86103

@@ -92,7 +109,7 @@ describe('test ValidatorProvider', () => {
92109
it('should not apply rules on blur when non-blurrable element', () => {
93110
const area = mount<ValidatorArea, ValidatorAreaProps>(
94111
<ValidatorArea rules="passes_not" name="test">
95-
<canvas />
112+
<canvas/>
96113
</ValidatorArea>
97114
);
98115

@@ -103,10 +120,10 @@ describe('test ValidatorProvider', () => {
103120
it('should render error when area dirty', async () => {
104121
const area = mount<ValidatorArea, ValidatorAreaProps>(
105122
<ValidatorArea rules="passes_not">
106-
{({ errors }) => {
123+
{({errors}) => {
107124
return (
108125
<>
109-
<input name="test" value="test" />
126+
<input name="test" value="test"/>
110127
{!!errors.length && <div>{errors[0]}</div>}
111128
</>
112129
);
@@ -125,14 +142,27 @@ describe('test ValidatorProvider', () => {
125142

126143
const area = mount<ValidatorArea, ValidatorAreaProps>(
127144
<ValidatorArea rules="passes_not">
128-
<input name="test" onBlur={mockFn} value="test" />
145+
<input name="test" onBlur={mockFn} value="test"/>
129146
</ValidatorArea>
130147
);
131148

132149
area.find('input').simulate('blur');
133150
expect(mockFn).toBeCalled();
134151
});
135152

153+
it('should call element\'s provided onChange along validator onChange', () => {
154+
const mockFn = jest.fn();
155+
156+
const area = mount<ValidatorArea, ValidatorAreaProps>(
157+
<ValidatorArea rules="passes_not">
158+
<input name="test" onChange={mockFn} value="test"/>
159+
</ValidatorArea>
160+
);
161+
162+
area.find('input').simulate('change');
163+
expect(mockFn).toBeCalled();
164+
});
165+
136166
it('should get all input refs from the provider', async () => {
137167
Validator.extend('test_all', (validator: Validator) => ({
138168
passed(): boolean {
@@ -146,15 +176,15 @@ describe('test ValidatorProvider', () => {
146176

147177
const provider = mount<ValidatorProvider, ValidatorProviderProps>(
148178
<ValidatorProvider rules="test_all">
149-
{({ validate }: ProviderScope) => (
179+
{({validate}: ProviderScope) => (
150180
<>
151181
<ValidatorArea name="test1">
152-
<input value="test" />
182+
<input value="test"/>
153183
</ValidatorArea>
154184
<ValidatorArea>
155-
<input value="test" name="test2" />
185+
<input value="test" name="test2"/>
156186
</ValidatorArea>
157-
<button onClick={() => validate(mockFn)} />
187+
<button onClick={() => validate(mockFn)}/>
158188
</>
159189
)}
160190
</ValidatorProvider>
@@ -169,7 +199,7 @@ describe('test ValidatorProvider', () => {
169199
Validator.extend('test_specific', (validator: Validator) => ({
170200
passed(): boolean {
171201
return validator.refs('test1').length === 2
172-
&& validator.refs('test2').length === 1;
202+
&& validator.refs('test2').length === 1;
173203
},
174204
message(): string {
175205
return 'test';
@@ -179,16 +209,16 @@ describe('test ValidatorProvider', () => {
179209

180210
const provider = mount<ValidatorProvider, ValidatorProviderProps>(
181211
<ValidatorProvider rules="test_specific">
182-
{({ validate }: ProviderScope) => (
212+
{({validate}: ProviderScope) => (
183213
<>
184214
<ValidatorArea name="test1">
185-
<input value="test" />
186-
<input value="test" />
215+
<input value="test"/>
216+
<input value="test"/>
187217
</ValidatorArea>
188218
<ValidatorArea>
189-
<input value="test" name="test2" />
219+
<input value="test" name="test2"/>
190220
</ValidatorArea>
191-
<button onClick={() => validate(mockFn)} />
221+
<button onClick={() => validate(mockFn)}/>
192222
</>
193223
)}
194224
</ValidatorProvider>
@@ -212,15 +242,15 @@ describe('test ValidatorProvider', () => {
212242

213243
const provider = mount<ValidatorProvider, ValidatorProviderProps>(
214244
<ValidatorProvider rules="test_not_existing">
215-
{({ validate }: ProviderScope) => (
245+
{({validate}: ProviderScope) => (
216246
<>
217247
<ValidatorArea name="test1">
218-
<input value="test" />
248+
<input value="test"/>
219249
</ValidatorArea>
220250
<ValidatorArea>
221-
<input value="test" name="test2" />
251+
<input value="test" name="test2"/>
222252
</ValidatorArea>
223-
<button onClick={() => validate(mockFn)} />
253+
<button onClick={() => validate(mockFn)}/>
224254
</>
225255
)}
226256
</ValidatorProvider>
@@ -245,7 +275,7 @@ describe('test ValidatorProvider', () => {
245275

246276
const area = mount<ValidatorArea, ValidatorAreaProps>(
247277
<ValidatorArea rules="no_other_areas">
248-
<input name="test" value="test" onBlur={mockFn} />
278+
<input name="test" value="test" onBlur={mockFn}/>
249279
</ValidatorArea>
250280
);
251281

@@ -269,15 +299,15 @@ describe('test ValidatorProvider', () => {
269299

270300
const provider = mount<ValidatorProvider, ValidatorProviderProps>(
271301
<ValidatorProvider rules="test_types">
272-
{({ validate }: ProviderScope) => (
302+
{({validate}: ProviderScope) => (
273303
<>
274304
<ValidatorArea name="test1">
275-
<textarea value="test" />
305+
<textarea value="test"/>
276306
</ValidatorArea>
277307
<ValidatorArea>
278-
<input value="test" name="test2" />
308+
<input value="test" name="test2"/>
279309
</ValidatorArea>
280-
<button onClick={() => validate(mockFn)} />
310+
<button onClick={() => validate(mockFn)}/>
281311
</>
282312
)}
283313
</ValidatorProvider>
@@ -300,7 +330,7 @@ describe('test ValidatorProvider', () => {
300330

301331
const area = mount<ValidatorArea, ValidatorAreaProps>(
302332
<ValidatorArea validationName="Foo" rules="passes_not">
303-
<input name="test" value="test" />
333+
<input name="test" value="test"/>
304334
</ValidatorArea>
305335
);
306336

@@ -313,12 +343,86 @@ describe('test ValidatorProvider', () => {
313343
const logFn = jest.spyOn(console, 'error');
314344
const area = mount(
315345
<ValidatorArea rules="min:foo">
316-
<input name="test" value="test" />
346+
<input name="test" value="test"/>
317347
</ValidatorArea>
318348
);
319349

320350
area.find('input').at(0).simulate('blur');
321351
await tick();
322352
expect(logFn).toHaveBeenCalled();
323-
})
353+
});
354+
355+
it('should indicate whether the area is valid', async () => {
356+
const area = mount(
357+
<ValidatorArea rules="required">
358+
{({valid}) => (
359+
<>
360+
<input name="test" value=""/>
361+
<div>{valid ? 'yes' : 'no'}</div>
362+
</>
363+
)}
364+
</ValidatorArea>
365+
);
366+
367+
area.find('input').at(0).simulate('blur');
368+
await tick();
369+
expect(area.find('div').text()).toBe('no');
370+
});
371+
372+
it('should indicate pending while validation is ongoing', async () => {
373+
jest.useFakeTimers();
374+
375+
const area = mount(
376+
<ValidatorArea rules="long_wait">
377+
{({pending}) => (
378+
<>
379+
<input name="test" value=""/>
380+
<div>{pending ? 'yes' : 'no'}</div>
381+
</>
382+
)}
383+
</ValidatorArea>
384+
);
385+
386+
area.find('input').at(0).simulate('blur');
387+
jest.advanceTimersByTime(90);
388+
expect(area.find('div').text()).toBe('yes');
389+
await Promise.resolve();
390+
jest.advanceTimersByTime(10);
391+
await Promise.resolve();
392+
expect(area.find('div').text()).toBe('no');
393+
});
394+
395+
it('should indicate dirty when input changed', async () => {
396+
const area = mount(
397+
<ValidatorArea>
398+
{({dirty}) => (
399+
<>
400+
<input name="test" value=""/>
401+
<div>{dirty ? 'yes' : 'no'}</div>
402+
</>
403+
)}
404+
</ValidatorArea>
405+
);
406+
407+
area.find('input').at(0).simulate('change', { target: { value: 'a' } });
408+
await tick();
409+
expect(area.find('div').text()).toBe('yes')
410+
});
411+
412+
it('should indicate touched when input blurred', async () => {
413+
const area = mount(
414+
<ValidatorArea rules="long_wait">
415+
{({touched}) => (
416+
<>
417+
<input name="test" value=""/>
418+
<div>{touched ? 'yes' : 'no'}</div>
419+
</>
420+
)}
421+
</ValidatorArea>
422+
);
423+
424+
area.find('input').at(0).simulate('blur');
425+
await tick();
426+
expect(area.find('div').text()).toBe('yes')
427+
});
324428
})

__tests__/suits/Provider.test.tsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,4 +142,24 @@ describe('test ValidatorProvider', () => {
142142
await tick();
143143
expect(mockFn).toHaveBeenCalled()
144144
});
145+
146+
it('should indicate whether the area is dirty', async () => {
147+
const provider = mount<ValidatorProvider, ValidatorProviderProps>(
148+
<ValidatorProvider>
149+
{({ dirty }) => (
150+
<>
151+
<ValidatorArea name="test1" rules="required">
152+
<input value="1" />
153+
</ValidatorArea>
154+
<div>{dirty ? 'yes' : 'no'}</div>
155+
</>
156+
)}
157+
</ValidatorProvider>
158+
);
159+
160+
provider.find('input').at(0).simulate('blur');
161+
await tick();
162+
expect(provider.find('div').text()).toBe('no');
163+
164+
})
145165
})

src/AreaScope.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,20 @@ export interface AreaScope {
33
* The errors after validating the area
44
*/
55
errors: string[];
6+
/**
7+
* Flag indicating the area is dirty
8+
*/
9+
valid: boolean;
10+
/**
11+
* Flag indicating the area has a pending validation
12+
*/
13+
pending: boolean;
14+
/**
15+
* Flag indicating the area was changed since the last valid or initial value
16+
*/
17+
dirty: boolean;
18+
/**
19+
* Flag indicating the area was touched since the last valid or initial value
20+
*/
21+
touched: boolean;
622
}

src/ProviderScope.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,8 @@ export interface ProviderScope {
33
* Validate all areas in the provider and call callback when valid
44
*/
55
validate: (onValidated?: () => void) => Promise<void>;
6+
/**
7+
* Flag indicating one or more areas is invalid
8+
*/
9+
valid: boolean;
610
}

0 commit comments

Comments
 (0)