Browse Source

Added basic validation logic.

Snow 8 years ago
parent
commit
fd79a288ff
2 changed files with 180 additions and 73 deletions
  1. 58 18
      src/__test__/Form.test.js
  2. 122 55
      src/components/Form/index.js

+ 58 - 18
src/__test__/Form.test.js

@@ -1,11 +1,11 @@
 import React from 'react';
-import Form from '../components/Form';
+import Form, { Warning } from '../components/Form';
 import { mount, shallow } from 'enzyme';
 
 describe('Place holder', () => {
   const colorTest = (inputWindow, color) => {
-    expect(inputWindow.find('input').at(0).prop('style'))
-      .toHaveProperty('color', color);
+    const inputField = inputWindow.find('input').at(0).prop('style');
+    expect(inputField).toHaveProperty('color', color);
   };
 
   it('Placeholder shows on loading and color is grey', () => {
@@ -22,28 +22,68 @@ describe('Place holder', () => {
   });
 
   it('Typing in the input area shows the text with color black, \
-  	deleting the text shows placeholder again on blur', () => {
+ deleting the text shows placeholder again on blur', () => {
     const inputWindow = mount(<Form />);
     const inputField = inputWindow.find('input').at(0);
-      inputField.simulate('focus');
-      const newValue = 'Entered new value'
-    inputField.node.value = newValue;
-    inputField.simulate('change', inputField);
+    const placeHolder = inputField.prop('value');
+    const name = inputField.prop('name');
+    inputField.simulate('focus');
+    expect(inputField.prop('value')).toBe('');
+    const newValue = 'Entered new value';
+    inputField.simulate('change', {
+      target: {
+        name: name,
+        value: newValue
+      }
+    });
     expect(inputField.prop('value')).toBe(newValue);
     colorTest(inputWindow, 'black');
-    inputField.simulate('change', { target: { value: '' } });
+    inputField.simulate('change', {
+      target: {
+        name: name,
+        value: ''
+      }
+    });
     inputField.simulate('blur');
-    expect(inputField.prop('value')).toBe('test');
+    expect(inputField.prop('value')).toBe(placeHolder);
     colorTest(inputWindow, 'grey');
   });
 });
 
 describe('Validation', () => {
-  it('Exceeding the max length shows show a warning', () => {
-    const inputWindow = mount(<InputWithPlaceHolder maxLength={8}/>)
-    const inputField = inputWindow.find('input')
-    const newValue = 'test   test'
-    inputField.simulate('change', { target: { value: newValue } });
-    expect(inputWindow.find('.warning').text()).toTruthy()
-  })
-})
+  it('Display a warning when isValid prop is false', () => {
+    const warning1 = shallow(
+      <Warning isValid={false} validationType="length" />
+    );
+    expect(warning1.find('span.warning').length).toBe(1);
+    const warning2 = shallow(
+      <Warning isValid={true} validationType="length" />
+    );
+    expect(warning2.find('span.warning').length).toBe(0);
+  });
+
+  it('Exceeding the max length shows a warning on submit', () => {
+    const formWindow = mount(<Form />);
+    const inputField = formWindow.find('input').at(0);
+    const name = inputField.prop('name');
+    const newValue = 'test';
+    inputField.simulate('change', {
+      target: { name: name, value: newValue }
+    });
+    formWindow.find('input').last().simulate('submit');
+    expect(formWindow.find('.warning').at(0).length).toBe(1);
+  });
+
+    it('Unmatched password shows a warning on submit', () => {
+    const formWindow = mount(<Form />);
+      const inputField = formWindow.find('input').at(1);
+      expect(inputField.prop('type')).toBe('password')
+    const name = inputField.prop('name');
+    const newValue = 'test';
+    inputField.simulate('change', {
+      target: { name: name, value: newValue }
+    });
+    formWindow.find('input').last().simulate('submit');
+    expect(formWindow.find('.warning').length).toBe(2);
+  });
+});

+ 122 - 55
src/components/Form/index.js

@@ -1,100 +1,167 @@
 import React from 'react';
