From 03eb86d5e7dd4ec3eacd80ecdef5b36b84283e76 Mon Sep 17 00:00:00 2001 From: reyraa Date: Wed, 28 Feb 2018 10:17:06 +0100 Subject: [PATCH 1/8] Create some generic steps --- test/integration/steps.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/integration/steps.js b/test/integration/steps.js index 561bf825c5..be1b657e46 100644 --- a/test/integration/steps.js +++ b/test/integration/steps.js @@ -10,3 +10,12 @@ export const containsMessage = (wrapper, elementName, message) => { const selector = `.${elementName.replace(/ /g, '-')}`; expect(wrapper.find(selector).first().text()).to.contain(message); }; + +export const fillInputField = (wrapper, value, field) => { + wrapper.find(`.${field} input`).first().simulate('change', { target: { value } }); +}; + +export const selectOptionItem = (wrapper, optionIndex, field) => { + const selector = `.${field.replace(/ /g, '-')} ul li`; + wrapper.find(selector).at(parseInt(optionIndex, 10) - 1).simulate('click'); +}; From 5c54fcb0b91201808facbb08ddad0e5f08f6b8ff Mon Sep 17 00:00:00 2001 From: reyraa Date: Wed, 28 Feb 2018 10:17:33 +0100 Subject: [PATCH 2/8] Create integration tests for Login page --- test/integration/login.test.js | 131 ++++++++++++++++++++++++++++++--- 1 file changed, 120 insertions(+), 11 deletions(-) diff --git a/test/integration/login.test.js b/test/integration/login.test.js index 9d51d9eb1b..a8d150fdf5 100644 --- a/test/integration/login.test.js +++ b/test/integration/login.test.js @@ -1,20 +1,129 @@ import { step } from 'mocha-steps'; +import thunk from 'redux-thunk'; +import { expect } from 'chai'; +import { mount } from 'enzyme'; +import { stub, spy } from 'sinon'; + +import * as peers from '../../src/utils/api/peers'; +import * as accountAPI from '../../src/utils/api/account'; +import * as delegateAPI from '../../src/utils/api/delegate'; +import * as netHash from '../../src/utils/api/nethash'; +import { prepareStore, renderWithRouter } from '../utils/applicationInit'; +import accountReducer from '../../src/store/reducers/account'; +import peersReducer from '../../src/store/reducers/peers'; +import settingsReducer from '../../src/store/reducers/settings'; +import savedAccountsReducer from '../../src/store/reducers/savedAccounts'; +import loginMiddleware from '../../src/store/middlewares/login'; +import accountMiddleware from '../../src/store/middlewares/account'; +import peerMiddleware from '../../src/store/middlewares/peers'; +import { activePeerSet } from '../../src/actions/peers'; +import * as toasterActions from '../../src/actions/toaster'; +import Login from './../../src/components/login'; +import accounts from '../constants/accounts'; +import { fillInputField, selectOptionItem } from './steps'; describe('@integration: Login', () => { + let store; + let wrapper; + const requestToActivePeerStub = stub(peers, 'requestToActivePeer'); + const accountAPIStub = stub(accountAPI, 'getAccount'); + const delegateAPIStub = stub(delegateAPI, 'getDelegate'); + const netHashAPIStub = stub(netHash, 'getNethash'); + const localStorageStub = stub(localStorage, 'getItem'); + const errorToastDisplayedSpy = spy(toasterActions, 'errorToastDisplayed'); + const localhostUrl = 'http://localhost:4218'; + const connectionErrorMessage = 'Unable to connect to the node'; + + afterEach(() => { + wrapper.update(); + }); + + const createStore = () => { + store = prepareStore({ + account: accountReducer, + peers: peersReducer, + savedAccounts: savedAccountsReducer, + settings: settingsReducer, + }, [ + thunk, + accountMiddleware, + loginMiddleware, + peerMiddleware, + ]); + }; + + const setupScenarioDefault = () => { + createStore(); + + localStorageStub.withArgs('accounts').returns(JSON.stringify([{}, {}])); + localStorageStub.withArgs('showNetwork').returns(JSON.stringify(true)); + accountAPIStub.returnsPromise().resolves({ + address: '6307319849853921018L', + unconfirmedBalance: '10190054753073', + balance: '10190054753073', + publicKey: '8ab0b8b0e663d49c8aaf3a8a6d75a46b477455f9d25ac92898461164c31758ee', + unconfirmedSignature: 0, + secondSignature: 0, + secondPublicKey: null, + multisignatures: [], + u_multisignatures: [], + }); + delegateAPIStub.returnsPromise().rejects(); + + wrapper = mount(renderWithRouter(Login, store, { location: { search: '' } })); + }; + + const setupScenarioInvalidNode = () => { + createStore(); + + localStorageStub.withArgs('accounts').returns(JSON.stringify([{}, {}])); + localStorageStub.withArgs('showNetwork').returns(JSON.stringify(true)); + netHashAPIStub.returnsPromise().rejects(); + accountAPIStub.returnsPromise().rejects(); + delegateAPIStub.returnsPromise().rejects(); + + wrapper = mount(renderWithRouter(Login, store, { location: { search: '' } }), { activePeerSet }); + }; + + const restoreStubs = () => { + requestToActivePeerStub.restore(); + localStorageStub.restore(); + accountAPIStub.restore(); + delegateAPIStub.restore(); + }; + + const submit = () => { + wrapper.find('form').simulate('submit', {}); + }; + + const checkIfInRoute = () => { + expect(store.getState().account).to.have.all.keys('passphrase', 'publicKey', 'address', 'delegate', + 'isDelegate', 'expireTime', 'u_multisignatures', 'multisignatures', 'unconfirmedBalance', + 'secondSignature', 'secondPublicKey', 'balance', 'unconfirmedSignature'); + restoreStubs(); + }; + + const checkIfErrorToastFired = () => { + expect(errorToastDisplayedSpy).to.have.been.calledWith({ label: connectionErrorMessage }); + restoreStubs(); + }; + describe('Scenario: should allow to login', () => { - step('Given I\'m on login page'); - step('When I fill in "wagon stock borrow episode laundry kitten salute link globe zero feed marble" to "passphrase" field'); - step('And I click "login button"'); - step('Then I should be logged in'); + step('Given I\'m on login page', setupScenarioDefault); + step(`When I fill "${accounts.genesis.passphrase}" into "passphrase" field`, + () => fillInputField(wrapper, accounts.genesis.passphrase, 'passphrase')); + step('And I click "login button"', () => submit(wrapper, 'login button')); + step('Then I should be logged in', () => checkIfInRoute()); }); describe('Scenario: should show toast when trying to connect to an unavailable custom node', () => { - step('Given I\'m on login page'); - step('When I fill in "wagon stock borrow episode laundry kitten salute link globe zero feed marble" to "passphrase" field'); - step('And I select option no. 3 from "network" select'); - step('And I clear "address" field'); - step('And I fill in "http://localhost:4218" to "address" field'); - step('And I click "login button"'); - step('Then I should see text "Unable to connect to the node" in "toast" element'); + step('Given I\'m on login page', setupScenarioInvalidNode); + step(`When I fill "${accounts.genesis.passphrase}" into "passphrase" field`, () => + fillInputField(wrapper, accounts.genesis.passphrase, 'passphrase')); + step('And I select option no. 3 from "network" select', () => selectOptionItem(wrapper, 3, 'network')); + step('And I clear "address" field', () => fillInputField(wrapper, '', 'address')); + step(`And I fill in "${localhostUrl}" to "address" field`, () => fillInputField(wrapper, localhostUrl, 'address')); + step('And I click "login button"', () => submit(wrapper, 'login button')); + step(`Then I should see text ${connectionErrorMessage} in "toast" element`, () => checkIfErrorToastFired()); }); }); From 570430bf13c065d9a8d6c57cb1b307cce3a54483 Mon Sep 17 00:00:00 2001 From: reyraa Date: Wed, 28 Feb 2018 11:20:20 +0100 Subject: [PATCH 3/8] Move generic methods to Helper class --- test/integration/steps.js | 9 --------- test/utils/genericStepDefinition.js | 22 ++++++++++++++++++++++ 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/test/integration/steps.js b/test/integration/steps.js index be1b657e46..561bf825c5 100644 --- a/test/integration/steps.js +++ b/test/integration/steps.js @@ -10,12 +10,3 @@ export const containsMessage = (wrapper, elementName, message) => { const selector = `.${elementName.replace(/ /g, '-')}`; expect(wrapper.find(selector).first().text()).to.contain(message); }; - -export const fillInputField = (wrapper, value, field) => { - wrapper.find(`.${field} input`).first().simulate('change', { target: { value } }); -}; - -export const selectOptionItem = (wrapper, optionIndex, field) => { - const selector = `.${field.replace(/ /g, '-')} ul li`; - wrapper.find(selector).at(parseInt(optionIndex, 10) - 1).simulate('click'); -}; diff --git a/test/utils/genericStepDefinition.js b/test/utils/genericStepDefinition.js index 2ae44a7202..cb325b4d45 100644 --- a/test/utils/genericStepDefinition.js +++ b/test/utils/genericStepDefinition.js @@ -41,4 +41,26 @@ export default class GenericStepDefinition { haveTextOf(query, text) { expect(this.wrapper.find(query)).to.have.text(text); } + /** + * + * @param {String} value - The value to fill in input + * @param {String} field - space separated class name of the input, without the initial dot + */ + fillInputField(value, field) { + const selector = `.${field.replace(/ /g, '-')} input`; + this.wrapper.find(selector).first().simulate('change', { target: { value } }); + } + /** + * + * @param {String} value - The index of option in the list to click on + * @param {String} field - space separated class name of the input, without the initial dot + */ + selectOptionItem(optionIndex, field) { + const selector = `.${field.replace(/ /g, '-')} ul li`; + this.wrapper.find(selector).at(parseInt(optionIndex, 10) - 1).simulate('click'); + } + + submitForm() { + this.wrapper.find('form').simulate('submit', {}); + } } From 6927f45f7b1551fc59df02159293ed0ced720d06 Mon Sep 17 00:00:00 2001 From: reyraa Date: Wed, 28 Feb 2018 11:21:06 +0100 Subject: [PATCH 4/8] Update tests to use Helper class --- test/integration/login.test.js | 90 +++++++++++++++++----------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/test/integration/login.test.js b/test/integration/login.test.js index a8d150fdf5..4223e13f80 100644 --- a/test/integration/login.test.js +++ b/test/integration/login.test.js @@ -20,11 +20,12 @@ import { activePeerSet } from '../../src/actions/peers'; import * as toasterActions from '../../src/actions/toaster'; import Login from './../../src/components/login'; import accounts from '../constants/accounts'; -import { fillInputField, selectOptionItem } from './steps'; +import GenericStepDefinition from '../utils/genericStepDefinition'; describe('@integration: Login', () => { let store; let wrapper; + let helper; const requestToActivePeerStub = stub(peers, 'requestToActivePeer'); const accountAPIStub = stub(accountAPI, 'getAccount'); const delegateAPIStub = stub(delegateAPI, 'getDelegate'); @@ -32,7 +33,8 @@ describe('@integration: Login', () => { const localStorageStub = stub(localStorage, 'getItem'); const errorToastDisplayedSpy = spy(toasterActions, 'errorToastDisplayed'); const localhostUrl = 'http://localhost:4218'; - const connectionErrorMessage = 'Unable to connect to the node'; + const errorMessage = 'Unable to connect to the node'; + const { passphrase } = accounts.genesis; afterEach(() => { wrapper.update(); @@ -52,9 +54,14 @@ describe('@integration: Login', () => { ]); }; - const setupScenarioDefault = () => { - createStore(); + const restoreStubs = () => { + requestToActivePeerStub.restore(); + localStorageStub.restore(); + accountAPIStub.restore(); + delegateAPIStub.restore(); + }; + const stubApisDefaultScenario = () => { localStorageStub.withArgs('accounts').returns(JSON.stringify([{}, {}])); localStorageStub.withArgs('showNetwork').returns(JSON.stringify(true)); accountAPIStub.returnsPromise().resolves({ @@ -69,61 +76,54 @@ describe('@integration: Login', () => { u_multisignatures: [], }); delegateAPIStub.returnsPromise().rejects(); - - wrapper = mount(renderWithRouter(Login, store, { location: { search: '' } })); }; - const setupScenarioInvalidNode = () => { - createStore(); - + const stubApisScenarioInvalidNode = () => { localStorageStub.withArgs('accounts').returns(JSON.stringify([{}, {}])); localStorageStub.withArgs('showNetwork').returns(JSON.stringify(true)); netHashAPIStub.returnsPromise().rejects(); accountAPIStub.returnsPromise().rejects(); delegateAPIStub.returnsPromise().rejects(); - - wrapper = mount(renderWithRouter(Login, store, { location: { search: '' } }), { activePeerSet }); }; - const restoreStubs = () => { - requestToActivePeerStub.restore(); - localStorageStub.restore(); - accountAPIStub.restore(); - delegateAPIStub.restore(); - }; - - const submit = () => { - wrapper.find('form').simulate('submit', {}); - }; - - const checkIfInRoute = () => { - expect(store.getState().account).to.have.all.keys('passphrase', 'publicKey', 'address', 'delegate', - 'isDelegate', 'expireTime', 'u_multisignatures', 'multisignatures', 'unconfirmedBalance', - 'secondSignature', 'secondPublicKey', 'balance', 'unconfirmedSignature'); - restoreStubs(); - }; - - const checkIfErrorToastFired = () => { - expect(errorToastDisplayedSpy).to.have.been.calledWith({ label: connectionErrorMessage }); - restoreStubs(); + class Helper extends GenericStepDefinition { + // eslint-disable-next-line class-methods-use-this + checkIfInRoute() { + expect(store.getState().account).to.have.all.keys('passphrase', 'publicKey', 'address', 'delegate', + 'isDelegate', 'expireTime', 'u_multisignatures', 'multisignatures', 'unconfirmedBalance', + 'secondSignature', 'secondPublicKey', 'balance', 'unconfirmedSignature'); + restoreStubs(); + } + + // eslint-disable-next-line class-methods-use-this + checkIfErrorToastFired() { + expect(errorToastDisplayedSpy).to.have.been.calledWith({ label: errorMessage }); + restoreStubs(); + } + } + + const setupStep = (stubApis) => { + createStore(); + stubApis(); + wrapper = mount(renderWithRouter(Login, store, { location: { search: '' } }), { activePeerSet }); + helper = new Helper(wrapper); }; describe('Scenario: should allow to login', () => { - step('Given I\'m on login page', setupScenarioDefault); - step(`When I fill "${accounts.genesis.passphrase}" into "passphrase" field`, - () => fillInputField(wrapper, accounts.genesis.passphrase, 'passphrase')); - step('And I click "login button"', () => submit(wrapper, 'login button')); - step('Then I should be logged in', () => checkIfInRoute()); + step('Given I\'m on login page', () => setupStep(stubApisDefaultScenario)); + step(`When I fill "${passphrase}" into "passphrase" field`, + () => helper.fillInputField(passphrase, 'passphrase')); + step('And I click "login button"', () => helper.submitForm()); + step('Then I should be logged in', () => helper.checkIfInRoute()); }); describe('Scenario: should show toast when trying to connect to an unavailable custom node', () => { - step('Given I\'m on login page', setupScenarioInvalidNode); - step(`When I fill "${accounts.genesis.passphrase}" into "passphrase" field`, () => - fillInputField(wrapper, accounts.genesis.passphrase, 'passphrase')); - step('And I select option no. 3 from "network" select', () => selectOptionItem(wrapper, 3, 'network')); - step('And I clear "address" field', () => fillInputField(wrapper, '', 'address')); - step(`And I fill in "${localhostUrl}" to "address" field`, () => fillInputField(wrapper, localhostUrl, 'address')); - step('And I click "login button"', () => submit(wrapper, 'login button')); - step(`Then I should see text ${connectionErrorMessage} in "toast" element`, () => checkIfErrorToastFired()); + step('Given I\'m on login page', () => setupStep(stubApisScenarioInvalidNode)); + step(`When I fill "${passphrase}" into "passphrase" field`, () => helper.fillInputField(passphrase, 'passphrase')); + step('And I select option no. 3 from "network" select', () => helper.selectOptionItem(3, 'network')); + step('And I clear "address" field', () => helper.fillInputField('', 'address')); + step(`And I fill in "${localhostUrl}" to "address" field`, () => helper.fillInputField(localhostUrl, 'address')); + step('And I click "login button"', () => helper.submitForm()); + step(`Then I should see text ${errorMessage} in "toast" element`, () => helper.checkIfErrorToastFired()); }); }); From c26e81af03e73c755d46ec99d6d2170ed55f7b9a Mon Sep 17 00:00:00 2001 From: reyraa Date: Wed, 28 Feb 2018 11:54:22 +0100 Subject: [PATCH 5/8] Stub and Spy Apis once the Scenario starts --- test/integration/login.test.js | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/test/integration/login.test.js b/test/integration/login.test.js index 4223e13f80..305fc06cc3 100644 --- a/test/integration/login.test.js +++ b/test/integration/login.test.js @@ -4,7 +4,6 @@ import { expect } from 'chai'; import { mount } from 'enzyme'; import { stub, spy } from 'sinon'; -import * as peers from '../../src/utils/api/peers'; import * as accountAPI from '../../src/utils/api/account'; import * as delegateAPI from '../../src/utils/api/delegate'; import * as netHash from '../../src/utils/api/nethash'; @@ -26,12 +25,12 @@ describe('@integration: Login', () => { let store; let wrapper; let helper; - const requestToActivePeerStub = stub(peers, 'requestToActivePeer'); - const accountAPIStub = stub(accountAPI, 'getAccount'); - const delegateAPIStub = stub(delegateAPI, 'getDelegate'); - const netHashAPIStub = stub(netHash, 'getNethash'); - const localStorageStub = stub(localStorage, 'getItem'); - const errorToastDisplayedSpy = spy(toasterActions, 'errorToastDisplayed'); + // const requestToActivePeerStub = stub(peers, 'requestToActivePeer'); + let accountAPIStub; + let delegateAPIStub; + let netHashAPIStub; + let localStorageStub; + let errorToastDisplayedSpy; const localhostUrl = 'http://localhost:4218'; const errorMessage = 'Unable to connect to the node'; const { passphrase } = accounts.genesis; @@ -55,15 +54,20 @@ describe('@integration: Login', () => { }; const restoreStubs = () => { - requestToActivePeerStub.restore(); + // requestToActivePeerStub.restore(); localStorageStub.restore(); accountAPIStub.restore(); delegateAPIStub.restore(); + netHashAPIStub.restore(); + errorToastDisplayedSpy.restore(); }; const stubApisDefaultScenario = () => { + netHashAPIStub = stub(netHash, 'getNethash').returnsPromise().rejects(); + localStorageStub = stub(localStorage, 'getItem'); localStorageStub.withArgs('accounts').returns(JSON.stringify([{}, {}])); localStorageStub.withArgs('showNetwork').returns(JSON.stringify(true)); + accountAPIStub = stub(accountAPI, 'getAccount'); accountAPIStub.returnsPromise().resolves({ address: '6307319849853921018L', unconfirmedBalance: '10190054753073', @@ -75,15 +79,18 @@ describe('@integration: Login', () => { multisignatures: [], u_multisignatures: [], }); - delegateAPIStub.returnsPromise().rejects(); + delegateAPIStub = stub(delegateAPI, 'getDelegate').returnsPromise().rejects(); + errorToastDisplayedSpy = spy(toasterActions, 'errorToastDisplayed'); }; const stubApisScenarioInvalidNode = () => { + localStorageStub = stub(localStorage, 'getItem'); localStorageStub.withArgs('accounts').returns(JSON.stringify([{}, {}])); localStorageStub.withArgs('showNetwork').returns(JSON.stringify(true)); - netHashAPIStub.returnsPromise().rejects(); - accountAPIStub.returnsPromise().rejects(); - delegateAPIStub.returnsPromise().rejects(); + netHashAPIStub = stub(netHash, 'getNethash').returnsPromise().rejects(); + accountAPIStub = stub(accountAPI, 'getAccount').returnsPromise().rejects(); + delegateAPIStub = stub(delegateAPI, 'getDelegate').returnsPromise().rejects(); + errorToastDisplayedSpy = spy(toasterActions, 'errorToastDisplayed'); }; class Helper extends GenericStepDefinition { From 58744fab864b2c35d284398c04683c6e7cea18b1 Mon Sep 17 00:00:00 2001 From: reyraa Date: Wed, 28 Feb 2018 12:33:38 +0100 Subject: [PATCH 6/8] Fix merge conflicts --- test/integration/accountSwitch.test.js | 32 ++-- test/integration/accountTransactions.test.js | 59 ++++--- test/integration/login.test.js | 31 ++-- test/integration/steps.js | 12 -- test/integration/transactionID.test.js | 25 +-- test/integration/voting.test.js | 2 +- test/integration/wallet.test.js | 153 +++++++++---------- test/utils/genericStepDefinition.js | 22 ++- 8 files changed, 162 insertions(+), 174 deletions(-) delete mode 100644 test/integration/steps.js diff --git a/test/integration/accountSwitch.test.js b/test/integration/accountSwitch.test.js index e79e575b2d..9dbf1dab1d 100644 --- a/test/integration/accountSwitch.test.js +++ b/test/integration/accountSwitch.test.js @@ -1,5 +1,4 @@ import { step } from 'mocha-steps'; -import { expect } from 'chai'; import { stub, match } from 'sinon'; import { mount } from 'enzyme'; import thunk from 'redux-thunk'; @@ -16,11 +15,12 @@ import savedAccountsReducer from '../../src/store/reducers/savedAccounts'; import SavedAccounts from '../../src/components/savedAccounts'; import * as accountApi from '../../src/utils/api/account'; import * as peers from '../../src/utils/api/peers'; -import { click } from './steps'; +import GenericStepDefinition from '../utils/genericStepDefinition'; describe('@integration: Account switch', () => { let store; let wrapper; + let helper; let getAccountStub; let requestToActivePeerStub; let localStorageStub; @@ -74,33 +74,21 @@ describe('@integration: Account switch', () => { wrapper = mount(renderWithRouter(SavedAccounts, store)); store.dispatch(accountsRetrieved()); wrapper.update(); - }; - - const clickStep = (elementName) => { - click(wrapper, elementName); - }; - - const shouldSeeCountInstancesOf = (count, elementName) => { - const selector = `.${elementName.replace(/ /g, '-')}`; - expect(wrapper.find(selector)).to.have.lengthOf(count); - }; - - const shouldBeLoggedInAs = (accountName) => { - expect(store.getState().account.publicKey).to.equal(accounts[accountName].publicKey); + helper = new GenericStepDefinition(wrapper, store); }; describe('Scenario: should allow to remove a saved account', () => { step('Given I\'m on "account switcher" with accounts: "genesis,delegate,empty account"', setupStep); - step('Then I should see 3 instances of "saved account card"', shouldSeeCountInstancesOf.bind(null, 3, 'saved account card')); - step('When I click "edit button"', clickStep.bind(null, 'edit button')); - step('When I click "remove button"', clickStep.bind(null, 'remove button')); - step('When I click "remove button"', clickStep.bind(null, 'remove button')); - step('Then I should see 2 instances of "saved account card"', shouldSeeCountInstancesOf.bind(null, 2, 'saved account card')); + step('Then I should see 3 instances of "saved account card"', () => helper.shouldSeeCountInstancesOf(3, '.saved-account-card')); + step('When I click "edit button"', () => helper.clickOnElement('button.edit-button')); + step('When I click "remove button"', () => helper.clickOnElement('button.remove-button')); + step('When I click "remove button"', () => helper.clickOnElement('button.remove-button')); + step('Then I should see 2 instances of "saved account card"', () => helper.shouldSeeCountInstancesOf(2, '.saved-account-card')); }); describe('Scenario: should allow to switch account', () => { step('Given I\'m on "account switcher" with accounts: "genesis,delegate,empty account"', setupStep); - step('When I click "saved account card"', clickStep.bind(null, 'saved account card')); - step('Then I should be logged in as "genesis" account', shouldBeLoggedInAs.bind(null, 'genesis')); + step('When I click "saved account card"', () => helper.clickOnElement('.saved-account-card')); + step('Then I should be logged in as "genesis" account', () => helper.shouldBeLoggedInAs(accounts.genesis.publicKey)); }); }); diff --git a/test/integration/accountTransactions.test.js b/test/integration/accountTransactions.test.js index ba3da61509..d8fac3af2c 100644 --- a/test/integration/accountTransactions.test.js +++ b/test/integration/accountTransactions.test.js @@ -20,10 +20,24 @@ import getNetwork from './../../src/utils/getNetwork'; import { accountLoggedIn } from '../../src/actions/account'; import AccountTransactions from './../../src/components/accountTransactions'; import accounts from '../constants/accounts'; -import { click } from './steps'; +import GenericStepDefinition from '../utils/genericStepDefinition'; + +class Helper extends GenericStepDefinition { + checkSelectedFilter(filter) { + const expectedClass = '_active'; + + const activeFilter = this.wrapper.find('.transaction-filter-item').filterWhere((item) => { + const className = item.prop('className'); + return className.includes(expectedClass); + }); + + expect(activeFilter.text().toLowerCase()).to.equal(filter); + } +} describe('@integration: Account Transactions', () => { let store; + let helper; let wrapper; let requestToActivePeerStub; let accountAPIStub; @@ -86,45 +100,28 @@ describe('@integration: Account Transactions', () => { if (accountType) { store.dispatch(accountLoggedIn(account)); } wrapper = mount(renderWithRouter(AccountTransactions, store, { match: { params: { address } } })); - }; - - const clickStep = (elementName) => { - click(wrapper, elementName); - }; - - const checkRowCount = (length) => { - expect(wrapper.find('TransactionRow')).to.have.length(length); - }; - - const checkSelectedFilter = (filter) => { - const expectedClass = '_active'; - const activeFilter = wrapper.find('.transaction-filter-item').filterWhere((item) => { - const className = item.prop('className'); - return className.includes(expectedClass); - }); - - expect(activeFilter.text().toLowerCase()).to.equal(filter); + helper = new Helper(wrapper, store); }; describe('Scenario: should allow to view transactions of any account', () => { - step('Given I\'m on "accounts/123L" as "genesis" account', setupStep.bind(null, { accountType: 'genesis', address: '123L' })); - step('Then I should see 20 transaction rows as result of the address 123L', checkRowCount.bind(null, 20)); + step('Given I\'m on "accounts/123L" as "genesis" account', () => setupStep({ accountType: 'genesis', address: '123L' })); + step('Then I should see 20 transaction rows as result of the address 123L', () => helper.shouldSeeCountInstancesOf(20, 'TransactionRow')); }); describe('Scenario: should allow to filter transactions', () => { - step('Given I\'m on "wallet" as "genesis" account', setupStep.bind(null, { accountType: 'genesis', address: '123L' })); - step('Then the "All" filter should be selected by default', checkSelectedFilter.bind(null, 'all')); - step('When I click on the "Outgoing" filter', clickStep.bind(null, 'filter out')); - step('Then I expect to see the results for "Outgoing"', checkRowCount.bind(null, 5)); - step('When I click on the "Incoming" filter', clickStep.bind(null, 'filter in')); - step('Then I expect to see the results for "Incoming"', checkRowCount.bind(null, 15)); - step('When I click again on the "All" filter', clickStep.bind(null, 'filter all')); - step('Then I expect to see the results for "All"', checkRowCount.bind(null, 20)); + step('Given I\'m on "wallet" as "genesis" account', () => setupStep({ accountType: 'genesis', address: '123L' })); + step('Then the "All" filter should be selected by default', () => helper.checkSelectedFilter('all')); + step('When I click on the "Outgoing" filter', () => helper.clickOnElement('.filter-out')); + step('Then I expect to see the results for "Outgoing"', () => helper.shouldSeeCountInstancesOf(5, 'TransactionRow')); + step('When I click on the "Incoming" filter', () => helper.clickOnElement('.filter-in')); + step('Then I expect to see the results for "Incoming"', () => helper.shouldSeeCountInstancesOf(15, 'TransactionRow')); + step('When I click again on the "All" filter', () => helper.clickOnElement('.filter-all')); + step('Then I expect to see the results for "All"', () => helper.shouldSeeCountInstancesOf(20, 'TransactionRow')); }); describe('Scenario: allows to view transactions without login', () => { - step('Given I\'m on "accounts/123L" with no account', setupStep.bind(null, { address: '123L' })); - step('Then I should see 20 transaction rows as result of the address 123L', checkRowCount.bind(null, 20)); + step('Given I\'m on "accounts/123L" with no account', () => setupStep({ address: '123L' })); + step('Then I should see 20 transaction rows as result of the address 123L', () => helper.shouldSeeCountInstancesOf(20, 'TransactionRow')); }); }); diff --git a/test/integration/login.test.js b/test/integration/login.test.js index 4223e13f80..305fc06cc3 100644 --- a/test/integration/login.test.js +++ b/test/integration/login.test.js @@ -4,7 +4,6 @@ import { expect } from 'chai'; import { mount } from 'enzyme'; import { stub, spy } from 'sinon'; -import * as peers from '../../src/utils/api/peers'; import * as accountAPI from '../../src/utils/api/account'; import * as delegateAPI from '../../src/utils/api/delegate'; import * as netHash from '../../src/utils/api/nethash'; @@ -26,12 +25,12 @@ describe('@integration: Login', () => { let store; let wrapper; let helper; - const requestToActivePeerStub = stub(peers, 'requestToActivePeer'); - const accountAPIStub = stub(accountAPI, 'getAccount'); - const delegateAPIStub = stub(delegateAPI, 'getDelegate'); - const netHashAPIStub = stub(netHash, 'getNethash'); - const localStorageStub = stub(localStorage, 'getItem'); - const errorToastDisplayedSpy = spy(toasterActions, 'errorToastDisplayed'); + // const requestToActivePeerStub = stub(peers, 'requestToActivePeer'); + let accountAPIStub; + let delegateAPIStub; + let netHashAPIStub; + let localStorageStub; + let errorToastDisplayedSpy; const localhostUrl = 'http://localhost:4218'; const errorMessage = 'Unable to connect to the node'; const { passphrase } = accounts.genesis; @@ -55,15 +54,20 @@ describe('@integration: Login', () => { }; const restoreStubs = () => { - requestToActivePeerStub.restore(); + // requestToActivePeerStub.restore(); localStorageStub.restore(); accountAPIStub.restore(); delegateAPIStub.restore(); + netHashAPIStub.restore(); + errorToastDisplayedSpy.restore(); }; const stubApisDefaultScenario = () => { + netHashAPIStub = stub(netHash, 'getNethash').returnsPromise().rejects(); + localStorageStub = stub(localStorage, 'getItem'); localStorageStub.withArgs('accounts').returns(JSON.stringify([{}, {}])); localStorageStub.withArgs('showNetwork').returns(JSON.stringify(true)); + accountAPIStub = stub(accountAPI, 'getAccount'); accountAPIStub.returnsPromise().resolves({ address: '6307319849853921018L', unconfirmedBalance: '10190054753073', @@ -75,15 +79,18 @@ describe('@integration: Login', () => { multisignatures: [], u_multisignatures: [], }); - delegateAPIStub.returnsPromise().rejects(); + delegateAPIStub = stub(delegateAPI, 'getDelegate').returnsPromise().rejects(); + errorToastDisplayedSpy = spy(toasterActions, 'errorToastDisplayed'); }; const stubApisScenarioInvalidNode = () => { + localStorageStub = stub(localStorage, 'getItem'); localStorageStub.withArgs('accounts').returns(JSON.stringify([{}, {}])); localStorageStub.withArgs('showNetwork').returns(JSON.stringify(true)); - netHashAPIStub.returnsPromise().rejects(); - accountAPIStub.returnsPromise().rejects(); - delegateAPIStub.returnsPromise().rejects(); + netHashAPIStub = stub(netHash, 'getNethash').returnsPromise().rejects(); + accountAPIStub = stub(accountAPI, 'getAccount').returnsPromise().rejects(); + delegateAPIStub = stub(delegateAPI, 'getDelegate').returnsPromise().rejects(); + errorToastDisplayedSpy = spy(toasterActions, 'errorToastDisplayed'); }; class Helper extends GenericStepDefinition { diff --git a/test/integration/steps.js b/test/integration/steps.js deleted file mode 100644 index 561bf825c5..0000000000 --- a/test/integration/steps.js +++ /dev/null @@ -1,12 +0,0 @@ -import { expect } from 'chai'; - -// eslint-disable-next-line import/prefer-default-export -export const click = (wrapper, elementName) => { - const selector = `.${elementName.replace(/ /g, '-')}`; - wrapper.find(selector).first().simulate('click'); -}; - -export const containsMessage = (wrapper, elementName, message) => { - const selector = `.${elementName.replace(/ /g, '-')}`; - expect(wrapper.find(selector).first().text()).to.contain(message); -}; diff --git a/test/integration/transactionID.test.js b/test/integration/transactionID.test.js index 58572629c8..296f26bd73 100644 --- a/test/integration/transactionID.test.js +++ b/test/integration/transactionID.test.js @@ -19,9 +19,19 @@ import getNetwork from './../../src/utils/getNetwork'; import { accountLoggedIn } from '../../src/actions/account'; import SingleTransaction from './../../src/components/singleTransaction'; import accounts from '../constants/accounts'; +import GenericStepDefinition from '../utils/genericStepDefinition'; + +class Helper extends GenericStepDefinition { + checkTxDetails() { + expect(this.wrapper.find('#transaction-id').first().text()).to.contain('123456789'); + expect(this.wrapper.find('#sender-address').first().text()).to.contain('123l'); + expect(this.wrapper.find('#receiver-address').first().text()).to.contain('456l'); + } +} describe('@integration: Single Transaction', () => { let store; + let helper; let wrapper; let requestToActivePeerStub; let accountAPIStub; @@ -68,21 +78,16 @@ describe('@integration: Single Transaction', () => { if (accountType) { store.dispatch(accountLoggedIn(account)); } wrapper = mount(renderWithRouter(SingleTransaction, store, { match: { params: { id } } })); - }; - - const checkTxDetails = () => { - expect(wrapper.find('#transaction-id').first().text()).to.contain('123456789'); - expect(wrapper.find('#sender-address').first().text()).to.contain('123l'); - expect(wrapper.find('#receiver-address').first().text()).to.contain('456l'); + helper = new Helper(wrapper, store); }; describe('Scenario: should allow to view transactions of any account', () => { - step('Given I\'m on "transactions/123456789" as "genesis" account', setupStep.bind(null, { accountType: 'genesis', id: '123456789' })); - step('Then I should see the transaction details of 123456789', checkTxDetails); + step('Given I\'m on "transactions/123456789" as "genesis" account', () => setupStep({ accountType: 'genesis', id: '123456789' })); + step('Then I should see the transaction details of 123456789', () => helper.checkTxDetails()); }); describe('Scenario: should allow to view transactions of any account without login', () => { - step('Given I\'m on "transactions/123456789" as "genesis" account', setupStep.bind(null, { id: '123456789' })); - step('Then I should see the transaction details of 123456789', checkTxDetails); + step('Given I\'m on "transactions/123456789" as "genesis" account', () => setupStep({ id: '123456789' })); + step('Then I should see the transaction details of 123456789', () => helper.checkTxDetails()); }); }); diff --git a/test/integration/voting.test.js b/test/integration/voting.test.js index b4ccc7f3bd..03241e4a89 100644 --- a/test/integration/voting.test.js +++ b/test/integration/voting.test.js @@ -140,7 +140,7 @@ const loginProcess = (votes = []) => { }); wrapper = mount(renderWithRouter(Voting, store)); - helper = new Helper(wrapper); + helper = new Helper(wrapper, store); expect(store.getState().account).to.be.an('Object'); expect(store.getState().voting).to.be.an('Object'); expect(store.getState().peers).to.be.an('Object'); diff --git a/test/integration/wallet.test.js b/test/integration/wallet.test.js index 805bc0a9ea..72d4f55911 100644 --- a/test/integration/wallet.test.js +++ b/test/integration/wallet.test.js @@ -21,7 +21,20 @@ import txTypes from './../../src/constants/transactionTypes'; import getNetwork from './../../src/utils/getNetwork'; import Wallet from '../../src/components/transactionDashboard'; import accounts from '../constants/accounts'; -import { click, containsMessage } from './steps'; +import GenericStepDefinition from '../utils/genericStepDefinition'; + +class Helper extends GenericStepDefinition { + checkSelectedFilter(filter) { + const expectedClass = '_active'; + + const activeFilter = this.wrapper.find('.transaction-filter-item').filterWhere((item) => { + const className = item.prop('className'); + return className.includes(expectedClass); + }); + + expect(activeFilter.text().toLowerCase()).to.equal(filter); + } +} describe('@integration: Wallet', () => { let store; @@ -29,6 +42,7 @@ describe('@integration: Wallet', () => { let requestToActivePeerStub; let accountAPIStub; let localStorageStub; + let helper; const successMessage = 'Transaction is being processed and will be confirmed. It may take up to 15 minutes to be secured in the blockchain.'; const errorMessage = 'An error occurred while creating the transaction.'; @@ -72,7 +86,6 @@ describe('@integration: Wallet', () => { requestToActivePeerStub.restore(); accountAPIStub.restore(); localStorageStub.restore(); - wrapper.update(); }); const setupStep = (accountType, isLocked = false) => { @@ -103,40 +116,14 @@ describe('@integration: Wallet', () => { accountAPIStub.withArgs(match.any).returnsPromise().resolves({ ...account }); store.dispatch(accountLoggedIn(account)); wrapper = mount(renderWithRouter(Wallet, store, { location: { search: '' } })); - }; - - const fillInputField = (value, field) => { - wrapper.find(`.${field} input`).first().simulate('change', { target: { value } }); - }; - - const clickStep = (elementName) => { - click(wrapper, elementName); - }; - - const shouldContainMessage = (elementName, message) => { - containsMessage(wrapper, elementName, message); - }; - - const checkRowCount = (length) => { - expect(wrapper.find('TransactionRow')).to.have.length(length); - }; - - const checkSelectedFilter = (filter) => { - const expectedClass = '_active'; - - const activeFilter = wrapper.find('.transaction-filter-item').filterWhere((item) => { - const className = item.prop('className'); - return className.includes(expectedClass); - }); - - expect(activeFilter.text().toLowerCase()).to.equal(filter); + helper = new Helper(wrapper, store); }; describe('Send', () => { describe('Scenario: should not allow to send when not enough funds', () => { - step('Given I\'m on "wallet" as "empty account"', setupStep.bind(null, 'empty account')); - step('And I fill in "1" to "amount" field', fillInputField.bind(null, '1', 'amount')); - step('And I fill in "537318935439898807L" to "recipient" field', fillInputField.bind(null, '537318935439898807L', 'recipient')); + step('Given I\'m on "wallet" as "empty account"', () => setupStep('empty account')); + step('And I fill in "1" to "amount" field', () => helper.fillInputField('1', 'amount')); + step('And I fill in "537318935439898807L" to "recipient" field', () => helper.fillInputField('537318935439898807L', 'recipient')); step('Then I should see "Not enough LSK" error message', () => { expect(wrapper.find('Input').at(1).html()).to.contain('Not enough LSK'); }); @@ -146,84 +133,82 @@ describe('@integration: Wallet', () => { }); describe('Scenario: should give and error message when sending fails', () => { - step('Given I\'m on "wallet" as "genesis" account', setupStep.bind(null, 'genesis')); - step('And I fill in "1" to "amount" field', fillInputField.bind(null, '1', 'amount')); - step('And I fill in "537318935439898807L" to "recipient" field', fillInputField.bind(null, '537318935439898807L', 'recipient')); - step('And I click "send next button"', clickStep.bind(null, 'send next button')); + step('Given I\'m on "wallet" as "genesis" account', () => setupStep('genesis')); + step('And I fill in "1" to "amount" field', () => helper.fillInputField('1', 'amount')); + step('And I fill in "537318935439898807L" to "recipient" field', () => helper.fillInputField('537318935439898807L', 'recipient')); + step('And I click "send next button"', () => helper.clickOnElement('button.send-next-button')); step('When I click "send button"', () => { requestToActivePeerStub.withArgs(match.any, 'transactions', match.any).returnsPromise().rejects({}); - wrapper.find('.send-button button').simulate('click'); + helper.clickOnElement('.send-button button'); }); - step(`Then I should see text ${errorMessage} in "result box message" element`, shouldContainMessage.bind(this, 'result box message', errorMessage)); + step(`Then I should see text ${errorMessage} in "result box message" element`, () => helper.haveTextOf('.result-box-message', errorMessage)); }); describe('Scenario: should allow to send LSK from unlocked account', () => { - step('Given I\'m on "wallet" as "genesis" account', setupStep.bind(null, 'genesis')); - step('And I fill in "1" to "amount" field', fillInputField.bind(null, '1', 'amount')); - step('And I fill in "537318935439898807L" to "recipient" field', fillInputField.bind(null, '537318935439898807L', 'recipient')); - step('And I click "send next button"', clickStep.bind(null, 'send next button')); - step('When I click "send button"', () => { wrapper.find('.send-button button').simulate('click'); }); - step(`Then I should see text ${successMessage} in "result box message" element`, shouldContainMessage.bind(this, 'result box message', successMessage)); + step('Given I\'m on "wallet" as "genesis" account', () => setupStep('genesis')); + step('And I fill in "1" to "amount" field', () => { helper.fillInputField('1', 'amount'); }); + step('And I fill in "537318935439898807L" to "recipient" field', () => { helper.fillInputField('537318935439898807L', 'recipient'); }); + step('And I click "send next button"', () => { helper.clickOnElement('button.send-next-button'); }); + step('When I click "send button"', () => helper.clickOnElement('button.send-button button')); + step(`Then I should see text ${successMessage} in "result box message" element`, () => helper.haveTextOf('.result-box-message', successMessage)); }); describe('Scenario: should allow to send LSK from locked account', () => { const { passphrase } = accounts.genesis; - step('Given I\'m on "wallet" as "genesis" account', setupStep.bind(null, 'genesis', true)); - step('And I fill in "1" to "amount" field', fillInputField.bind(null, '1', 'amount')); - step('And I fill in "537318935439898807L" to "recipient" field', fillInputField.bind(null, '537318935439898807L', 'recipient')); - step('And I click "send next button"', clickStep.bind(null, 'send next button')); - step('And I fill in passphrase of "genesis" to "passphrase" field', fillInputField.bind(null, passphrase, 'passphrase')); - step('When I click "next button"', () => { wrapper.find('.first-passphrase-next button').simulate('click'); }); - step('When I click "send button"', () => { wrapper.find('.send-button button').simulate('click'); }); - step(`Then I should see text ${successMessage} in "result box message" element`, shouldContainMessage.bind(this, 'result box message', successMessage)); + step('Given I\'m on "wallet" as "genesis" account', () => setupStep('genesis', true)); + step('And I fill in "1" to "amount" field', () => { helper.fillInputField('1', 'amount'); }); + step('And I fill in "537318935439898807L" to "recipient" field', () => { helper.fillInputField('537318935439898807L', 'recipient'); }); + step('And I click "send next button"', () => helper.clickOnElement('button.send-next-button')); + step('And I fill in passphrase of "genesis" to "passphrase" field', () => { helper.fillInputField(passphrase, 'passphrase'); }); + step('When I click "next button"', () => helper.clickOnElement('.first-passphrase-next button')); + step('When I click "send button"', () => helper.clickOnElement('.send-button button')); + step(`Then I should see text ${successMessage} in "result box message" element`, () => helper.haveTextOf('.result-box-message', successMessage)); }); describe('Scenario: should allow to send LSK from unlocked account with 2nd passphrase', () => { const { secondPassphrase } = accounts['second passphrase account']; - step('Given I\'m on "wallet" as "second passphrase account"', setupStep.bind(null, 'second passphrase account')); - step('And I fill in "1" to "amount" field', fillInputField.bind(null, '1', 'amount')); - step('And I fill in "537318935439898807L" to "recipient" field', fillInputField.bind(null, '537318935439898807L', 'recipient')); - step('And I click "send next button"', clickStep.bind(null, 'send next button')); - step('And I fill in second passphrase of "second passphrase account" to "second passphrase" field', fillInputField.bind(null, secondPassphrase, 'second-passphrase')); - step('When I click "next button"', () => { wrapper.find('.second-passphrase-next button').simulate('click'); }); - step('When I click "send button"', () => { wrapper.find('.send-button button').simulate('click'); }); - step(`Then I should see text ${successMessage} in "result box message" element`, shouldContainMessage.bind(this, 'result box message', successMessage)); + step('Given I\'m on "wallet" as "second passphrase account"', () => setupStep('second passphrase account')); + step('And I fill in "1" to "amount" field', () => { helper.fillInputField('1', 'amount'); }); + step('And I fill in "537318935439898807L" to "recipient" field', () => { helper.fillInputField('537318935439898807L', 'recipient'); }); + step('And I click "send next button"', () => helper.clickOnElement('button.send-next-button')); + step('And I fill in second passphrase of "second passphrase account" to "second passphrase" field', () => { helper.fillInputField(secondPassphrase, 'second-passphrase'); }); + step('When I click "next button"', () => helper.clickOnElement('.second-passphrase-next button')); + step('When I click "send button"', () => helper.clickOnElement('.send-button button')); + step(`Then I should see text ${successMessage} in "result box message" element`, () => helper.haveTextOf('.result-box-message', successMessage)); }); describe('Scenario: should allow to send LSK from locked account with 2nd passphrase', () => { const { secondPassphrase, passphrase } = accounts['second passphrase account']; - step('Given I\'m on "wallet" as "second passphrase account"', setupStep.bind(null, 'second passphrase account', true)); - step('And I fill in "1" to "amount" field', fillInputField.bind(null, '1', 'amount')); - step('And I fill in "537318935439898807L" to "recipient" field', fillInputField.bind(null, '537318935439898807L', 'recipient')); - step('And I click "send next button"', clickStep.bind(null, 'send next button')); - step('And I fill in passphrase of "second passphrase account" to "passphrase" field', fillInputField.bind(null, passphrase, 'passphrase')); - step('When I click "next button"', () => { wrapper.find('.first-passphrase-next button').simulate('click'); }); - step('And I fill in second passphrase of "second passphrase account" to "second passphrase" field', fillInputField.bind(null, secondPassphrase, 'second-passphrase')); - step('When I click "next button"', () => { wrapper.find('.second-passphrase-next button').simulate('click'); }); - step('When I click "send button"', () => { wrapper.find('.send-button button').simulate('click'); }); - step(`Then I should see text ${successMessage} in "result box message" element`, shouldContainMessage.bind(this, 'result box message', successMessage)); + step('Given I\'m on "wallet" as "second passphrase account"', () => setupStep('second passphrase account', true)); + step('And I fill in "1" to "amount" field', () => { helper.fillInputField('1', 'amount'); }); + step('And I fill in "537318935439898807L" to "recipient" field', () => { helper.fillInputField('537318935439898807L', 'recipient'); }); + step('And I click "send next button"', () => helper.clickOnElement('button.send-next-button')); + step('And I fill in passphrase of "second passphrase account" to "passphrase" field', () => { helper.fillInputField(passphrase, 'passphrase'); }); + step('When I click "next button"', () => helper.clickOnElement('.first-passphrase-next button')); + step('And I fill in second passphrase of "second passphrase account" to "second passphrase" field', () => { helper.fillInputField(secondPassphrase, 'second-passphrase'); }); + step('When I click "next button"', () => helper.clickOnElement('.second-passphrase-next button')); + step('When I click "send button"', () => helper.clickOnElement('.send-button button')); + step(`Then I should see text ${successMessage} in "result box message" element`, () => helper.haveTextOf('.result-box-message', successMessage)); }); }); - describe('transactions', () => { + describe('Transactions', () => { describe('Scenario: should allow to view transactions', () => { - step('Given I\'m on "wallet" as "genesis" account', setupStep.bind(null, 'genesis')); - step('Then I should see 25 rows', checkRowCount.bind(null, 25)); + step('Given I\'m on "wallet" as "genesis" account', () => setupStep('genesis')); + step('Then I should see 25 rows', () => helper.shouldSeeCountInstancesOf(25, 'TransactionRow')); step('When I scroll to the bottom of "transactions box"', () => { wrapper.find('Waypoint').props().onEnter(); }); - step('Then I should see 50 rows', checkRowCount.bind(null, 50)); + step('Then I should see 50 rows', () => { wrapper.update(); helper.shouldSeeCountInstancesOf(50, 'TransactionRow'); }); }); describe('Scenario: should allow to filter transactions', () => { - step('Given I\'m on "wallet" as "genesis" account', setupStep.bind(null, 'genesis')); - step('Then the "All" filter should be selected by default', checkSelectedFilter.bind(null, 'all')); - step('When I click on the "Outgoing" filter', clickStep.bind(null, 'filter out')); - step('Then I expect to see the results for "Outgoing"', checkRowCount.bind(null, 5)); - step('When I click on the "Incoming" filter', clickStep.bind(null, 'filter in')); - step('Then I expect to see the results for "Incoming"', checkRowCount.bind(null, 15)); - step('When I click again on the "All" filter', clickStep.bind(null, 'filter all')); - step('Then I expect to see the results for "All"', checkRowCount.bind(null, 25)); + step('Given I\'m on "wallet" as "genesis" account', () => setupStep('genesis')); + step('Then the "All" filter should be selected by default', () => helper.checkSelectedFilter('all')); + step('When I click on the "Outgoing" filter', () => helper.clickOnElement('.filter-out')); + step('Then I expect to see the results for "Outgoing"', () => helper.shouldSeeCountInstancesOf(5, 'TransactionRow')); + step('When I click on the "Incoming" filter', () => helper.clickOnElement('.filter-in')); + step('Then I expect to see the results for "Incoming"', () => helper.shouldSeeCountInstancesOf(15, 'TransactionRow')); + step('When I click again on the "All" filter', () => helper.clickOnElement('.filter-all')); + step('Then I expect to see the results for "All"', () => helper.shouldSeeCountInstancesOf(25, 'TransactionRow')); }); - - describe.skip('Scenario: should allow to search transactions'); }); }); diff --git a/test/utils/genericStepDefinition.js b/test/utils/genericStepDefinition.js index cb325b4d45..85ccc20133 100644 --- a/test/utils/genericStepDefinition.js +++ b/test/utils/genericStepDefinition.js @@ -2,15 +2,16 @@ import { expect } from 'chai'; export default class GenericStepDefinition { - constructor(input) { + constructor(input, store) { this.wrapper = input; + this.store = store; } /** * simulate click on a dom query * @param {String} query - dom query that we need to simulate clink on it */ clickOnElement(query) { - this.wrapper.find(query).simulate('click'); + this.wrapper.find(query).first().simulate('click'); } /** * check that dom query entry is disable or enable @@ -63,4 +64,21 @@ export default class GenericStepDefinition { submitForm() { this.wrapper.find('form').simulate('submit', {}); } + + /** + * + * @param {String} expectedPublicKey - Valid publicKey + */ + shouldBeLoggedInAs(expectedPublicKey) { + expect(this.store.getState().account.publicKey).to.equal(expectedPublicKey); + } + + /** + * + * @param {Number} count - Valid publicKey + * @param {String} selector - Valid css selector + */ + shouldSeeCountInstancesOf(count, selector) { + expect(this.wrapper.find(selector)).to.have.lengthOf(count); + } } From fe5862634557887ad4ec26ec26c49df8d8d34457 Mon Sep 17 00:00:00 2001 From: reyraa Date: Thu, 1 Mar 2018 10:09:09 +0100 Subject: [PATCH 7/8] Use the hlper instance to access store --- test/integration/login.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/integration/login.test.js b/test/integration/login.test.js index 305fc06cc3..83157f97ef 100644 --- a/test/integration/login.test.js +++ b/test/integration/login.test.js @@ -96,7 +96,7 @@ describe('@integration: Login', () => { class Helper extends GenericStepDefinition { // eslint-disable-next-line class-methods-use-this checkIfInRoute() { - expect(store.getState().account).to.have.all.keys('passphrase', 'publicKey', 'address', 'delegate', + expect(this.store.getState().account).to.have.all.keys('passphrase', 'publicKey', 'address', 'delegate', 'isDelegate', 'expireTime', 'u_multisignatures', 'multisignatures', 'unconfirmedBalance', 'secondSignature', 'secondPublicKey', 'balance', 'unconfirmedSignature'); restoreStubs(); @@ -113,7 +113,7 @@ describe('@integration: Login', () => { createStore(); stubApis(); wrapper = mount(renderWithRouter(Login, store, { location: { search: '' } }), { activePeerSet }); - helper = new Helper(wrapper); + helper = new Helper(wrapper, store); }; describe('Scenario: should allow to login', () => { From f0df398ade002b274a16748b11c21225affb3b51 Mon Sep 17 00:00:00 2001 From: Vit Stanislav Date: Thu, 1 Mar 2018 10:17:37 +0100 Subject: [PATCH 8/8] Remove global store variable in login integration tests --- test/integration/login.test.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/test/integration/login.test.js b/test/integration/login.test.js index 83157f97ef..af508fce2a 100644 --- a/test/integration/login.test.js +++ b/test/integration/login.test.js @@ -22,7 +22,6 @@ import accounts from '../constants/accounts'; import GenericStepDefinition from '../utils/genericStepDefinition'; describe('@integration: Login', () => { - let store; let wrapper; let helper; // const requestToActivePeerStub = stub(peers, 'requestToActivePeer'); @@ -39,8 +38,8 @@ describe('@integration: Login', () => { wrapper.update(); }); - const createStore = () => { - store = prepareStore({ + const createStore = () => ( + prepareStore({ account: accountReducer, peers: peersReducer, savedAccounts: savedAccountsReducer, @@ -50,8 +49,8 @@ describe('@integration: Login', () => { accountMiddleware, loginMiddleware, peerMiddleware, - ]); - }; + ]) + ); const restoreStubs = () => { // requestToActivePeerStub.restore(); @@ -110,7 +109,7 @@ describe('@integration: Login', () => { } const setupStep = (stubApis) => { - createStore(); + const store = createStore(); stubApis(); wrapper = mount(renderWithRouter(Login, store, { location: { search: '' } }), { activePeerSet }); helper = new Helper(wrapper, store);