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

Review and improve React unit test coverage - Closes #531 #601

Merged
merged 20 commits into from
Aug 16, 2017
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ module.exports = function (config) {
colors: true,
logLevel: config.LOG_INFO,
autoWatch: false,
browsers: ['Chrome'],
browsers: ['ChromeHeadless'],
singleRun: true,
browserNoActivityTimeout: 60000,
browserDisconnectTolerance: 3,
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,9 @@
"imports-loader": "=0.6.5",
"js-nacl": "=1.2.2",
"json-loader": "=0.5.4",
"karma": "^1.7.0",
"karma": "=1.7.0",
"karma-chai": "=0.1.0",
"karma-chrome-launcher": "^2.2.0",
"karma-chrome-launcher": "=2.2.0",
"karma-coverage": "=1.1.1",
"karma-jenkins-reporter": "0.0.2",
"karma-mocha": "=1.3.0",
Expand Down
60 changes: 32 additions & 28 deletions src/components/account/accountComponent.test.js
Original file line number Diff line number Diff line change
@@ -1,55 +1,59 @@
import React from 'react';
import chai, { expect } from 'chai';
import { spy } from 'sinon';
import sinon, { spy, mock } from 'sinon';
import sinonChai from 'sinon-chai';
import { shallow, mount } from 'enzyme';
import { Provider } from 'react-redux';
import * as accountApi from '../../utils/api/account';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You defined 'accountApi' and 'sinon' and 'mock' but you didn't use them. please remove them.

import store from '../../store';
import AccountComponent from './accountComponent';
import ClickToSend from '../send/clickToSend';

chai.use(sinonChai);

describe('AccountComponent', () => {
// Mocking store
const onActivePeerUpdated = () => {};
const peers = {
status: {
online: false,
},
data: {
currentPeer: 'localhost',
port: 4000,
options: {
name: 'Custom Node',
let props;

beforeEach(() => {
props = {
onActivePeerUpdated: sinon.spy(),
onAccountUpdated: sinon.spy(),
peers: {
status: {
online: false,
},
data: {
currentPeer: 'localhost',
port: 4000,
options: {
name: 'Custom Node',
},
},
},
account: {
isDelegate: false,
address: '16313739661670634666L',
username: 'lisk-nano',
balance: 1e8,
},
},
};
const testAccount = {
isDelegate: false,
address: '16313739661670634666L',
username: 'lisk-nano',
balance: 1e8,
};
};
});

it(' should render 3 article tags', () => {
const wrapper = shallow(<AccountComponent account={testAccount} peers={peers}
onActivePeerUpdated={onActivePeerUpdated} />);
it('should render 3 article tags', () => {
const wrapper = shallow(<AccountComponent {...props} />);
expect(wrapper.find('article')).to.have.lengthOf(3);
});

it('depicts being online when peers.status.online is true', () => {
const onlinePeers = Object.assign({}, peers, { status: { online: true } });
const wrapper = shallow(<AccountComponent account={testAccount} peers={onlinePeers}
onActivePeerUpdated={onActivePeerUpdated} />);
props.peers.status.online = true;
const wrapper = shallow(<AccountComponent {...props} />);
const expectedValue = 'check';
expect(wrapper.find('.material-icons').text()).to.be.equal(expectedValue);
});

it('should render balance with ClickToSend component', () => {
const wrapper = mount(<Provider store={store}>
<AccountComponent account={testAccount} peers={peers}
onActivePeerUpdated={onActivePeerUpdated} />
<AccountComponent {...props} />
</Provider>);
expect(wrapper.find('.balance').find(ClickToSend)).to.have.lengthOf(1);
});
Expand Down
33 changes: 31 additions & 2 deletions src/components/account/index.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import React from 'react';
import { expect } from 'chai';
import { mount } from 'enzyme';
import sinon from 'sinon';
import * as accountActions from '../../actions/account';
import * as transactionsActions from '../../actions/transactions';
import * as peersActions from '../../actions/peers';
import Account from './index';
import AccountComponent from './accountComponent';

Expand Down Expand Up @@ -38,12 +42,37 @@ describe('Account', () => {
context: { store },
// childContextTypes: { store: PropTypes.object.isRequired },
};
let props;

it('should mount AccountComponent with appropriate properties', () => {
beforeEach(() => {
const mountedAccount = mount(<Account/>, options);
const props = mountedAccount.find(AccountComponent).props();
props = mountedAccount.find(AccountComponent).props();
});

it('should mount AccountComponent with appropriate properties', () => {
expect(props.peers).to.be.equal(peers);
expect(props.account).to.be.equal(account);
expect(typeof props.onActivePeerUpdated).to.be.equal('function');
});

it('should bind activePeerUpdate action to AccountComponent props.onActivePeerUpdated', () => {
const actionsSpy = sinon.spy(peersActions, 'activePeerUpdate');
props.onActivePeerUpdated({});
expect(actionsSpy).to.be.calledWith();
actionsSpy.restore();
});

it('should bind accountUpdated action to AccountComponent props.onAccountUpdated', () => {
const actionsSpy = sinon.spy(accountActions, 'accountUpdated');
props.onAccountUpdated({});
expect(actionsSpy).to.be.calledWith();
actionsSpy.restore();
});

it('should bind transactionsUpdated action to AccountComponent props.onTransactionsUpdated', () => {
const actionsSpy = sinon.spy(transactionsActions, 'transactionsUpdated');
props.onTransactionsUpdated({});
expect(actionsSpy).to.be.calledWith();
actionsSpy.restore();
});
});
53 changes: 42 additions & 11 deletions src/components/forging/forgingComponent.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,42 @@ import React from 'react';
import chai, { expect } from 'chai';
import sinonChai from 'sinon-chai';
import { mount } from 'enzyme';
import sinon from 'sinon';
import ForgingComponent from './forgingComponent';
import * as forgingApi from '../../utils/api/forging';

chai.use(sinonChai);


describe('ForgingComponent', () => {
let wrapper;
const props = {
account: {
delegate: {},
isDelegate: true,
},
peers: {},
statistics: {},
forgedBlocks: [],
loadStats: () => {},
loadForgedBlocks: () => {},
};
let props;
let forginApiMock;

beforeEach(() => {
props = {
account: {
delegate: {},
isDelegate: true,
},
peers: {},
statistics: {},
forgedBlocks: [],
onForgingStatsUpdate: sinon.spy(),
onForgedBlocksLoaded: sinon.spy(),
};

forginApiMock = sinon.mock(forgingApi);
forginApiMock.expects('getForgedStats').atLeast(5).resolves({ success: true });
forginApiMock.expects('getForgedBlocks').resolves({ success: true, blocks: [] });

wrapper = mount(<ForgingComponent {...props} />);
});

afterEach(() => {
forginApiMock.restore();
});

it('should render ForgingTitle', () => {
expect(wrapper.find('ForgingTitle')).to.have.lengthOf(1);
});
Expand All @@ -40,4 +53,22 @@ describe('ForgingComponent', () => {
it('should render ForgedBlocks', () => {
expect(wrapper.find('ForgedBlocks')).to.have.lengthOf(1);
});

it('should render only a "not delegate" message if !props.account.isDelegate', () => {
props.account.isDelegate = false;
wrapper = mount(<ForgingComponent {...props} />);

expect(wrapper.find('ForgedBlocks')).to.have.lengthOf(0);
expect(wrapper.find('DelegateStats')).to.have.lengthOf(0);
expect(wrapper.find('p')).to.have.lengthOf(1);
});

// TODO: make these tests work
it.skip('should call props.onForgingStatsUpdate', () => {
expect(props.onForgingStatsUpdate).to.have.been.calledWith();
});

it.skip('should call props.onForgedBlocksLoaded', () => {
expect(props.onForgedBlocksLoaded).to.have.been.calledWith();
});
});
24 changes: 23 additions & 1 deletion src/components/forging/index.test.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import React from 'react';
import chai, { expect } from 'chai';
import sinonChai from 'sinon-chai';
import sinon from 'sinon';
import { mount } from 'enzyme';
import { Provider } from 'react-redux';
import configureMockStore from 'redux-mock-store';
import * as forgingActions from '../../actions/forging';
import Forging from './';
import store from '../../store';

chai.use(sinonChai);

Expand All @@ -13,10 +15,30 @@ describe('Forging', () => {
let wrapper;

beforeEach(() => {
const store = configureMockStore([])({
account: {},
peers: {},
forging: {
statistics: {},
forgedBlocks: [],
},
});
wrapper = mount(<Provider store={store}><Forging /></Provider>);
});

it('should render ForgingComponent', () => {
expect(wrapper.find('ForgingComponent')).to.have.lengthOf(1);
});

it('should bind updateForgedBlocks action to ForgingComponent props.onForgedBlocksLoaded', () => {
const actionsSpy = sinon.spy(forgingActions, 'updateForgedBlocks');
wrapper.find('ForgingComponent').props().onForgedBlocksLoaded([]);
expect(actionsSpy).to.be.calledWith();
});

it('should bind updateForgingStats action to ForgingComponent props.onForgingStatsUpdate', () => {
const actionsSpy = sinon.spy(forgingActions, 'updateForgingStats');
wrapper.find('ForgingComponent').props().onForgingStatsUpdate({});
expect(actionsSpy).to.be.calledWith();
});
});
36 changes: 36 additions & 0 deletions src/components/header/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React from 'react';
import { expect } from 'chai';
import { mount } from 'enzyme';
import { Provider } from 'react-redux';
import sinon from 'sinon';
import * as accountActions from '../../actions/account';
import * as dialogActions from '../../actions/dialog';
import Header from './index';
import store from '../../store';


describe('Header', () => {
let wrapper;

beforeEach(() => {
wrapper = mount(<Provider store={store}><Header /></Provider>);
});

it('should render HeaderElement', () => {
expect(wrapper.find('HeaderElement')).to.have.lengthOf(1);
});

it('should bind accountLoggedOut action to HeaderElement props.logOut', () => {
const actionsSpy = sinon.spy(accountActions, 'accountLoggedOut');
wrapper.find('HeaderElement').props().logOut({});
expect(actionsSpy).to.be.calledWith();
actionsSpy.restore();
});

it('should bind dialogDisplayed action to HeaderElement props.setActiveDialog', () => {
const actionsSpy = sinon.spy(dialogActions, 'dialogDisplayed');
wrapper.find('HeaderElement').props().setActiveDialog({});
expect(actionsSpy).to.be.calledWith();
actionsSpy.restore();
});
});
9 changes: 9 additions & 0 deletions src/components/login/loginForm.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,13 @@ describe('LoginForm', () => {
expect(data).to.deep.equal(undefined);
});
});

describe('setActiveDialog', () => {
it('should return a dispatch object', () => {
const mountedAccount = mount(<Router><LoginForm/></Router>, options);
const props = mountedAccount.find(LoginFormComponent).props();
const data = props.setActiveDialog({});
expect(data).to.deep.equal(undefined);
});
});
});
4 changes: 3 additions & 1 deletion src/components/login/loginFormComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import networksRaw from './networks';
import Passphrase from '../passphrase';
import styles from './login.css';

// ignore else in coverage as it is hard to test and not our business logic
/* istanbul ignore else */
if (global._bitcore) delete global._bitcore;

/**
Expand Down Expand Up @@ -130,7 +132,7 @@ class LoginFormComponent extends React.Component {
/>
{
this.state.network === 2 &&
<Input type='text' label='Node address' name='address'
<Input type='text' label='Node address' name='address' className='address'
value={this.state.address} error={this.state.addressValidity}
onChange={this.validateUrl.bind(this)} />
}
Expand Down
Loading