diff options
Diffstat (limited to 'web-ui/src')
6 files changed, 95 insertions, 11 deletions
diff --git a/web-ui/src/account_recovery/backup_account_step/backup_account_step.js b/web-ui/src/account_recovery/backup_account_step/backup_account_step.js new file mode 100644 index 00000000..b4dcbaaf --- /dev/null +++ b/web-ui/src/account_recovery/backup_account_step/backup_account_step.js @@ -0,0 +1,35 @@ +/* + * 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"; + +export const BackupAccountStep = ({ t }) => ( +  <div className='account-recovery-form backup-account'> +    <img +      className='account-recovery-progress' +      src='/public/images/account-recovery/step_4.svg' +      alt={t('account-recovery.backup-account-step.image-description')} +    /> +    <h1>{t('account-recovery.backup-account-step.title')}</h1> +  </div> +); + +BackupAccountStep.propTypes = { +  t: React.PropTypes.func.isRequired +}; + +export default translate('', { wait: true })(BackupAccountStep); diff --git a/web-ui/src/account_recovery/backup_account_step/backup_account_step.spec.js b/web-ui/src/account_recovery/backup_account_step/backup_account_step.spec.js new file mode 100644 index 00000000..3b27b369 --- /dev/null +++ b/web-ui/src/account_recovery/backup_account_step/backup_account_step.spec.js @@ -0,0 +1,17 @@ +import { shallow } from 'enzyme'; +import expect from 'expect'; +import React from 'react'; +import { BackupAccountStep } from './backup_account_step'; + +describe('BackupAccountStep', () => { +  let backupAccountStep; + +  beforeEach(() => { +    const mockTranslations = key => key; +    backupAccountStep = shallow(<BackupAccountStep t={mockTranslations} />); +  }); + +  it('renders title for backup account step', () => { +    expect(backupAccountStep.find('h1').text()).toEqual('account-recovery.backup-account-step.title'); +  }); +}); diff --git a/web-ui/src/account_recovery/new_password_form/new_password_form.js b/web-ui/src/account_recovery/new_password_form/new_password_form.js index 4c418900..e7f689e8 100644 --- a/web-ui/src/account_recovery/new_password_form/new_password_form.js +++ b/web-ui/src/account_recovery/new_password_form/new_password_form.js @@ -28,11 +28,12 @@ import './new_password_form.scss';  export class NewPasswordForm extends React.Component {    submitHandler = (event) => { +    event.preventDefault();      submitForm(event, '/account-recovery', {        userCode: this.props.userCode,        password: this.state.password,        confirmation: this.state.confirmation -    }); +    }).then(() => this.props.next());    }    handlePasswordChange = (event) => { @@ -72,6 +73,7 @@ export class NewPasswordForm extends React.Component {  NewPasswordForm.propTypes = {    t: React.PropTypes.func.isRequired, +  next: React.PropTypes.func.isRequired,    previous: React.PropTypes.func.isRequired,    userCode: React.PropTypes.string.isRequired  }; diff --git a/web-ui/src/account_recovery/new_password_form/new_password_form.spec.js b/web-ui/src/account_recovery/new_password_form/new_password_form.spec.js index 26b8651c..b57dd42e 100644 --- a/web-ui/src/account_recovery/new_password_form/new_password_form.spec.js +++ b/web-ui/src/account_recovery/new_password_form/new_password_form.spec.js @@ -7,9 +7,11 @@ import { NewPasswordForm } from './new_password_form';  describe('NewPasswordForm', () => {    let newPasswordForm;    let mockPrevious; +  let mockNext; +  let mockTranslations;    beforeEach(() => { -    const mockTranslations = key => key; +    mockTranslations = key => key;      mockPrevious = expect.createSpy();      newPasswordForm = shallow(        <NewPasswordForm t={mockTranslations} previous={mockPrevious} userCode='def234' /> @@ -40,7 +42,11 @@ describe('NewPasswordForm', () => {    });    describe('Submit', () => { -    beforeEach(() => { +    beforeEach((done) => { +      mockNext = expect.createSpy().andCall(() => done()); +      newPasswordForm = shallow( +        <NewPasswordForm t={mockTranslations} previous={mockPrevious} userCode='def234' next={mockNext} /> +      );        fetchMock.post('/account-recovery', 200);        newPasswordForm.find('InputField[name="new-password"]').simulate('change', { target: { value: '123' } });        newPasswordForm.find('InputField[name="confirm-password"]').simulate('change', { target: { value: '456' } }); @@ -62,5 +68,9 @@ describe('NewPasswordForm', () => {      it('sends password confirmation as content', () => {        expect(fetchMock.lastOptions('/account-recovery').body).toContain('"confirmation":"456"');      }); + +    it('calls next handler on success', () => { +      expect(mockNext).toHaveBeenCalled(); +    });    });  }); diff --git a/web-ui/src/account_recovery/page.js b/web-ui/src/account_recovery/page.js index 2d33e2fb..89441d26 100644 --- a/web-ui/src/account_recovery/page.js +++ b/web-ui/src/account_recovery/page.js @@ -22,6 +22,7 @@ import Header from 'src/common/header/header';  import AdminRecoveryCodeForm from 'src/account_recovery/admin_recovery_code_form/admin_recovery_code_form';  import UserRecoveryCodeForm from 'src/account_recovery/user_recovery_code_form/user_recovery_code_form';  import NewPasswordForm from 'src/account_recovery/new_password_form/new_password_form'; +import BackupAccountStep from 'src/account_recovery/backup_account_step/backup_account_step';  import Footer from 'src/common/footer/footer';  import 'font-awesome/scss/font-awesome.scss'; @@ -36,7 +37,9 @@ export class Page extends React.Component {    }    nextStep = (event) => { -    event.preventDefault(); +    if (event) { +      event.preventDefault(); +    }      this.setState({ step: this.state.step + 1 });    } @@ -53,7 +56,8 @@ export class Page extends React.Component {      1: (<UserRecoveryCodeForm        previous={this.previousStep} next={this.nextStep} saveCode={this.saveUserCode}      />), -    2: <NewPasswordForm previous={this.previousStep} userCode={this.state.userCode} /> +    2: <NewPasswordForm previous={this.previousStep} userCode={this.state.userCode} next={this.nextStep} />, +    3: <BackupAccountStep />    })    mainContent = () => this.steps()[this.state.step]; diff --git a/web-ui/src/account_recovery/page.spec.js b/web-ui/src/account_recovery/page.spec.js index 31a748be..8e4ccc33 100644 --- a/web-ui/src/account_recovery/page.spec.js +++ b/web-ui/src/account_recovery/page.spec.js @@ -9,6 +9,7 @@ import Footer from 'src/common/footer/footer';  import AdminRecoveryCodeFormWrapper from './admin_recovery_code_form/admin_recovery_code_form';  import UserRecoveryCodeFormWrapper from './user_recovery_code_form/user_recovery_code_form';  import NewPasswordFormWrapper from './new_password_form/new_password_form'; +import BackupAccountStepWrapper from './backup_account_step/backup_account_step';  describe('Account Recovery Page', () => {    let page; @@ -37,6 +38,13 @@ describe('Account Recovery Page', () => {      expect(pageInstance.state.userCode).toEqual('123');    }); +  it('prevents default event before next', () => { +    const eventSpy = expect.createSpy(); +    pageInstance.nextStep({ preventDefault: eventSpy }); + +    expect(eventSpy).toHaveBeenCalled(); +  }); +    context('main content', () => {      it('renders admin recovery code form as default form', () => {        expect(page.find(AdminRecoveryCodeFormWrapper).length).toEqual(1); @@ -45,31 +53,39 @@ describe('Account Recovery Page', () => {      });      it('renders user recovery code form when admin code submitted', () => { -      pageInstance.nextStep({ preventDefault: () => {} }); +      pageInstance.nextStep();        expect(page.find(UserRecoveryCodeFormWrapper).length).toEqual(1);      });      it('returns to admin code form on user code form back link', () => { -      pageInstance.nextStep({ preventDefault: () => {} }); +      pageInstance.nextStep();        pageInstance.previousStep();        expect(page.find(AdminRecoveryCodeFormWrapper).length).toEqual(1);      });      it('renders new password form when user code submitted', () => { -      pageInstance.nextStep({ preventDefault: () => {} }); -      pageInstance.nextStep({ preventDefault: () => {} }); +      pageInstance.nextStep(); +      pageInstance.nextStep();        expect(page.find(NewPasswordFormWrapper).length).toEqual(1);      });      it('returns to user code form on new password form back link', () => { -      pageInstance.nextStep({ preventDefault: () => {} }); -      pageInstance.nextStep({ preventDefault: () => {} }); +      pageInstance.nextStep(); +      pageInstance.nextStep();        pageInstance.previousStep();        expect(page.find(UserRecoveryCodeFormWrapper).length).toEqual(1);      }); + +    it('renders backup account form after submitting new password', () => { +      pageInstance.nextStep(); +      pageInstance.nextStep(); +      pageInstance.nextStep(); + +      expect(page.find(BackupAccountStepWrapper).length).toEqual(1); +    });    });  });  | 
