diff --git a/package-lock.json b/package-lock.json index 6a6f5d6..a07d10e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,36 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@fortawesome/fontawesome-common-types": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.2.tgz", + "integrity": "sha512-OBzXzYJ+nDMece2nKeuV7hLuwqPN3jv1Fk56gag2DL4BiwWl8gkFQplj5Krep9HwtjFxbM6/DWN6ZG7FRC5N0w==" + }, + "@fortawesome/fontawesome-svg-core": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.2.tgz", + "integrity": "sha512-j+DmvRF3FPekdLir3ocSl3fO12FxKXEot/kqeodUqTBsmU0EcPvRLn9ip3xzQrMSJ2cWyqv4GNxFm5kT0XR8mw==", + "requires": { + "@fortawesome/fontawesome-common-types": "0.2.2" + } + }, + "@fortawesome/free-solid-svg-icons": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.2.0.tgz", + "integrity": "sha512-ZgUtvhtdOMGaXSenAxzjVhn+Bz1tYKqUPIVeZ/40vrilOu8dF95EjRW1JcUJ938gNE8pjaB/G2AlJN8T0wcXxw==", + "requires": { + "@fortawesome/fontawesome-common-types": "0.2.2" + } + }, + "@fortawesome/react-fontawesome": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.0.tgz", + "integrity": "sha512-CFulvjNIz/Z8SQ/Wikm8iPCiYDMVJKGVVh+9oxESpOgN8TIIK+bYOGv4HjOhjKKpKEHmns3n5vC/m6ormM8Y7A==", + "requires": { + "humps": "2.0.1", + "prop-types": "15.6.2" + } + }, "@types/jest": { "version": "23.3.1", "resolved": "https://registry.npmjs.org/@types/jest/-/jest-23.3.1.tgz", @@ -5092,6 +5122,11 @@ "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" }, + "humps": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/humps/-/humps-2.0.1.tgz", + "integrity": "sha1-3QLqYIG9BWjcXQcxhEY5V7qe+ao=" + }, "iconv-lite": { "version": "0.4.23", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", diff --git a/package.json b/package.json index e96bfba..68c1cd1 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,9 @@ "license": "MIT", "author": "Stuart 'Stevie' Leitch", "dependencies": { + "@fortawesome/fontawesome-svg-core": "^1.2.2", + "@fortawesome/free-solid-svg-icons": "^5.2.0", + "@fortawesome/react-fontawesome": "^0.1.0", "bulma": "^0.7.1", "enzyme": "^3.3.0", "enzyme-adapter-react-16": "^1.1.1", diff --git a/src/UserRegistration.js b/src/UserRegistration.js index ab59397..1f8b8d0 100644 --- a/src/UserRegistration.js +++ b/src/UserRegistration.js @@ -1,5 +1,7 @@ import React, { Component } from 'react'; import 'bulma/css/bulma.css' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { faExclamationCircle } from '@fortawesome/free-solid-svg-icons' export class UserRegistration extends Component { @@ -9,30 +11,34 @@ export class UserRegistration extends Component { username: '', password: '', confirm: '', - submitEnabled: false + passwordMatchesConfirm: true }; this.handleSubmit = this.handleSubmit.bind(this); } + submitEnabled = () => { + return this.state.password && this.state.passwordMatchesConfirm; + }; + handleInputChange = (event) => { const target = event.target; // Logic to check passwords match must check input change against existing field value. - let submitEnabled = false; + let passwordMatchesConfirm = this.state.passwordMatchesConfirm; if (target.name === 'password') { - submitEnabled = target.value && (target.value === this.state.confirm); + passwordMatchesConfirm = target.value && (target.value === this.state.confirm); } else if (target.name === 'confirm') { - submitEnabled = target.value && (target.value === this.state.password); + passwordMatchesConfirm = target.value && (target.value === this.state.password); } this.setState({ [target.name]: target.value, - submitEnabled: submitEnabled + passwordMatchesConfirm: passwordMatchesConfirm }); }; handleSubmit = () => { - if (this.state.submitEnabled) { + if (this.submitEnabled()) { this.props.onSubmit(this.state.username, this.state.password); } else { console.error("Attempt to submit form when form has validation errors"); @@ -43,25 +49,30 @@ export class UserRegistration extends Component { return (

Create an account

-
+
- +
-
+
- +
-
+
-
- +
+ + {!this.state.passwordMatchesConfirm && + + + + }
- +
); } diff --git a/src/UserRegistration.test.js b/src/UserRegistration.test.js index 4b477b5..7739adc 100644 --- a/src/UserRegistration.test.js +++ b/src/UserRegistration.test.js @@ -67,11 +67,33 @@ describe ('', () => { expect(onSubmit).not.toBeCalled(); }); + it('shows error markers when password does not match confirmation', () => { + const wrapper = shallow(); + setFieldValues(wrapper, username, password, 'mismatch'); + + const inputField = wrapper.find('#confirmField input') + const errorIcon = wrapper.find('#confirmField .icon'); + + expect(inputField.hasClass('is-danger')).toBe(true); + expect(errorIcon.exists()).toBe(true); + }); + + it('hides error marker when password does matches confirmation', () => { + const wrapper = shallow(); + setFieldValues(wrapper, username, password, password); + + const inputField = wrapper.find('#confirmField input') + const errorIcon = wrapper.find('#confirmField .icon'); + + expect(inputField.hasClass('is-danger')).toBe(false); + expect(errorIcon.exists()).toBe(false); + }); + function setFieldValues(wrapper, username, password, confirm) { - const usernameField = wrapper.find('input.username'); - const passwordField = wrapper.find('input.password'); - const confirmField = wrapper.find('input.confirm'); + const usernameField = wrapper.find('#usernameField input'); + const passwordField = wrapper.find('#passwordField input'); + const confirmField = wrapper.find('#confirmField input'); usernameField.simulate('change', stubEvent(usernameField, username)); passwordField.simulate('change', stubEvent(passwordField, password));