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

Commit

Permalink
Merge branch 'development' into 642-setup-stylelint-rules-and-run-it-…
Browse files Browse the repository at this point in the history
…in-jenkins
  • Loading branch information
yasharAyari committed Sep 1, 2017
2 parents c0e0ea7 + 27195e4 commit 16453ee
Show file tree
Hide file tree
Showing 13 changed files with 112 additions and 43 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ npm run dev

Open http://localhost:8080

For ease of development, you can set a cookie to prefill a passphrase, e.g.:
For ease of development, you can setItem in localStorage to prefill a passphrase, e.g.:
```
document.cookie = 'passphrase=wagon stock borrow episode laundry kitten salute link globe zero feed marble'
localStorage.setItem('passphrase', 'wagon stock borrow episode laundry kitten salute link globe zero feed marble')
```

And then you can set a cookie to login automatically
And then you can setItem in localStorage to login automatically
```
document.cookie = 'autologin=true'
localStorage.setItem('autologin', true)
```

## Build
Expand Down
3 changes: 3 additions & 0 deletions features/menu.feature
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ Feature: Top right menu
And I fill in "test" to "username" field
And I click "register button"
Then I should see alert dialog with title "Success" and text "Delegate registration was successfully submitted. It can take several seconds before it is processed."
And I click "ok button"
And I wait 15 seconds
And I should see text "test" in "delegate name" element

Scenario: should not allow to register a delegate again
Given I'm logged in as "delegate"
Expand Down
9 changes: 7 additions & 2 deletions features/step_definitions/generic.step.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const {
waitTime,
} = require('../support/util.js');
const accounts = require('../support/accounts.js');
const localStorage = require('../support/localStorage.js');

chai.use(chaiAsPromised);
const expect = chai.expect;
Expand All @@ -31,6 +32,10 @@ defineSupportCode(({ Given, When, Then, setDefaultTimeout }) => {
waitForElemAndSendKeys(`${selectorClass} input, ${selectorClass} textarea`, secondPassphrase, callback);
});

When('I wait {seconds} seconds', (seconds, callback) => {
browser.sleep(seconds * 1000).then(callback);
});


