This repository has been archived by the owner on May 28, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add LoginForm shell accessible at /login
- Loading branch information
Showing
6 changed files
with
254 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import React, {PropTypes} from 'react' | ||
import { FormGroup, ControlLabel, FormControl, Button, HelpBlock } from 'react-bootstrap' | ||
import ValidatedFormControl from '../common/ValidatedFormControl' | ||
|
||
const LoginForm = ({user, onLoginClick, errors, onChange}) => { | ||
return ( | ||
<form> | ||
<FormGroup> | ||
<ControlLabel className="required">Email</ControlLabel> | ||
<ValidatedFormControl name="email" type="email" placeholder="Email" onChange={onChange} value={user.email} error={errors.email}/> | ||
</FormGroup> | ||
<FormGroup> | ||
<ControlLabel className="required">Mot de passe</ControlLabel> | ||
<ValidatedFormControl name="password" type="password" placeholder="Mot de passe" onChange={onChange} value={user.password} error={errors.password} /> | ||
</FormGroup> | ||
<Button bsStyle="primary" onClick={onLoginClick}>Connexion</Button> | ||
</form> | ||
) | ||
} | ||
|
||
LoginForm.propTypes = { | ||
user: PropTypes.object.isRequired, | ||
onLoginClick: PropTypes.func.isRequired, | ||
onChange: PropTypes.func.isRequired, | ||
errors: PropTypes.object | ||
} | ||
|
||
export default LoginForm |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import expect from 'expect' | ||
import React from 'react' | ||
import {shallow} from 'enzyme' | ||
import LoginForm from './LoginForm' | ||
|
||
function setup(user = {}) { | ||
const props = { | ||
user: Object.assign({ | ||
email: '', | ||
password: '' | ||
}, user), | ||
errors: {}, | ||
onLoginClick: () => { }, | ||
onChange: () => { }, | ||
} | ||
return shallow(<LoginForm {...props} />) | ||
} | ||
|
||
describe('<LoginForm>', () => { | ||
it('renders form', () => { | ||
const wrapper = setup() | ||
expect(wrapper.find('form').length).toBe(1) | ||
}) | ||
it('renders given email', () => { | ||
const testEmail = 'testEmail@mail.com' | ||
const wrapper = setup({email: testEmail}) | ||
expect(wrapper.find('[name="email"]').props().value).toEqual(testEmail) | ||
}) | ||
it('renders given password', () => { | ||
const testPassword = 'testPassword' | ||
const wrapper = setup({password: testPassword}) | ||
expect(wrapper.find('form').length).toBe(1) | ||
expect(wrapper.find('[name="password"]').props().value).toEqual(testPassword) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import React, { PropTypes } from 'react' | ||
import LoginForm from './LoginForm' | ||
import Validation from '../common/Validation' | ||
import {userValidationConstraints} from './userValidationConstraints' | ||
|
||
export class LoginPage extends React.Component { | ||
constructor(props, context) { | ||
super(props, context) | ||
this.state = { | ||
user: { | ||
email: '', | ||
password: '' | ||
}, | ||
errors: {}, | ||
} | ||
this.updateUserState = this.updateUserState.bind(this) | ||
this.loginUser = this.loginUser.bind(this) | ||
this.userValidation = new Validation(userValidationConstraints) | ||
} | ||
|
||
updateUserState(event) { | ||
const field = event.target.name | ||
let user = this.state.user | ||
user[field] = event.target.value | ||
this.validateUserField(field, event.target.value) | ||
return this.setState({ user }) | ||
} | ||
|
||
loginUser(event) { | ||
event.preventDefault() | ||
} | ||
|
||
validateUserField(field, value) { | ||
let errors = this.state.errors | ||
errors[field] = this.userValidation.validateField(field, value) | ||
if (errors[field] == null) { | ||
delete errors[field] | ||
} | ||
return this.setState({ errors }) | ||
} | ||
|
||
render() { | ||
return ( | ||
<div className="container"> | ||
<div className="page-header"> | ||
<h1>Connexion à l'espace PEPITE</h1> | ||
</div> | ||
<LoginForm | ||
user={this.state.user} | ||
onLoginClick={this.loginUser} | ||
onChange={this.updateUserState} | ||
errors={this.state.errors} /> | ||
</div> | ||
) | ||
} | ||
} | ||
|
||
LoginPage.propTypes = { | ||
} | ||
|
||
export default LoginPage |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
import expect from 'expect' | ||
import React from 'react' | ||
import { mount } from 'enzyme' | ||
import { LoginPage } from './LoginPage' | ||
|
||
function setup() { | ||
const props = { | ||
} | ||
return mount(<LoginPage {...props} />) | ||
} | ||
|
||
describe('<LoginPage>', () => { | ||
it('does not have any error on first load', () => { | ||
const wrapper = setup() | ||
const blockInError = wrapper.find('.has-error') | ||
expect(blockInError.length).toBe(0) | ||
}) | ||
|
||
describe('Password Field', () => { | ||
it('set in error when left empty', () => { | ||
const wrapper = setup() | ||
const passwordInput = wrapper.find('input[name="password"]') | ||
passwordInput.simulate('change', { | ||
target: { | ||
name: 'password', | ||
value: '' | ||
} | ||
}) | ||
const blockInError = wrapper.find('.has-error') | ||
expect(blockInError.length).toBe(1) | ||
expect(blockInError.contains(<div className="help-block">obligatoire</div>)).toBe(true) | ||
}) | ||
it('does not have any error after one caracter', () => { | ||
const wrapper = setup() | ||
const passwordInput = wrapper.find('input[name="password"]') | ||
passwordInput.simulate('change', { | ||
target: { | ||
name: 'password', | ||
value: 'c' | ||
} | ||
}) | ||
const blockInError = wrapper.find('.has-error') | ||
expect(blockInError.length).toBe(0) | ||
}) | ||
it('does not show inputed information', () => { | ||
const wrapper = setup() | ||
const inputedPassword = 'secret' | ||
const passwordInput = wrapper.find('input[name="password"]') | ||
passwordInput.simulate('change', { | ||
target: { | ||
name: 'password', | ||
value: inputedPassword | ||
} | ||
}) | ||
expect(passwordInput.text()).toNotEqual(inputedPassword) | ||
}) | ||
}) | ||
|
||
describe('Email Field', () => { | ||
it('set in error when left empty', () => { | ||
const wrapper = setup() | ||
const emailInput = wrapper.find('input[name="email"]') | ||
emailInput.simulate('change', { | ||
target: { | ||
name: 'email', | ||
value: '' | ||
} | ||
}) | ||
const blockInError = wrapper.find('.has-error') | ||
expect(blockInError.length).toBe(1) | ||
expect(blockInError.contains(<div className="help-block">Tu dois renseigner une adresse email valide</div>)).toBe(true) | ||
}) | ||
it('set in error when email is invalid', () => { | ||
const wrapper = setup() | ||
const emailInput = wrapper.find('input[name="email"]') | ||
emailInput.simulate('change', { | ||
target: { | ||
name: 'email', | ||
value: 'invalidmailmail.com' | ||
} | ||
}) | ||
const blockInError = wrapper.find('.has-error') | ||
expect(blockInError.length).toBe(1) | ||
expect(blockInError.contains(<div className="help-block">Tu dois renseigner une adresse email valide</div>)).toBe(true) | ||
}) | ||
it('does not have any error when it\'s a valid email', () => { | ||
const wrapper = setup() | ||
const emailInput = wrapper.find('input[name="email"]') | ||
emailInput.simulate('change', { | ||
target: { | ||
name: 'email', | ||
value: 'validmail@mail.com' | ||
} | ||
}) | ||
const blockInError = wrapper.find('.has-error') | ||
expect(blockInError.length).toBe(0) | ||
}) | ||
it('does not show inputed information', () => { | ||
const wrapper = setup() | ||
const inputedEmail = 'secret' | ||
const emailInput = wrapper.find('input[name="email"]') | ||
emailInput.simulate('change', { | ||
target: { | ||
name: 'email', | ||
value: inputedEmail | ||
} | ||
}) | ||
expect(emailInput.text()).toNotEqual(inputedEmail) | ||
}) | ||
}) | ||
|
||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import validator from 'validator' | ||
|
||
function isNotEmpty(value) { | ||
return (value && value.length && value.trim()) | ||
} | ||
|
||
export const userValidationConstraints = { | ||
email: { | ||
isValid: validator.isEmail, | ||
errorMessage: "Tu dois renseigner une adresse email valide" | ||
}, | ||
password: { | ||
isValid: isNotEmpty, | ||
errorMessage: "obligatoire" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters