diff --git a/package.json b/package.json index 0969d9245..d2b7a7a91 100644 --- a/package.json +++ b/package.json @@ -39,10 +39,10 @@ "bitcore-mnemonic": "1.2.5", "copy-to-clipboard": "3.0.8", "flexboxgrid": "=6.3.1", - "history": "^4.7.2", - "i18next": "^9.0.0", - "i18next-localstorage-cache": "^1.1.1", - "i18next-xhr-backend": "^1.4.2", + "history": "=4.7.2", + "i18next": "=10.0.3", + "i18next-localstorage-cache": "=1.1.1", + "i18next-xhr-backend": "=1.4.2", "lisk-js": "0.5.0", "moment": "2.18.1", "numeral": "=2.0.6", @@ -50,12 +50,12 @@ "postcss-cssnext": "2.11.0", "prop-types": "=15.5.10", "qrcode.react": "0.7.2", - "react": "=15.6.x", - "react-animate-on-change": "^1.0.0", + "react": "=16.0.0", + "react-animate-on-change": "=1.0.0", "react-circular-progressbar": "0.2.1", "react-css-themr": "=2.1.2", - "react-dom": "=15.6.x", - "react-i18next": "^5.2.0", + "react-dom": "=16.0.0", + "react-i18next": "=6.0.6", "react-redux": "5.0.6", "react-router": "4.2.0", "react-router-dom": "4.2.2", @@ -63,14 +63,15 @@ "react-waypoint": "7.1.0", "redux": "3.7.2", "redux-logger": "=3.0.6", - "redux-thunk": "^2.2.0", - "webpack-merge": "^4.1.0" + "redux-thunk": "=2.2.0", + "webpack-merge": "=4.1.0" }, "devDependencies": { "@storybook/addon-actions": "3.2.12", "@storybook/react": "3.2.10", "babel-core": "6.26.0", "babel-loader": "7.1.2", + "babel-plugin-import-glob": "=2.0.0", "babel-plugin-istanbul": "4.1.5", "babel-plugin-syntax-trailing-function-commas": "=6.22.0", "babel-preset-es2015": "6.24.1", @@ -78,7 +79,7 @@ "babel-preset-stage-3": "=6.24.1", "chai": "4.1.2", "chai-as-promised": "7.1.1", - "chai-enzyme": "0.8.0", + "chai-enzyme": "=1.0.0-beta.0", "cpx": "=1.5.0", "css-hot-loader": "=1.3.1", "css-loader": "0.28.7", @@ -86,8 +87,9 @@ "del-cli": "1.1.0", "electron": "1.8.1", "electron-builder": "19.32.2", - "electron-json-storage": "^3.2.0", - "enzyme": "2.9.1", + "electron-json-storage": "=3.2.0", + "enzyme": "=3.1.0", + "enzyme-adapter-react-16": "=1.0.2", "eslint": "4.8.0", "eslint-config-airbnb": "15.1.0", "eslint-config-google": "0.9.1", @@ -122,17 +124,17 @@ "protractor-cucumber-framework": "3.1.0", "raw-loader": "1.0.0-beta.0", "react-addons-test-utils": "=15.6.0", - "react-hot-loader": "^1.3.1", - "react-test-renderer": "=15.6.1", + "react-hot-loader": "=1.3.1", + "react-test-renderer": "=16.0.0", "redux-mock-store": "1.3.0", "should": "13.1.0", "sinon": "3.3.0", "sinon-chai": "2.13.0", - "sinon-stub-promise": "^4.0.0", + "sinon-stub-promise": "=4.0.0", "style-loader": "0.18.2", - "stylelint": "^8.0.0", - "stylelint-config-standard": "^17.0.0", - "stylelint-webpack-plugin": "^0.9.0", + "stylelint": "=8.0.0", + "stylelint-config-standard": "=17.0.0", + "stylelint-webpack-plugin": "=0.9.0", "url-loader": "0.5.9", "webpack": "3.6.0", "webpack-bundle-analyzer": "2.9.0", diff --git a/src/components/login/login.test.js b/src/components/login/login.test.js index 3f6ae13a5..9e3dc1b71 100644 --- a/src/components/login/login.test.js +++ b/src/components/login/login.test.js @@ -62,7 +62,7 @@ describe('Login', () => { const expectedError = 'Passphrase should have 12 words, entered passphrase has 11'; wrapper.find('.passphrase input').simulate('change', { target: { value: ' ' } }); wrapper.find('.passphrase input').simulate('change', { target: { value: passphrase } }); - expect(wrapper.find('.passphrase').html()).to.contain(expectedError); + expect(wrapper.find('.passphrase')).to.contain(expectedError); }); }); diff --git a/src/components/offlineWrapper/index.js b/src/components/offlineWrapper/index.js index 786094495..f284bab58 100644 --- a/src/components/offlineWrapper/index.js +++ b/src/components/offlineWrapper/index.js @@ -3,7 +3,7 @@ import { connect } from 'react-redux'; import styles from './offlineWrapper.css'; export const OfflineWrapperComponent = props => ( - + { props.children } ); diff --git a/src/components/passphrase/passphrase.test.js b/src/components/passphrase/passphrase.test.js index 3dbc8d25e..a34d75e22 100644 --- a/src/components/passphrase/passphrase.test.js +++ b/src/components/passphrase/passphrase.test.js @@ -11,7 +11,9 @@ const fakeStore = configureStore(); describe('Passphrase Component', () => { let wrapper; - const clock = sinon.useFakeTimers(); + const clock = sinon.useFakeTimers({ + toFake: ['setTimeout', 'clearTimeout', 'Date'], + }); const props = { t: key => key, }; diff --git a/src/components/passphrase/passphraseGenerator.test.js b/src/components/passphrase/passphraseGenerator.test.js index 535790a6f..4c767e54a 100644 --- a/src/components/passphrase/passphraseGenerator.test.js +++ b/src/components/passphrase/passphraseGenerator.test.js @@ -29,7 +29,8 @@ describe('PassphraseGenerator', () => { const isTouchDeviceMock = mock(wrapper.instance()).expects('isTouchDevice'); isTouchDeviceMock.returns(true); wrapper.instance().setState({}); // to rerender the component - expect(wrapper.find('.touch-fallback textarea')).to.have.lengthOf(1); + wrapper.update(); + expect(wrapper.find('Input.touch-fallback textarea')).to.have.lengthOf(1); }); it('shows at least some progress on pressing input if this.isTouchDevice()', () => { @@ -37,7 +38,8 @@ describe('PassphraseGenerator', () => { const isTouchDeviceMock = mock(wrapper.instance()).expects('isTouchDevice'); isTouchDeviceMock.returns(true).twice(); wrapper.instance().setState({}); // to rerender the component - wrapper.find('.touch-fallback textarea').simulate('change', { target: { value: 'random key presses' } }); + wrapper.update(); + wrapper.find('Input.touch-fallback textarea').simulate('change', { target: { value: 'random key presses' } }); expect(wrapper.find('ProgressBar').props().value).to.be.at.least(1); }); diff --git a/src/components/passphraseInput/index.test.js b/src/components/passphraseInput/index.test.js index e7f3876bf..80d71d283 100644 --- a/src/components/passphraseInput/index.test.js +++ b/src/components/passphraseInput/index.test.js @@ -93,9 +93,9 @@ describe('PassphraseInput', () => { it('should allow to change the input field to type="text" and back', () => { expect(wrapper.find('input').props().type).to.equal('password'); - wrapper.find('.show-passphrase-toggle').simulate('click'); + wrapper.find('button.show-passphrase-toggle').simulate('click'); expect(wrapper.find('input').props().type).to.equal('text'); - wrapper.find('.show-passphrase-toggle').simulate('click'); + wrapper.find('button.show-passphrase-toggle').simulate('click'); expect(wrapper.find('input').props().type).to.equal('password'); }); }); diff --git a/src/components/receiveDialog/receiveDialog.test.js b/src/components/receiveDialog/receiveDialog.test.js index 31e8ddace..87a2b39c5 100644 --- a/src/components/receiveDialog/receiveDialog.test.js +++ b/src/components/receiveDialog/receiveDialog.test.js @@ -40,7 +40,7 @@ describe('ReceiveDialog', () => { const closeDialogSpy = sinon.spy(props, 'closeDialog'); const copyToClipboardSpy = sinon.spy(props, 'copyToClipboard'); - wrapper.find('.copy-address-button').simulate('click'); + wrapper.find('button.copy-address-button').simulate('click'); // TODO figure out why this doesn't work even though test coverage shows it's been called // expect(successToastSpy).to.have.been.calledWith(); diff --git a/src/components/registerDelegate/registerDelegate.test.js b/src/components/registerDelegate/registerDelegate.test.js index 8ede63945..bdcf0ac6b 100644 --- a/src/components/registerDelegate/registerDelegate.test.js +++ b/src/components/registerDelegate/registerDelegate.test.js @@ -92,7 +92,7 @@ describe('RegisterDelegate', () => { it('allows register as delegate for a non delegate account', () => { wrapper.find('.username input').simulate('change', { target: { value: 'sample_username' } }); - wrapper.find('.next-button').simulate('submit'); + wrapper.find('button.next-button').simulate('submit'); expect(wrapper.find('.primary-button button').props().disabled).to.not.equal(true); expect(props.delegateRegistered).to.have.been.calledWith(); }); diff --git a/src/components/saveAccount/saveAccount.test.js b/src/components/saveAccount/saveAccount.test.js index f7fa3f39a..d2d6b41cd 100644 --- a/src/components/saveAccount/saveAccount.test.js +++ b/src/components/saveAccount/saveAccount.test.js @@ -50,7 +50,7 @@ describe('SaveAccount', () => { }); it('should call props.closeDialog and props.accountSaved on "save button" click', () => { - wrapper.find('.save-account-button').simulate('click'); + wrapper.find('button.save-account-button').simulate('click'); const componentProps = wrapper.find(SaveAccount).props(); expect(componentProps.closeDialog).to.have.been.calledWith(); expect(componentProps.accountSaved).to.have.been.calledWith(); diff --git a/src/components/send/send.test.js b/src/components/send/send.test.js index d9fb79cf4..b4395125a 100644 --- a/src/components/send/send.test.js +++ b/src/components/send/send.test.js @@ -49,44 +49,44 @@ describe('Send', () => { it('accepts valid amount', () => { wrapper.find('.amount input').simulate('change', { target: { value: '120.25' } }); - expect(wrapper.find('.amount').text()).to.not.contain('Invalid'); + expect(wrapper.find('Input.amount').text()).to.not.contain('Invalid'); }); it('recognizes invalid amount', () => { wrapper.find('.amount input').simulate('change', { target: { value: '120 INVALID' } }); - expect(wrapper.find('.amount').text()).to.contain('Invalid'); + expect(wrapper.find('Input.amount').text()).to.contain('Invalid'); }); it('recognizes zero amount', () => { wrapper.find('.amount input').simulate('change', { target: { value: '0' } }); - expect(wrapper.find('.amount').text()).to.contain('Zero not allowed'); + expect(wrapper.find('Input.amount').text()).to.contain('Zero not allowed'); }); it('recognizes too high amount', () => { wrapper.find('.amount input').simulate('change', { target: { value: '12000' } }); - expect(wrapper.find('.amount').text()).to.contain('Insufficient funds'); + expect(wrapper.find('Input.amount').text()).to.contain('Insufficient funds'); }); it('recognizes empty amount', () => { wrapper.find('.amount input').simulate('change', { target: { value: '12000' } }); wrapper.find('.amount input').simulate('change', { target: { value: '' } }); - expect(wrapper.find('.amount').text()).to.contain('Required'); + expect(wrapper.find('Input.amount').text()).to.contain('Required'); }); it('accepts valid recipient', () => { wrapper.find('.recipient input').simulate('change', { target: { value: '11004588490103196952L' } }); - expect(wrapper.find('.recipient').text()).to.not.contain('Invalid'); + expect(wrapper.find('Input.recipient').text()).to.not.contain('Invalid'); }); it('recognizes invalid recipient', () => { wrapper.find('.recipient input').simulate('change', { target: { value: '11004588490103196952' } }); - expect(wrapper.find('.recipient').text()).to.contain('Invalid'); + expect(wrapper.find('Input.recipient').text()).to.contain('Invalid'); }); it('allows to set maximum amount', () => { - wrapper.find('.transaction-amount').simulate('click'); - wrapper.find('.send-maximum-amount').simulate('click'); - expect(wrapper.find('.amount input').props().value).to.equal('999.9'); + wrapper.find('IconMenu.transaction-amount').simulate('click'); + wrapper.find('MenuItem.send-maximum-amount').simulate('click'); + expect(wrapper.find('Input.amount input').props().value).to.equal('999.9'); }); it('allows to send a transaction', () => { diff --git a/src/components/timestamp/index.test.js b/src/components/timestamp/index.test.js index a3d72cc3f..5487bc364 100644 --- a/src/components/timestamp/index.test.js +++ b/src/components/timestamp/index.test.js @@ -6,7 +6,10 @@ import PropTypes from 'prop-types'; import i18n from '../../i18n'; import { Time, TooltipTime, TooltipWrapper } from './index'; -sinon.useFakeTimers(new Date(2017, 1, 15).getTime()); +sinon.useFakeTimers({ + now: new Date(2017, 1, 15).getTime(), + toFake: ['setTimeout', 'clearTimeout', 'Date'], +}); describe('Time', () => { it('shows "5 months" for the equivalent timestamp (35929631)', () => { const inputValue = 35929631; diff --git a/src/components/toaster/toaster.test.js b/src/components/toaster/toaster.test.js index 4ef403932..38a9f7292 100644 --- a/src/components/toaster/toaster.test.js +++ b/src/components/toaster/toaster.test.js @@ -26,7 +26,9 @@ describe('Toaster', () => { describe('hideToast', () => { it('hides the toast and after the animation ends calls this.props.hideToast()', () => { - const clock = sinon.useFakeTimers(); + const clock = sinon.useFakeTimers({ + toFake: ['setTimeout', 'clearTimeout', 'Date'], + }); wrapper.instance().hideToast(toasts[0]); expect(wrapper.state('hidden')).to.deep.equal({ [toasts[0].index]: true }); clock.tick(510); diff --git a/src/components/verifyMessage/index.test.js b/src/components/verifyMessage/index.test.js index ba7e1778e..de748d53f 100644 --- a/src/components/verifyMessage/index.test.js +++ b/src/components/verifyMessage/index.test.js @@ -25,12 +25,12 @@ describe('VerifyMessage', () => { it('recognizes invalid public key', () => { wrapper.find('.public-key input').simulate('change', { target: { value: publicKey.substr(3) } }); wrapper.find('.signature textarea').simulate('change', { target: { value: signature } }); - expect(wrapper.find('.public-key').text()).to.contain('Invalid'); + expect(wrapper.find('Input.public-key').text()).to.contain('Invalid'); }); it('recognizes invalid signature', () => { wrapper.find('.public-key input').simulate('change', { target: { value: publicKey } }); wrapper.find('.signature textarea').simulate('change', { target: { value: signature.substr(3) } }); - expect(wrapper.find('.signature').text()).to.contain('Invalid'); + expect(wrapper.find('Input.signature').text()).to.contain('Invalid'); }); }); diff --git a/src/components/voteDialog/voteAutocomplete.test.js b/src/components/voteDialog/voteAutocomplete.test.js index eb64e125d..fc53ba1fb 100644 --- a/src/components/voteDialog/voteAutocomplete.test.js +++ b/src/components/voteDialog/voteAutocomplete.test.js @@ -56,21 +56,27 @@ describe('VoteAutocomplete', () => { }); it('should suggestionStatus(false, className) change value of className in state', () => { - const clock = sinon.useFakeTimers(); + const clock = sinon.useFakeTimers({ + toFake: ['setTimeout', 'clearTimeout', 'Date'], + }); wrapper.instance().suggestionStatus(false, 'className'); clock.tick(200); expect(wrapper.state('className').match(/hidden/g)).to.have.lengthOf(1); }); it('should suggestionStatus(true, className) clear value of className in state', () => { - const clock = sinon.useFakeTimers(); + const clock = sinon.useFakeTimers({ + toFake: ['setTimeout', 'clearTimeout', 'Date'], + }); wrapper.instance().suggestionStatus(true, 'className'); clock.tick(200); expect(wrapper.state('className')).to.be.equal(''); }); it('should search hide suggestion boxes when value is equal to ""', () => { - const clock = sinon.useFakeTimers(); + const clock = sinon.useFakeTimers({ + toFake: ['setTimeout', 'clearTimeout', 'Date'], + }); sinon.spy(VoteAutocomplete.prototype, 'setState'); wrapper.instance().search('votedListSearch', ''); clock.tick(250); @@ -82,7 +88,9 @@ describe('VoteAutocomplete', () => { VoteAutocomplete.prototype.setState.restore(); }); it('search should call "voteAutocomplete" when name is equal to "votedListSearch" when search term exists', () => { - const clock = sinon.useFakeTimers(); + const clock = sinon.useFakeTimers({ + toFake: ['setTimeout', 'clearTimeout', 'Date'], + }); const existingSearchTerm = 'username2'; const delegateApiMock = sinon.mock(delegateApi).expects('voteAutocomplete'); @@ -97,7 +105,9 @@ describe('VoteAutocomplete', () => { }); it('search should call "voteAutocomplete" when name is equal to "votedListSearch" when search term does not exist', () => { - const clock = sinon.useFakeTimers(); + const clock = sinon.useFakeTimers({ + toFake: ['setTimeout', 'clearTimeout', 'Date'], + }); const nonExistingSearchTerm = 'doesntexist'; const delegateApiMock = sinon.mock(delegateApi).expects('voteAutocomplete'); @@ -113,7 +123,9 @@ describe('VoteAutocomplete', () => { }); it('search should call "unvoteAutocomplete" when name is equal to "unvotedListSearch" when search term exists', () => { - const clock = sinon.useFakeTimers(); + const clock = sinon.useFakeTimers({ + toFake: ['setTimeout', 'clearTimeout', 'Date'], + }); const existingSearchTerm = 'username1'; const delegateApiMock = sinon.mock(delegateApi).expects('unvoteAutocomplete'); @@ -128,7 +140,9 @@ describe('VoteAutocomplete', () => { }); it('search should call "unvoteAutocomplete" when name is equal to "unvotedListSearch" when search term does not exists', () => { - const clock = sinon.useFakeTimers(); + const clock = sinon.useFakeTimers({ + toFake: ['setTimeout', 'clearTimeout', 'Date'], + }); const nonExistingSearchTerm = 'username2'; const delegateApiMock = sinon.mock(delegateApi).expects('unvoteAutocomplete'); diff --git a/src/components/voting/voting.test.js b/src/components/voting/voting.test.js index 2b8b9f360..84de9f96c 100644 --- a/src/components/voting/voting.test.js +++ b/src/components/voting/voting.test.js @@ -71,7 +71,9 @@ describe('Voting', () => { }); it('should define search method to reload delegates based on given query', () => { - const clock = sinon.useFakeTimers(); + const clock = sinon.useFakeTimers({ + toFake: ['setTimeout', 'clearTimeout', 'Date'], + }); props.delegatesFetched.reset(); wrapper.find('.search input').simulate('change', { target: { value: 'query' } }); clock.tick(251); diff --git a/src/components/voting/votingHeader.test.js b/src/components/voting/votingHeader.test.js index 94397dfd8..68711e670 100644 --- a/src/components/voting/votingHeader.test.js +++ b/src/components/voting/votingHeader.test.js @@ -78,16 +78,21 @@ describe('VotingHeader', () => { }); it('should this.props.search when this.search is called', () => { - const clock = sinon.useFakeTimers(); + const clock = sinon.useFakeTimers({ + toFake: ['setTimeout', 'clearTimeout', 'Date'], + }); wrapper.find('.search input').simulate('change', { target: { value: '555' } }); clock.tick(250); expect(props.search).to.have.been.calledWith('555'); }); it('click on #searchIcon should clear value of search input', () => { - wrapper.find('.search input').simulate('change', { target: { value: '555' } }); - wrapper.find('#searchIcon').simulate('click'); - expect(wrapper.find('.search input').get(0).value).to.be.equal(''); + wrapper.find('Input.search input').simulate('change', { target: { value: '555' } }); + wrapper.update(); + expect(wrapper.find('Input.search input').props().value).to.be.equal('555'); + wrapper.find('i#searchIcon').simulate('click'); + wrapper.update(); + expect(wrapper.find('Input.search input').props().value).to.be.equal(''); }); }); diff --git a/src/tests.js b/src/tests.js index 7947673f2..3a46581f0 100644 --- a/src/tests.js +++ b/src/tests.js @@ -4,6 +4,10 @@ import chaiEnzyme from 'chai-enzyme'; import chaiAsPromised from 'chai-as-promised'; import sinon from 'sinon'; import sinonStubPromise from 'sinon-stub-promise'; +import Enzyme from 'enzyme'; +import Adapter from 'enzyme-adapter-react-16'; + +Enzyme.configure({ adapter: new Adapter() }); chai.use(sinonChai); chai.use(chaiEnzyme());