-import PropTypes from 'prop-types'
+import PropTypes from 'prop-types';
+
+const Warning = ({ isValid, validationType, length }) => {
+  switch(validationType) {
+  case 'length':
+    if (isValid === undefined || isValid) {
+      return null;
+    } else {
+      return (
+        <span className="warning">
+          This field should at least have {length} characters.
+        </span>
+      );
+    }
+  case 'passwordMatch':
+    if (isValid === undefined || isValid) {
+      return null;
+    } else {
+      return (
+        <span className="warning">
+          Password don't match.
+        </span>
+      );
+    }
+  default:
+    return null
+  }
+};
+
+export { Warning };
+
+Warning.propTypes = {
+  isValid: PropTypes.bool,
+  validationType: PropTypes.string.isRequired,
+  length: PropTypes.number
+};
 
 export default class Form extends React.Component {
   static placeHolder = {
-    name: 'Enter your name',
-    password: '12345678',
-    password2: '12345678',
-    comment: 'Enter your comment'
-  }
-  
+    name: { message: 'Enter your name', color: 'grey' },
+    password: { message: '12345678', color: 'grey' },
+    password2: { message: '12345678', color: 'grey' },
+    comment: { message: 'Enter your comment', color: 'grey' }
+  };
+
   state = {
     ...this.constructor.placeHolder
-  }
+  };
+
+  validateHelper = {
+    length: (name, length) => {
+      if (
+        this.state[name].message.length <= length ||
+        this.state[name].color === 'grey'
+      ) {
+        this.setState({
+          [name]: Object.assign({}, this.state[name], { isValid: false })
+        });
+      }
+    },
+    passwordMatch: name => {
+      const password1 = this.state.password.message;
+      const password2 = this.state.password2.message;
+      if (password1 !== password2 || this.state[name].color === 'grey') {
+        this.setState({
+          password2: Object.assign({}, this.state.password2, { isValid: false })
+        });
+      }
+    }
+  };
+
+  validateCenter = () => {
+    this.validateHelper.length('name', 8);
+    this.validateHelper.passwordMatch('password');
+  };
 
-  handleFocus = (event) => {
-    const target = event.target
-    const color = target.style.color;
+  handleSubmit = event => {
+    event.preventDefault();
+    this.validateCenter();
+    console.log(this.state);
+  };
+  handleFocus = event => {
+    const target = event.target;
     const name = target.name;
-    if (target.value === this.constructor.placeHolder[name] && color === 'grey') {
+    const color = this.state[name].color;
+    if (color === 'grey') {
       this.setState({
-        [name]:'',
-      })
+        [name]: Object.assign({}, this.state[name], {
+          message: '',
+          color: 'black'
+        })
+      });
     }
   };
-   
-  handleBlur = (event) => {
-    const target = event.target
-    const name = target.name
+
+  handleBlur = event => {
+    const target = event.target;
+    const name = target.name;
+    const message = this.constructor.placeHolder[name].message;
     if (target.value.length === 0) {
       this.setState({
-        [name]: this.constructor.placeHolder[name],
+        [name]: Object.assign({}, this.state[name], {
+          message: message,
+          color: 'grey'
+        })
       });
     }
   };
-  
+
   handleChange = event => {
     const target = event.target;
     const value = target.type === 'checkbox' ? target.checked : target.value;
     const name = target.name;
-    this.setState({[name]:value})
+    this.setState({
+      [name]: Object.assign({}, this.state[name], { message: value })
+    });
   };
 
+  renderInput = (type, name) => {
+    const props = {
+      type: type,
+      name: name,
+      value: this.state[name].message,
+      onFocus: this.handleFocus,
+      onChange: this.handleChange,
+      style: { color: this.state[name].color },
+      onBlur: this.handleBlur,
+      className: 'input ' + name
+    };
 
-  renderInput = (type,name) => {
-    const color = (this.state[name].length === 0) ? 'black' : 'grey'
-    
     if (type === 'textarea') {
-      return (
-        <textarea
-           type={type}
-           name={name}
-          value={this.state[name]}
-          onFocus={this.handleFocus}
-          onChange={this.handleChange}
-          style={{ color: color }}
-          onBlur={this.handleBlur}
-          className={"input " + name}
-        />
-      );
+      return <textarea {...props} />;
     }
 
-    return (
-      <input
-           type={type}
-           name={name}
-          value={this.state[name]}
-          onFocus={this.handleFocus}
-          onChange={this.handleChange}
-          style={{ color: color }}
-          onBlur={this.handleBlur}
-           className={"input " + name}
-      />
-    );
-  }
-  
+    return <input {...props} />;
+  };
+
   render() {
     return (
-      <form>
+      <form onSubmit={this.handleSubmit}>
         <label>
           Name:
-          {this.renderInput('text','name')}
+          {this.renderInput('text', 'name')}
+          <Warning isValid={this.state.name.isValid} validationType="length" />
         </label>
         <br />
         <label>
           Password:
-          {this.renderInput('password','password')}
+          {this.renderInput('password', 'password')}
         </label>
         <br />
         <label>
           Password:
-{this.renderInput('password','password2')}
+          {this.renderInput('password', 'password2')}
+          <Warning
+            isValid={this.state.password2.isValid}
+            validationType="passwordMatch"
+          />
         </label>
         <br />
         <label>
           Comments: <br />
-          {this.renderInput('textarea','comment')}
+          {this.renderInput('textarea', 'comment')}
         </label>
         <br />
         <input type="submit" value="Submit" />