Skip to content

Commit

Permalink
Merge branch 'master' into feature/use-field-array-support-multiple-r…
Browse files Browse the repository at this point in the history
…emove-index
  • Loading branch information
bluebill1049 committed Feb 7, 2020
2 parents 32ddf5c + 872805e commit 7100156
Show file tree
Hide file tree
Showing 46 changed files with 689 additions and 191 deletions.
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -39,7 +39,7 @@
- [Tiny size](https://bundlephobia.com/result?p=react-hook-form@latest) without any dependency
- Follows HTML standard for validation
- Compatible with React Native
- Supports [Yup](https://github.com/jquense/yup) schema-based validation
- Supports [Yup](https://github.com/jquense/yup), [Joi](https://github.com/hapijs/joi), [Superstruct](https://github.com/ianstormtaylor/superstruct) or custom
- Supports native browser validation
- Build forms quickly with the [form builder](https://react-hook-form.com/form-builder)

Expand Down
2 changes: 2 additions & 0 deletions app/package.json
Expand Up @@ -3,7 +3,9 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@hapi/joi": "^17.1.0",
"@material-ui/core": "^4.8.0",
"@types/hapi__joi": "^16.0.9",
"@types/jest": "24.0.24",
"@types/node": "12.12.21",
"@types/react": "16.9.17",
Expand Down
6 changes: 6 additions & 0 deletions app/src/app.tsx
Expand Up @@ -21,6 +21,7 @@ import SetValueWithTrigger from './setValueWithTrigger';
import IsValid from './isValid';
import Controller from './controller';
import UseFieldArray from './useFieldArray';
import CustomSchemaValidation from './customSchemaValidation';

const App: React.FC = () => {
return (
Expand Down Expand Up @@ -78,6 +79,11 @@ const App: React.FC = () => {
exact
component={WatchDefaultValues}
/>
<Route
path="/customSchemaValidation/:mode"
exact
component={CustomSchemaValidation}
/>
</Router>
);
};
Expand Down
115 changes: 115 additions & 0 deletions app/src/customSchemaValidation.tsx
@@ -0,0 +1,115 @@
import React from 'react';
import { useForm } from 'react-hook-form';
import Joi from '@hapi/joi';

let renderCounter = 0;

const validationSchema = Joi.object({
firstName: Joi.string().required(),
lastName: Joi.string()
.max(5)
.required(),
min: Joi.number()
.min(10)
.required(),
max: Joi.number()
.max(20)
.required(),
minDate: Joi.date().min('2019-08-01'),
maxDate: Joi.date().max('2019-08-01'),
minLength: Joi.string().min(2),
minRequiredLength: Joi.string().required(),
selectNumber: Joi.string().required(),
pattern: Joi.string().required(),
radio: Joi.string().required(),
checkbox: Joi.required(),
});

const validationResolver = (data: any) => {
const { error, value: values } = validationSchema.validate(data, {
abortEarly: false,
});

return {
values: error ? {} : values,
errors: error
? error.details.reduce((previous, currentError) => {
return {
...previous,
[currentError.path[0]]: currentError,
};
}, {})
: {},
};
};

const BasicSchemaValidation: React.FC = (props: any) => {
const { register, handleSubmit, errors } = useForm<{
firstName: string;
lastName: string;
min: string;
max: string;
minDate: string;
maxDate: string;
minLength: string;
minRequiredLength: string;
selectNumber: string;
pattern: string;
radio: string;
checkbox: string;
multiple: string;
validate: string;
}>({
validationResolver,
mode: props.match.params.mode,
});
const onSubmit = () => {};

renderCounter++;

return (
<form onSubmit={handleSubmit(onSubmit)}>
<input name="firstName" ref={register} placeholder="firstName" />
{errors.firstName && <p>firstName error</p>}
<input name="lastName" ref={register} placeholder="lastName" />
{errors.lastName && <p>lastName error</p>}
<input type="number" name="min" ref={register} placeholder="min" />
{errors.min && <p>min error</p>}
<input type="number" name="max" ref={register} placeholder="max" />
{errors.max && <p>max error</p>}
<input type="date" name="minDate" ref={register} placeholder="minDate" />
{errors.minDate && <p>minDate error</p>}
<input type="date" name="maxDate" ref={register} placeholder="maxDate" />
{errors.maxDate && <p>maxDate error</p>}
<input name="minLength" ref={register} placeholder="minLength" />
{errors.minLength && <p>minLength error</p>}
<input
name="minRequiredLength"
ref={register}
placeholder="minRequiredLength"
/>
{errors.minRequiredLength && <p>minRequiredLength error</p>}
<select name="selectNumber" ref={register}>
<option value="">Select</option>
<option value={1}>1</option>
<option value={2}>1</option>
</select>
{errors.selectNumber && <p>selectNumber error</p>}
<input name="pattern" ref={register} placeholder="pattern" />
{errors.pattern && <p>pattern error</p>}
Radio1
<input type="radio" name="radio" ref={register} value="1" />
Radio2
<input type="radio" name="radio" ref={register} value="2" />
Radio3
<input type="radio" name="radio" ref={register} value="3" />
{errors.radio && <p>radio error</p>}
<input type="checkbox" name="checkbox" ref={register} />
{errors.checkbox && <p>checkbox error</p>}
<button>Submit</button>
<div id="renderCount">{renderCounter}</div>
</form>
);
};

export default BasicSchemaValidation;
45 changes: 45 additions & 0 deletions app/yarn.lock
Expand Up @@ -1815,11 +1815,28 @@
resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.0.0.tgz#9f05469c88cb2fd3dcd624776b54ee95c312126a"
integrity sha512-mV6T0IYqb0xL1UALPFplXYQmR0twnXG0M6jUswpquqT2sD12BOiCiLy3EvMp/Fy7s3DZElC4/aPjEjo2jeZpvw==

"@hapi/address@^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@hapi/address/-/address-4.0.0.tgz#36affb4509b5a6adc628bcc394450f2a7d51d111"
integrity sha512-GDDpkCdSUfkQCznmWUHh9dDN85BWf/V8TFKQ2JLuHdGB4Yy3YTEGBzZxoBNxfNBEvreSR/o+ZxBBSNNEVzY+lQ==
dependencies:
"@hapi/hoek" "^9.0.0"

"@hapi/formula@^2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@hapi/formula/-/formula-2.0.0.tgz#edade0619ed58c8e4f164f233cda70211e787128"
integrity sha512-V87P8fv7PI0LH7LiVi8Lkf3x+KCO7pQozXRssAHNXXL9L1K+uyu4XypLXwxqVDKgyQai6qj3/KteNlrqDx4W5A==

"@hapi/hoek@6.x.x":
version "6.2.1"
resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-6.2.1.tgz#d3a66329159af879bfdf0b0cff2229c43c5a3451"
integrity sha512-+ryw4GU9pjr1uT6lBuErHJg3NYqzwJTvZ75nKuJijEzpd00Uqi6oiawTGDDf5Hl0zWmI7qHfOtaqB0kpQZJQzA==

"@hapi/hoek@^9.0.0":
version "9.0.2"
resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.0.2.tgz#57597083f763eafbfdc902d16ec868aa787b24d2"
integrity sha512-LyibKv2QnD9BPI5g2L+g85yiIPv3ajYpENGFgy4u0xCLPhXWG1Zdx29neSB8sgX0/wz6k5TMjHzTwJ6+DaBYOA==

"@hapi/joi@^15.0.0":
version "15.0.2"
resolved "https://registry.yarnpkg.com/@hapi/joi/-/joi-15.0.2.tgz#2989041a06ee2941cf6dd247ffff8032640d16bb"
Expand All @@ -1829,13 +1846,36 @@
"@hapi/hoek" "6.x.x"
"@hapi/topo" "3.x.x"

"@hapi/joi@^17.1.0":
version "17.1.0"
resolved "https://registry.yarnpkg.com/@hapi/joi/-/joi-17.1.0.tgz#cc4000b6c928a6a39b9bef092151b6bdee10ce55"
integrity sha512-ob67RcPlwRWxBzLCnWvcwx5qbwf88I3ykD7gcJLWOTRfLLgosK7r6aeChz4thA3XRvuBfI0KB1tPVl2EQFlPXw==
dependencies:
"@hapi/address" "^4.0.0"
"@hapi/formula" "^2.0.0"
"@hapi/hoek" "^9.0.0"
"@hapi/pinpoint" "^2.0.0"
"@hapi/topo" "^5.0.0"

"@hapi/pinpoint@^2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@hapi/pinpoint/-/pinpoint-2.0.0.tgz#805b40d4dbec04fc116a73089494e00f073de8df"
integrity sha512-vzXR5MY7n4XeIvLpfl3HtE3coZYO4raKXW766R6DZw/6aLqR26iuZ109K7a0NtF2Db0jxqh7xz2AxkUwpUFybw==

"@hapi/topo@3.x.x":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-3.1.0.tgz#5c47cd9637c2953db185aa957a27bcb2a8b7a6f8"
integrity sha512-gZDI/eXOIk8kP2PkUKjWu9RW8GGVd2Hkgjxyr/S7Z+JF+0mr7bAlbw+DkTRxnD580o8Kqxlnba9wvqp5aOHBww==
dependencies:
"@hapi/hoek" "6.x.x"

"@hapi/topo@^5.0.0":
version "5.0.0"
resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-5.0.0.tgz#c19af8577fa393a06e9c77b60995af959be721e7"
integrity sha512-tFJlT47db0kMqVm3H4nQYgn6Pwg10GTZHb1pwmSiv1K4ks6drQOtfEF5ZnPjkvC+y4/bUPHK+bc87QvLcL+WMw==
dependencies:
"@hapi/hoek" "^9.0.0"

"@jest/console@^24.7.1":
version "24.7.1"
resolved "https://registry.yarnpkg.com/@jest/console/-/console-24.7.1.tgz#32a9e42535a97aedfe037e725bd67e954b459545"
Expand Down Expand Up @@ -2264,6 +2304,11 @@
"@types/minimatch" "*"
"@types/node" "*"

"@types/hapi__joi@^16.0.9":
version "16.0.9"
resolved "https://registry.yarnpkg.com/@types/hapi__joi/-/hapi__joi-16.0.9.tgz#0ad11f9de3753748444ac16249a264fc7c798ab4"
integrity sha512-FV+rJxm4UBxBsRvT5hpiRvnxbpi9iJu4qdwXQvNXf6eXJkcgKGlTwHnstIDAxSTKTUMSmpJnyXpr6XI9X/4SjA==

"@types/history@*":
version "4.7.2"
resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.2.tgz#0e670ea254d559241b6eeb3894f8754991e73220"
Expand Down
161 changes: 161 additions & 0 deletions cypress/integration/customSchemaValidation.ts
@@ -0,0 +1,161 @@
context('customSchemaValidation form validation', () => {
it('should validate the form with onSubmit mode', () => {
cy.visit('http://localhost:3000/customSchemaValidation/onSubmit');
cy.get('button').click();

cy.focused().should('have.attr', 'name', 'firstName');

cy.get('input[name="firstName"] + p').contains('firstName error');
cy.get('input[name="lastName"] + p').contains('lastName error');
cy.get('select[name="selectNumber"] + p').contains('selectNumber error');
cy.get('input[name="minRequiredLength"] + p').contains(
'minRequiredLength error',
);
cy.get('input[name="radio"] + p').contains('radio error');

cy.get('input[name="firstName"]').type('bill');
cy.get('input[name="lastName"]').type('luo123456');
cy.get('input[name="lastName"] + p').contains('lastName error');
cy.get('select[name="selectNumber"]').select('1');
cy.get('input[name="pattern"]').type('luo');
cy.get('input[name="min"]').type('1');
cy.get('input[name="max"]').type('21');
cy.get('input[name="minDate"]').type('2019-07-30');
cy.get('input[name="maxDate"]').type('2019-08-02');
cy.get('input[name="lastName"]')
.clear()
.type('luo');
cy.get('input[name="minLength"]').type('2');
cy.get('input[name="minLength"] + p').contains('minLength error');
cy.get('input[name="min"] + p').contains('min error');
cy.get('input[name="max"] + p').contains('max error');
cy.get('input[name="minDate"] + p').contains('minDate error');
cy.get('input[name="maxDate"] + p').contains('maxDate error');

cy.get('input[name="pattern"]').type('23');
cy.get('input[name="minLength"]').type('bi');
cy.get('input[name="minRequiredLength"]').type('bi');
cy.get('input[name="radio"]').check('1');
cy.get('input[name="min"]')
.clear()
.type('11');
cy.get('input[name="max"]')
.clear()
.type('19');
cy.get('input[name="minDate"]').type('2019-08-01');
cy.get('input[name="maxDate"]').type('2019-08-01');
cy.get('input[name="checkbox"]').check();

cy.get('p').should('have.length', 0);
cy.get('#renderCount').contains('25');
});

it('should validate the form with onBlur mode', () => {
cy.visit('http://localhost:3000/customSchemaValidation/onBlur');

cy.get('input[name="firstName"]').focus();
cy.get('input[name="firstName"]').blur();
cy.get('input[name="firstName"] + p').contains('firstName error');
cy.get('input[name="firstName"]').type('bill');
cy.get('input[name="lastName"]').focus();
cy.get('input[name="lastName"]').blur();
cy.get('input[name="lastName"] + p').contains('lastName error');
cy.get('input[name="lastName"]').type('luo123456');
cy.get('input[name="lastName"]').blur();
cy.get('input[name="lastName"] + p').contains('lastName error');
cy.get('select[name="selectNumber"]').focus();
cy.get('select[name="selectNumber"]').blur();
cy.get('select[name="selectNumber"] + p').contains('selectNumber error');
cy.get('select[name="selectNumber"]').select('1');
cy.get('input[name="pattern"]').type('luo');
cy.get('input[name="min"]').type('1');
cy.get('input[name="max"]').type('21');
cy.get('input[name="minDate"]').type('2019-07-30');
cy.get('input[name="maxDate"]').type('2019-08-02');
cy.get('input[name="lastName"]')
.clear()
.type('luo');
cy.get('input[name="minLength"]').type('2');
cy.get('input[name="minLength"]').blur();

cy.get('input[name="minLength"] + p').contains('minLength error');
cy.get('input[name="min"] + p').contains('min error');
cy.get('input[name="max"] + p').contains('max error');
cy.get('input[name="minDate"] + p').contains('minDate error');
cy.get('input[name="maxDate"] + p').contains('maxDate error');

cy.get('input[name="pattern"]').type('23');
cy.get('input[name="minLength"]').type('bi');
cy.get('input[name="minRequiredLength"]').type('bi');
cy.get('input[name="radio"]')
.first()
.focus();
cy.get('input[name="radio"]')
.first()
.blur();
cy.get('input[name="radio"] + p').contains('radio error');
cy.get('input[name="radio"]').check('1');
cy.get('input[name="min"]')
.clear()
.type('11');
cy.get('input[name="max"]')
.clear()
.type('19');
cy.get('input[name="minDate"]').type('2019-08-01');
cy.get('input[name="maxDate"]').type('2019-08-01');
cy.get('input[name="checkbox"]').check();

cy.get('p').should('have.length', 0);
cy.get('#renderCount').contains('27');
});

it('should validate the form with onChange mode', () => {
cy.visit('http://localhost:3000/customSchemaValidation/onChange');

cy.get('input[name="firstName"]').type('bill');
cy.get('input[name="lastName"]').focus();
cy.get('input[name="lastName"]').type('luo123456');
cy.get('input[name="lastName"]').clear();
cy.get('input[name="lastName"] + p').contains('lastName error');
cy.get('input[name="lastName"]').type('luo123456');
cy.get('input[name="lastName"] + p').contains('lastName error');
cy.get('select[name="selectNumber"]').select('');
cy.get('select[name="selectNumber"] + p').contains('selectNumber error');
cy.get('select[name="selectNumber"]').select('1');
cy.get('input[name="pattern"]').type('luo');
cy.get('input[name="min"]').type('1');
cy.get('input[name="max"]').type('21');
cy.get('input[name="minDate"]').type('2019-07-30');
cy.get('input[name="maxDate"]').type('2019-08-02');
cy.get('input[name="lastName"]')
.clear()
.type('luo');
cy.get('input[name="minLength"]').type('2');

cy.get('input[name="minLength"] + p').contains('minLength error');
cy.get('input[name="min"] + p').contains('min error');
cy.get('input[name="max"] + p').contains('max error');
cy.get('input[name="minDate"] + p').contains('minDate error');
cy.get('input[name="maxDate"] + p').contains('maxDate error');

cy.get('input[name="pattern"]').type('23');
cy.get('input[name="minLength"]').type('bi');
cy.get('input[name="minRequiredLength"]').type('bi');
cy.get('input[name="radio"]')
.first()
.focus();
cy.get('input[name="radio"]').check('1');
cy.get('input[name="min"]')
.clear()
.type('11');
cy.get('input[name="max"]')
.clear()
.type('19');
cy.get('input[name="minDate"]').type('2019-08-01');
cy.get('input[name="maxDate"]').type('2019-08-01');
cy.get('input[name="checkbox"]').check();

cy.get('p').should('have.length', 0);
cy.get('#renderCount').contains('29');
});
});

0 comments on commit 7100156

Please sign in to comment.