From d277fb6097cdcd5dfd1dcbb018031478ee364cfc Mon Sep 17 00:00:00 2001 From: Yurii Fediv Date: Tue, 27 Feb 2018 10:59:04 +0200 Subject: [PATCH 1/4] Added isFieldValid method to Validation --- README.md | 6 +++++- __tests__/index.test.js | 22 ++++++++++++++++++++++ src/index.js | 30 +++++++++++++++++++++++++----- 3 files changed, 52 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index f8111ec..a79083d 100644 --- a/README.md +++ b/README.md @@ -228,7 +228,11 @@ this.setState( Use this method inside the render function, like in the [example](#form-example). It will return the object with fields keys and their error messages. If the field is valid there will be an empty error string. ### isFormValid({state}) -Use this method to check, if the field is valid. It will return true, if all the fields in the form are valid. See the [example](#form-example) +Use this method to check, if the form is valid. It will return true, if all the fields in the form are valid. See the [example](#form-example) + +### isFieldValid({state}, fieldName) +Use this method to check, if particular field is valid. Returns true if it is valid, false otherwise + ## Compatibility This package id fully compatible with the React v.16, because it uses state updater functions inside. diff --git a/__tests__/index.test.js b/__tests__/index.test.js index bda7d6d..972701f 100644 --- a/__tests__/index.test.js +++ b/__tests__/index.test.js @@ -190,5 +190,27 @@ describe('Unit tests for Validation class', () => { state = Object.assign({}, state, result); expect(Validator.isFormValid(state)).toEqual(true); }); + + test('Validator.isFieldValid(state,"login") method returns false', () => { + const updater = Validator.validate({ + login: '' + }); + const result = updater(state); + state = Object.assign({}, state, result); + expect(Validator.isFieldValid(state, 'login')).toEqual(false); + }); + + test('Validator.isFieldValid(state,"password") method returns true', () => { + expect(Validator.isFieldValid(state, 'password')).toEqual(true); + }); + + test('Validator.isFieldValid(state,"login") method returns true after login field became validated', () => { + const updater = Validator.validate({ + login: 'peterson' + }); + const result = updater(state); + state = Object.assign({}, state, result); + expect(Validator.isFieldValid(state, 'login')).toEqual(true); + }); }); }); diff --git a/src/index.js b/src/index.js index 4c27282..9dddc4c 100644 --- a/src/index.js +++ b/src/index.js @@ -37,6 +37,7 @@ class Validation { storage: string; statuses: Array; + // TODO: errorsStorageName is misleading, storage contains fields mapped to statuses but not errors constructor( fields: FieldsDescription, errorsStorageName: string = 'validationStorage' @@ -202,15 +203,15 @@ class Validation { } isFormValid(state: Object): boolean { - const errors = state[this.storage]; - if (typeof errors !== 'object') { - throw new Error('Invalid errors parameter for fields, must be object'); + const fieldsMappedToStatuses = state[this.storage]; + if (typeof fieldsMappedToStatuses !== 'object') { + throw new Error('Invalid fieldsMappedToStatuses object, must be object'); } - const keys = Object.keys(errors); + const keys = Object.keys(fieldsMappedToStatuses); const [validationPassed] = this.statuses; for (let i = 0; i < keys.length; i++) { - const currentStatuses = errors[keys[i]]; + const currentStatuses = fieldsMappedToStatuses[keys[i]]; for (let j = 0; j < currentStatuses.length; j++) { if (currentStatuses[j] !== validationPassed) { return false; @@ -220,6 +221,25 @@ class Validation { // if form valid return true return true; } + + isFieldValid(state: Object, fieldName: string): boolean { + const fieldsMappedToStatuses = state[this.storage]; + if (typeof fieldsMappedToStatuses !== 'object') { + throw new Error('Invalid fieldsMappedToStatuses object, must be object'); + } + const fieldStatuses = fieldsMappedToStatuses[fieldName]; + if (!fieldStatuses) { + throw new Error("Attempt to validate field that doesn't exist"); + } + + const [validationPassed] = this.statuses; + for (let j = 0; j < fieldStatuses.length; j++) { + if (fieldStatuses[j] !== validationPassed) { + return false; + } + } + return true; + } } const allRulesInArrays = ( From 5db62d87973a7d6238dbda790827a08971d39e85 Mon Sep 17 00:00:00 2001 From: Yurii Fediv Date: Tue, 27 Feb 2018 12:00:20 +0200 Subject: [PATCH 2/4] Added test for error case --- __tests__/index.test.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/__tests__/index.test.js b/__tests__/index.test.js index 972701f..3187f44 100644 --- a/__tests__/index.test.js +++ b/__tests__/index.test.js @@ -212,5 +212,11 @@ describe('Unit tests for Validation class', () => { state = Object.assign({}, state, result); expect(Validator.isFieldValid(state, 'login')).toEqual(true); }); + + test('Validator.isFieldValid(state,"asdasd") method throws error due to attempt to validate not existed field', () => { + expect(() => { + Validator.isFieldValid(state, 'asdasd'); + }).toThrow(); + }); }); }); From cb5a73f37489d9c5edd558a01ddfb6cddfd4ed74 Mon Sep 17 00:00:00 2001 From: Yurii Fediv Date: Tue, 27 Feb 2018 13:38:52 +0200 Subject: [PATCH 3/4] Changed names and replaced error throwing with console warn --- .eslintrc | 1 + __tests__/index.test.js | 6 ------ src/index.js | 37 +++++++++++++++++++++---------------- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/.eslintrc b/.eslintrc index 82bfa38..e271786 100644 --- a/.eslintrc +++ b/.eslintrc @@ -19,6 +19,7 @@ "keyword-spacing": ["warn", {"after": true}], "jsx-quotes": ["warn", "prefer-double"], "no-extra-boolean-cast": "off", + "no-console": 0, "no-multi-spaces": "warn", "no-spaced-func": "warn", "no-unused-vars": "warn", diff --git a/__tests__/index.test.js b/__tests__/index.test.js index 3187f44..972701f 100644 --- a/__tests__/index.test.js +++ b/__tests__/index.test.js @@ -212,11 +212,5 @@ describe('Unit tests for Validation class', () => { state = Object.assign({}, state, result); expect(Validator.isFieldValid(state, 'login')).toEqual(true); }); - - test('Validator.isFieldValid(state,"asdasd") method throws error due to attempt to validate not existed field', () => { - expect(() => { - Validator.isFieldValid(state, 'asdasd'); - }).toThrow(); - }); }); }); diff --git a/src/index.js b/src/index.js index 9dddc4c..b70a141 100644 --- a/src/index.js +++ b/src/index.js @@ -37,10 +37,9 @@ class Validation { storage: string; statuses: Array; - // TODO: errorsStorageName is misleading, storage contains fields mapped to statuses but not errors constructor( fields: FieldsDescription, - errorsStorageName: string = 'validationStorage' + validationStorageName: string = 'validationStorage' ) { if (typeof fields !== 'object') { throw new Error('Invalid fields parameter for fields, must be object'); @@ -49,7 +48,7 @@ class Validation { this.fields = allRulesInArrays(fields); this.fieldsToValidateList = []; this.fieldsToShowErrors = []; - this.storage = errorsStorageName; + this.validationStorageName = validationStorageName; this.statuses = [ 'validation-passed', 'prevalidation-failed', @@ -95,7 +94,7 @@ class Validation { ); return Object.assign(state, { - [this.storage]: toStorage + [this.validationStorageName]: toStorage }); } @@ -130,7 +129,7 @@ class Validation { // computing the state as a merge from prevState and stateUpdates to do the right validation let state = Object.assign({}, prevState, stateUpdates || {}); // clean the service error storage field, so the rule will have no acces to it - delete state[this.storage]; + delete state[this.validationStorageName]; keysToValidate.map(key => { if (this.fields[key]) { toStorage[key] = this._validateField( @@ -143,7 +142,11 @@ class Validation { }); this.fieldsToShowErrors = []; return Object.assign(stateUpdates || {}, { - [this.storage]: Object.assign({}, prevState[this.storage], toStorage) + [this.validationStorageName]: Object.assign( + {}, + prevState[this.validationStorageName], + toStorage + ) }); }; } @@ -186,7 +189,7 @@ class Validation { const validationFailed = this.statuses[2]; keys.map(key => { - const current = state[this.storage][key]; + const current = state[this.validationStorageName][key]; // check every rule for (let i = 0; i < current.length; i++) { if (current[i] === validationFailed) { @@ -203,15 +206,15 @@ class Validation { } isFormValid(state: Object): boolean { - const fieldsMappedToStatuses = state[this.storage]; - if (typeof fieldsMappedToStatuses !== 'object') { + const storage = state[this.validationStorageName]; + if (typeof storage !== 'object') { throw new Error('Invalid fieldsMappedToStatuses object, must be object'); } - const keys = Object.keys(fieldsMappedToStatuses); + const keys = Object.keys(storage); const [validationPassed] = this.statuses; for (let i = 0; i < keys.length; i++) { - const currentStatuses = fieldsMappedToStatuses[keys[i]]; + const currentStatuses = storage[keys[i]]; for (let j = 0; j < currentStatuses.length; j++) { if (currentStatuses[j] !== validationPassed) { return false; @@ -223,13 +226,15 @@ class Validation { } isFieldValid(state: Object, fieldName: string): boolean { - const fieldsMappedToStatuses = state[this.storage]; - if (typeof fieldsMappedToStatuses !== 'object') { - throw new Error('Invalid fieldsMappedToStatuses object, must be object'); + const storage = state[this.validationStorageName]; + if (typeof storage !== 'object') { + throw new Error('Invalid storage object, must be object'); } - const fieldStatuses = fieldsMappedToStatuses[fieldName]; + const fieldStatuses = storage[fieldName]; if (!fieldStatuses) { - throw new Error("Attempt to validate field that doesn't exist"); + // TODO: how to disable warnings in production + console.warn("Attempt to validate field that doesn't exist"); + return false; } const [validationPassed] = this.statuses; From dae739c0ab6a6579fe1adfe9a4abcb59ecaafd30 Mon Sep 17 00:00:00 2001 From: Yurii Fediv Date: Tue, 27 Feb 2018 14:50:03 +0200 Subject: [PATCH 4/4] README change --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a79083d..ed26e7b 100644 --- a/README.md +++ b/README.md @@ -156,7 +156,7 @@ If there are many rules, the their priority will be similar to the array order. ## Api -### constructor({FieldsDescription}, errorsStorageName = 'validationStorage') +### constructor({FieldsDescription}, validationStorageName = 'validationStorage') Describe in the constructor all the fields, that you will check. Like in the [example](#form-example). By default all validation data will be added to the 'validationStorage' key of the state object. You can change it, if you need. You can describe for each field [1 or many rules](#creating-validation-rules).