From 625399ba80439adc84708f3ac9bde84bcbd7d917 Mon Sep 17 00:00:00 2001 From: reyraa Date: Wed, 26 Jul 2017 17:40:31 +0200 Subject: [PATCH 1/8] Show dialog in header --- src/components/header/headerElement.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/header/headerElement.js b/src/components/header/headerElement.js index c00689dd2..a3c7d5dc0 100644 --- a/src/components/header/headerElement.js +++ b/src/components/header/headerElement.js @@ -5,6 +5,7 @@ import logo from '../../assets/images/LISK-nano.png'; import styles from './header.css'; import VerifyMessage from '../signVerify/verifyMessage'; import SignMessage from '../signVerify/signMessage'; +import RegisterDelegate from '../registerDelegate'; const HeaderElement = props => (
@@ -17,7 +18,12 @@ const HeaderElement = props => ( theme={styles} > - + props.setActiveDialog({ + title: 'Register as delegate', + childComponent: RegisterDelegate, + })} + /> props.setActiveDialog({ From 6124963e8674aa295f2451b4e94a47b56853e775 Mon Sep 17 00:00:00 2001 From: reyraa Date: Thu, 27 Jul 2017 09:23:40 +0200 Subject: [PATCH 2/8] temp --- src/components/registerDelegate/index.js | 22 +++++++ .../registerDelegate/registerDelegate.js | 57 +++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 src/components/registerDelegate/index.js create mode 100644 src/components/registerDelegate/registerDelegate.js diff --git a/src/components/registerDelegate/index.js b/src/components/registerDelegate/index.js new file mode 100644 index 000000000..378f047da --- /dev/null +++ b/src/components/registerDelegate/index.js @@ -0,0 +1,22 @@ +import { connect } from 'react-redux'; +import RegisterDelegate from './registerDelegate'; +import { accountUpdated } from '../../actions/account'; + +/** + * Using react-redux connect to pass state and dispatch to RegisterDelegate + */ +const mapStateToProps = state => ({ + account: state.account, + peers: state.peers, +}); + +const mapDispatchToProps = dispatch => ({ + onAccountUpdated: data => dispatch(accountUpdated(data)), +}); + +const RegisterDelegateConnected = connect( + mapStateToProps, + mapDispatchToProps, +)(RegisterDelegate); + +export default RegisterDelegateConnected; diff --git a/src/components/registerDelegate/registerDelegate.js b/src/components/registerDelegate/registerDelegate.js new file mode 100644 index 000000000..9f28b1b52 --- /dev/null +++ b/src/components/registerDelegate/registerDelegate.js @@ -0,0 +1,57 @@ +import React from 'react'; +import grid from 'flexboxgrid/dist/flexboxgrid.css'; +import Input from 'react-toolbox/lib/input'; +import Dropdown from 'react-toolbox/lib/dropdown'; +import Button from 'react-toolbox/lib/button'; +import InfoParagraph from '../infoParagraph'; +import registerDelegate from '../../utils/api/delegate'; + +class RegisterDelegate extends React.Component { + constructor() { + super(); + + this.state = { + title: 'register as delegate', + name: { + error: '', + name: '', + }, + }; + } + + register(username) { + console.log(name); + const secondSecret = this.props.account.secondSecret ? this.props.account.secondSecret : null; + registerDelegate(this.props.peers.data, username, this.props.account.passphrase, secondSecret) + .then((res) => { + console.log('res', res); + }); + } + + render() { + return ( +
+ +
+ + Becoming a delegate requires registration. You may choose your own + delegate name, which can be used to promote your delegate. Only the + top 101 delegates are eligible to forge. All fees are shared equally + between the top 101 delegates. + +
+
+
+ ); + } +} + +export default RegisterDelegate; From 8e4f2b44ca50f4ca11a5ca8c811442fc362df712 Mon Sep 17 00:00:00 2001 From: reyraa Date: Tue, 1 Aug 2017 15:50:12 +0200 Subject: [PATCH 3/8] Create register deliegate componenet base logic --- src/components/registerDelegate/index.js | 6 +-- .../registerDelegate/registerDelegate.js | 52 +++++++++++++------ 2 files changed, 38 insertions(+), 20 deletions(-) diff --git a/src/components/registerDelegate/index.js b/src/components/registerDelegate/index.js index 378f047da..58d390486 100644 --- a/src/components/registerDelegate/index.js +++ b/src/components/registerDelegate/index.js @@ -1,10 +1,8 @@ import { connect } from 'react-redux'; import RegisterDelegate from './registerDelegate'; import { accountUpdated } from '../../actions/account'; +import { successAlertDialogDisplayed, errorAlertDialogDisplayed } from '../../actions/dialog'; -/** - * Using react-redux connect to pass state and dispatch to RegisterDelegate - */ const mapStateToProps = state => ({ account: state.account, peers: state.peers, @@ -12,6 +10,8 @@ const mapStateToProps = state => ({ const mapDispatchToProps = dispatch => ({ onAccountUpdated: data => dispatch(accountUpdated(data)), + showSuccessAlert: data => dispatch(successAlertDialogDisplayed(data)), + showErrorAlert: data => dispatch(errorAlertDialogDisplayed(data)), }); const RegisterDelegateConnected = connect( diff --git a/src/components/registerDelegate/registerDelegate.js b/src/components/registerDelegate/registerDelegate.js index 9f28b1b52..e96ce5c0b 100644 --- a/src/components/registerDelegate/registerDelegate.js +++ b/src/components/registerDelegate/registerDelegate.js @@ -1,10 +1,9 @@ import React from 'react'; import grid from 'flexboxgrid/dist/flexboxgrid.css'; import Input from 'react-toolbox/lib/input'; -import Dropdown from 'react-toolbox/lib/dropdown'; import Button from 'react-toolbox/lib/button'; import InfoParagraph from '../infoParagraph'; -import registerDelegate from '../../utils/api/delegate'; +import { registerDelegate } from '../../utils/api/delegate'; class RegisterDelegate extends React.Component { constructor() { @@ -12,29 +11,48 @@ class RegisterDelegate extends React.Component { this.state = { title: 'register as delegate', - name: { - error: '', - name: '', - }, + name: '', + nameError: '', }; } - register(username) { - console.log(name); - const secondSecret = this.props.account.secondSecret ? this.props.account.secondSecret : null; - registerDelegate(this.props.peers.data, username, this.props.account.passphrase, secondSecret) - .then((res) => { - console.log('res', res); - }); + changeHandler(name, value) { + this.setState({ [name]: value }); + } + + register(username, secondSecret) { + registerDelegate(this.props.peers.data, username, + this.props.account.passphrase, secondSecret) + .then(() => { + this.props.showSuccessAlert({ + text: `Delegate registration was successfully submitted with username: "${this.state.name}". It can take several seconds before it is processed.`, + }); + }) + .catch((error) => { + if (error && error.message === 'Username already exists') { + this.setState({ nameError: error.message }); + } else { + this.props.showErrorAlert({ + text: error && error.message ? `${error.message}.` : 'An error occurred while registering as delegate.', + }); + } + }); } render() { + // notify use about insufficient balance return (
+ onChange={this.changeHandler.bind(this, 'name')} + error={this.state.nameError} + value={this.state.name} /> + { + this.props.account.secondSecret && + + }
Becoming a delegate requires registration. You may choose your own @@ -46,8 +64,8 @@ class RegisterDelegate extends React.Component {
); From 64b64628980abb486069456be0819698bf2a4187 Mon Sep 17 00:00:00 2001 From: reyraa Date: Tue, 1 Aug 2017 16:13:25 +0200 Subject: [PATCH 4/8] Fixing eslint bugs and adding account to Header properties --- src/components/header/headerElement.test.js | 4 +++- src/components/login/loginFormComponent.js | 2 ++ src/components/passphrase/passphraseGenerator.test.js | 2 +- src/components/voting/votingHeader.test.js | 2 +- src/utils/passphrase.test.js | 6 +----- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/components/header/headerElement.test.js b/src/components/header/headerElement.test.js index f21e99c40..8cab3d560 100644 --- a/src/components/header/headerElement.test.js +++ b/src/components/header/headerElement.test.js @@ -18,9 +18,11 @@ describe('HeaderElement', () => { beforeEach(() => { const mockInputProps = { setActiveDialog: () => { }, + account: {}, }; propsMock = sinon.mock(mockInputProps); - wrapper = shallow(); + wrapper = shallow(); }); afterEach(() => { diff --git a/src/components/login/loginFormComponent.js b/src/components/login/loginFormComponent.js index c46814c8d..3bfaf7a74 100644 --- a/src/components/login/loginFormComponent.js +++ b/src/components/login/loginFormComponent.js @@ -98,8 +98,10 @@ class LoginFormComponent extends React.Component { getAccount(this.props.peers.data, accountInfo.address).then((result) => { onAccountUpdated(result); getDelegate(this.props.peers.data, accountInfo.publicKey).then((data) => { + console.log('success'); onAccountUpdated({ delegate: data.delegate, isDelegate: true }); }).catch(() => { + console.log('error'); onAccountUpdated({ delegate: {}, isDelegate: false }); }); // redirect to main/transactions diff --git a/src/components/passphrase/passphraseGenerator.test.js b/src/components/passphrase/passphraseGenerator.test.js index 30898988d..3ab0edf0f 100644 --- a/src/components/passphrase/passphraseGenerator.test.js +++ b/src/components/passphrase/passphraseGenerator.test.js @@ -2,7 +2,7 @@ import React from 'react'; import chai, { expect } from 'chai'; import { spy } from 'sinon'; import sinonChai from 'sinon-chai'; -import { mount, shallow } from 'enzyme'; +import { shallow } from 'enzyme'; import PassphraseGenerator from './passphraseGenerator'; chai.use(sinonChai); diff --git a/src/components/voting/votingHeader.test.js b/src/components/voting/votingHeader.test.js index b47c0dcd8..fc1eb4edc 100644 --- a/src/components/voting/votingHeader.test.js +++ b/src/components/voting/votingHeader.test.js @@ -41,7 +41,7 @@ describe('VotingHeader', () => { it('click on i.material-icons should clear vlaue of search input', () => { wrapper.instance().search('query', '555'); - wrapper.find('i.material-icons').simulate('click') + wrapper.find('i.material-icons').simulate('click'); expect(wrapper.state('query')).to.be.equal(''); }); }); diff --git a/src/utils/passphrase.test.js b/src/utils/passphrase.test.js index 7340a1a15..723998859 100644 --- a/src/utils/passphrase.test.js +++ b/src/utils/passphrase.test.js @@ -1,13 +1,9 @@ -import chai, { expect } from 'chai'; -import { spy } from 'sinon'; -import sinonChai from 'sinon-chai'; +import { expect } from 'chai'; import { generateSeed, generatePassphrase } from './passphrase'; if (global._bitcore) delete global._bitcore; const mnemonic = require('bitcore-mnemonic'); -chai.use(sinonChai); - const randoms = [ 0.35125316992864564, 0.6836880327771695, 0.05720201294124072, 0.7136064360838184, 0.7655709865481362, 0.9670469669099078, 0.6699998930954159, 0.4377283727720742, From 9074cf3bd1a1a4c7414a556e00eed7340da962e8 Mon Sep 17 00:00:00 2001 From: reyraa Date: Wed, 2 Aug 2017 13:48:16 +0200 Subject: [PATCH 5/8] Add unit test coverage --- src/components/registerDelegate/index.test.js | 87 ++++++++++++ .../registerDelegate/registerDelegate.js | 4 +- .../registerDelegate/registerDelegate.test.js | 128 ++++++++++++++++++ 3 files changed, 218 insertions(+), 1 deletion(-) create mode 100644 src/components/registerDelegate/index.test.js create mode 100644 src/components/registerDelegate/registerDelegate.test.js diff --git a/src/components/registerDelegate/index.test.js b/src/components/registerDelegate/index.test.js new file mode 100644 index 000000000..9b9ab396e --- /dev/null +++ b/src/components/registerDelegate/index.test.js @@ -0,0 +1,87 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { expect } from 'chai'; +import { mount } from 'enzyme'; +import { BrowserRouter as Router } from 'react-router-dom'; +import RegisterDelegate from './registerDelegate'; +import RegisterDelegateConnected from './index'; +import { accountUpdated } from '../../actions/account'; + +describe('RegisterDelegateConnected', () => { + let mountedAccount; + // Mocking store + const peers = { + status: { + online: false, + }, + data: { + currentPeer: 'localhost', + port: 4000, + options: { + name: 'Custom Node', + }, + }, + }; + + const account = { + isDelegate: false, + address: '16313739661670634666L', + username: 'lisk-nano', + }; + + const store = { + dispatch: () => {}, + subscribe: () => {}, + getState: () => ({ + peers, + account, + }), + onAccountUpdated: () => (data) => { + store.account = data; + return accountUpdated(data); + }, + showSuccessAlert: () => {}, + showErrorAlert: () => {}, + }; + const options = { + context: { store }, + childContextTypes: { store: PropTypes.object.isRequired }, + }; + + beforeEach(() => { + mountedAccount = mount(, options); + }); + + it('should mount registerDelegate with appropriate properties', () => { + const props = mountedAccount.find(RegisterDelegate).props(); + expect(props.peers).to.be.equal(peers); + expect(props.account).to.be.equal(account); + expect(typeof props.onAccountUpdated).to.be.equal('function'); + expect(typeof props.showSuccessAlert).to.be.equal('function'); + expect(typeof props.showErrorAlert).to.be.equal('function'); + }); + + describe('onAccountUpdated', () => { + it('should return a dispatch object', () => { + const props = mountedAccount.find(RegisterDelegate).props(); + const data = props.onAccountUpdated(account); + expect(data).to.be.equal(); + }); + }); + + describe('showSuccessAlert', () => { + it('should return a dispatch object', () => { + const props = mountedAccount.find(RegisterDelegate).props(); + const data = props.showSuccessAlert('sample text'); + expect(data).to.be.equal(); + }); + }); + + describe('showErrorAlert', () => { + it('should return a dispatch object', () => { + const props = mountedAccount.find(RegisterDelegate).props(); + const data = props.showErrorAlert('sample text'); + expect(data).to.be.equal(); + }); + }); +}); diff --git a/src/components/registerDelegate/registerDelegate.js b/src/components/registerDelegate/registerDelegate.js index e96ce5c0b..0be18a0f2 100644 --- a/src/components/registerDelegate/registerDelegate.js +++ b/src/components/registerDelegate/registerDelegate.js @@ -10,7 +10,6 @@ class RegisterDelegate extends React.Component { super(); this.state = { - title: 'register as delegate', name: '', nameError: '', }; @@ -45,12 +44,14 @@ class RegisterDelegate extends React.Component {
{ this.props.account.secondSecret && }
@@ -65,6 +66,7 @@ class RegisterDelegate extends React.Component {
diff --git a/src/components/registerDelegate/registerDelegate.test.js b/src/components/registerDelegate/registerDelegate.test.js new file mode 100644 index 000000000..269ac44d7 --- /dev/null +++ b/src/components/registerDelegate/registerDelegate.test.js @@ -0,0 +1,128 @@ +import React from 'react'; +import chai, { expect } from 'chai'; +import { mount } from 'enzyme'; +import chaiEnzyme from 'chai-enzyme'; +import sinon from 'sinon'; +import Lisk from 'lisk-js'; +import RegisterDelegate from './registerDelegate'; +import * as delegateApi from '../../utils/api/delegate'; + +chai.use(chaiEnzyme()); + +const normalAccount = { + isDelegate: false, + address: '16313739661670634666L', + balance: 1000e8, +}; + +const delegateAccount = { + isDelegate: true, + address: '16313739661670634666L', + balance: 1000e8, + delegate: { + username: 'lisk-nano', + }, +}; + +const withSecondSecretAccount = { + isDelegate: true, + address: '16313739661670634666L', + balance: 1000e8, + delegate: { + username: 'lisk-nano', + }, + secondSecret: 'sample phrase', +}; + +const props = { + peers: { + data: Lisk.api({ + name: 'Custom Node', + custom: true, + address: 'http://localhost:4000', + testnet: true, + nethash: '198f2b61a8eb95fbeed58b8216780b68f697f26b849acf00c8c93bb9b24f783d', + }), + }, + closeDialog: () => {}, + onAccountUpdated: () => {}, + showSuccessAlert: () => {}, + showErrorAlert: () => {}, +}; + +const delegateProps = { ...props, account: delegateAccount }; +const normalProps = { ...props, account: normalAccount }; +const withSecondSecretProps = { ...props, account: withSecondSecretAccount }; + +describe('RegisterDelegate', () => { + let wrapper; + let delegateApiMock; + + beforeEach(() => { + delegateApiMock = sinon.mock(delegateApi); + }); + + afterEach(() => { + delegateApiMock.verify(); + delegateApiMock.restore(); + }); + + describe('Ordinary account', () => { + beforeEach(() => { + wrapper = mount(); + }); + + it('renders an InfoParagraph components', () => { + expect(wrapper.find('InfoParagraph')).to.have.length(1); + }); + + it('renders one Input component for a normal account', () => { + expect(wrapper.find('Input')).to.have.length(1); + }); + + it('allows register as delegate for a non delegate account', () => { + delegateApiMock.expects('registerDelegate').resolves({ success: true }); + + wrapper.find('.username input').simulate('change', { target: { value: 'sample_username' } }); + wrapper.find('.submit-button').simulate('click'); + }); + + it('does not allow registering an existing username', () => { + delegateApiMock.expects('registerDelegate').resolves({ success: false }); + + wrapper.find('.username input').simulate('change', { target: { value: 'sample_username' } }); + wrapper.find('.submit-button').simulate('click'); + }); + }); + + describe('Ordinary account with second secret', () => { + beforeEach(() => { + wrapper = mount(); + }); + + it('renders two Input component for a an account with second secret', () => { + expect(wrapper.find('Input')).to.have.length(2); + }); + + it('allows register as delegate for a non delegate account with second secret', () => { + delegateApiMock.expects('registerDelegate').resolves({ success: true }); + + wrapper.find('.username input').simulate('change', { target: { value: 'sample_username' } }); + wrapper.find('.second-secret input').simulate('change', { target: { value: 'sample phrase' } }); + wrapper.find('.submit-button').simulate('click'); + }); + }); + + describe('Delegate account', () => { + beforeEach(() => { + wrapper = mount(); + }); + + it('does not allow register as delegate for a delegate account', () => { + delegateApiMock.expects('registerDelegate').resolves({ success: false }); + + wrapper.find('.username input').simulate('change', { target: { value: 'sample_username' } }); + wrapper.find('.submit-button').simulate('click'); + }); + }); +}); From 8a2328e3d5b6c3122809a5056282707406817e50 Mon Sep 17 00:00:00 2001 From: reyraa Date: Wed, 2 Aug 2017 14:05:23 +0200 Subject: [PATCH 6/8] Minor fixing --- src/components/header/headerElement.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/components/header/headerElement.js b/src/components/header/headerElement.js index 2510387ac..de56399af 100644 --- a/src/components/header/headerElement.js +++ b/src/components/header/headerElement.js @@ -21,13 +21,15 @@ const HeaderElement = props => ( theme={styles} > - props.setActiveDialog({ - title: 'Register as delegate', - childComponent: RegisterDelegate, - })} - /> + { + !props.account.isDelegate && + props.setActiveDialog({ + title: 'Register as delegate', + childComponent: RegisterDelegate, + })} + /> + } props.setActiveDialog({ From 702482277689fb2f46f2ac233e879b57a50d4b6a Mon Sep 17 00:00:00 2001 From: reyraa Date: Fri, 4 Aug 2017 15:08:09 +0200 Subject: [PATCH 7/8] Improve unit tests --- src/components/registerDelegate/index.test.js | 62 +++++++++++++------ 1 file changed, 43 insertions(+), 19 deletions(-) diff --git a/src/components/registerDelegate/index.test.js b/src/components/registerDelegate/index.test.js index 9b9ab396e..217a0b0fd 100644 --- a/src/components/registerDelegate/index.test.js +++ b/src/components/registerDelegate/index.test.js @@ -1,11 +1,14 @@ import React from 'react'; -import PropTypes from 'prop-types'; import { expect } from 'chai'; import { mount } from 'enzyme'; -import { BrowserRouter as Router } from 'react-router-dom'; +import configureStore from 'redux-mock-store'; import RegisterDelegate from './registerDelegate'; import RegisterDelegateConnected from './index'; import { accountUpdated } from '../../actions/account'; +import actionTypes from '../../constants/actions'; +import Alert from '../dialog/alert'; + +const fakeStore = configureStore(); describe('RegisterDelegateConnected', () => { let mountedAccount; @@ -29,13 +32,12 @@ describe('RegisterDelegateConnected', () => { username: 'lisk-nano', }; - const store = { - dispatch: () => {}, - subscribe: () => {}, - getState: () => ({ - peers, - account, - }), + const store = fakeStore({ + account, + peers, + }); + + const initialProps = { onAccountUpdated: () => (data) => { store.account = data; return accountUpdated(data); @@ -43,13 +45,9 @@ describe('RegisterDelegateConnected', () => { showSuccessAlert: () => {}, showErrorAlert: () => {}, }; - const options = { - context: { store }, - childContextTypes: { store: PropTypes.object.isRequired }, - }; beforeEach(() => { - mountedAccount = mount(, options); + mountedAccount = mount(); }); it('should mount registerDelegate with appropriate properties', () => { @@ -65,23 +63,49 @@ describe('RegisterDelegateConnected', () => { it('should return a dispatch object', () => { const props = mountedAccount.find(RegisterDelegate).props(); const data = props.onAccountUpdated(account); - expect(data).to.be.equal(); + + expect(data).to.deep.equal({ + type: actionTypes.accountUpdated, + data: account, + }); }); }); describe('showSuccessAlert', () => { it('should return a dispatch object', () => { const props = mountedAccount.find(RegisterDelegate).props(); - const data = props.showSuccessAlert('sample text'); - expect(data).to.be.equal(); + const data = props.showSuccessAlert({ text: 'sample text' }); + + expect(data).to.deep.equal({ + type: actionTypes.dialogDisplayed, + data: { + title: 'Success', + type: 'success', + childComponent: Alert, + childComponentProps: { + text: 'sample text', + }, + }, + }); }); }); describe('showErrorAlert', () => { it('should return a dispatch object', () => { const props = mountedAccount.find(RegisterDelegate).props(); - const data = props.showErrorAlert('sample text'); - expect(data).to.be.equal(); + const data = props.showErrorAlert({ text: 'sample text' }); + + expect(data).to.deep.equal({ + type: actionTypes.dialogHidden, + data: { + title: 'Error', + type: 'error', + childComponent: Alert, + childComponentProps: { + text: 'sample text', + }, + }, + }); }); }); }); From 55ac4496837d0ce7b34619426c83849b10346ef7 Mon Sep 17 00:00:00 2001 From: reyraa Date: Fri, 11 Aug 2017 14:01:17 +0200 Subject: [PATCH 8/8] Adapt unit tests --- src/components/registerDelegate/index.js | 6 +- src/components/registerDelegate/index.test.js | 110 ++---------------- .../registerDelegate/registerDelegate.js | 41 ++++--- .../registerDelegate/registerDelegate.test.js | 32 ++--- 4 files changed, 51 insertions(+), 138 deletions(-) diff --git a/src/components/registerDelegate/index.js b/src/components/registerDelegate/index.js index 58d390486..4ffeb88a6 100644 --- a/src/components/registerDelegate/index.js +++ b/src/components/registerDelegate/index.js @@ -1,6 +1,7 @@ import { connect } from 'react-redux'; import RegisterDelegate from './registerDelegate'; import { accountUpdated } from '../../actions/account'; +import { transactionAdded } from '../../actions/transactions'; import { successAlertDialogDisplayed, errorAlertDialogDisplayed } from '../../actions/dialog'; const mapStateToProps = state => ({ @@ -12,11 +13,10 @@ const mapDispatchToProps = dispatch => ({ onAccountUpdated: data => dispatch(accountUpdated(data)), showSuccessAlert: data => dispatch(successAlertDialogDisplayed(data)), showErrorAlert: data => dispatch(errorAlertDialogDisplayed(data)), + addTransaction: data => dispatch(transactionAdded(data)), }); -const RegisterDelegateConnected = connect( +export default connect( mapStateToProps, mapDispatchToProps, )(RegisterDelegate); - -export default RegisterDelegateConnected; diff --git a/src/components/registerDelegate/index.test.js b/src/components/registerDelegate/index.test.js index 217a0b0fd..3b9feade8 100644 --- a/src/components/registerDelegate/index.test.js +++ b/src/components/registerDelegate/index.test.js @@ -1,111 +1,23 @@ import React from 'react'; import { expect } from 'chai'; import { mount } from 'enzyme'; -import configureStore from 'redux-mock-store'; -import RegisterDelegate from './registerDelegate'; -import RegisterDelegateConnected from './index'; -import { accountUpdated } from '../../actions/account'; -import actionTypes from '../../constants/actions'; -import Alert from '../dialog/alert'; +import { Provider } from 'react-redux'; +import store from '../../store'; +import RegisterDelegate from './index'; -const fakeStore = configureStore(); - -describe('RegisterDelegateConnected', () => { - let mountedAccount; - // Mocking store - const peers = { - status: { - online: false, - }, - data: { - currentPeer: 'localhost', - port: 4000, - options: { - name: 'Custom Node', - }, - }, - }; - - const account = { - isDelegate: false, - address: '16313739661670634666L', - username: 'lisk-nano', - }; - - const store = fakeStore({ - account, - peers, - }); - - const initialProps = { - onAccountUpdated: () => (data) => { - store.account = data; - return accountUpdated(data); - }, - showSuccessAlert: () => {}, - showErrorAlert: () => {}, - }; +describe('RegisterDelegate HOC', () => { + let wrapper; beforeEach(() => { - mountedAccount = mount(); - }); - - it('should mount registerDelegate with appropriate properties', () => { - const props = mountedAccount.find(RegisterDelegate).props(); - expect(props.peers).to.be.equal(peers); - expect(props.account).to.be.equal(account); - expect(typeof props.onAccountUpdated).to.be.equal('function'); - expect(typeof props.showSuccessAlert).to.be.equal('function'); - expect(typeof props.showErrorAlert).to.be.equal('function'); + wrapper = mount( {}} />); }); - describe('onAccountUpdated', () => { - it('should return a dispatch object', () => { - const props = mountedAccount.find(RegisterDelegate).props(); - const data = props.onAccountUpdated(account); - - expect(data).to.deep.equal({ - type: actionTypes.accountUpdated, - data: account, - }); - }); + it('should render RegisterDelegate', () => { + expect(wrapper.find('RegisterDelegate')).to.have.lengthOf(1); }); - describe('showSuccessAlert', () => { - it('should return a dispatch object', () => { - const props = mountedAccount.find(RegisterDelegate).props(); - const data = props.showSuccessAlert({ text: 'sample text' }); - - expect(data).to.deep.equal({ - type: actionTypes.dialogDisplayed, - data: { - title: 'Success', - type: 'success', - childComponent: Alert, - childComponentProps: { - text: 'sample text', - }, - }, - }); - }); - }); - - describe('showErrorAlert', () => { - it('should return a dispatch object', () => { - const props = mountedAccount.find(RegisterDelegate).props(); - const data = props.showErrorAlert({ text: 'sample text' }); - - expect(data).to.deep.equal({ - type: actionTypes.dialogHidden, - data: { - title: 'Error', - type: 'error', - childComponent: Alert, - childComponentProps: { - text: 'sample text', - }, - }, - }); - }); + it('should mount registerDelegate with appropriate properties', () => { + const props = wrapper.find('RegisterDelegate').props(); + expect(typeof props.closeDialog).to.be.equal('function'); }); }); diff --git a/src/components/registerDelegate/registerDelegate.js b/src/components/registerDelegate/registerDelegate.js index 0be18a0f2..d33751f3b 100644 --- a/src/components/registerDelegate/registerDelegate.js +++ b/src/components/registerDelegate/registerDelegate.js @@ -1,9 +1,9 @@ import React from 'react'; -import grid from 'flexboxgrid/dist/flexboxgrid.css'; import Input from 'react-toolbox/lib/input'; -import Button from 'react-toolbox/lib/button'; import InfoParagraph from '../infoParagraph'; +import ActionBar from '../actionBar'; import { registerDelegate } from '../../utils/api/delegate'; +import Fees from '../../constants/fees'; class RegisterDelegate extends React.Component { constructor() { @@ -22,10 +22,19 @@ class RegisterDelegate extends React.Component { register(username, secondSecret) { registerDelegate(this.props.peers.data, username, this.props.account.passphrase, secondSecret) - .then(() => { + .then((data) => { this.props.showSuccessAlert({ text: `Delegate registration was successfully submitted with username: "${this.state.name}". It can take several seconds before it is processed.`, }); + + // add to pending transaction + this.props.addTransaction({ + id: data.transactionId, + senderPublicKey: this.props.account.publicKey, + senderId: this.props.account.address, + amount: 0, + fee: Fees.registerDelegate, + }); }) .catch((error) => { if (error && error.message === 'Username already exists') { @@ -39,7 +48,6 @@ class RegisterDelegate extends React.Component { } render() { - // notify use about insufficient balance return (
{ - this.props.account.secondSecret && - }
@@ -61,14 +71,17 @@ class RegisterDelegate extends React.Component { top 101 delegates are eligible to forge. All fees are shared equally between the top 101 delegates. -
-
+
); } diff --git a/src/components/registerDelegate/registerDelegate.test.js b/src/components/registerDelegate/registerDelegate.test.js index 269ac44d7..c16dfb093 100644 --- a/src/components/registerDelegate/registerDelegate.test.js +++ b/src/components/registerDelegate/registerDelegate.test.js @@ -4,6 +4,8 @@ import { mount } from 'enzyme'; import chaiEnzyme from 'chai-enzyme'; import sinon from 'sinon'; import Lisk from 'lisk-js'; +import { Provider } from 'react-redux'; +import store from '../../store'; import RegisterDelegate from './registerDelegate'; import * as delegateApi from '../../utils/api/delegate'; @@ -25,13 +27,12 @@ const delegateAccount = { }; const withSecondSecretAccount = { - isDelegate: true, address: '16313739661670634666L', balance: 1000e8, delegate: { username: 'lisk-nano', }, - secondSecret: 'sample phrase', + secondSignature: 1, }; const props = { @@ -69,7 +70,7 @@ describe('RegisterDelegate', () => { describe('Ordinary account', () => { beforeEach(() => { - wrapper = mount(); + wrapper = mount(); }); it('renders an InfoParagraph components', () => { @@ -80,24 +81,16 @@ describe('RegisterDelegate', () => { expect(wrapper.find('Input')).to.have.length(1); }); - it('allows register as delegate for a non delegate account', () => { - delegateApiMock.expects('registerDelegate').resolves({ success: true }); - - wrapper.find('.username input').simulate('change', { target: { value: 'sample_username' } }); - wrapper.find('.submit-button').simulate('click'); - }); - - it('does not allow registering an existing username', () => { - delegateApiMock.expects('registerDelegate').resolves({ success: false }); - + it.skip('allows register as delegate for a non delegate account', () => { wrapper.find('.username input').simulate('change', { target: { value: 'sample_username' } }); - wrapper.find('.submit-button').simulate('click'); + expect(wrapper.find('.primary-button button').props().disabled).to.not.equal(true); }); }); describe('Ordinary account with second secret', () => { beforeEach(() => { - wrapper = mount(); + wrapper = mount( + ); }); it('renders two Input component for a an account with second secret', () => { @@ -105,24 +98,19 @@ describe('RegisterDelegate', () => { }); it('allows register as delegate for a non delegate account with second secret', () => { - delegateApiMock.expects('registerDelegate').resolves({ success: true }); - wrapper.find('.username input').simulate('change', { target: { value: 'sample_username' } }); wrapper.find('.second-secret input').simulate('change', { target: { value: 'sample phrase' } }); - wrapper.find('.submit-button').simulate('click'); }); }); describe('Delegate account', () => { beforeEach(() => { - wrapper = mount(); + wrapper = mount(); }); it('does not allow register as delegate for a delegate account', () => { - delegateApiMock.expects('registerDelegate').resolves({ success: false }); - wrapper.find('.username input').simulate('change', { target: { value: 'sample_username' } }); - wrapper.find('.submit-button').simulate('click'); + expect(wrapper.find('.primary-button button').props().disabled).to.be.equal(true); }); }); });