@hookform/resolvers 2.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +420 -0
- package/class-validator/dist/class-validator.d.ts +2 -0
- package/class-validator/dist/class-validator.js +2 -0
- package/class-validator/dist/class-validator.js.map +1 -0
- package/class-validator/dist/class-validator.mjs +2 -0
- package/class-validator/dist/class-validator.modern.js +2 -0
- package/class-validator/dist/class-validator.modern.js.map +1 -0
- package/class-validator/dist/class-validator.module.js +2 -0
- package/class-validator/dist/class-validator.module.js.map +1 -0
- package/class-validator/dist/class-validator.umd.js +2 -0
- package/class-validator/dist/class-validator.umd.js.map +1 -0
- package/class-validator/dist/index.d.ts +2 -0
- package/class-validator/dist/types.d.ts +8 -0
- package/class-validator/package.json +19 -0
- package/class-validator/src/__tests__/Form-native-validation.tsx +83 -0
- package/class-validator/src/__tests__/Form.tsx +55 -0
- package/class-validator/src/__tests__/__fixtures__/data.ts +88 -0
- package/class-validator/src/__tests__/__snapshots__/class-validator.ts.snap +207 -0
- package/class-validator/src/__tests__/class-validator.ts +87 -0
- package/class-validator/src/class-validator.ts +62 -0
- package/class-validator/src/index.ts +2 -0
- package/class-validator/src/types.ts +22 -0
- package/computed-types/dist/computed-types.d.ts +2 -0
- package/computed-types/dist/computed-types.js +2 -0
- package/computed-types/dist/computed-types.js.map +1 -0
- package/computed-types/dist/computed-types.mjs +2 -0
- package/computed-types/dist/computed-types.modern.js +2 -0
- package/computed-types/dist/computed-types.modern.js.map +1 -0
- package/computed-types/dist/computed-types.module.js +2 -0
- package/computed-types/dist/computed-types.module.js.map +1 -0
- package/computed-types/dist/computed-types.umd.js +2 -0
- package/computed-types/dist/computed-types.umd.js.map +1 -0
- package/computed-types/dist/index.d.ts +2 -0
- package/computed-types/dist/types.d.ts +2 -0
- package/computed-types/package.json +17 -0
- package/computed-types/src/__tests__/Form-native-validation.tsx +85 -0
- package/computed-types/src/__tests__/Form.tsx +54 -0
- package/computed-types/src/__tests__/__fixtures__/data.ts +72 -0
- package/computed-types/src/__tests__/__snapshots__/computed-types.ts.snap +55 -0
- package/computed-types/src/__tests__/computed-types.ts +24 -0
- package/computed-types/src/computed-types.ts +43 -0
- package/computed-types/src/index.ts +2 -0
- package/computed-types/src/types.ts +14 -0
- package/dist/index.d.ts +2 -0
- package/dist/resolvers.js +2 -0
- package/dist/resolvers.js.map +1 -0
- package/dist/resolvers.mjs +2 -0
- package/dist/resolvers.mjs.map +1 -0
- package/dist/resolvers.module.js +2 -0
- package/dist/resolvers.module.js.map +1 -0
- package/dist/resolvers.umd.js +2 -0
- package/dist/resolvers.umd.js.map +1 -0
- package/dist/toNestError.d.ts +2 -0
- package/dist/validateFieldsNatively.d.ts +2 -0
- package/io-ts/dist/arrayToPath.d.ts +3 -0
- package/io-ts/dist/errorsToRecord.d.ts +5 -0
- package/io-ts/dist/index.d.ts +2 -0
- package/io-ts/dist/io-ts.d.ts +2 -0
- package/io-ts/dist/io-ts.js +2 -0
- package/io-ts/dist/io-ts.js.map +1 -0
- package/io-ts/dist/io-ts.mjs +2 -0
- package/io-ts/dist/io-ts.modern.js +2 -0
- package/io-ts/dist/io-ts.modern.js.map +1 -0
- package/io-ts/dist/io-ts.module.js +2 -0
- package/io-ts/dist/io-ts.module.js.map +1 -0
- package/io-ts/dist/io-ts.umd.js +2 -0
- package/io-ts/dist/io-ts.umd.js.map +1 -0
- package/io-ts/dist/types.d.ts +7 -0
- package/io-ts/package.json +19 -0
- package/io-ts/src/__tests__/Form-native-validation.tsx +89 -0
- package/io-ts/src/__tests__/Form.tsx +65 -0
- package/io-ts/src/__tests__/__fixtures__/data.ts +129 -0
- package/io-ts/src/__tests__/__snapshots__/io-ts.ts.snap +89 -0
- package/io-ts/src/__tests__/io-ts.ts +37 -0
- package/io-ts/src/arrayToPath.ts +18 -0
- package/io-ts/src/errorsToRecord.ts +131 -0
- package/io-ts/src/index.ts +2 -0
- package/io-ts/src/io-ts.ts +33 -0
- package/io-ts/src/types.ts +23 -0
- package/joi/dist/index.d.ts +2 -0
- package/joi/dist/joi.d.ts +2 -0
- package/joi/dist/joi.js +2 -0
- package/joi/dist/joi.js.map +1 -0
- package/joi/dist/joi.mjs +2 -0
- package/joi/dist/joi.modern.js +2 -0
- package/joi/dist/joi.modern.js.map +1 -0
- package/joi/dist/joi.module.js +2 -0
- package/joi/dist/joi.module.js.map +1 -0
- package/joi/dist/joi.umd.js +2 -0
- package/joi/dist/joi.umd.js.map +1 -0
- package/joi/dist/types.d.ts +5 -0
- package/joi/package.json +17 -0
- package/joi/src/__tests__/Form-native-validation.tsx +89 -0
- package/joi/src/__tests__/Form.tsx +61 -0
- package/joi/src/__tests__/__fixtures__/data.ts +85 -0
- package/joi/src/__tests__/__snapshots__/joi.ts.snap +293 -0
- package/joi/src/__tests__/joi.ts +98 -0
- package/joi/src/index.ts +2 -0
- package/joi/src/joi.ts +81 -0
- package/joi/src/types.ts +16 -0
- package/nope/dist/index.d.ts +2 -0
- package/nope/dist/nope.d.ts +2 -0
- package/nope/dist/nope.js +2 -0
- package/nope/dist/nope.js.map +1 -0
- package/nope/dist/nope.mjs +2 -0
- package/nope/dist/nope.modern.js +2 -0
- package/nope/dist/nope.modern.js.map +1 -0
- package/nope/dist/nope.module.js +2 -0
- package/nope/dist/nope.module.js.map +1 -0
- package/nope/dist/nope.umd.js +2 -0
- package/nope/dist/nope.umd.js.map +1 -0
- package/nope/dist/types.d.ts +6 -0
- package/nope/package.json +18 -0
- package/nope/src/__tests__/Form-native-validation.tsx +89 -0
- package/nope/src/__tests__/Form.tsx +57 -0
- package/nope/src/__tests__/__fixtures__/data.ts +70 -0
- package/nope/src/__tests__/__snapshots__/nope.ts.snap +43 -0
- package/nope/src/__tests__/nope.ts +28 -0
- package/nope/src/index.ts +2 -0
- package/nope/src/nope.ts +46 -0
- package/nope/src/types.ts +22 -0
- package/package.json +216 -0
- package/superstruct/dist/index.d.ts +2 -0
- package/superstruct/dist/superstruct.d.ts +2 -0
- package/superstruct/dist/superstruct.js +2 -0
- package/superstruct/dist/superstruct.js.map +1 -0
- package/superstruct/dist/superstruct.mjs +2 -0
- package/superstruct/dist/superstruct.modern.js +2 -0
- package/superstruct/dist/superstruct.modern.js.map +1 -0
- package/superstruct/dist/superstruct.module.js +2 -0
- package/superstruct/dist/superstruct.module.js.map +1 -0
- package/superstruct/dist/superstruct.umd.js +2 -0
- package/superstruct/dist/superstruct.umd.js.map +1 -0
- package/superstruct/dist/types.d.ts +5 -0
- package/superstruct/package.json +18 -0
- package/superstruct/src/__tests__/Form-native-validation.tsx +86 -0
- package/superstruct/src/__tests__/Form.tsx +62 -0
- package/superstruct/src/__tests__/__fixtures__/data.ts +75 -0
- package/superstruct/src/__tests__/__snapshots__/superstruct.ts.snap +64 -0
- package/superstruct/src/__tests__/superstruct.ts +24 -0
- package/superstruct/src/index.ts +2 -0
- package/superstruct/src/superstruct.ts +37 -0
- package/superstruct/src/types.ts +17 -0
- package/typanion/dist/index.d.ts +2 -0
- package/typanion/dist/typanion.d.ts +2 -0
- package/typanion/dist/typanion.js +2 -0
- package/typanion/dist/typanion.js.map +1 -0
- package/typanion/dist/typanion.mjs +2 -0
- package/typanion/dist/typanion.modern.js +2 -0
- package/typanion/dist/typanion.modern.js.map +1 -0
- package/typanion/dist/typanion.module.js +2 -0
- package/typanion/dist/typanion.module.js.map +1 -0
- package/typanion/dist/typanion.umd.js +2 -0
- package/typanion/dist/typanion.umd.js.map +1 -0
- package/typanion/dist/types.d.ts +6 -0
- package/typanion/package.json +18 -0
- package/typanion/src/__tests__/Form-native-validation.tsx +89 -0
- package/typanion/src/__tests__/Form.tsx +61 -0
- package/typanion/src/__tests__/__fixtures__/data.ts +77 -0
- package/typanion/src/__tests__/__snapshots__/typanion.ts.snap +67 -0
- package/typanion/src/__tests__/typanion.ts +31 -0
- package/typanion/src/index.ts +2 -0
- package/typanion/src/typanion.ts +44 -0
- package/typanion/src/types.ts +28 -0
- package/vest/dist/index.d.ts +1 -0
- package/vest/dist/vest.d.ts +2 -0
- package/vest/dist/vest.js +2 -0
- package/vest/dist/vest.js.map +1 -0
- package/vest/dist/vest.mjs +2 -0
- package/vest/dist/vest.modern.js +2 -0
- package/vest/dist/vest.modern.js.map +1 -0
- package/vest/dist/vest.module.js +2 -0
- package/vest/dist/vest.module.js.map +1 -0
- package/vest/dist/vest.umd.js +2 -0
- package/vest/dist/vest.umd.js.map +1 -0
- package/vest/package.json +18 -0
- package/vest/src/__tests__/Form-native-validation.tsx +93 -0
- package/vest/src/__tests__/Form.tsx +64 -0
- package/vest/src/__tests__/__fixtures__/data.ts +67 -0
- package/vest/src/__tests__/__snapshots__/vest.ts.snap +141 -0
- package/vest/src/__tests__/vest.ts +71 -0
- package/vest/src/index.ts +1 -0
- package/vest/src/types.ts +20 -0
- package/vest/src/vest.ts +51 -0
- package/yup/dist/index.d.ts +2 -0
- package/yup/dist/types.d.ts +8 -0
- package/yup/dist/yup.d.ts +2 -0
- package/yup/dist/yup.js +2 -0
- package/yup/dist/yup.js.map +1 -0
- package/yup/dist/yup.mjs +2 -0
- package/yup/dist/yup.modern.js +2 -0
- package/yup/dist/yup.modern.js.map +1 -0
- package/yup/dist/yup.module.js +2 -0
- package/yup/dist/yup.module.js.map +1 -0
- package/yup/dist/yup.umd.js +2 -0
- package/yup/dist/yup.umd.js.map +1 -0
- package/yup/package.json +17 -0
- package/yup/src/__tests__/Form-native-validation.tsx +85 -0
- package/yup/src/__tests__/Form.tsx +54 -0
- package/yup/src/__tests__/__fixtures__/data.ts +72 -0
- package/yup/src/__tests__/__snapshots__/yup.ts.snap +231 -0
- package/yup/src/__tests__/yup.ts +174 -0
- package/yup/src/index.ts +2 -0
- package/yup/src/types.ts +21 -0
- package/yup/src/yup.ts +75 -0
- package/zod/dist/index.d.ts +2 -0
- package/zod/dist/types.d.ts +5 -0
- package/zod/dist/zod.d.ts +2 -0
- package/zod/dist/zod.js +2 -0
- package/zod/dist/zod.js.map +1 -0
- package/zod/dist/zod.mjs +2 -0
- package/zod/dist/zod.modern.js +2 -0
- package/zod/dist/zod.modern.js.map +1 -0
- package/zod/dist/zod.module.js +2 -0
- package/zod/dist/zod.module.js.map +1 -0
- package/zod/dist/zod.umd.js +2 -0
- package/zod/dist/zod.umd.js.map +1 -0
- package/zod/package.json +17 -0
- package/zod/src/__tests__/Form-native-validation.tsx +85 -0
- package/zod/src/__tests__/Form.tsx +54 -0
- package/zod/src/__tests__/__fixtures__/data.ts +81 -0
- package/zod/src/__tests__/__snapshots__/zod.ts.snap +377 -0
- package/zod/src/__tests__/zod.ts +77 -0
- package/zod/src/index.ts +2 -0
- package/zod/src/types.ts +16 -0
- package/zod/src/zod.ts +85 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"joi.module.js","sources":["../src/joi.ts"],"sourcesContent":["import { appendErrors, FieldError } from 'react-hook-form';\nimport { toNestError, validateFieldsNatively } from '@hookform/resolvers';\nimport type { ValidationError } from 'joi';\nimport { Resolver } from './types';\n\nconst parseErrorSchema = (\n error: ValidationError,\n validateAllFieldCriteria: boolean,\n) =>\n error.details.length\n ? error.details.reduce<Record<string, FieldError>>((previous, error) => {\n const _path = error.path.join('.');\n\n if (!previous[_path]) {\n previous[_path] = { message: error.message, type: error.type };\n }\n\n if (validateAllFieldCriteria) {\n const types = previous[_path].types;\n const messages = types && types[error.type!];\n\n previous[_path] = appendErrors(\n _path,\n validateAllFieldCriteria,\n previous,\n error.type,\n messages\n ? ([] as string[]).concat(messages as string[], error.message)\n : error.message,\n ) as FieldError;\n }\n\n return previous;\n }, {})\n : {};\n\nexport const joiResolver: Resolver =\n (\n schema,\n schemaOptions = {\n abortEarly: false,\n },\n resolverOptions = {},\n ) =>\n async (values, context, options) => {\n const _schemaOptions = Object.assign({}, schemaOptions, {\n context,\n });\n\n let result: Record<string, any> = {};\n if (resolverOptions.mode === 'sync') {\n result = schema.validate(values, _schemaOptions);\n } else {\n try {\n result.value = await schema.validateAsync(values, _schemaOptions);\n } catch (e) {\n result.error = e;\n }\n }\n\n if (result.error) {\n return {\n values: {},\n errors: toNestError(\n parseErrorSchema(\n result.error,\n !options.shouldUseNativeValidation &&\n options.criteriaMode === 'all',\n ),\n options,\n ),\n };\n }\n\n options.shouldUseNativeValidation && validateFieldsNatively({}, options);\n\n return {\n errors: {},\n values: result.value,\n };\n };\n"],"names":["joiResolver","schema","schemaOptions","resolverOptions","abortEarly","values","context","options","result","error","errors","toNestError","validateAllFieldCriteria","shouldUseNativeValidation","criteriaMode","details","length","reduce","previous","_path","path","join","message","type","types","messages","appendErrors","concat","validateFieldsNatively","value","_schemaOptions","Object","assign","mode","validate","validateAsync","e"],"mappings":"6HAKA,IA+BaA,EACX,SACEC,EACAC,EAGAC,mBAHAD,IAAAA,EAAgB,CACdE,YAAY,aAEdD,IAAAA,EAAkB,aAEbE,EAAQC,EAASC,wBAgBtB,OAAIC,EAAOC,MACF,CACLJ,OAAQ,GACRK,OAAQC,GAzDdF,EA2DUD,EAAOC,MA1DjBG,GA2DWL,EAAQM,2BACkB,QAAzBN,EAAQO,aA1DpBL,EAAMM,QAAQC,OACVP,EAAMM,QAAQE,OAAmC,SAACC,EAAUT,GAC1D,IAAMU,EAAQV,EAAMW,KAAKC,KAAK,KAM9B,GAJKH,EAASC,KACZD,EAASC,GAAS,CAAEG,QAASb,EAAMa,QAASC,KAAMd,EAAMc,OAGtDX,EAA0B,CAC5B,IAAMY,EAAQN,EAASC,GAAOK,MACxBC,EAAWD,GAASA,EAAMf,EAAMc,MAEtCL,EAASC,GAASO,EAChBP,EACAP,EACAM,EACAT,EAAMc,KACNE,EACK,GAAgBE,OAAOF,EAAsBhB,EAAMa,SACpDb,EAAMa,SAId,OAAOJ,GACN,IACH,IAmCIX,KAKNA,EAAQM,2BAA6Be,EAAuB,GAAIrB,GAEzD,CACLG,OAAQ,GACRL,OAAQG,EAAOqB,QAzEI,IACvBpB,EACAG,GAsCQkB,EAAiBC,OAAOC,OAAO,GAAI9B,EAAe,CACtDI,QAAAA,IAGEE,EAA8B,mBACL,SAAzBL,EAAgB8B,KAClBzB,EAASP,EAAOiC,SAAS7B,EAAQyB,sIAGV7B,EAAOkC,cAAc9B,EAAQyB,qBAAlDtB,EAAOqB,oBACAO,GACP5B,EAAOC,MAAQ2B,iGAnBrB"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
!function(e,r){"object"==typeof exports&&"undefined"!=typeof module?r(exports,require("react-hook-form"),require("@hookform/resolvers")):"function"==typeof define&&define.amd?define(["exports","react-hook-form","@hookform/resolvers"],r):r((e||self).hookformResolversJoi={},e.reactHookForm,e.hookformResolvers)}(this,function(e,r,o){e.joiResolver=function(e,t,n){return void 0===t&&(t={abortEarly:!1}),void 0===n&&(n={}),function(i,s,a){try{var u=function(){return f.error?{values:{},errors:o.toNestError((e=f.error,t=!a.shouldUseNativeValidation&&"all"===a.criteriaMode,e.details.length?e.details.reduce(function(e,o){var n=o.path.join(".");if(e[n]||(e[n]={message:o.message,type:o.type}),t){var i=e[n].types,s=i&&i[o.type];e[n]=r.appendErrors(n,t,e,o.type,s?[].concat(s,o.message):o.message)}return e},{}):{}),a)}:(a.shouldUseNativeValidation&&o.validateFieldsNatively({},a),{errors:{},values:f.value});var e,t},l=Object.assign({},t,{context:s}),f={},c=function(){if("sync"===n.mode)f=e.validate(i,l);else{var r=function(e,r){try{var o=e()}catch(e){return r(e)}return o&&o.then?o.then(void 0,r):o}(function(){return Promise.resolve(e.validateAsync(i,l)).then(function(e){f.value=e})},function(e){f.error=e});if(r&&r.then)return r.then(function(){})}}();return Promise.resolve(c&&c.then?c.then(u):u())}catch(e){return Promise.reject(e)}}}});
|
|
2
|
+
//# sourceMappingURL=joi.umd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"joi.umd.js","sources":["../src/joi.ts"],"sourcesContent":["import { appendErrors, FieldError } from 'react-hook-form';\nimport { toNestError, validateFieldsNatively } from '@hookform/resolvers';\nimport type { ValidationError } from 'joi';\nimport { Resolver } from './types';\n\nconst parseErrorSchema = (\n error: ValidationError,\n validateAllFieldCriteria: boolean,\n) =>\n error.details.length\n ? error.details.reduce<Record<string, FieldError>>((previous, error) => {\n const _path = error.path.join('.');\n\n if (!previous[_path]) {\n previous[_path] = { message: error.message, type: error.type };\n }\n\n if (validateAllFieldCriteria) {\n const types = previous[_path].types;\n const messages = types && types[error.type!];\n\n previous[_path] = appendErrors(\n _path,\n validateAllFieldCriteria,\n previous,\n error.type,\n messages\n ? ([] as string[]).concat(messages as string[], error.message)\n : error.message,\n ) as FieldError;\n }\n\n return previous;\n }, {})\n : {};\n\nexport const joiResolver: Resolver =\n (\n schema,\n schemaOptions = {\n abortEarly: false,\n },\n resolverOptions = {},\n ) =>\n async (values, context, options) => {\n const _schemaOptions = Object.assign({}, schemaOptions, {\n context,\n });\n\n let result: Record<string, any> = {};\n if (resolverOptions.mode === 'sync') {\n result = schema.validate(values, _schemaOptions);\n } else {\n try {\n result.value = await schema.validateAsync(values, _schemaOptions);\n } catch (e) {\n result.error = e;\n }\n }\n\n if (result.error) {\n return {\n values: {},\n errors: toNestError(\n parseErrorSchema(\n result.error,\n !options.shouldUseNativeValidation &&\n options.criteriaMode === 'all',\n ),\n options,\n ),\n };\n }\n\n options.shouldUseNativeValidation && validateFieldsNatively({}, options);\n\n return {\n errors: {},\n values: result.value,\n };\n };\n"],"names":["schema","schemaOptions","resolverOptions","abortEarly","values","context","options","result","error","errors","toNestError","validateAllFieldCriteria","shouldUseNativeValidation","criteriaMode","details","length","reduce","previous","_path","path","join","message","type","types","messages","appendErrors","concat","validateFieldsNatively","value","_schemaOptions","Object","assign","mode","validate","validateAsync","e"],"mappings":"sYAqCE,SACEA,EACAC,EAGAC,mBAHAD,IAAAA,EAAgB,CACdE,YAAY,aAEdD,IAAAA,EAAkB,aAEbE,EAAQC,EAASC,wBAgBtB,OAAIC,EAAOC,MACF,CACLJ,OAAQ,GACRK,OAAQC,eAzDdF,EA2DUD,EAAOC,MA1DjBG,GA2DWL,EAAQM,2BACkB,QAAzBN,EAAQO,aA1DpBL,EAAMM,QAAQC,OACVP,EAAMM,QAAQE,OAAmC,SAACC,EAAUT,GAC1D,IAAMU,EAAQV,EAAMW,KAAKC,KAAK,KAM9B,GAJKH,EAASC,KACZD,EAASC,GAAS,CAAEG,QAASb,EAAMa,QAASC,KAAMd,EAAMc,OAGtDX,EAA0B,CAC5B,IAAMY,EAAQN,EAASC,GAAOK,MACxBC,EAAWD,GAASA,EAAMf,EAAMc,MAEtCL,EAASC,GAASO,eAChBP,EACAP,EACAM,EACAT,EAAMc,KACNE,EACK,GAAgBE,OAAOF,EAAsBhB,EAAMa,SACpDb,EAAMa,SAId,OAAOJ,GACN,IACH,IAmCIX,KAKNA,EAAQM,2BAA6Be,yBAAuB,GAAIrB,GAEzD,CACLG,OAAQ,GACRL,OAAQG,EAAOqB,QAzEI,IACvBpB,EACAG,GAsCQkB,EAAiBC,OAAOC,OAAO,GAAI9B,EAAe,CACtDI,QAAAA,IAGEE,EAA8B,mBACL,SAAzBL,EAAgB8B,KAClBzB,EAASP,EAAOiC,SAAS7B,EAAQyB,sIAGV7B,EAAOkC,cAAc9B,EAAQyB,qBAAlDtB,EAAOqB,oBACAO,GACP5B,EAAOC,MAAQ2B,iGAnBrB"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { ResolverOptions, ResolverResult, UnpackNestedValue } from 'react-hook-form';
|
|
2
|
+
import type { AsyncValidationOptions, Schema } from 'joi';
|
|
3
|
+
export declare type Resolver = <T extends Schema, TFieldValues, TContext>(schema: T, schemaOptions?: AsyncValidationOptions, factoryOptions?: {
|
|
4
|
+
mode?: 'async' | 'sync';
|
|
5
|
+
}) => (values: UnpackNestedValue<TFieldValues>, context: TContext | undefined, options: ResolverOptions<TFieldValues>) => Promise<ResolverResult<TFieldValues>>;
|
package/joi/package.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "joi",
|
|
3
|
+
"amdName": "hookformResolversJoi",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"private": true,
|
|
6
|
+
"description": "React Hook Form validation resolver: joi",
|
|
7
|
+
"main": "dist/joi.js",
|
|
8
|
+
"module": "dist/joi.module.js",
|
|
9
|
+
"umd:main": "dist/joi.umd.js",
|
|
10
|
+
"source": "src/index.ts",
|
|
11
|
+
"types": "dist/index.d.ts",
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"peerDependencies": {
|
|
14
|
+
"react-hook-form": "^7.0.0",
|
|
15
|
+
"@hookform/resolvers": "^2.0.0"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen, act } from '@testing-library/react';
|
|
3
|
+
import user from '@testing-library/user-event';
|
|
4
|
+
import { useForm } from 'react-hook-form';
|
|
5
|
+
import * as Joi from 'joi';
|
|
6
|
+
import { joiResolver } from '..';
|
|
7
|
+
|
|
8
|
+
const schema = Joi.object({
|
|
9
|
+
username: Joi.string().required(),
|
|
10
|
+
password: Joi.string().required(),
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
interface FormData {
|
|
14
|
+
username: string;
|
|
15
|
+
password: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface Props {
|
|
19
|
+
onSubmit: (data: FormData) => void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function TestComponent({ onSubmit }: Props) {
|
|
23
|
+
const { register, handleSubmit } = useForm<FormData>({
|
|
24
|
+
resolver: joiResolver(schema),
|
|
25
|
+
shouldUseNativeValidation: true,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<form onSubmit={handleSubmit(onSubmit)}>
|
|
30
|
+
<input {...register('username')} placeholder="username" />
|
|
31
|
+
|
|
32
|
+
<input {...register('password')} placeholder="password" />
|
|
33
|
+
|
|
34
|
+
<button type="submit">submit</button>
|
|
35
|
+
</form>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
test("form's native validation with Joi", async () => {
|
|
40
|
+
const handleSubmit = jest.fn();
|
|
41
|
+
render(<TestComponent onSubmit={handleSubmit} />);
|
|
42
|
+
|
|
43
|
+
// username
|
|
44
|
+
let usernameField = screen.getByPlaceholderText(
|
|
45
|
+
/username/i,
|
|
46
|
+
) as HTMLInputElement;
|
|
47
|
+
expect(usernameField.validity.valid).toBe(true);
|
|
48
|
+
expect(usernameField.validationMessage).toBe('');
|
|
49
|
+
|
|
50
|
+
// password
|
|
51
|
+
let passwordField = screen.getByPlaceholderText(
|
|
52
|
+
/password/i,
|
|
53
|
+
) as HTMLInputElement;
|
|
54
|
+
expect(passwordField.validity.valid).toBe(true);
|
|
55
|
+
expect(passwordField.validationMessage).toBe('');
|
|
56
|
+
|
|
57
|
+
await act(async () => {
|
|
58
|
+
user.click(screen.getByText(/submit/i));
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// username
|
|
62
|
+
usernameField = screen.getByPlaceholderText(/username/i) as HTMLInputElement;
|
|
63
|
+
expect(usernameField.validity.valid).toBe(false);
|
|
64
|
+
expect(usernameField.validationMessage).toBe(
|
|
65
|
+
'"username" is not allowed to be empty',
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
// password
|
|
69
|
+
passwordField = screen.getByPlaceholderText(/password/i) as HTMLInputElement;
|
|
70
|
+
expect(passwordField.validity.valid).toBe(false);
|
|
71
|
+
expect(passwordField.validationMessage).toBe(
|
|
72
|
+
'"password" is not allowed to be empty',
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
await act(async () => {
|
|
76
|
+
user.type(screen.getByPlaceholderText(/username/i), 'joe');
|
|
77
|
+
user.type(screen.getByPlaceholderText(/password/i), 'password');
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// username
|
|
81
|
+
usernameField = screen.getByPlaceholderText(/username/i) as HTMLInputElement;
|
|
82
|
+
expect(usernameField.validity.valid).toBe(true);
|
|
83
|
+
expect(usernameField.validationMessage).toBe('');
|
|
84
|
+
|
|
85
|
+
// password
|
|
86
|
+
passwordField = screen.getByPlaceholderText(/password/i) as HTMLInputElement;
|
|
87
|
+
expect(passwordField.validity.valid).toBe(true);
|
|
88
|
+
expect(passwordField.validationMessage).toBe('');
|
|
89
|
+
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen, act } from '@testing-library/react';
|
|
3
|
+
import user from '@testing-library/user-event';
|
|
4
|
+
import { useForm } from 'react-hook-form';
|
|
5
|
+
import * as Joi from 'joi';
|
|
6
|
+
import { joiResolver } from '..';
|
|
7
|
+
|
|
8
|
+
const schema = Joi.object({
|
|
9
|
+
username: Joi.string().required(),
|
|
10
|
+
password: Joi.string().required(),
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
interface FormData {
|
|
14
|
+
username: string;
|
|
15
|
+
password: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface Props {
|
|
19
|
+
onSubmit: (data: FormData) => void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function TestComponent({ onSubmit }: Props) {
|
|
23
|
+
const {
|
|
24
|
+
register,
|
|
25
|
+
formState: { errors },
|
|
26
|
+
handleSubmit,
|
|
27
|
+
} = useForm<FormData>({
|
|
28
|
+
resolver: joiResolver(schema), // Useful to check TypeScript regressions
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<form onSubmit={handleSubmit(onSubmit)}>
|
|
33
|
+
<input {...register('username')} />
|
|
34
|
+
{errors.username && <span role="alert">{errors.username.message}</span>}
|
|
35
|
+
|
|
36
|
+
<input {...register('password')} />
|
|
37
|
+
{errors.password && <span role="alert">{errors.password.message}</span>}
|
|
38
|
+
|
|
39
|
+
<button type="submit">submit</button>
|
|
40
|
+
</form>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
test("form's validation with Joi and TypeScript's integration", async () => {
|
|
45
|
+
const handleSubmit = jest.fn();
|
|
46
|
+
render(<TestComponent onSubmit={handleSubmit} />);
|
|
47
|
+
|
|
48
|
+
expect(screen.queryAllByRole(/alert/i)).toHaveLength(0);
|
|
49
|
+
|
|
50
|
+
await act(async () => {
|
|
51
|
+
user.click(screen.getByText(/submit/i));
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
expect(
|
|
55
|
+
screen.getByText(/"username" is not allowed to be empty/i),
|
|
56
|
+
).toBeInTheDocument();
|
|
57
|
+
expect(
|
|
58
|
+
screen.getByText(/"password" is not allowed to be empty/i),
|
|
59
|
+
).toBeInTheDocument();
|
|
60
|
+
expect(handleSubmit).not.toHaveBeenCalled();
|
|
61
|
+
});
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import * as Joi from 'joi';
|
|
2
|
+
|
|
3
|
+
import { Field, InternalFieldName } from 'react-hook-form';
|
|
4
|
+
|
|
5
|
+
export const schema = Joi.object({
|
|
6
|
+
username: Joi.string().alphanum().min(3).max(30).required(),
|
|
7
|
+
password: Joi.string()
|
|
8
|
+
.pattern(new RegExp('.*[A-Z].*'), 'One uppercase character')
|
|
9
|
+
.pattern(new RegExp('.*[a-z].*'), 'One lowercase character')
|
|
10
|
+
.pattern(new RegExp('.*\\d.*'), 'One number')
|
|
11
|
+
.pattern(
|
|
12
|
+
new RegExp('.*[`~<>?,./!@#$%^&*()\\-_+="\'|{}\\[\\];:\\\\].*'),
|
|
13
|
+
'One special character',
|
|
14
|
+
)
|
|
15
|
+
.min(8)
|
|
16
|
+
.required(),
|
|
17
|
+
repeatPassword: Joi.ref('password'),
|
|
18
|
+
accessToken: [Joi.string(), Joi.number()],
|
|
19
|
+
birthYear: Joi.number().integer().min(1900).max(2013),
|
|
20
|
+
email: Joi.string().email({
|
|
21
|
+
minDomainSegments: 2,
|
|
22
|
+
tlds: { allow: ['com', 'net'] },
|
|
23
|
+
}),
|
|
24
|
+
tags: Joi.array().items(Joi.string()).required(),
|
|
25
|
+
enabled: Joi.boolean().required(),
|
|
26
|
+
like: Joi.array()
|
|
27
|
+
.items(
|
|
28
|
+
Joi.object({ id: Joi.number(), name: Joi.string().length(4).regex(/a/) }),
|
|
29
|
+
)
|
|
30
|
+
.optional(),
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
interface Data {
|
|
34
|
+
username: string;
|
|
35
|
+
password: string;
|
|
36
|
+
repeatPassword: string;
|
|
37
|
+
accessToken?: number | string;
|
|
38
|
+
birthYear?: number;
|
|
39
|
+
email?: string;
|
|
40
|
+
tags: string[];
|
|
41
|
+
enabled: boolean;
|
|
42
|
+
like: { id: number; name: string }[];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export const validData: Data = {
|
|
46
|
+
username: 'Doe',
|
|
47
|
+
password: 'Password123_',
|
|
48
|
+
repeatPassword: 'Password123_',
|
|
49
|
+
birthYear: 2000,
|
|
50
|
+
email: 'john@doe.com',
|
|
51
|
+
tags: ['tag1', 'tag2'],
|
|
52
|
+
enabled: true,
|
|
53
|
+
like: [
|
|
54
|
+
{
|
|
55
|
+
id: 1,
|
|
56
|
+
name: 'name',
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export const invalidData = {
|
|
62
|
+
password: '___',
|
|
63
|
+
email: '',
|
|
64
|
+
birthYear: 'birthYear',
|
|
65
|
+
like: [{ id: 'z', name: 'r' }],
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export const fields: Record<InternalFieldName, Field['_f']> = {
|
|
69
|
+
username: {
|
|
70
|
+
ref: { name: 'username' },
|
|
71
|
+
name: 'username',
|
|
72
|
+
},
|
|
73
|
+
password: {
|
|
74
|
+
ref: { name: 'password' },
|
|
75
|
+
name: 'password',
|
|
76
|
+
},
|
|
77
|
+
email: {
|
|
78
|
+
ref: { name: 'email' },
|
|
79
|
+
name: 'email',
|
|
80
|
+
},
|
|
81
|
+
birthday: {
|
|
82
|
+
ref: { name: 'birthday' },
|
|
83
|
+
name: 'birthday',
|
|
84
|
+
},
|
|
85
|
+
};
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`joiResolver should return a single error from joiResolver when validation fails 1`] = `
|
|
4
|
+
Object {
|
|
5
|
+
"errors": Object {
|
|
6
|
+
"birthYear": Object {
|
|
7
|
+
"message": "\\"birthYear\\" must be a number",
|
|
8
|
+
"ref": undefined,
|
|
9
|
+
"type": "number.base",
|
|
10
|
+
},
|
|
11
|
+
"email": Object {
|
|
12
|
+
"message": "\\"email\\" is not allowed to be empty",
|
|
13
|
+
"ref": Object {
|
|
14
|
+
"name": "email",
|
|
15
|
+
},
|
|
16
|
+
"type": "string.empty",
|
|
17
|
+
},
|
|
18
|
+
"enabled": Object {
|
|
19
|
+
"message": "\\"enabled\\" is required",
|
|
20
|
+
"ref": undefined,
|
|
21
|
+
"type": "any.required",
|
|
22
|
+
},
|
|
23
|
+
"like": Array [
|
|
24
|
+
Object {
|
|
25
|
+
"id": Object {
|
|
26
|
+
"message": "\\"like[0].id\\" must be a number",
|
|
27
|
+
"ref": undefined,
|
|
28
|
+
"type": "number.base",
|
|
29
|
+
},
|
|
30
|
+
"name": Object {
|
|
31
|
+
"message": "\\"like[0].name\\" length must be 4 characters long",
|
|
32
|
+
"ref": undefined,
|
|
33
|
+
"type": "string.length",
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
"password": Object {
|
|
38
|
+
"message": "\\"password\\" with value \\"___\\" fails to match the One uppercase character pattern",
|
|
39
|
+
"ref": Object {
|
|
40
|
+
"name": "password",
|
|
41
|
+
},
|
|
42
|
+
"type": "string.pattern.name",
|
|
43
|
+
},
|
|
44
|
+
"tags": Object {
|
|
45
|
+
"message": "\\"tags\\" is required",
|
|
46
|
+
"ref": undefined,
|
|
47
|
+
"type": "any.required",
|
|
48
|
+
},
|
|
49
|
+
"username": Object {
|
|
50
|
+
"message": "\\"username\\" is required",
|
|
51
|
+
"ref": Object {
|
|
52
|
+
"name": "username",
|
|
53
|
+
},
|
|
54
|
+
"type": "any.required",
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
"values": Object {},
|
|
58
|
+
}
|
|
59
|
+
`;
|
|
60
|
+
|
|
61
|
+
exports[`joiResolver should return a single error from joiResolver with \`mode: sync\` when validation fails 1`] = `
|
|
62
|
+
Object {
|
|
63
|
+
"errors": Object {
|
|
64
|
+
"birthYear": Object {
|
|
65
|
+
"message": "\\"birthYear\\" must be a number",
|
|
66
|
+
"ref": undefined,
|
|
67
|
+
"type": "number.base",
|
|
68
|
+
},
|
|
69
|
+
"email": Object {
|
|
70
|
+
"message": "\\"email\\" is not allowed to be empty",
|
|
71
|
+
"ref": Object {
|
|
72
|
+
"name": "email",
|
|
73
|
+
},
|
|
74
|
+
"type": "string.empty",
|
|
75
|
+
},
|
|
76
|
+
"enabled": Object {
|
|
77
|
+
"message": "\\"enabled\\" is required",
|
|
78
|
+
"ref": undefined,
|
|
79
|
+
"type": "any.required",
|
|
80
|
+
},
|
|
81
|
+
"like": Array [
|
|
82
|
+
Object {
|
|
83
|
+
"id": Object {
|
|
84
|
+
"message": "\\"like[0].id\\" must be a number",
|
|
85
|
+
"ref": undefined,
|
|
86
|
+
"type": "number.base",
|
|
87
|
+
},
|
|
88
|
+
"name": Object {
|
|
89
|
+
"message": "\\"like[0].name\\" length must be 4 characters long",
|
|
90
|
+
"ref": undefined,
|
|
91
|
+
"type": "string.length",
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
],
|
|
95
|
+
"password": Object {
|
|
96
|
+
"message": "\\"password\\" with value \\"___\\" fails to match the One uppercase character pattern",
|
|
97
|
+
"ref": Object {
|
|
98
|
+
"name": "password",
|
|
99
|
+
},
|
|
100
|
+
"type": "string.pattern.name",
|
|
101
|
+
},
|
|
102
|
+
"tags": Object {
|
|
103
|
+
"message": "\\"tags\\" is required",
|
|
104
|
+
"ref": undefined,
|
|
105
|
+
"type": "any.required",
|
|
106
|
+
},
|
|
107
|
+
"username": Object {
|
|
108
|
+
"message": "\\"username\\" is required",
|
|
109
|
+
"ref": Object {
|
|
110
|
+
"name": "username",
|
|
111
|
+
},
|
|
112
|
+
"type": "any.required",
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
"values": Object {},
|
|
116
|
+
}
|
|
117
|
+
`;
|
|
118
|
+
|
|
119
|
+
exports[`joiResolver should return all the errors from joiResolver when validation fails with \`validateAllFieldCriteria\` set to true 1`] = `
|
|
120
|
+
Object {
|
|
121
|
+
"errors": Object {
|
|
122
|
+
"birthYear": Object {
|
|
123
|
+
"message": "\\"birthYear\\" must be a number",
|
|
124
|
+
"ref": undefined,
|
|
125
|
+
"type": "number.base",
|
|
126
|
+
"types": Object {
|
|
127
|
+
"number.base": "\\"birthYear\\" must be a number",
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
"email": Object {
|
|
131
|
+
"message": "\\"email\\" is not allowed to be empty",
|
|
132
|
+
"ref": Object {
|
|
133
|
+
"name": "email",
|
|
134
|
+
},
|
|
135
|
+
"type": "string.empty",
|
|
136
|
+
"types": Object {
|
|
137
|
+
"string.empty": "\\"email\\" is not allowed to be empty",
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
"enabled": Object {
|
|
141
|
+
"message": "\\"enabled\\" is required",
|
|
142
|
+
"ref": undefined,
|
|
143
|
+
"type": "any.required",
|
|
144
|
+
"types": Object {
|
|
145
|
+
"any.required": "\\"enabled\\" is required",
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
"like": Array [
|
|
149
|
+
Object {
|
|
150
|
+
"id": Object {
|
|
151
|
+
"message": "\\"like[0].id\\" must be a number",
|
|
152
|
+
"ref": undefined,
|
|
153
|
+
"type": "number.base",
|
|
154
|
+
"types": Object {
|
|
155
|
+
"number.base": "\\"like[0].id\\" must be a number",
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
"name": Object {
|
|
159
|
+
"message": "\\"like[0].name\\" length must be 4 characters long",
|
|
160
|
+
"ref": undefined,
|
|
161
|
+
"type": "string.length",
|
|
162
|
+
"types": Object {
|
|
163
|
+
"string.length": "\\"like[0].name\\" length must be 4 characters long",
|
|
164
|
+
"string.pattern.base": "\\"like[0].name\\" with value \\"r\\" fails to match the required pattern: /a/",
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
],
|
|
169
|
+
"password": Object {
|
|
170
|
+
"message": "\\"password\\" with value \\"___\\" fails to match the One uppercase character pattern",
|
|
171
|
+
"ref": Object {
|
|
172
|
+
"name": "password",
|
|
173
|
+
},
|
|
174
|
+
"type": "string.pattern.name",
|
|
175
|
+
"types": Object {
|
|
176
|
+
"string.min": "\\"password\\" length must be at least 8 characters long",
|
|
177
|
+
"string.pattern.name": Array [
|
|
178
|
+
"\\"password\\" with value \\"___\\" fails to match the One uppercase character pattern",
|
|
179
|
+
"\\"password\\" with value \\"___\\" fails to match the One lowercase character pattern",
|
|
180
|
+
"\\"password\\" with value \\"___\\" fails to match the One number pattern",
|
|
181
|
+
],
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
"tags": Object {
|
|
185
|
+
"message": "\\"tags\\" is required",
|
|
186
|
+
"ref": undefined,
|
|
187
|
+
"type": "any.required",
|
|
188
|
+
"types": Object {
|
|
189
|
+
"any.required": "\\"tags\\" is required",
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
"username": Object {
|
|
193
|
+
"message": "\\"username\\" is required",
|
|
194
|
+
"ref": Object {
|
|
195
|
+
"name": "username",
|
|
196
|
+
},
|
|
197
|
+
"type": "any.required",
|
|
198
|
+
"types": Object {
|
|
199
|
+
"any.required": "\\"username\\" is required",
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
"values": Object {},
|
|
204
|
+
}
|
|
205
|
+
`;
|
|
206
|
+
|
|
207
|
+
exports[`joiResolver should return all the errors from joiResolver when validation fails with \`validateAllFieldCriteria\` set to true and \`mode: sync\` 1`] = `
|
|
208
|
+
Object {
|
|
209
|
+
"errors": Object {
|
|
210
|
+
"birthYear": Object {
|
|
211
|
+
"message": "\\"birthYear\\" must be a number",
|
|
212
|
+
"ref": undefined,
|
|
213
|
+
"type": "number.base",
|
|
214
|
+
"types": Object {
|
|
215
|
+
"number.base": "\\"birthYear\\" must be a number",
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
"email": Object {
|
|
219
|
+
"message": "\\"email\\" is not allowed to be empty",
|
|
220
|
+
"ref": Object {
|
|
221
|
+
"name": "email",
|
|
222
|
+
},
|
|
223
|
+
"type": "string.empty",
|
|
224
|
+
"types": Object {
|
|
225
|
+
"string.empty": "\\"email\\" is not allowed to be empty",
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
"enabled": Object {
|
|
229
|
+
"message": "\\"enabled\\" is required",
|
|
230
|
+
"ref": undefined,
|
|
231
|
+
"type": "any.required",
|
|
232
|
+
"types": Object {
|
|
233
|
+
"any.required": "\\"enabled\\" is required",
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
"like": Array [
|
|
237
|
+
Object {
|
|
238
|
+
"id": Object {
|
|
239
|
+
"message": "\\"like[0].id\\" must be a number",
|
|
240
|
+
"ref": undefined,
|
|
241
|
+
"type": "number.base",
|
|
242
|
+
"types": Object {
|
|
243
|
+
"number.base": "\\"like[0].id\\" must be a number",
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
"name": Object {
|
|
247
|
+
"message": "\\"like[0].name\\" length must be 4 characters long",
|
|
248
|
+
"ref": undefined,
|
|
249
|
+
"type": "string.length",
|
|
250
|
+
"types": Object {
|
|
251
|
+
"string.length": "\\"like[0].name\\" length must be 4 characters long",
|
|
252
|
+
"string.pattern.base": "\\"like[0].name\\" with value \\"r\\" fails to match the required pattern: /a/",
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
],
|
|
257
|
+
"password": Object {
|
|
258
|
+
"message": "\\"password\\" with value \\"___\\" fails to match the One uppercase character pattern",
|
|
259
|
+
"ref": Object {
|
|
260
|
+
"name": "password",
|
|
261
|
+
},
|
|
262
|
+
"type": "string.pattern.name",
|
|
263
|
+
"types": Object {
|
|
264
|
+
"string.min": "\\"password\\" length must be at least 8 characters long",
|
|
265
|
+
"string.pattern.name": Array [
|
|
266
|
+
"\\"password\\" with value \\"___\\" fails to match the One uppercase character pattern",
|
|
267
|
+
"\\"password\\" with value \\"___\\" fails to match the One lowercase character pattern",
|
|
268
|
+
"\\"password\\" with value \\"___\\" fails to match the One number pattern",
|
|
269
|
+
],
|
|
270
|
+
},
|
|
271
|
+
},
|
|
272
|
+
"tags": Object {
|
|
273
|
+
"message": "\\"tags\\" is required",
|
|
274
|
+
"ref": undefined,
|
|
275
|
+
"type": "any.required",
|
|
276
|
+
"types": Object {
|
|
277
|
+
"any.required": "\\"tags\\" is required",
|
|
278
|
+
},
|
|
279
|
+
},
|
|
280
|
+
"username": Object {
|
|
281
|
+
"message": "\\"username\\" is required",
|
|
282
|
+
"ref": Object {
|
|
283
|
+
"name": "username",
|
|
284
|
+
},
|
|
285
|
+
"type": "any.required",
|
|
286
|
+
"types": Object {
|
|
287
|
+
"any.required": "\\"username\\" is required",
|
|
288
|
+
},
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
"values": Object {},
|
|
292
|
+
}
|
|
293
|
+
`;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { joiResolver } from '..';
|
|
2
|
+
import { schema, validData, fields, invalidData } from './__fixtures__/data';
|
|
3
|
+
|
|
4
|
+
const shouldUseNativeValidation = false;
|
|
5
|
+
|
|
6
|
+
describe('joiResolver', () => {
|
|
7
|
+
it('should return values from joiResolver when validation pass', async () => {
|
|
8
|
+
const validateAsyncSpy = jest.spyOn(schema, 'validateAsync');
|
|
9
|
+
const validateSpy = jest.spyOn(schema, 'validate');
|
|
10
|
+
|
|
11
|
+
const result = await joiResolver(schema)(validData, undefined, {
|
|
12
|
+
fields,
|
|
13
|
+
shouldUseNativeValidation,
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
expect(validateSpy).not.toHaveBeenCalled();
|
|
17
|
+
expect(validateAsyncSpy).toHaveBeenCalledTimes(1);
|
|
18
|
+
expect(result).toEqual({ errors: {}, values: validData });
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should return values from joiResolver with `mode: sync` when validation pass', async () => {
|
|
22
|
+
const validateAsyncSpy = jest.spyOn(schema, 'validateAsync');
|
|
23
|
+
const validateSpy = jest.spyOn(schema, 'validate');
|
|
24
|
+
|
|
25
|
+
const result = await joiResolver(schema, undefined, {
|
|
26
|
+
mode: 'sync',
|
|
27
|
+
})(validData, undefined, { fields, shouldUseNativeValidation });
|
|
28
|
+
|
|
29
|
+
expect(validateAsyncSpy).not.toHaveBeenCalled();
|
|
30
|
+
expect(validateSpy).toHaveBeenCalledTimes(1);
|
|
31
|
+
expect(result).toEqual({ errors: {}, values: validData });
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should return a single error from joiResolver when validation fails', async () => {
|
|
35
|
+
const result = await joiResolver(schema)(invalidData, undefined, {
|
|
36
|
+
fields,
|
|
37
|
+
shouldUseNativeValidation,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
expect(result).toMatchSnapshot();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('should return a single error from joiResolver with `mode: sync` when validation fails', async () => {
|
|
44
|
+
const validateAsyncSpy = jest.spyOn(schema, 'validateAsync');
|
|
45
|
+
const validateSpy = jest.spyOn(schema, 'validate');
|
|
46
|
+
|
|
47
|
+
const result = await joiResolver(schema, undefined, {
|
|
48
|
+
mode: 'sync',
|
|
49
|
+
})(invalidData, undefined, { fields, shouldUseNativeValidation });
|
|
50
|
+
|
|
51
|
+
expect(validateAsyncSpy).not.toHaveBeenCalled();
|
|
52
|
+
expect(validateSpy).toHaveBeenCalledTimes(1);
|
|
53
|
+
expect(result).toMatchSnapshot();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('should return all the errors from joiResolver when validation fails with `validateAllFieldCriteria` set to true', async () => {
|
|
57
|
+
const result = await joiResolver(schema)(invalidData, undefined, {
|
|
58
|
+
fields,
|
|
59
|
+
criteriaMode: 'all',
|
|
60
|
+
shouldUseNativeValidation,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
expect(result).toMatchSnapshot();
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('should return all the errors from joiResolver when validation fails with `validateAllFieldCriteria` set to true and `mode: sync`', async () => {
|
|
67
|
+
const result = await joiResolver(schema, undefined, { mode: 'sync' })(
|
|
68
|
+
invalidData,
|
|
69
|
+
undefined,
|
|
70
|
+
{
|
|
71
|
+
fields,
|
|
72
|
+
criteriaMode: 'all',
|
|
73
|
+
shouldUseNativeValidation,
|
|
74
|
+
},
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
expect(result).toMatchSnapshot();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('should return values from joiResolver when validation pass and pass down the Joi context', async () => {
|
|
81
|
+
const context = { value: 'context' };
|
|
82
|
+
const validateAsyncSpy = jest.spyOn(schema, 'validateAsync');
|
|
83
|
+
const validateSpy = jest.spyOn(schema, 'validate');
|
|
84
|
+
|
|
85
|
+
const result = await joiResolver(schema)(validData, context, {
|
|
86
|
+
fields,
|
|
87
|
+
shouldUseNativeValidation,
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
expect(validateSpy).not.toHaveBeenCalled();
|
|
91
|
+
expect(validateAsyncSpy).toHaveBeenCalledTimes(1);
|
|
92
|
+
expect(validateAsyncSpy).toHaveBeenCalledWith(validData, {
|
|
93
|
+
abortEarly: false,
|
|
94
|
+
context,
|
|
95
|
+
});
|
|
96
|
+
expect(result).toEqual({ errors: {}, values: validData });
|
|
97
|
+
});
|
|
98
|
+
});
|
package/joi/src/index.ts
ADDED