Skip to content
This repository has been archived by the owner on Apr 15, 2019. It is now read-only.

Commit

Permalink
Merge pull request #784 from LiskHQ/783-relative-lisnk-e2e-test
Browse files Browse the repository at this point in the history
Stabilise RelativeLink e2e tests - Closes #783
  • Loading branch information
reyraa authored Sep 28, 2017
2 parents 9890360 + 4e4eb0f commit 629c06e
Show file tree
Hide file tree
Showing 10 changed files with 226 additions and 48 deletions.
1 change: 0 additions & 1 deletion features/login.feature
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ Feature: Login page
Then I should be logged in
And I should see text "Testnet" in "peer network" element

@ignore
Scenario: should allow to create a new account
Given I'm on login page
When I click "new account button"
Expand Down
1 change: 1 addition & 0 deletions src/components/app/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const App = () => (
<Route path={`${match.url}/forging/:dialog?`} component={Forging} />
</main>
)} />
<Route exact path="/register" component={Login} />
<Route exact path="/" component={Login} />
</main>
<Dialog />
Expand Down
82 changes: 51 additions & 31 deletions src/components/dialog/dialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,70 +10,90 @@ class DialogElement extends Component {
constructor() {
super();
this.state = {};
this.path = {
name: '/',
this.routesReg = [
{
regex: /\/main\/transactions(?:\/[^/]*)?$/,
path: '/main/transactions/',
params: 'dialog',
name: 'transactions',
}, {
regex: /\/main\/voting(?:\/[^/]*)?$/,
path: '/main/voting/',
params: 'dialog',
name: 'voting',
}, {
regex: /\/main\/forging(?:\/[^/]*)?$/,
path: '/main/forging/',
params: 'dialog',
name: 'forging',
}, {
regex: /\/(\w+)?$/,
path: '/',
params: 'dialog',
name: 'login',
},
];
this.current = {
pathname: '/',
reg: this.routesReg[3],
list: [],
dialog: '',
};
}

componentDidMount() {
this.checkForDialog(this.props.history.location);
this.checkForDialog();
}

componentDidUpdate() {
if (this.path.name !== this.props.history.location.pathname) {
this.path.name = this.props.history.location.pathname;
this.checkForDialog(this.props.history.location);
this.checkForDialog();
}

checkForDialog() {
if (this.current.pathname !== this.props.history.location.pathname) {
this.current.reg = this.routesReg.find(item =>
item.regex.test(this.props.history.location.pathname));
this.current.pathname = this.props.history.location.pathname;
const dialogName = this.props.history.location.pathname.replace(this.current.reg.path, '');
if (dialogs[dialogName] !== undefined) {
this.open(this.current.reg, dialogs[dialogName]);
} else {
this.close();
}
}
}

checkForDialog(location) {
const parseParams = search => search.replace(/^\?/, '').split('&&').reduce((acc, param) => {
// eslint-disable-next-line class-methods-use-this
parseParams(search) {
return search.replace(/^\?/, '').split('&&').reduce((acc, param) => {
const keyValue = param.split('=');
if (keyValue[0] !== '' && keyValue[1] !== 'undefined') {
acc[keyValue[0]] = keyValue[1];
}
return acc;
}, {});

this.path.list = location.pathname.replace(/\/$/, '').split('/');
this.dialog = this.path.list[3];

if (this.path.list.length === 5) {
this.props.history.push(`/${this.path.list[1]}/${this.path.list[2]}/${this.path.list[4]}`);
} else if (this.path.list.length === 4 && Object.keys(dialogs).includes(this.dialog)) {
this.routeWithDialog(dialogs[this.dialog], parseParams(location.search));
} else {
this.routeWithOutDialog();
}
}

routeWithDialog(dialog, childComponentProps) {
open(config, dialog) {
clearTimeout(this.timeout);
this.setState({ hidden: false });
this.props.dialogDisplayed({
title: dialog.title,
childComponent: dialog.component,
childComponentProps,
childComponentProps: this.parseParams(this.props.history.location.search),
});
}

routeWithOutDialog() {
close() {
this.timeout = setTimeout(() => {
this.props.dialogHidden();
this.setState({ hidden: false });
}, 500);
this.setState({ hidden: true });
}

closeDialog() {
if (this.props.dialog.childComponentProps.noRouter) {
this.routeWithOutDialog();
} else {
const upperRoute = this.path.name.replace(/\/$/, '').replace(this.dialog, '');
this.props.history.push(upperRoute);
}
goBack() {
this.props.history.push(this.current.reg.path);
}

render() {
Expand All @@ -85,14 +105,14 @@ class DialogElement extends Component {
<AppBar title={this.props.dialog.title} flat={true}
className={styles[this.props.dialog.type]}>
<Navigation type='horizontal'>
<IconButton className={`${styles['x-button']} x-button`} onClick={this.closeDialog.bind(this)} icon='close'/>
<IconButton className={`${styles['x-button']} x-button`} onClick={this.goBack.bind(this)} icon='close'/>
</Navigation>
</AppBar>
<div className='modal-dialog-body'>
{this.props.dialog.childComponent ?
<this.props.dialog.childComponent
{...(this.props.dialog.childComponentProps || {})}
closeDialog={this.closeDialog.bind(this)}
closeDialog={this.goBack.bind(this)}
/> :
null
}
Expand Down
5 changes: 5 additions & 0 deletions src/components/dialog/dialogs.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import SecondPassphrase from '../secondPassphrase';
import VoteDialog from '../voteDialog';
import ReceiveDialog from '../receiveDialog';
import SaveAccount from '../saveAccount';
import Register from '../register';

export default {
send: {
Expand Down Expand Up @@ -36,6 +37,10 @@ export default {
title: 'Receive LSK',
component: ReceiveDialog,
},
register: {
title: 'New Account',
component: Register,
},
'save-account': {
title: 'Remember this account',
component: SaveAccount,
Expand Down
20 changes: 4 additions & 16 deletions src/components/login/login.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import networksRaw from './networks';
import PassphraseInput from '../passphraseInput';
import styles from './login.css';
import env from '../../constants/env';
import Passphrase from '../passphrase';
import RelativeLink from '../relativeLink';

/**
* The container component containing login
Expand Down Expand Up @@ -188,25 +188,13 @@ class Login extends React.Component {
onChange={this.changeHandler.bind(this, 'passphrase')} />
<footer className={ `${grid.row} ${grid['center-xs']}` }>
<div className={grid['col-xs-12']}>
<Button label={this.props.t('New Account')} flat primary
className={`${styles.newAccount} new-account-button`}
onClick={() => this.props.setActiveDialog({
title: this.props.t('New Account'),
childComponent: Passphrase,
childComponentProps: {
onPassGenerated: this.onLoginSubmission.bind(this),
keepModal: false,
noRouter: true,
confirmButton: 'Login',
useCaseNote: 'your passphrase will be required for logging in to your account.',
securityNote: 'This passphrase is not recoverable and if you lose it, you will lose access to your account forever.',
},
})} />
<RelativeLink to='register' flat primary
className={`${styles.newAccount} new-account-button`}>{this.props.t('New Account')}</RelativeLink>
<Button label='LOGIN' primary raised
onClick={this.onLoginSubmission.bind(this, this.state.passphrase)}
className='login-button'
disabled={(this.state.network === 2 && this.state.addressValidity !== '') ||
this.state.passphraseValidity !== ''} />
this.state.passphraseValidity !== ''} />
</div>
</footer>
</form>
Expand Down
15 changes: 15 additions & 0 deletions src/components/register/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { connect } from 'react-redux';
import { translate } from 'react-i18next';
import { dialogDisplayed } from '../../actions/dialog';
import { activePeerSet } from '../../actions/peers';
import Register from './register';

const mapDispatchToProps = dispatch => ({
setActiveDialog: data => dispatch(dialogDisplayed(data)),
activePeerSet: data => dispatch(activePeerSet(data)),
});

export default connect(
null,
mapDispatchToProps,
)(translate()(Register));
31 changes: 31 additions & 0 deletions src/components/register/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React from 'react';
import { expect } from 'chai';
import { mount } from 'enzyme';
import { Provider } from 'react-redux';
import { I18nextProvider } from 'react-i18next';
import configureMockStore from 'redux-mock-store';
import i18n from '../../i18n';
import Register from './index';


describe('RegisterHOC', () => {
let wrapper;
const peers = {};
const account = {};
const store = configureMockStore([])({
peers,
account,
});

beforeEach(() => {
wrapper = mount(<Provider store={store}>
<I18nextProvider i18n={ i18n }>
<Register />
</I18nextProvider>
</Provider>);
});

it('should render Register', () => {
expect(wrapper.find('Register')).to.have.lengthOf(1);
});
});
3 changes: 3 additions & 0 deletions src/components/register/register.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.hidden {
display: none;
}
60 changes: 60 additions & 0 deletions src/components/register/register.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import React from 'react';
import Passphrase from '../passphrase';
import networksRaw from '../login/networks';

const Register = ({
activePeerSet, closeDialog, t,
}) => {
const validateUrl = (value) => {
const addHttp = (url) => {
const reg = /^(?:f|ht)tps?:\/\//i;
return reg.test(url) ? url : `http://${url}`;
};

const errorMessage = 'URL is invalid';

const isValidLocalhost = url => url.hostname === 'localhost' && url.port.length > 1;
const isValidRemote = url => /(([a-z\d]([a-z\d-]*[a-z\d])*)\.)+[a-z]{2,}|((\d{1,3}\.){3}\d{1,3})/.test(url.hostname);

let addressValidity = '';
try {
const url = new URL(addHttp(value));
addressValidity = url && (isValidRemote(url) || isValidLocalhost(url)) ? '' : errorMessage;
} catch (e) {
addressValidity = errorMessage;
}

return addressValidity === '';
};

const onLoginSubmission = (passphrase) => {
let NetworkIndex = parseInt(localStorage.getItem('network'), 10) || 0;
const address = localStorage.getItem('address') || '';
if (!NetworkIndex || (NetworkIndex === 2 && !validateUrl(address))) {
NetworkIndex = 0;
}

const network = Object.assign({}, networksRaw[NetworkIndex]);
if (NetworkIndex === 2) {
network.address = address;
}

// set active peer
activePeerSet({
passphrase,
network,
});
};

return (
<Passphrase
onPassGenerated={onLoginSubmission}
keepModal={false}
closeDialog={closeDialog}
confirmButton={'Login'}
useCaseNote={t('your passphrase will be required for logging in to your account.')}
securityNote={t('This passphrase is not recoverable and if you lose it, you will lose access to your account forever.')}/>
);
};

export default Register;
56 changes: 56 additions & 0 deletions src/components/register/register.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import React from 'react';
import { expect } from 'chai';
import { mount } from 'enzyme';
import { spy } from 'sinon';
import PropTypes from 'prop-types';
import configureMockStore from 'redux-mock-store';
import Register from './register';

describe('Register', () => {
let wrapper;
const peers = { data: {} };
const account = {};
const store = configureMockStore([])({
peers,
account,
activePeerSet: () => {},
});
const options = {
context: { store },
childContextTypes: {
store: PropTypes.object.isRequired,
},
};
const prop = {
account,
peers,
activePeerSet: spy(),
t: key => key,
};

beforeEach(() => {
wrapper = mount(<Register {...prop} />, options);
});

it('renders Passphrase component', () => {
expect(wrapper.find('Passphrase')).to.have.length(1);
});

it('should mount Register with appropriate properties', () => {
const props = wrapper.find('Passphrase').props();
expect(props.useCaseNote).to.be.equal('your passphrase will be required for logging in to your account.');
expect(props.securityNote).to.be.equal('This passphrase is not recoverable and if you lose it, you will lose access to your account forever.');
expect(props.confirmButton).to.be.equal('Login');
expect(props.keepModal).to.be.equal(false);
expect(typeof props.onPassGenerated).to.be.equal('function');
});

it('should call activePeerSet if props.onPassGenerated is called', () => {
const props = wrapper.find('Passphrase').props();
props.onPassGenerated('sample passphrase');
expect(prop.activePeerSet).to.have.been.calledWith({
network: { name: 'Mainnet', port: 443, ssl: true },
passphrase: 'sample passphrase',
});
});
});

0 comments on commit 629c06e

Please sign in to comment.