Skip to content

Feature/flags #27

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Feb 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 136 additions & 32 deletions __tests__/suits/Area.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,30 @@ describe('test ValidatorProvider', () => {
return 'not passed';
}
});
Validator.extend('required', required)
Validator.extend('required', required);

Validator.extend('long_wait', {
async passed(): Promise<boolean> {
return new Promise((resolve: (value: boolean) => void): void => {
setTimeout(() => {
resolve(true);
}, 100);
})
},
message(): string {
return 'test';
}
});
});

afterEach(() => {
jest.useRealTimers();
});

it('should render input', () => {
const area = mount<ValidatorArea, ValidatorAreaProps>(
<ValidatorArea>
<input name="test" />
<input name="test"/>
</ValidatorArea>
);

Expand All @@ -34,7 +51,7 @@ describe('test ValidatorProvider', () => {
const area = mount<ValidatorArea, ValidatorAreaProps>(
<ValidatorArea>
{() => (
<input name="test" />
<input name="test"/>
)}
</ValidatorArea>
);
Expand Down Expand Up @@ -65,8 +82,8 @@ describe('test ValidatorProvider', () => {
<>
<><input/></>
<div>
<input />
<input />
<input/>
<input/>
<><input/></>
</div>
</>
Expand All @@ -80,7 +97,7 @@ describe('test ValidatorProvider', () => {
it('should apply rules on blur', async () => {
const area = mount<ValidatorArea, ValidatorAreaProps>(
<ValidatorArea rules="passes_not">
<input name="test" value="test" />
<input name="test" value="test"/>
</ValidatorArea>
);

Expand All @@ -92,7 +109,7 @@ describe('test ValidatorProvider', () => {
it('should not apply rules on blur when non-blurrable element', () => {
const area = mount<ValidatorArea, ValidatorAreaProps>(
<ValidatorArea rules="passes_not" name="test">
<canvas />
<canvas/>
</ValidatorArea>
);

Expand All @@ -103,10 +120,10 @@ describe('test ValidatorProvider', () => {
it('should render error when area dirty', async () => {
const area = mount<ValidatorArea, ValidatorAreaProps>(
<ValidatorArea rules="passes_not">
{({ errors }) => {
{({errors}) => {
return (
<>
<input name="test" value="test" />
<input name="test" value="test"/>
{!!errors.length && <div>{errors[0]}</div>}
</>
);
Expand All @@ -125,14 +142,27 @@ describe('test ValidatorProvider', () => {

const area = mount<ValidatorArea, ValidatorAreaProps>(
<ValidatorArea rules="passes_not">
<input name="test" onBlur={mockFn} value="test" />
<input name="test" onBlur={mockFn} value="test"/>
</ValidatorArea>
);

area.find('input').simulate('blur');
expect(mockFn).toBeCalled();
});

it('should call element\'s provided onChange along validator onChange', () => {
const mockFn = jest.fn();

const area = mount<ValidatorArea, ValidatorAreaProps>(
<ValidatorArea rules="passes_not">
<input name="test" onChange={mockFn} value="test"/>
</ValidatorArea>
);

area.find('input').simulate('change');
expect(mockFn).toBeCalled();
});

it('should get all input refs from the provider', async () => {
Validator.extend('test_all', (validator: Validator) => ({
passed(): boolean {
Expand All @@ -146,15 +176,15 @@ describe('test ValidatorProvider', () => {

const provider = mount<ValidatorProvider, ValidatorProviderProps>(
<ValidatorProvider rules="test_all">
{({ validate }: ProviderScope) => (
{({validate}: ProviderScope) => (
<>
<ValidatorArea name="test1">
<input value="test" />
<input value="test"/>
</ValidatorArea>
<ValidatorArea>
<input value="test" name="test2" />
<input value="test" name="test2"/>
</ValidatorArea>
<button onClick={() => validate(mockFn)} />
<button onClick={() => validate(mockFn)}/>
</>
)}
</ValidatorProvider>
Expand All @@ -169,7 +199,7 @@ describe('test ValidatorProvider', () => {
Validator.extend('test_specific', (validator: Validator) => ({
passed(): boolean {
return validator.refs('test1').length === 2
&& validator.refs('test2').length === 1;
&& validator.refs('test2').length === 1;
},
message(): string {
return 'test';
Expand All @@ -179,16 +209,16 @@ describe('test ValidatorProvider', () => {

const provider = mount<ValidatorProvider, ValidatorProviderProps>(
<ValidatorProvider rules="test_specific">
{({ validate }: ProviderScope) => (
{({validate}: ProviderScope) => (
<>
<ValidatorArea name="test1">
<input value="test" />
<input value="test" />
<input value="test"/>
<input value="test"/>
</ValidatorArea>
<ValidatorArea>
<input value="test" name="test2" />
<input value="test" name="test2"/>
</ValidatorArea>
<button onClick={() => validate(mockFn)} />
<button onClick={() => validate(mockFn)}/>
</>
)}
</ValidatorProvider>
Expand All @@ -212,15 +242,15 @@ describe('test ValidatorProvider', () => {

const provider = mount<ValidatorProvider, ValidatorProviderProps>(
<ValidatorProvider rules="test_not_existing">
{({ validate }: ProviderScope) => (
{({validate}: ProviderScope) => (
<>
<ValidatorArea name="test1">
<input value="test" />
<input value="test"/>
</ValidatorArea>
<ValidatorArea>
<input value="test" name="test2" />
<input value="test" name="test2"/>
</ValidatorArea>
<button onClick={() => validate(mockFn)} />
<button onClick={() => validate(mockFn)}/>
</>
)}
</ValidatorProvider>
Expand All @@ -245,7 +275,7 @@ describe('test ValidatorProvider', () => {

const area = mount<ValidatorArea, ValidatorAreaProps>(
<ValidatorArea rules="no_other_areas">
<input name="test" value="test" onBlur={mockFn} />
<input name="test" value="test" onBlur={mockFn}/>
</ValidatorArea>
);

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

const provider = mount<ValidatorProvider, ValidatorProviderProps>(
<ValidatorProvider rules="test_types">
{({ validate }: ProviderScope) => (
{({validate}: ProviderScope) => (
<>
<ValidatorArea name="test1">
<textarea value="test" />
<textarea value="test"/>
</ValidatorArea>
<ValidatorArea>
<input value="test" name="test2" />
<input value="test" name="test2"/>
</ValidatorArea>
<button onClick={() => validate(mockFn)} />
<button onClick={() => validate(mockFn)}/>
</>
)}
</ValidatorProvider>
Expand All @@ -300,7 +330,7 @@ describe('test ValidatorProvider', () => {

const area = mount<ValidatorArea, ValidatorAreaProps>(
<ValidatorArea validationName="Foo" rules="passes_not">
<input name="test" value="test" />
<input name="test" value="test"/>
</ValidatorArea>
);

Expand All @@ -313,12 +343,86 @@ describe('test ValidatorProvider', () => {
const logFn = jest.spyOn(console, 'error');
const area = mount(
<ValidatorArea rules="min:foo">
<input name="test" value="test" />
<input name="test" value="test"/>
</ValidatorArea>
);

area.find('input').at(0).simulate('blur');
await tick();
expect(logFn).toHaveBeenCalled();
})
});

it('should indicate whether the area is valid', async () => {
const area = mount(
<ValidatorArea rules="required">
{({valid}) => (
<>
<input name="test" value=""/>
<div>{valid ? 'yes' : 'no'}</div>
</>
)}
</ValidatorArea>
);

area.find('input').at(0).simulate('blur');
await tick();
expect(area.find('div').text()).toBe('no');
});

it('should indicate pending while validation is ongoing', async () => {
jest.useFakeTimers();

const area = mount(
<ValidatorArea rules="long_wait">
{({pending}) => (
<>
<input name="test" value=""/>
<div>{pending ? 'yes' : 'no'}</div>
</>
)}
</ValidatorArea>
);

area.find('input').at(0).simulate('blur');
jest.advanceTimersByTime(90);
expect(area.find('div').text()).toBe('yes');
await Promise.resolve();
jest.advanceTimersByTime(10);
await Promise.resolve();
expect(area.find('div').text()).toBe('no');
});

it('should indicate dirty when input changed', async () => {
const area = mount(
<ValidatorArea>
{({dirty}) => (
<>
<input name="test" value=""/>
<div>{dirty ? 'yes' : 'no'}</div>
</>
)}
</ValidatorArea>
);

area.find('input').at(0).simulate('change', { target: { value: 'a' } });
await tick();
expect(area.find('div').text()).toBe('yes')
});

it('should indicate touched when input blurred', async () => {
const area = mount(
<ValidatorArea rules="long_wait">
{({touched}) => (
<>
<input name="test" value=""/>
<div>{touched ? 'yes' : 'no'}</div>
</>
)}
</ValidatorArea>
);

area.find('input').at(0).simulate('blur');
await tick();
expect(area.find('div').text()).toBe('yes')
});
})
20 changes: 20 additions & 0 deletions __tests__/suits/Provider.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,24 @@ describe('test ValidatorProvider', () => {
await tick();
expect(mockFn).toHaveBeenCalled()
});

it('should indicate whether the area is dirty', async () => {
const provider = mount<ValidatorProvider, ValidatorProviderProps>(
<ValidatorProvider>
{({ dirty }) => (
<>
<ValidatorArea name="test1" rules="required">
<input value="1" />
</ValidatorArea>
<div>{dirty ? 'yes' : 'no'}</div>
</>
)}
</ValidatorProvider>
);

provider.find('input').at(0).simulate('blur');
await tick();
expect(provider.find('div').text()).toBe('no');

})
})
16 changes: 16 additions & 0 deletions src/AreaScope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,20 @@ export interface AreaScope {
* The errors after validating the area
*/
errors: string[];
/**
* Flag indicating the area is dirty
*/
valid: boolean;
/**
* Flag indicating the area has a pending validation
*/
pending: boolean;
/**
* Flag indicating the area was changed since the last valid or initial value
*/
dirty: boolean;
/**
* Flag indicating the area was touched since the last valid or initial value
*/
touched: boolean;
}
4 changes: 4 additions & 0 deletions src/ProviderScope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,8 @@ export interface ProviderScope {
* Validate all areas in the provider and call callback when valid
*/
validate: (onValidated?: () => void) => Promise<void>;
/**
* Flag indicating one or more areas is invalid
*/
valid: boolean;
}
Loading