diff options
Diffstat (limited to 'web-ui')
| -rw-r--r-- | web-ui/src/common/flat_button/flat_button.js | 58 | ||||
| -rw-r--r-- | web-ui/src/common/flat_button/flat_button.spec.js | 32 | ||||
| -rw-r--r-- | web-ui/src/common/header/header.js | 15 | ||||
| -rw-r--r-- | web-ui/src/common/header/header.scss | 5 | ||||
| -rw-r--r-- | web-ui/src/common/header/header.spec.js | 12 | ||||
| -rw-r--r-- | web-ui/src/common/logout/logout.js | 48 | ||||
| -rw-r--r-- | web-ui/src/common/logout/logout.spec.js | 49 | ||||
| -rw-r--r-- | web-ui/test/integration/backup_account.spec.js | 6 | 
8 files changed, 205 insertions, 20 deletions
| diff --git a/web-ui/src/common/flat_button/flat_button.js b/web-ui/src/common/flat_button/flat_button.js new file mode 100644 index 00000000..b8c6c2c7 --- /dev/null +++ b/web-ui/src/common/flat_button/flat_button.js @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2017 ThoughtWorks, Inc. + * + * Pixelated is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Pixelated is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Pixelated. If not, see <http://www.gnu.org/licenses/>. + */ + +import React from 'react'; +import FlatButton from 'material-ui/FlatButton'; +import FontIcon from 'material-ui/FontIcon'; +import { grey500 } from 'material-ui/styles/colors'; + +const labelStyle = { +  textTransform: 'none', +  verticalAlign: 'middle' +}; + +const iconStyle = { +  marginRight: 0 +}; + +const flatButtonStyle = { +  minWidth: 0, +  verticalAlign: 'top' +}; + +const SubmitFlatButton = ({ name, buttonText, fontIconClass }) => ( +  <FlatButton +    name={name} +    type='submit' +    hoverColor='transparent' +    style={flatButtonStyle} +    labelPosition='before' +    label={buttonText} +    labelStyle={labelStyle} +    aria-label={buttonText} +    title={buttonText} +    icon={<FontIcon className={fontIconClass} color={grey500} style={iconStyle} />} +  /> +); + +SubmitFlatButton.propTypes = { +  name: React.PropTypes.string.isRequired, +  buttonText: React.PropTypes.string.isRequired, +  fontIconClass: React.PropTypes.string.isRequired +}; + +export default SubmitFlatButton; diff --git a/web-ui/src/common/flat_button/flat_button.spec.js b/web-ui/src/common/flat_button/flat_button.spec.js new file mode 100644 index 00000000..16f03acb --- /dev/null +++ b/web-ui/src/common/flat_button/flat_button.spec.js @@ -0,0 +1,32 @@ +import { shallow } from 'enzyme'; +import expect from 'expect'; +import React from 'react'; +import FlatButton from 'src/common/flat_button/flat_button'; + +describe('FlatButton', () => { +  let flatButton; + +  beforeEach(() => { +    flatButton = shallow(<FlatButton name='logout' buttonText='Logout' fontIconClass='fa fa-sign-out' />); +  }); + +  it('renders a FlatButton of type submit with name logout', () => { +    expect(flatButton.find('FlatButton').props().name).toEqual('logout'); +  }); + +  it('renders a FlatButton of type submit with text logout', () => { +    expect(flatButton.find('FlatButton').props().label).toEqual('Logout'); +  }); + +  it('renders a FlatButton of type submit with title logout', () => { +    expect(flatButton.find('FlatButton').props().title).toEqual('Logout'); +  }); + +  it('renders a FlatButton of type submit with aria-label logout', () => { +    expect(flatButton.find('FlatButton').props()['aria-label']).toEqual('Logout'); +  }); + +  it('renders a FlatButton with given fontIcon class', () => { +    expect(flatButton.find('FlatButton').props().icon.props.className).toEqual('fa fa-sign-out'); +  }); +}); diff --git a/web-ui/src/common/header/header.js b/web-ui/src/common/header/header.js index 50c863b5..715d54c6 100644 --- a/web-ui/src/common/header/header.js +++ b/web-ui/src/common/header/header.js @@ -16,10 +16,10 @@   */  import React from 'react'; -import { translate } from 'react-i18next'; +import Logout from 'src/common/logout/logout';  import './header.scss'; -export const Header = ({ t }) => ( +export const Header = () => (    <header className='header-wrapper'>      <div className='header-content'>        <a href='/'> @@ -30,17 +30,10 @@ export const Header = ({ t }) => (          />        </a>        <div className='header-icons'> -        <a href='/'> -          <span>{t('logout')}</span> -          <i className='fa fa-sign-out' aria-hidden='true' /> -        </a> +        <Logout />        </div>      </div>    </header>  ); -Header.propTypes = { -  t: React.PropTypes.func.isRequired -}; - -export default translate('', { wait: true })(Header); +export default Header; diff --git a/web-ui/src/common/header/header.scss b/web-ui/src/common/header/header.scss index d56629bf..3e10ba39 100644 --- a/web-ui/src/common/header/header.scss +++ b/web-ui/src/common/header/header.scss @@ -28,7 +28,6 @@  .header-content {    display: flex; -  align-items: center;  }  .header-logo { @@ -41,7 +40,7 @@    position: absolute;    right: 6%; -  top: 13px; +  line-height: 0;    span {      display: none; @@ -51,6 +50,7 @@      font-size: 1.3em;      margin-left: 0.4em;      color: $medium_light_grey; +    overflow: visible;    }  } @@ -78,6 +78,7 @@        font-style: normal;        font-size: 0.7em;        padding-bottom: 0.1em; +      line-height: 36px;      }      .fa { diff --git a/web-ui/src/common/header/header.spec.js b/web-ui/src/common/header/header.spec.js index 82e29e1c..81a952c7 100644 --- a/web-ui/src/common/header/header.spec.js +++ b/web-ui/src/common/header/header.spec.js @@ -2,16 +2,20 @@ import { shallow } from 'enzyme';  import expect from 'expect';  import React from 'react';  import { Header } from 'src/common/header/header'; +import Logout from 'src/common/logout/logout';  describe('Header', () => {    let header;    beforeEach(() => { -    const mockTranslations = key => key; -    header = shallow(<Header t={mockTranslations} />); +    header = shallow(<Header />);    }); -  it('renders the header content', () => { -    expect(header.find('header').text()).toContain('logout'); +  it('renders the header containing the logout button', () => { +    expect(header.find('header').find(Logout)).toExist(); +  }); + +  it('renders the header pixelated logo', () => { +    expect(header.find('header').find('img').props().alt).toEqual('Pixelated');    });  }); diff --git a/web-ui/src/common/logout/logout.js b/web-ui/src/common/logout/logout.js new file mode 100644 index 00000000..259b448e --- /dev/null +++ b/web-ui/src/common/logout/logout.js @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2017 ThoughtWorks, Inc. + * + * Pixelated is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Pixelated is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Pixelated. If not, see <http://www.gnu.org/licenses/>. + */ + +import React from 'react'; +import { translate } from 'react-i18next'; +import browser from 'helpers/browser'; + +import SubmitFlatButton from 'src/common/flat_button/flat_button'; + +export class Logout extends React.Component { + +  constructor(props) { +    super(props); +    this.state = { csrf_token: browser.getCookie('XSRF-TOKEN') }; +  } + +  render() { +    const t = this.props.t; +    return ( +      <div className='logout-container'> +        <form id='logout-form' method='POST' action='logout'> +          <input type='hidden' name='csrftoken' value={this.state.csrf_token} /> +          <SubmitFlatButton name='logout' buttonText={t('logout')} fontIconClass='fa fa-sign-out' /> +        </form> +      </div> +    ); +  } +} + +Logout.propTypes = { +  t: React.PropTypes.func.isRequired +}; + +export default translate('', { wait: true })(Logout); diff --git a/web-ui/src/common/logout/logout.spec.js b/web-ui/src/common/logout/logout.spec.js new file mode 100644 index 00000000..ba228e61 --- /dev/null +++ b/web-ui/src/common/logout/logout.spec.js @@ -0,0 +1,49 @@ +import { shallow } from 'enzyme'; +import expect from 'expect'; +import React from 'react'; +import { Logout } from 'src/common/logout/logout'; + +describe('Logout', () => { +  let logout; + +  beforeEach(() => { +    const mockTranslations = key => key; +    logout = shallow(<Logout t={mockTranslations} fontIconClass='fa fa-sign-out' />); +  }); + +  it('renders the logout container', () => { +    expect(logout.find('div.logout-container')).toExist(); +  }); + +  describe('logout form', () => { +    let logoutForm; + +    beforeEach(() => { +      logoutForm = logout.find('form#logout-form'); +    }); + +    it('renders logout form', () => { +      expect(logoutForm).toExist(); +    }); + +    it('renders logout form with POST method', () => { +      expect(logoutForm.props().method).toEqual('POST'); +    }); + +    it('renders logout form with action as logout', () => { +      expect(logoutForm.props().action).toEqual('logout'); +    }); + +    it('renders csrf hidden input', () => { +      expect(logoutForm.find('input[name="csrftoken"]')).toExist(); +    }); + +    it('renders SubmitFlatButton for logout', () => { +      expect(logoutForm.find('SubmitFlatButton').props().buttonText).toEqual('logout'); +    }); + +    it('renders SubmitFlatButton for logout with fontIcon', () => { +      expect(logoutForm.find('SubmitFlatButton').props().fontIconClass).toEqual('fa fa-sign-out'); +    }); +  }); +}); diff --git a/web-ui/test/integration/backup_account.spec.js b/web-ui/test/integration/backup_account.spec.js index b44c3b2c..b9667a41 100644 --- a/web-ui/test/integration/backup_account.spec.js +++ b/web-ui/test/integration/backup_account.spec.js @@ -16,7 +16,7 @@ describe('Backup account email validation', () => {      context('with valid email', () => {        beforeEach(() => { -        backupAccountPage.find('input').simulate('change', {target: {value: 'test@test.com'}}); +        backupAccountPage.find('input[name="email"]').simulate('change', {target: {value: 'test@test.com'}});        });        it('shows no validation error', () => { @@ -30,7 +30,7 @@ describe('Backup account email validation', () => {      context('with invalid email', () => {        beforeEach(() => { -        backupAccountPage.find('input').simulate('change', {target: {value: 'test'}}); +        backupAccountPage.find('input[name="email"]').simulate('change', {target: {value: 'test'}});        });        it('shows validation error', () => { @@ -44,7 +44,7 @@ describe('Backup account email validation', () => {      context('with empty email', () => {        beforeEach(() => { -        backupAccountPage.find('input').simulate('change', {target: {value: ''}}); +        backupAccountPage.find('input[name="email"]').simulate('change', {target: {value: ''}});        });        it('shows no validation error', () => { | 
