Skip to content

Commit

Permalink
Merge pull request #547 from LiskHQ/536-increase-test-coverage-part4
Browse files Browse the repository at this point in the history
Increase test coverage of ignored files above 80% Part 4 - Closes #536
  • Loading branch information
faival authored Mar 20, 2018
2 parents daab25d + 54e2bba commit ae220c0
Show file tree
Hide file tree
Showing 7 changed files with 238 additions and 53 deletions.
11 changes: 1 addition & 10 deletions karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ module.exports = function (config) {
'src/components/menuBar/menuBar.js',
'src/components/accountVisual/demo.js',
'src/components/delegateList/votingHeader.js',
'src/components/dialog/index.js',
'src/components/app/index.js',
'src/components/transactions/transactionList.js',
'src/components/relativeLink/index.js',
Expand All @@ -86,16 +87,6 @@ module.exports = function (config) {
'src/components/register/index.js',
'src/components/register/register.js',
'src/components/transactions/transactionOverview.js',
'src/components/transactions/transactionDetailView.js',
'src/components/voting/index.js',
'src/components/delegateList/index.js',
'src/components/delegateList/delegateList.js',
'src/components/dialog/index.js',
'src/components/dialog/dialog.js',
'src/components/toaster/index.js',
'src/components/mainMenu/mainMenu.js',
'src/components/setting/setting.js',
'src/components/votesPreview/index.js',
],
overrides: {
'src/store/**/*.js': {
Expand Down
151 changes: 131 additions & 20 deletions src/components/delegateList/delegateList.test.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import React from 'react';
import { expect } from 'chai';
import { mount } from 'enzyme';
import PropTypes from 'prop-types';
import { BrowserRouter as Router } from 'react-router-dom';
import sinon from 'sinon';
import DelegateList from './delegateList';
import { mountWithContext } from './../../../test/utils/mountHelpers';
import store from '../../store';
import history from '../../history';
import i18n from '../../i18n';
import voteFilters from './../../constants/voteFilters';

describe('DelegateList', () => {
let wrapper;
Expand Down Expand Up @@ -43,21 +40,21 @@ describe('DelegateList', () => {
delegatesFetched: sinon.spy(),
t: key => key,
};

let clock;
let loadMoreSpy;

beforeEach(() => {
wrapper = mount(<Router><DelegateList {...props}></DelegateList></Router>,
{
context: { store, history, i18n },
childContextTypes: {
store: PropTypes.object.isRequired,
history: PropTypes.object.isRequired,
i18n: PropTypes.object.isRequired,
},
},
);
clock = sinon.useFakeTimers({
toFake: ['setTimeout', 'clearTimeout', 'Date'],
});
loadMoreSpy = sinon.spy(DelegateList.prototype, 'loadMore');
wrapper = mountWithContext(<DelegateList {...props}/>, {});
});

afterEach(() => {
// Voting.prototype.setStatus.restore();
clock.restore();
loadMoreSpy.restore();
});

it('should render VotingHeader', () => {
Expand All @@ -73,11 +70,9 @@ describe('DelegateList', () => {
});

it('should define search method to reload delegates based on given query', () => {
const clock = sinon.useFakeTimers({
toFake: ['setTimeout', 'clearTimeout', 'Date'],
});
props.delegatesFetched.reset();
wrapper.find('.search input').at(0).simulate('change', { nativeEvent: { target: { value: 'query' } } });
wrapper.find('.search input')
.at(0).simulate('change', { nativeEvent: { target: { value: 'query' } } });
clock.tick(251);
expect(props.delegatesFetched).to.be.calledWith({
activePeer: props.activePeer,
Expand All @@ -87,4 +82,120 @@ describe('DelegateList', () => {
});
clock.restore();
});

it('should call loadMore and not loadDelegates if still loading', () => {
const loadMoreProps = {
...props,
totalDelegates: 100,
};
wrapper = mountWithContext(<DelegateList {...loadMoreProps}/>, {});
const waypoint = wrapper.find('Waypoint').at(1);
waypoint.props().onEnter();
expect(loadMoreSpy).to.have.been.calledWith();
expect(wrapper).to.have.exactly(delegates.length).descendants('.delegate-row');
});

it('should call loadMore and loadDelegates if not still loading', () => {
const loadMoreProps = {
...props,
totalDelegates: 100,
};
const loadDelegates = sinon.spy(DelegateList.prototype, 'loadDelegates');
wrapper = mountWithContext(<DelegateList {...props}/>, { ...store });
const waypoint = wrapper.find('Waypoint').at(1);

const nextProps = {
delegates: [
...loadMoreProps.delegates,
{
address: 'address 3',
username: 'username3',
publicKey: 'sample_key',
rank: 23,
}],
};

/*
Force trigger componentWillUpdate,
will reset freezeLoading flag to cover loadMore
*/
wrapper.setProps(nextProps);
clock.tick(300);
waypoint.props().onEnter();
expect(loadMoreSpy).to.have.been.calledWith();
expect(wrapper).to.have.exactly(delegates.length + 1).descendants('.delegate-row');
loadDelegates.restore();
clock.restore();
});

it('should filter voted delegates', () => {
const filterVotedProps = {
...props,
};
wrapper = mountWithContext(<DelegateList {...filterVotedProps}/>, {});
wrapper.find('.transaction-filter-item').at(voteFilters.voted).simulate('click');
wrapper.update();
const delegateRow = wrapper.find('.delegate-row');
expect(delegateRow.length).to.equal(delegates.length - 1);
expect(delegateRow.find('li').at(2)).to.have.text(delegates[0].username);
});

it('should filter notVoted delegates', () => {
const filterVotedProps = {
...props,
};
wrapper = mountWithContext(<DelegateList {...filterVotedProps}/>, {});
wrapper.find('.transaction-filter-item').at(voteFilters.notVoted).simulate('click');
wrapper.update();
const delegateRow = wrapper.find('.delegate-row');
expect(delegateRow.length).to.equal(delegates.length - 1);
expect(delegateRow.find('li').at(2)).to.have.text(delegates[1].username);
});

it('should show no voted message', () => {
const emptyMessageProps = {
...props,
};
emptyMessageProps.delegates = [];
emptyMessageProps.votes = {};
wrapper = mountWithContext(<DelegateList {...emptyMessageProps}/>, {});
const nextProps = {
delegates: [],
};

/*
force to have no delegates and
trigger voted filter
*/
wrapper.setProps(nextProps);
clock.tick(300);
wrapper.find('.transaction-filter-item').at(voteFilters.voted).simulate('click');
wrapper.update();
const delegateRow = wrapper.find('.empty-message');
expect(delegateRow).to.have.text('You have not voted yet.');
});

it('should show no results message', () => {
const emptyMessageProps = {
...props,
};
emptyMessageProps.delegates = [];
emptyMessageProps.votes = {};
wrapper = mountWithContext(<DelegateList {...emptyMessageProps}/>, {});
const nextProps = {
delegates: [delegates[1]],
};

/*
force to reset isInitial flag
and then reset delegates
*/
wrapper.setProps(nextProps);
clock.tick(300);
wrapper.update();

wrapper.setProps({ delegates: [] });
const delegateRow = wrapper.find('.empty-message');
expect(delegateRow).to.have.text('No delegates found.');
});
});
56 changes: 56 additions & 0 deletions src/components/delegateList/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import React from 'react';
import { expect } from 'chai';
import { mount } from 'enzyme';
import { Provider } from 'react-redux';
import PropTypes from 'prop-types';
import { BrowserRouter as Router } from 'react-router-dom';
import store from '../../store';
import DelegateList from './index';
import i18n from '../../i18n';
import history from '../../history';

describe('DelegateListHOC', () => {
let wrapper;
const account = { address: '16313739661670634666L' };
const peers = { data: {} };
const voting = {
votes: {},
delegates: [],
totalDelegates: 10,
refresh: false,
};

beforeEach(() => {
store.getState = () => ({
peers,
account,
voting,
loading: [],
});
wrapper = mount(<Provider store={store}><Router><DelegateList /></Router></Provider>, {
context: { store, history, i18n },
childContextTypes: {
store: PropTypes.object.isRequired,
history: PropTypes.object.isRequired,
i18n: PropTypes.object.isRequired,
},
});
});

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

it('should mount DelegatesList with appropriate properties', () => {
const props = wrapper.find('DelegateList').first().props();
expect(props.refreshDelegates).to.be.equal(voting.refresh);
expect(props.delegates).to.be.equal(voting.delegates);
expect(props.votes).to.be.equal(voting.votes);
expect(props.totalDelegates).to.be.equal(voting.totalDelegates);
expect(props.activePeer).to.be.equal(peers.data);
expect(props.address).to.be.equal(account.address);
expect(typeof props.voteToggled).to.be.equal('function');
expect(typeof props.votesFetched).to.be.equal('function');
expect(typeof props.delegatesFetched).to.be.equal('function');
});
});
4 changes: 2 additions & 2 deletions src/components/toaster/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import { connect } from 'react-redux';
import Toaster from './toaster';
import { toastHidden } from '../../actions/toaster';

const mapStateToProps = state => ({
export const mapStateToProps = state => ({
toasts: state.toaster || [],
});

const mapDispatchToProps = dispatch => ({
export const mapDispatchToProps = dispatch => ({
hideToast: data => dispatch(toastHidden(data)),
});

Expand Down
1 change: 0 additions & 1 deletion src/components/toaster/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import Toaster from './toaster';
import ToasterHOC from './index';
import store from '../../store';


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

Expand Down
61 changes: 41 additions & 20 deletions src/components/toaster/toaster.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { expect } from 'chai';
import sinon from 'sinon';
import { mount } from 'enzyme';
import Toaster from './toaster';
import actionTypes from '../../constants/actions';
import { mapStateToProps, mapDispatchToProps } from './index';

describe('Toaster', () => {
const toasts = [{
Expand All @@ -12,36 +14,55 @@ describe('Toaster', () => {
}];
const toasterProps = {
toasts,
hideToast: sinon.spy(),
hideToast: () => {},
};

const hideToastSpy = sinon.spy(toasterProps, 'hideToast');

it('renders <Snackbar /> component from react-toolbox', () => {
const wrapper = mount(<Toaster {...toasterProps} />);
expect(wrapper.find('Snackbar')).to.have.length(1);
});

describe('hideToast', () => {
it('hides the toast and after the animation ends calls this.props.hideToast()', () => {
document.body.prepend(document.createElement('div'));
const clock = sinon.useFakeTimers({
toFake: ['setTimeout', 'clearTimeout', 'Date'],
});
mount(<Toaster {...toasterProps} />, { attachTo: document.body.firstChild });
let toastElement = document.getElementsByClassName('toast');
it('hides the toast and after the animation ends calls this.props.hideToast()', () => {
document.body.prepend(document.createElement('div'));
const clock = sinon.useFakeTimers({
toFake: ['setTimeout', 'clearTimeout', 'Date'],
});
mount(<Toaster {...toasterProps} />, { attachTo: document.body.firstChild });
let toastElement = document.getElementsByClassName('toast');

// check if the toast is activated
expect(toastElement.length > 0 &&
toastElement[0].className.indexOf('active') > 0)
.to.equal(true);
// check if the toast is activated
expect(toastElement.length > 0 &&
toastElement[0].className.indexOf('active') > 0)
.to.equal(true);

clock.tick(4510);
clock.tick(4510);

// check if the toast is deactivated
toastElement = document.getElementsByClassName('toast');
// check if the toast is deactivated
toastElement = document.getElementsByClassName('toast');

// check if hideToast is called
expect(toasterProps.hideToast).to.have.been.calledWith(toasts[0]);
clock.restore();
});
// check if hideToast is called
expect(hideToastSpy).to.have.been.calledWith(toasts[0]);

hideToastSpy.restore();

clock.restore();
});

it('hideToast dispatches toastHidden action', () => {
const dispatchSpy = sinon.spy();
const { hideToast } = mapDispatchToProps(dispatchSpy);
const payload = [{ toast1: {} }];
hideToast(payload);
const dispatchSpyCallArgs = dispatchSpy.args[0][0];
expect(dispatchSpyCallArgs.type).to.be.eql(actionTypes.toastHidden);
expect(dispatchSpyCallArgs.data).to.be.eql(payload);
});

it('inits with empty toasts when empty state', () => {
const initialState = {};
const toastsState = mapStateToProps(initialState);
expect(toastsState.toasts.length).to.be.equal(0);
});
});
7 changes: 7 additions & 0 deletions src/components/transactions/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,20 @@ describe('TransactionsHOC', () => {
};
const account = { address: '16313739661670634666L' };
const peers = { data: {} };
const voting = {
votes: {},
delegates: [],
totalDelegates: [],
refresh: false,
};

beforeEach(() => {
store.getState = () => ({
peers,
transactions,
account,
loading: [],
voting,
});
wrapper = mount(<Provider store={store}><Router><TransactionsHOC /></Router></Provider>, {
context: { store, history, i18n },
Expand Down

0 comments on commit ae220c0

Please sign in to comment.