Then('I should see "{value}" in "{fieldName}" field', (value, fieldName, callback) => {
const elem = element(by.css(`.${fieldName.replace(/ /g, '-')} input, .${fieldName.replace(/ /g, '-')} textarea`));
Expand Down Expand Up @@ -105,8 +110,8 @@ defineSupportCode(({ Given, When, Then, setDefaultTimeout }) => {
browser.ignoreSynchronization = true;
browser.driver.manage().window().setSize(1000, 1000);
browser.get('http://localhost:8080/');
browser.manage().addCookie({ name: 'address', value: 'http://localhost:4000' });
browser.manage().addCookie({ name: 'network', value: '2' });
localStorage.setItem('address', 'http://localhost:4000');
localStorage.setItem('network', 2);
browser.get('http://localhost:8080/');
waitForElemAndSendKeys('.passphrase input', accounts[accountName].passphrase);
waitForElemAndClickIt('.login-button', callback);
Expand Down
11 changes: 11 additions & 0 deletions features/support/localStorage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const localStorage = {
setItem: (key, value) => (
browser.executeScript(`return window.localStorage.setItem('${key}', '${value}');`)
),
clear: () => (
browser.executeScript('return window.localStorage.clear();')
),
};

module.exports = localStorage;

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
"bitcore-mnemonic": "=1.1.1",
"copy-to-clipboard": "=3.0.6",
"flexboxgrid": "=6.3.1",
"js-cookie": "^2.1.4",
"lisk-js": "=0.4.5",
"moment": "=2.15.1",
"postcss": "=6.0.2",
Expand Down
2 changes: 1 addition & 1 deletion src/components/account/address.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const Address = (props) => {
const title = props.isDelegate ? 'Delegate' : 'Address';
const content = props.isDelegate ?
(<div>
<p className="inner primary">
<p className="inner primary delegate-name">
{props.delegate.username}
</p>
<p className="inner secondary address">
Expand Down
2 changes: 1 addition & 1 deletion src/components/dialog/alert.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const Alert = props => (
<br />
<section className={`${grid.row} ${grid['between-xs']}`}>
<span />
<Button label='Ok' onClick={props.closeDialog}/>
<Button label='Ok' onClick={props.closeDialog} className='ok-button'/>
</section>
</div>
);
Expand Down
13 changes: 6 additions & 7 deletions src/components/login/login.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React from 'react';
import Cookies from 'js-cookie';
import grid from 'flexboxgrid/dist/flexboxgrid.css';
import Input from 'react-toolbox/lib/input';
import Dropdown from 'react-toolbox/lib/dropdown';
Expand Down Expand Up @@ -47,9 +46,9 @@ class Login extends React.Component {
this.props.history.replace(
search.indexOf('?referrer') === 0 ? search.replace('?referrer=', '') : '/main/transactions');
if (this.state.address) {
Cookies.set('address', this.state.address);
localStorage.setItem('address', this.state.address);
}
Cookies.set('network', this.state.network);
localStorage.setItem('network', this.state.network);
}
}

Expand Down Expand Up @@ -108,9 +107,9 @@ class Login extends React.Component {
}

devPreFill() {
const address = Cookies.get('address');
const passphrase = Cookies.get('passphrase');
const network = parseInt(Cookies.get('network'), 10) || 0;
const address = localStorage.getItem('address') || '';
const passphrase = localStorage.getItem('passphrase') || '';
const network = parseInt(localStorage.getItem('network'), 10) || 0;

this.setState({
network,
Expand All @@ -120,7 +119,7 @@ class Login extends React.Component {

// ignore this in coverage as it is hard to test and does not run in production
/* istanbul ignore if */
if (!env.production && Cookies.get('autologin') && !this.props.account.afterLogout && passphrase) {
if (!env.production && localStorage.getItem('autologin') && !this.props.account.afterLogout && passphrase) {
setTimeout(() => {
this.onLoginSubmission(passphrase);
});
Expand Down
15 changes: 7 additions & 8 deletions src/components/login/login.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { spy } from 'sinon';
import sinonChai from 'sinon-chai';
import { mount, shallow } from 'enzyme';
import Lisk from 'lisk-js';
import Cookies from 'js-cookie';
import Login from './login';

chai.use(sinonChai);
Expand Down Expand Up @@ -84,15 +83,15 @@ describe('Login', () => {
expect(props.history.replace).to.have.been.calledWith('/main/transactions');
});

it('calls Cookies.set(\'address\', address) if this.state.address', () => {
const spyFn = spy(Cookies, 'set');
it('calls localStorage.setItem(\'address\', address) if this.state.address', () => {
const spyFn = spy(localStorage, 'setItem');
wrapper = mount(<Login {...props} />);
wrapper.setState({ address });
wrapper.setProps(props);
expect(spyFn).to.have.been.calledWith('address', address);

spyFn.restore();
Cookies.remove('address');
localStorage.removeItem('address');
});
});

Expand Down Expand Up @@ -198,8 +197,8 @@ describe('Login', () => {
it('should set state with correct network index and passphrase', () => {
const spyFn = spy(Login.prototype, 'validateUrl');
const passphrase = 'Test Passphrase';
document.cookie = 'address=http:localhost:4000';
document.cookie = `passphrase=${passphrase}`;
localStorage.setItem('address', 'http:localhost:4000');
localStorage.setItem('passphrase', passphrase);

// for invalid address, it should set network to 0
mount(<Login {...props} />);
Expand All @@ -215,8 +214,8 @@ describe('Login', () => {
const spyFn = spy(Login.prototype, 'validateUrl');
// for valid address should set network to 2
const passphrase = 'Test Passphrase';
document.cookie = `passphrase=${passphrase}`;
document.cookie = 'address=http://localhost:4000';
localStorage.setItem('passphrase', passphrase);
localStorage.setItem('address', 'http:localhost:4000');
mount(<Login {...props} />);
expect(spyFn).to.have.been.calledWith({
passphrase,
Expand Down
10 changes: 6 additions & 4 deletions src/components/transactions/amount.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,20 @@ import styles from './transactions.css';
import LiskAmount from '../liskAmount';
import { TooltipWrapper } from '../timestamp';
import ClickToSend from '../clickToSend';
import transactionTypes from '../../constants/transactionTypes';

const Amount = (props) => {
const params = {};
if (props.value.type === 0 &&
if (props.value.type === transactionTypes.send &&
props.value.senderId === props.value.recipientId) {
params.className = 'grayButton';
} else if (props.value.senderId !== props.address) {
params.className = 'inButton';
} else if (props.value.type !== 0 || props.value.recipientId !== props.address) {
} else if (props.value.type !== transactionTypes.send ||
props.value.recipientId !== props.address) {
params.className = 'outButton';
params.tooltipText = props.value.type === 0 ? 'Repeat the transaction' : undefined;
params.clickToSendEnabled = props.value.type === 0;
params.tooltipText = props.value.type === transactionTypes.send ? 'Repeat the transaction' : undefined;
params.clickToSendEnabled = props.value.type === transactionTypes.send;
}
return <TooltipWrapper tooltip={params.tooltipText}>
<ClickToSend rawAmount={props.value.amount}
Expand Down
7 changes: 7 additions & 0 deletions src/constants/transactionTypes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default {
send: 0,
setSecondPassphrase: 1,
registerDelegate: 2,
vote: 3,
};

40 changes: 29 additions & 11 deletions src/store/middlewares/account.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
import { getAccountStatus, getAccount, transactions } from '../../utils/api/account';
import { accountUpdated } from '../../actions/account';
import { accountUpdated, accountLoggedIn } from '../../actions/account';
import { transactionsUpdated } from '../../actions/transactions';
import { activePeerUpdate } from '../../actions/peers';
import actionTypes from '../../constants/actions';
import { fetchAndUpdateForgedBlocks } from '../../actions/forging';
import { getDelegate } from '../../utils/api/delegate';
import transactionTypes from '../../constants/transactionTypes';

const updateAccountData = next => (store) => { // eslint-disable-line
const updateAccountData = (store) => { // eslint-disable-line
const { peers, account } = store.getState();

getAccount(peers.data, account.address).then((result) => {
if (result.balance !== account.balance) {
const maxBlockSize = 25;
transactions(peers.data, account.address, maxBlockSize)
.then(response => next(transactionsUpdated({
confirmed: response.transactions,
count: parseInt(response.count, 10),
})));
.then(response => store.dispatch(transactionsUpdated({
confirmed: response.transactions,
count: parseInt(response.count, 10),
})));
if (account.isDelegate) {
store.dispatch(fetchAndUpdateForgedBlocks({
activePeer: peers.data,
Expand All @@ -25,22 +27,38 @@ const updateAccountData = next => (store) => { // eslint-disable-line
}));
}
}
next(accountUpdated(result));
store.dispatch(accountUpdated(result));
});

return getAccountStatus(peers.data).then(() => {
next(activePeerUpdate({ online: true }));
store.dispatch(activePeerUpdate({ online: true }));
}).catch((res) => {
next(activePeerUpdate({ online: false, code: res.error.code }));
store.dispatch(activePeerUpdate({ online: false, code: res.error.code }));
});
};

const delegateRegistration = (store, action) => {
const delegateRegistrationTx = action.data.confirmed.filter(
transaction => transaction.type === transactionTypes.registerDelegate)[0];
const state = store.getState();

if (delegateRegistrationTx) {
getDelegate(state.peers.data, state.account.publicKey)
.then((delegateData) => {
store.dispatch(accountLoggedIn(Object.assign({},
{ delegate: delegateData.delegate, isDelegate: true })));
});
}
};

const accountMiddleware = store => next => (action) => {
next(action);
const update = updateAccountData(next);
switch (action.type) {
case actionTypes.metronomeBeat:
update(store);
updateAccountData(store);
break;
case actionTypes.transactionsUpdated:
delegateRegistration(store, action);
break;
default: break;
}
Expand Down
34 changes: 30 additions & 4 deletions src/store/middlewares/account.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,22 @@ import { expect } from 'chai';
import { spy, stub } from 'sinon';
import middleware from './account';
import * as accountApi from '../../utils/api/account';
import * as delegateApi from '../../utils/api/delegate';
import actionTypes from '../../constants/actions';
// import * as forgingActions from '../../actions/forging';
import transactionTypes from '../../constants/transactionTypes';

describe('Account middleware', () => {
let store;
let next;
let state;
const transactionsUpdatedAction = {
type: actionTypes.transactionsUpdated,
data: {
confirmed: [{
type: transactionTypes.registerDelegate,
}],
},
};

beforeEach(() => {
store = stub();
Expand All @@ -21,11 +30,11 @@ describe('Account middleware', () => {
balance: 0,
},
};
store.getState = () => (state);
next = spy();
});

it('should passes the action to next middleware', () => {
store.getState = () => (state);
const expectedAction = {
type: 'TEST_ACTION',
};
Expand All @@ -35,7 +44,6 @@ describe('Account middleware', () => {
});

it(`should call account API methods on ${actionTypes.metronomeBeat} action`, () => {
store.getState = () => (state);
const stubGetAccount = stub(accountApi, 'getAccount').resolves({ balance: 0 });
const stubGetAccountStatus = stub(accountApi, 'getAccountStatus').resolves(true);

Expand All @@ -49,7 +57,6 @@ describe('Account middleware', () => {
});

it(`should call transactions API methods on ${actionTypes.metronomeBeat} action if account.balance changes`, () => {
store.getState = () => (state);
const stubGetAccount = stub(accountApi, 'getAccount').resolves({ balance: 10e8 });
const stubTransactions = stub(accountApi, 'transactions').resolves(true);

Expand Down Expand Up @@ -78,5 +85,24 @@ describe('Account middleware', () => {
stubGetAccount.restore();
stubGetAccountStatus.restore();
});

it(`should fetch delegate info on ${actionTypes.transactionsUpdated} action if action.data.confirmed contains delegateRegistration transactions`, () => {
const delegateApiMock = stub(delegateApi, 'getDelegate').returnsPromise().resolves({ success: true, delegate: {} });

middleware(store)(next)(transactionsUpdatedAction);
expect(store.dispatch).to.have.been.calledWith();

delegateApiMock.restore();
});

it(`should not fetch delegate info on ${actionTypes.transactionsUpdated} action if action.data.confirmed does not contain delegateRegistration transactions`, () => {
const delegateApiMock = stub(delegateApi, 'getDelegate').returnsPromise().resolves({ success: true, delegate: {} });
transactionsUpdatedAction.data.confirmed[0].type = transactionTypes.send;

middleware(store)(next)(transactionsUpdatedAction);
expect(store.dispatch).to.not.have.been.calledWith();

delegateApiMock.restore();
});
});

0 comments on commit 16453ee

Please sign in to comment.