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

Commit

Permalink
Merge pull request #836 from LiskHQ/823-delegate-autocomplete
Browse files Browse the repository at this point in the history
Add error messages for autocomplete - Closes #823
  • Loading branch information
ginacontrino authored Oct 6, 2017
2 parents ffabc10 + 40b6352 commit eaaba4d
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 24 deletions.
39 changes: 31 additions & 8 deletions src/components/voteDialog/voteAutocomplete.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ export class VoteAutocompleteRaw extends React.Component {
unvotedResult: [],
votedListSearch: '',
unvotedListSearch: '',
votedSuggestionError: '',
unvotedSuggestionError: '',

};
}

Expand All @@ -41,24 +44,42 @@ export class VoteAutocompleteRaw extends React.Component {
if (name === 'votedListSearch') {
voteAutocomplete(this.props.activePeer, value, this.props.votes)
.then((res) => {
this.setState({
votedResult: res,
votedSuggestionClass: '',
});
if (res.length > 0) {
this.setState({
votedResult: res,
votedSuggestionClass: '',
votedSuggestionError: '',
});
} else {
this.setState({
votedSuggestionError: this.props.t('No matches'),
votedSuggestionClass: styles.hidden,
});
}
});
} else {
unvoteAutocomplete(value, this.props.votes)
.then((res) => {
this.setState({
unvotedResult: res,
unvotedSuggestionClass: '',
});
if (res.length > 0) {
this.setState({
unvotedResult: res,
unvotedSuggestionClass: '',
unvotedSuggestionError: '',
});
} else {
this.setState({
unvotedSuggestionError: this.props.t('No matches'),
unvotedSuggestionClass: styles.hidden,
});
}
});
}
} else {
this.setState({
votedResult: [],
unvotedResult: [],
votedSuggestionError: '',
unvotedSuggestionError: '',
votedSuggestionClass: styles.hidden,
unvotedSuggestionClass: styles.hidden,
});
Expand Down Expand Up @@ -188,6 +209,7 @@ export class VoteAutocompleteRaw extends React.Component {
<section className={styles.searchContainer}>
<Input type='text' label={this.props.t('Search by username')} name='votedListSearch'
className='votedListSearch' value={this.state.votedListSearch}
error={this.state.votedSuggestionError}
theme={styles}
onBlur={this.suggestionStatus.bind(this, false, 'votedSuggestionClass')}
onKeyDown={this.votedSearchKeyDown.bind(this)}
Expand Down Expand Up @@ -220,6 +242,7 @@ export class VoteAutocompleteRaw extends React.Component {
<section className={styles.searchContainer}>
<Input type='text' label={this.props.t('Search by username')} name='unvotedListSearch'
className='unvotedListSearch' value={this.state.unvotedListSearch}
error={this.state.unvotedSuggestionError}
theme={styles}
onBlur={this.suggestionStatus.bind(this, false, 'unvotedSuggestionClass')}
onKeyDown={this.unvotedSearchKeyDown.bind(this)}
Expand Down
62 changes: 52 additions & 10 deletions src/components/voteDialog/voteAutocomplete.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ describe('VoteAutocomplete', () => {
sinon.spy(VoteAutocomplete.prototype, 'handleArrowDown');
sinon.spy(VoteAutocomplete.prototype, 'handleArrowUp');

voteAutocompleteApiMock = sinon.stub(delegateApi, 'voteAutocomplete');
unvoteAutocompleteApiMock = sinon.stub(delegateApi, 'unvoteAutocomplete');
voteAutocompleteApiMock = sinon.mock(delegateApi, 'voteAutocomplete');
unvoteAutocompleteApiMock = sinon.mock(delegateApi, 'unvoteAutocomplete');
wrapper = mount(<VoteAutocomplete {...props} store={store} i18n={i18n}/>);
});

Expand Down Expand Up @@ -81,24 +81,66 @@ describe('VoteAutocomplete', () => {
expect(wrapper.state('unvotedSuggestionClass').match(/hidden/g)).to.have.lengthOf(1);
VoteAutocomplete.prototype.setState.restore();
});
it('search should call "voteAutocomplete" when name is equal to "votedListSearch"', () => {
it('search should call "voteAutocomplete" when name is equal to "votedListSearch" when search term exists', () => {
const clock = sinon.useFakeTimers();
voteAutocompleteApiMock.returnsPromise().resolves({ success: true })
.returnsPromise().resolves([]);
// sinon.stub(delegateApi, 'listDelegates').returnsPromise().resolves({ success: true });
wrapper.instance().search('votedListSearch', 'val');
const existingSearchTerm = 'username2';
const delegateApiMock = sinon.mock(delegateApi).expects('voteAutocomplete');

delegateApiMock.once().withExactArgs(props.activePeer, existingSearchTerm, props.votes)
.returnsPromise().resolves(delegates);

wrapper.find('.votedListSearch input').simulate('change', { target: { value: existingSearchTerm } });
clock.tick(250);
expect(wrapper.state('votedSuggestionClass')).to.be.equal('');

delegateApiMock.restore();
});

it('search should call "unvoteAutocomplete" when name is equal to "unvotedListSearch"', () => {
it('search should call "voteAutocomplete" when name is equal to "votedListSearch" when search term does not exist', () => {
const clock = sinon.useFakeTimers();
unvoteAutocompleteApiMock.returnsPromise().resolves([]);
wrapper.instance().search('unvotedListSearch', 'val');
const nonExistingSearchTerm = 'doesntexist';
const delegateApiMock = sinon.mock(delegateApi).expects('voteAutocomplete');

delegateApiMock.once().withExactArgs(props.activePeer, nonExistingSearchTerm, props.votes)
.returnsPromise().resolves([]);


wrapper.find('.votedListSearch input').simulate('change', { target: { value: nonExistingSearchTerm } });
clock.tick(250);
expect(wrapper.state('votedSuggestionClass').match(/hidden/g)).to.have.lengthOf(1);

delegateApiMock.restore();
});

it('search should call "unvoteAutocomplete" when name is equal to "unvotedListSearch" when search term exists', () => {
const clock = sinon.useFakeTimers();
const existingSearchTerm = 'username1';
const delegateApiMock = sinon.mock(delegateApi).expects('unvoteAutocomplete');

delegateApiMock.once().withExactArgs(existingSearchTerm, props.votes)
.returnsPromise().resolves(delegates);

wrapper.find('.unvotedListSearch input').simulate('change', { target: { value: existingSearchTerm } });
clock.tick(250);
expect(wrapper.state('unvotedSuggestionClass')).to.be.equal('');

delegateApiMock.restore();
});

it('search should call "unvoteAutocomplete" when name is equal to "unvotedListSearch" when search term does not exists', () => {
const clock = sinon.useFakeTimers();
const nonExistingSearchTerm = 'username2';
const delegateApiMock = sinon.mock(delegateApi).expects('unvoteAutocomplete');

delegateApiMock.once().withExactArgs(nonExistingSearchTerm, props.votes)
.returnsPromise().resolves([]);

wrapper.find('.unvotedListSearch input').simulate('change', { target: { value: nonExistingSearchTerm } });
clock.tick(250);
expect(wrapper.state('unvotedSuggestionClass').match(/hidden/g)).to.have.lengthOf(1);

delegateApiMock.restore();
});
it('should "votedSearchKeydown" call "keyPress"', () => {
wrapper.instance().votedSearchKeyDown({});
expect(VoteAutocomplete.prototype.keyPress).to.have.property('callCount', 1);
Expand Down
2 changes: 2 additions & 0 deletions src/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"Fee": "Fee",
"Fee: LSK": "Fee: LSK",
"Fee: {{amount}} LSK": "Fee: {{amount}} LSK",
"Fee: {{fee}} LSK": "Fee: {{fee}} LSK",
"Forget this account": "Forget this account",
"Forging": "Forging",
"From / To": "From / To",
Expand All @@ -55,6 +56,7 @@
"New Account": "New Account",
"Next": "Next",
"No delegates found": "No delegates found",
"No matches": "No matches",
"Node address": "Node address",
"Note: After registration completes,": "Note: After registration completes,",
"Note: Digital Signatures and signed messages are not encrypted!": "Note: Digital Signatures and signed messages are not encrypted!",
Expand Down
10 changes: 4 additions & 6 deletions src/utils/api/delegate.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,10 @@ export const voteAutocomplete = (activePeer, username, votedDict) => {
};

export const unvoteAutocomplete = (username, votedDict) =>
new Promise((resolve) => {
resolve(
Object.keys(votedDict)
.filter(delegate => delegate.indexOf(username) !== -1)
.map(element => ({ username: element, publicKey: votedDict[element].publicKey })));
});
new Promise(resolve => resolve(Object.keys(votedDict)
.filter(delegate => delegate.indexOf(username) !== -1)
.map(element => ({ username: element, publicKey: votedDict[element].publicKey }))),
);

export const registerDelegate = (activePeer, username, secret, secondSecret = null) => {
const data = { username, secret };
Expand Down

0 comments on commit eaaba4d

Please sign in to comment.