diff --git a/test/unit/ui/app/actions.spec.js b/test/unit/ui/app/actions.spec.js index 5e9ad3909..6a02830a8 100644 --- a/test/unit/ui/app/actions.spec.js +++ b/test/unit/ui/app/actions.spec.js @@ -1,135 +1,119 @@ import assert from 'assert' import sinon from 'sinon' -import { cloneDeep } from 'lodash' import configureStore from 'redux-mock-store' import thunk from 'redux-thunk' import EthQuery from 'eth-query' import Eth from 'ethjs' -import KeyringController from 'eth-keyring-controller' import { createTestProviderTools } from '../../../stub/provider' import enLocale from '../../../../app/_locales/en/messages.json' import * as actions from '../../../../ui/app/store/actions' import MetaMaskController from '../../../../app/scripts/metamask-controller' -import firstTimeState from '../../localhostState' import { TRANSACTION_STATUSES } from '../../../../shared/constants/transaction' const { provider } = createTestProviderTools({ scaffold: {} }) const middleware = [thunk] -const defaultState = { metamask: { provider: { chainId: '0x1' } } } -const mockStore = (state = defaultState) => configureStore(middleware)(state) -const extensionMock = { - runtime: { - onInstalled: { - addListener: () => undefined, - }, +const defaultState = { + metamask: { + currentLocale: 'test', + selectedAddress: '0xFirstAddress', + provider: { chainId: '0x1' }, }, } +const mockStore = (state = defaultState) => configureStore(middleware)(state) describe('Actions', function () { - const noop = () => undefined + let background const currentNetworkId = '42' - let background, metamaskController - - const TEST_SEED = - 'debris dizzy just program just float decrease vacant alarm reduce speak stadium' - const password = 'a-fake-password' - const importPrivkey = - '4cfd3e90fc78b0f86bf7524722150bb8da9c60cd532564d7ff43f5716514f553' - beforeEach(async function () { - metamaskController = new MetaMaskController({ - extension: extensionMock, - platform: { getVersion: () => 'foo' }, - provider, - keyringController: new KeyringController({}), - showUserConfirmation: noop, - encryptor: { - encrypt(_, object) { - this.object = object - return Promise.resolve('mock-encrypted') - }, - decrypt() { - return Promise.resolve(this.object) - }, - }, - initLangCode: 'en_US', - initState: cloneDeep(firstTimeState), - infuraProjectId: 'foo', + background = sinon.createStubInstance(MetaMaskController, { + getState: sinon.stub().callsFake((cb) => + cb(null, { + currentLocale: 'test', + selectedAddress: '0xFirstAddress', + }), + ), }) - metamaskController.threeBoxController = { - new3Box: sinon.spy(), - getThreeBoxSyncingState: sinon.spy(), - } - - await metamaskController.createNewVaultAndRestore(password, TEST_SEED) - - await metamaskController.importAccountWithStrategy('Private Key', [ - importPrivkey, - ]) - - background = metamaskController.getApi() - - actions._setBackgroundConnection(background) - global.ethQuery = new EthQuery(provider) }) describe('#tryUnlockMetamask', function () { - let submitPasswordSpy, verifySeedPhraseSpy - afterEach(function () { - submitPasswordSpy.restore() - verifySeedPhraseSpy.restore() + sinon.restore() }) it('calls submitPassword and verifySeedPhrase', async function () { const store = mockStore() - submitPasswordSpy = sinon.spy(background, 'submitPassword') - verifySeedPhraseSpy = sinon.spy(background, 'verifySeedPhrase') + const submitPassword = background.submitPassword.callsFake((_, cb) => + cb(), + ) + + const verifySeedPhrase = background.verifySeedPhrase.callsFake((cb) => + cb(), + ) + + actions._setBackgroundConnection(background) + + const expectedActions = [ + { type: 'SHOW_LOADING_INDICATION', value: undefined }, + { type: 'UNLOCK_IN_PROGRESS' }, + { type: 'UNLOCK_SUCCEEDED', value: undefined }, + { + type: 'UPDATE_METAMASK_STATE', + value: { + currentLocale: 'test', + selectedAddress: '0xFirstAddress', + }, + }, + { type: 'HIDE_LOADING_INDICATION' }, + ] await store.dispatch(actions.tryUnlockMetamask()) - assert(submitPasswordSpy.calledOnce) - assert(verifySeedPhraseSpy.calledOnce) + + assert(submitPassword.calledOnce) + assert(verifySeedPhrase.calledOnce) + + assert.deepStrictEqual(store.getActions(), expectedActions) }) it('errors on submitPassword will fail', async function () { const store = mockStore() + background.submitPassword.callsFake((_, cb) => cb(new Error('error'))) + + actions._setBackgroundConnection(background) + const expectedActions = [ { type: 'SHOW_LOADING_INDICATION', value: undefined }, { type: 'UNLOCK_IN_PROGRESS' }, - { type: 'UNLOCK_FAILED', value: 'error in submitPassword' }, + { type: 'UNLOCK_FAILED', value: 'error' }, { type: 'HIDE_LOADING_INDICATION' }, ] - submitPasswordSpy = sinon.stub(background, 'submitPassword') - - submitPasswordSpy.callsFake((_, callback) => { - callback(new Error('error in submitPassword')) - }) - try { await store.dispatch(actions.tryUnlockMetamask('test')) assert.fail('Should have thrown error') } catch (_) { - assert.deepEqual(store.getActions(), expectedActions) + assert.deepStrictEqual(store.getActions(), expectedActions) } }) it('displays warning error and unlock failed when verifySeed fails', async function () { const store = mockStore() - const displayWarningError = [{ type: 'DISPLAY_WARNING', value: 'error' }] - const unlockFailedError = [{ type: 'UNLOCK_FAILED', value: 'error' }] - verifySeedPhraseSpy = sinon.stub(background, 'verifySeedPhrase') - verifySeedPhraseSpy.callsFake((callback) => { - callback(new Error('error')) + background.submitPassword.callsFake((_, cb) => cb()) + background.verifySeedPhrase.callsFake((cb) => { + cb(new Error('error')) }) + actions._setBackgroundConnection(background) + + const displayWarningError = [{ type: 'DISPLAY_WARNING', value: 'error' }] + const unlockFailedError = [{ type: 'UNLOCK_FAILED', value: 'error' }] + try { await store.dispatch(actions.tryUnlockMetamask('test')) assert.fail('Should have thrown error') @@ -141,111 +125,149 @@ describe('Actions', function () { const unlockFailed = actions1.filter( (action) => action.type === 'UNLOCK_FAILED', ) - assert.deepEqual(warning, displayWarningError) - assert.deepEqual(unlockFailed, unlockFailedError) + assert.deepStrictEqual(warning, displayWarningError) + assert.deepStrictEqual(unlockFailed, unlockFailedError) } }) }) describe('#createNewVaultAndRestore', function () { - let createNewVaultAndRestoreSpy - afterEach(function () { - createNewVaultAndRestoreSpy.restore() + sinon.restore() }) - it('restores new vault', async function () { + it('calls createNewVaultAndRestore', async function () { const store = mockStore() - createNewVaultAndRestoreSpy = sinon.spy( - background, - 'createNewVaultAndRestore', + const createNewVaultAndRestore = background.createNewVaultAndRestore.callsFake( + (_, __, cb) => cb(), ) - try { - await store.dispatch(actions.createNewVaultAndRestore()) - assert.fail('Should have thrown error') - } catch (_) { - assert(createNewVaultAndRestoreSpy.calledOnce) - } + background.unMarkPasswordForgotten.callsFake((cb) => cb()) + + actions._setBackgroundConnection(background) + + await store.dispatch(actions.createNewVaultAndRestore()) + assert(createNewVaultAndRestore.calledOnce) }) - it('errors when callback in createNewVaultAndRestore throws', async function () { + it('calls the expected actions', async function () { const store = mockStore() + background.createNewVaultAndRestore.callsFake((_, __, cb) => cb()) + background.unMarkPasswordForgotten.callsFake((cb) => cb()) + + actions._setBackgroundConnection(background) + const expectedActions = [ { type: 'SHOW_LOADING_INDICATION', value: undefined }, - { type: 'DISPLAY_WARNING', value: 'error' }, + { type: 'FORGOT_PASSWORD', value: false }, + { + type: 'UPDATE_METAMASK_STATE', + value: { + currentLocale: 'test', + selectedAddress: '0xFirstAddress', + }, + }, + { type: 'SHOW_ACCOUNTS_PAGE' }, { type: 'HIDE_LOADING_INDICATION' }, ] - createNewVaultAndRestoreSpy = sinon.stub( - background, - 'createNewVaultAndRestore', + await store.dispatch(actions.createNewVaultAndRestore()) + + assert.deepStrictEqual(store.getActions(), expectedActions) + }) + + it('errors when callback in createNewVaultAndRestore throws', async function () { + const store = mockStore() + + background.createNewVaultAndRestore.callsFake((_, __, cb) => + cb(new Error('error')), ) - createNewVaultAndRestoreSpy.callsFake((_, __, callback) => { - callback(new Error('error')) - }) + actions._setBackgroundConnection(background) + + const expectedActions = [ + { type: 'SHOW_LOADING_INDICATION', value: undefined }, + { type: 'DISPLAY_WARNING', value: 'error' }, + { type: 'HIDE_LOADING_INDICATION' }, + ] try { await store.dispatch(actions.createNewVaultAndRestore()) assert.fail('Should have thrown error') } catch (_) { - assert.deepEqual(store.getActions(), expectedActions) + assert.deepStrictEqual(store.getActions(), expectedActions) } }) }) describe('#requestRevealSeedWords', function () { - let submitPasswordSpy - afterEach(function () { - submitPasswordSpy.restore() + sinon.restore() }) - it('calls submitPassword in background', async function () { + it('calls verifyPassword in background', async function () { const store = mockStore() - submitPasswordSpy = sinon.spy(background, 'verifySeedPhrase') + const verifyPassword = background.verifyPassword.callsFake((_, cb) => + cb(), + ) + const verifySeedPhrase = background.verifySeedPhrase.callsFake((cb) => + cb(), + ) + + actions._setBackgroundConnection(background) await store.dispatch(actions.requestRevealSeedWords()) - assert(submitPasswordSpy.calledOnce) + assert(verifyPassword.calledOnce) + assert(verifySeedPhrase.calledOnce) }) it('displays warning error message then callback in background errors', async function () { const store = mockStore() + background.verifyPassword.callsFake((_, cb) => cb()) + background.verifySeedPhrase.callsFake((cb) => { + cb(new Error('error')) + }) + + actions._setBackgroundConnection(background) + const expectedActions = [ { type: 'SHOW_LOADING_INDICATION', value: undefined }, { type: 'DISPLAY_WARNING', value: 'error' }, { type: 'HIDE_LOADING_INDICATION' }, ] - submitPasswordSpy = sinon.stub(background, 'verifySeedPhrase') - submitPasswordSpy.callsFake((callback) => { - callback(new Error('error')) - }) - try { await store.dispatch(actions.requestRevealSeedWords()) assert.fail('Should have thrown error') } catch (_) { - assert.deepEqual(store.getActions(), expectedActions) + assert.deepStrictEqual(store.getActions(), expectedActions) } }) }) describe('#removeAccount', function () { - let removeAccountStub - afterEach(function () { - removeAccountStub.restore() + sinon.restore() }) it('calls removeAccount in background and expect actions to show account', async function () { const store = mockStore() + background.getState.callsFake((cb) => + cb(null, { + currentLocale: 'test', + selectedAddress: '0xAnotherAddress', + }), + ) + + const removeAccount = background.removeAccount.callsFake((_, cb) => cb()) + + actions._setBackgroundConnection(background) + const expectedActions = [ 'SHOW_LOADING_INDICATION', 'SELECTED_ADDRESS_CHANGED', @@ -254,31 +276,29 @@ describe('Actions', function () { 'SHOW_ACCOUNTS_PAGE', ] - removeAccountStub = sinon.stub(background, 'removeAccount') - removeAccountStub.callsFake((_, callback) => callback()) - await store.dispatch( actions.removeAccount('0xe18035bf8712672935fdb4e5e431b1a0183d2dfc'), ) - assert(removeAccountStub.calledOnce) + assert(removeAccount.calledOnce) const actionTypes = store.getActions().map((action) => action.type) - assert.deepEqual(actionTypes, expectedActions) + assert.deepStrictEqual(actionTypes, expectedActions) }) it('displays warning error message when removeAccount callback errors', async function () { const store = mockStore() + background.removeAccount.callsFake((_, cb) => { + cb(new Error('error')) + }) + + actions._setBackgroundConnection(background) + const expectedActions = [ 'SHOW_LOADING_INDICATION', 'DISPLAY_WARNING', 'HIDE_LOADING_INDICATION', ] - removeAccountStub = sinon.stub(background, 'removeAccount') - removeAccountStub.callsFake((_, callback) => { - callback(new Error('error')) - }) - try { await store.dispatch( actions.removeAccount('0xe18035bf8712672935fdb4e5e431b1a0183d2dfc'), @@ -286,83 +306,91 @@ describe('Actions', function () { assert.fail('Should have thrown error') } catch (_) { const actionTypes = store.getActions().map((action) => action.type) - assert.deepEqual(actionTypes, expectedActions) + assert.deepStrictEqual(actionTypes, expectedActions) } }) }) describe('#resetAccount', function () { - let resetAccountSpy - afterEach(function () { - resetAccountSpy.restore() + sinon.restore() }) it('resets account', async function () { const store = mockStore() + const resetAccount = background.resetAccount.callsFake((cb) => cb()) + + actions._setBackgroundConnection(background) + const expectedActions = [ { type: 'SHOW_LOADING_INDICATION', value: undefined }, { type: 'HIDE_LOADING_INDICATION' }, { type: 'SHOW_ACCOUNTS_PAGE' }, ] - resetAccountSpy = sinon.spy(background, 'resetAccount') - await store.dispatch(actions.resetAccount()) - assert(resetAccountSpy.calledOnce) - assert.deepEqual(store.getActions(), expectedActions) + assert(resetAccount.calledOnce) + assert.deepStrictEqual(store.getActions(), expectedActions) }) it('throws if resetAccount throws', async function () { const store = mockStore() + background.resetAccount.callsFake((cb) => { + cb(new Error('error')) + }) + + actions._setBackgroundConnection(background) + const expectedActions = [ { type: 'SHOW_LOADING_INDICATION', value: undefined }, { type: 'HIDE_LOADING_INDICATION' }, { type: 'DISPLAY_WARNING', value: 'error' }, ] - resetAccountSpy = sinon.stub(background, 'resetAccount') - resetAccountSpy.callsFake((callback) => { - callback(new Error('error')) - }) - try { await store.dispatch(actions.resetAccount()) assert.fail('Should have thrown error') } catch (_) { - assert.deepEqual(store.getActions(), expectedActions) + assert.deepStrictEqual(store.getActions(), expectedActions) } }) }) describe('#importNewAccount', function () { - let importAccountWithStrategySpy - afterEach(function () { - importAccountWithStrategySpy.restore() + sinon.restore() }) it('calls importAccountWithStrategies in background', async function () { const store = mockStore() - importAccountWithStrategySpy = sinon.spy( - background, - 'importAccountWithStrategy', + const importAccountWithStrategy = background.importAccountWithStrategy.callsFake( + (_, __, cb) => { + cb() + }, ) + actions._setBackgroundConnection(background) + await store.dispatch( actions.importNewAccount('Private Key', [ 'c87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3', ]), ) - assert(importAccountWithStrategySpy.calledOnce) + assert(importAccountWithStrategy.calledOnce) }) it('displays warning error message when importAccount in background callback errors', async function () { const store = mockStore() + background.importAccountWithStrategy.callsFake((_, __, cb) => + cb(new Error('error')), + ) + + actions._setBackgroundConnection(background) + const expectedActions = [ { type: 'SHOW_LOADING_INDICATION', @@ -372,19 +400,11 @@ describe('Actions', function () { { type: 'HIDE_LOADING_INDICATION' }, ] - importAccountWithStrategySpy = sinon.stub( - background, - 'importAccountWithStrategy', - ) - importAccountWithStrategySpy.callsFake((_, __, callback) => { - callback(new Error('error')) - }) - try { await store.dispatch(actions.importNewAccount()) assert.fail('Should have thrown error') } catch (_) { - assert.deepEqual(store.getActions(), expectedActions) + assert.deepStrictEqual(store.getActions(), expectedActions) } }) }) @@ -393,38 +413,73 @@ describe('Actions', function () { it('Adds a new account', async function () { const store = mockStore({ metamask: { identities: {} } }) - const addNewAccountSpy = sinon.spy(background, 'addNewAccount') + const addNewAccount = background.addNewAccount.callsFake((cb) => + cb(null, { + identities: {}, + }), + ) + + actions._setBackgroundConnection(background) await store.dispatch(actions.addNewAccount()) - assert(addNewAccountSpy.calledOnce) + assert(addNewAccount.calledOnce) + }) + + it('displays warning error message when addNewAccount in background callback errors', async function () { + const store = mockStore() + + background.addNewAccount.callsFake((cb) => { + cb(new Error('error')) + }) + + actions._setBackgroundConnection(background) + + const expectedActions = [ + { type: 'SHOW_LOADING_INDICATION', value: undefined }, + { type: 'DISPLAY_WARNING', value: 'error' }, + { type: 'HIDE_LOADING_INDICATION' }, + ] + + try { + await store.dispatch(actions.addNewAccount()) + assert.fail('Should have thrown error') + } catch (_) { + assert.deepStrictEqual(store.getActions(), expectedActions) + } }) }) describe('#checkHardwareStatus', function () { - let checkHardwareStatusSpy - afterEach(function () { - checkHardwareStatusSpy.restore() + sinon.restore() }) it('calls checkHardwareStatus in background', async function () { - checkHardwareStatusSpy = sinon - .stub(background, 'checkHardwareStatus') - .callsArgWith(2, null) const store = mockStore() + const checkHardwareStatus = background.checkHardwareStatus.callsFake( + (_, __, cb) => { + cb() + }, + ) + + actions._setBackgroundConnection(background) + await store.dispatch( actions.checkHardwareStatus('ledger', `m/44'/60'/0'/0`), ) - assert.equal(checkHardwareStatusSpy.calledOnce, true) + assert.strictEqual(checkHardwareStatus.calledOnce, true) }) it('shows loading indicator and displays error', async function () { - checkHardwareStatusSpy = sinon - .stub(background, 'checkHardwareStatus') - .callsArgWith(2, new Error('error')) const store = mockStore() + background.checkHardwareStatus.callsFake((_, __, cb) => + cb(new Error('error')), + ) + + actions._setBackgroundConnection(background) + const expectedActions = [ { type: 'SHOW_LOADING_INDICATION', value: undefined }, { type: 'DISPLAY_WARNING', value: 'error' }, @@ -435,34 +490,34 @@ describe('Actions', function () { await store.dispatch(actions.checkHardwareStatus()) assert.fail('Should have thrown error') } catch (_) { - assert.deepEqual(store.getActions(), expectedActions) + assert.deepStrictEqual(store.getActions(), expectedActions) } }) }) describe('#forgetDevice', function () { - let forgetDeviceSpy - afterEach(function () { - forgetDeviceSpy.restore() + sinon.restore() }) it('calls forgetDevice in background', async function () { - forgetDeviceSpy = sinon - .stub(background, 'forgetDevice') - .callsArgWith(1, null) const store = mockStore() + const forgetDevice = background.forgetDevice.callsFake((_, cb) => cb()) + + actions._setBackgroundConnection(background) + await store.dispatch(actions.forgetDevice('ledger')) - assert.equal(forgetDeviceSpy.calledOnce, true) + assert(forgetDevice.calledOnce) }) it('shows loading indicator and displays error', async function () { - forgetDeviceSpy = sinon - .stub(background, 'forgetDevice') - .callsArgWith(1, new Error('error')) const store = mockStore() + background.forgetDevice.callsFake((_, cb) => cb(new Error('error'))) + + actions._setBackgroundConnection(background) + const expectedActions = [ { type: 'SHOW_LOADING_INDICATION', value: undefined }, { type: 'DISPLAY_WARNING', value: 'error' }, @@ -473,36 +528,40 @@ describe('Actions', function () { await store.dispatch(actions.forgetDevice()) assert.fail('Should have thrown error') } catch (_) { - assert.deepEqual(store.getActions(), expectedActions) + assert.deepStrictEqual(store.getActions(), expectedActions) } }) }) describe('#connectHardware', function () { - let connectHardwareSpy - afterEach(function () { - connectHardwareSpy.restore() + sinon.restore() }) it('calls connectHardware in background', async function () { - connectHardwareSpy = sinon - .stub(background, 'connectHardware') - .callsArgWith(3, null) const store = mockStore() + const connectHardware = background.connectHardware.callsFake( + (_, __, ___, cb) => cb(), + ) + + actions._setBackgroundConnection(background) + await store.dispatch( actions.connectHardware('ledger', 0, `m/44'/60'/0'/0`), ) - assert.equal(connectHardwareSpy.calledOnce, true) + assert(connectHardware.calledOnce) }) it('shows loading indicator and displays error', async function () { - connectHardwareSpy = sinon - .stub(background, 'connectHardware') - .callsArgWith(3, new Error('error')) const store = mockStore() + background.connectHardware.callsFake((_, __, ___, cb) => + cb(new Error('error')), + ) + + actions._setBackgroundConnection(background) + const expectedActions = [ { type: 'SHOW_LOADING_INDICATION', @@ -516,36 +575,39 @@ describe('Actions', function () { await store.dispatch(actions.connectHardware('ledger')) assert.fail('Should have thrown error') } catch (_) { - assert.deepEqual(store.getActions(), expectedActions) + assert.deepStrictEqual(store.getActions(), expectedActions) } }) }) describe('#unlockHardwareWalletAccount', function () { - let unlockHardwareWalletAccountSpy - afterEach(function () { - unlockHardwareWalletAccountSpy.restore() + sinon.restore() }) it('calls unlockHardwareWalletAccount in background', async function () { - unlockHardwareWalletAccountSpy = sinon - .stub(background, 'unlockHardwareWalletAccount') - .callsArgWith(3, null) const store = mockStore() + const unlockHardwareWalletAccount = background.unlockHardwareWalletAccount.callsFake( + (_, __, ___, cb) => cb(), + ) + + actions._setBackgroundConnection(background) await store.dispatch( actions.unlockHardwareWalletAccount('ledger', 0, `m/44'/60'/0'/0`), ) - assert.equal(unlockHardwareWalletAccountSpy.calledOnce, true) + assert(unlockHardwareWalletAccount.calledOnce) }) it('shows loading indicator and displays error', async function () { - unlockHardwareWalletAccountSpy = sinon - .stub(background, 'unlockHardwareWalletAccount') - .callsArgWith(3, new Error('error')) const store = mockStore() + background.unlockHardwareWalletAccount.callsFake((_, __, ___, cb) => + cb(new Error('error')), + ) + + actions._setBackgroundConnection(background) + const expectedActions = [ { type: 'SHOW_LOADING_INDICATION', value: undefined }, { type: 'HIDE_LOADING_INDICATION' }, @@ -556,33 +618,40 @@ describe('Actions', function () { await store.dispatch(actions.unlockHardwareWalletAccount()) assert.fail('Should have thrown error') } catch (error) { - assert.deepEqual(store.getActions(), expectedActions) + assert.deepStrictEqual(store.getActions(), expectedActions) } }) }) describe('#setCurrentCurrency', function () { - let setCurrentCurrencySpy - afterEach(function () { - setCurrentCurrencySpy.restore() + sinon.restore() }) it('calls setCurrentCurrency', async function () { - setCurrentCurrencySpy = sinon - .stub(background, 'setCurrentCurrency') - .callsArgWith(1, null, {}) const store = mockStore() + const setCurrentCurrency = background.setCurrentCurrency.callsFake( + (_, cb) => + cb(null, { + currentCurrency: 'currency', + conversionRate: 100, + conversionDate: 1611839083653, + }), + ) + + actions._setBackgroundConnection(background) await store.dispatch(actions.setCurrentCurrency('jpy')) - assert(setCurrentCurrencySpy.calledOnce) + assert(setCurrentCurrency.calledOnce) }) it('throws if setCurrentCurrency throws', async function () { - setCurrentCurrencySpy = sinon - .stub(background, 'setCurrentCurrency') - .callsArgWith(1, new Error('error')) const store = mockStore() + + background.setCurrentCurrency.callsFake((_, cb) => cb(new Error('error'))) + + actions._setBackgroundConnection(background) + const expectedActions = [ { type: 'SHOW_LOADING_INDICATION', value: undefined }, { type: 'DISPLAY_WARNING', value: 'error' }, @@ -590,104 +659,96 @@ describe('Actions', function () { ] await store.dispatch(actions.setCurrentCurrency()) - assert.deepEqual(store.getActions(), expectedActions) + assert.deepStrictEqual(store.getActions(), expectedActions) }) }) describe('#signMsg', function () { - let signMessageSpy, metamaskMsgs, msgId, messages - const msgParams = { + metamaskId: 123, from: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', data: '0x879a053d4800c6354e76c7985a865d2922c82fb5b3f4577b2fe08b998954f2e0', } - beforeEach(function () { - metamaskController.newUnsignedMessage(msgParams, noop) - metamaskMsgs = metamaskController.messageManager.getUnapprovedMsgs() - messages = metamaskController.messageManager.messages - msgId = Object.keys(metamaskMsgs)[0] - messages[0].msgParams.metamaskId = parseInt(msgId, 10) - }) - afterEach(function () { - signMessageSpy.restore() + sinon.restore() }) it('calls signMsg in background', async function () { const store = mockStore() - signMessageSpy = sinon.spy(background, 'signMessage') + const signMessage = background.signMessage.callsFake((_, cb) => + cb(null, defaultState), + ) + + actions._setBackgroundConnection(background) + await store.dispatch(actions.signMsg(msgParams)) - assert(signMessageSpy.calledOnce) + assert(signMessage.calledOnce) }) it('errors when signMessage in background throws', async function () { const store = mockStore() + + background.signMessage.callsFake((_, cb) => cb(new Error('error'))) + + actions._setBackgroundConnection(background) + const expectedActions = [ { type: 'SHOW_LOADING_INDICATION', value: undefined }, { type: 'DISPLAY_WARNING', value: 'error' }, { type: 'HIDE_LOADING_INDICATION' }, ] - signMessageSpy = sinon.stub(background, 'signMessage') - signMessageSpy.callsFake((_, callback) => { - callback(new Error('error')) - }) - try { - await store.dispatch(actions.signMsg()) + await store.dispatch(actions.signMsg(msgParams)) assert.fail('Should have thrown error') } catch (_) { - assert.deepEqual(store.getActions(), expectedActions) + assert.deepStrictEqual(store.getActions(), expectedActions) } }) }) describe('#signPersonalMsg', function () { - let signPersonalMessageSpy, metamaskMsgs, msgId, personalMessages - const msgParams = { from: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', data: '0x879a053d4800c6354e76c7985a865d2922c82fb5b3f4577b2fe08b998954f2e0', } - beforeEach(function () { - metamaskController.newUnsignedPersonalMessage(msgParams, noop) - metamaskMsgs = metamaskController.personalMessageManager.getUnapprovedMsgs() - personalMessages = metamaskController.personalMessageManager.messages - msgId = Object.keys(metamaskMsgs)[0] - personalMessages[0].msgParams.metamaskId = parseInt(msgId, 10) - }) - afterEach(function () { - signPersonalMessageSpy.restore() + sinon.restore() }) it('calls signPersonalMessage', async function () { const store = mockStore() - signPersonalMessageSpy = sinon.spy(background, 'signPersonalMessage') + const signPersonalMessage = background.signPersonalMessage.callsFake( + (_, cb) => cb(null, defaultState), + ) + + actions._setBackgroundConnection(background) await store.dispatch(actions.signPersonalMsg(msgParams)) - assert(signPersonalMessageSpy.calledOnce) + assert(signPersonalMessage.calledOnce) }) it('throws if signPersonalMessage throws', async function () { const store = mockStore() + + background.signPersonalMessage.callsFake((_, cb) => { + cb(new Error('error')) + }) + + actions._setBackgroundConnection(background) + const expectedActions = [ { type: 'SHOW_LOADING_INDICATION', value: undefined }, { type: 'DISPLAY_WARNING', value: 'error' }, { type: 'HIDE_LOADING_INDICATION' }, ] - signPersonalMessageSpy = sinon.stub(background, 'signPersonalMessage') - signPersonalMessageSpy.callsFake((_, callback) => { - callback(new Error('error')) - }) - try { await store.dispatch(actions.signPersonalMsg(msgParams)) assert.fail('Should have thrown error') @@ -698,8 +759,6 @@ describe('Actions', function () { }) describe('#signTypedMsg', function () { - let signTypedMsgSpy, messages, typedMessages, msgId - const msgParamsV3 = { from: '0x0DCD5D886577d5081B0c52e242Ef29E70Be3E7bc', data: JSON.stringify({ @@ -740,33 +799,30 @@ describe('Actions', function () { }), } - beforeEach(function () { - metamaskController.newUnsignedTypedMessage(msgParamsV3, null, 'V3') - messages = metamaskController.typedMessageManager.getUnapprovedMsgs() - typedMessages = metamaskController.typedMessageManager.messages - msgId = Object.keys(messages)[0] - typedMessages[0].msgParams.metamaskId = parseInt(msgId, 10) - }) - afterEach(function () { - signTypedMsgSpy.restore() + sinon.restore() }) it('calls signTypedMsg in background with no error', async function () { - signTypedMsgSpy = sinon - .stub(background, 'signTypedMessage') - .callsArgWith(1, null, defaultState) const store = mockStore() + const signTypedMsg = background.signTypedMessage.callsFake((_, cb) => + cb(null, defaultState), + ) + + actions._setBackgroundConnection(background) + await store.dispatch(actions.signTypedMsg(msgParamsV3)) - assert(signTypedMsgSpy.calledOnce) + assert(signTypedMsg.calledOnce) }) it('returns expected actions with error', async function () { - signTypedMsgSpy = sinon - .stub(background, 'signTypedMessage') - .callsArgWith(1, new Error('error')) const store = mockStore() + + background.signTypedMessage.callsFake((_, cb) => cb(new Error('error'))) + + actions._setBackgroundConnection(background) + const expectedActions = [ { type: 'SHOW_LOADING_INDICATION', value: undefined }, { type: 'DISPLAY_WARNING', value: 'error' }, @@ -777,27 +833,27 @@ describe('Actions', function () { await store.dispatch(actions.signTypedMsg()) assert.fail('Should have thrown error') } catch (_) { - assert.deepEqual(store.getActions(), expectedActions) + assert.deepStrictEqual(store.getActions(), expectedActions) } }) }) describe('#signTx', function () { - let sendTransactionSpy + let sendTransaction beforeEach(function () { - sendTransactionSpy = sinon.stub(global.ethQuery, 'sendTransaction') + sendTransaction = sinon.stub(global.ethQuery, 'sendTransaction') }) afterEach(function () { - sendTransactionSpy.restore() + sendTransaction.restore() }) it('calls sendTransaction in global ethQuery', function () { const store = mockStore() store.dispatch(actions.signTx()) - assert(sendTransactionSpy.calledOnce) + assert(sendTransaction.calledOnce) }) it('errors in when sendTransaction throws', function () { @@ -806,12 +862,12 @@ describe('Actions', function () { { type: 'DISPLAY_WARNING', value: 'error' }, { type: 'SHOW_CONF_TX_PAGE', id: undefined }, ] - sendTransactionSpy.callsFake((_, callback) => { + sendTransaction.callsFake((_, callback) => { callback(new Error('error')) }) store.dispatch(actions.signTx()) - assert.deepEqual(store.getActions(), expectedActions) + assert.deepStrictEqual(store.getActions(), expectedActions) }) }) @@ -840,7 +896,7 @@ describe('Actions', function () { await store.dispatch(actions.updateGasData(mockData)) assert.fail('Should have thrown error') } catch (error) { - assert.deepEqual(store.getActions(), expectedActions) + assert.deepStrictEqual(store.getActions(), expectedActions) } }) @@ -867,7 +923,7 @@ describe('Actions', function () { ] await store.dispatch(actions.updateGasData(mockData)) - assert.deepEqual(store.getActions(), expectedActions) + assert.deepStrictEqual(store.getActions(), expectedActions) global.eth.getCode.reset() }) }) @@ -884,8 +940,6 @@ describe('Actions', function () { }) describe('#updateTransaction', function () { - let updateTransactionSpy - const txParams = { from: '0x1', gas: '0x5208', @@ -901,24 +955,32 @@ describe('Actions', function () { txParams, } - beforeEach(async function () { - await metamaskController.txController.txStateManager.addTx(txData) - }) - afterEach(function () { - updateTransactionSpy.restore() + sinon.restore() }) it('updates transaction', async function () { const store = mockStore() - updateTransactionSpy = sinon.spy(background, 'updateTransaction') + const updateTransactionStub = sinon.stub().callsFake((_, cb) => cb()) + + background.getApi.returns({ + updateTransaction: updateTransactionStub, + getState: sinon.stub().callsFake((cb) => + cb(null, { + currentLocale: 'test', + selectedAddress: '0xFirstAddress', + }), + ), + }) + + actions._setBackgroundConnection(background.getApi()) await store.dispatch(actions.updateTransaction(txData)) const resultantActions = store.getActions() - assert.ok(updateTransactionSpy.calledOnce) - assert.deepEqual(resultantActions[1], { + assert(updateTransactionStub.calledOnce) + assert.deepStrictEqual(resultantActions[1], { type: 'UPDATE_TRANSACTION_PARAMS', id: txData.id, value: txParams, @@ -928,72 +990,86 @@ describe('Actions', function () { it('rejects with error message', async function () { const store = mockStore() - updateTransactionSpy = sinon.stub(background, 'updateTransaction') - updateTransactionSpy.callsFake((_, callback) => { - callback(new Error('error')) + background.getApi.returns({ + updateTransaction: (_, callback) => { + callback(new Error('error')) + }, + getState: sinon.stub().callsFake((cb) => + cb(null, { + currentLocale: 'test', + selectedAddress: '0xFirstAddress', + }), + ), }) + actions._setBackgroundConnection(background.getApi()) + try { await store.dispatch(actions.updateTransaction(txData)) assert.fail('Should have thrown error') } catch (error) { - assert.equal(error.message, 'error') + assert.strictEqual(error.message, 'error') } }) }) describe('#lockMetamask', function () { - let backgroundSetLockedSpy - afterEach(function () { - backgroundSetLockedSpy.restore() + sinon.restore() }) it('calls setLocked', async function () { const store = mockStore() - backgroundSetLockedSpy = sinon.spy(background, 'setLocked') + const backgroundSetLocked = background.setLocked.callsFake((cb) => cb()) + + actions._setBackgroundConnection(background) await store.dispatch(actions.lockMetamask()) - assert(backgroundSetLockedSpy.calledOnce) + assert(backgroundSetLocked.calledOnce) }) it('returns display warning error with value when setLocked in background callback errors', async function () { const store = mockStore() + background.setLocked.callsFake((cb) => { + cb(new Error('error')) + }) + + actions._setBackgroundConnection(background) + const expectedActions = [ { type: 'SHOW_LOADING_INDICATION', value: undefined }, { type: 'DISPLAY_WARNING', value: 'error' }, { type: 'HIDE_LOADING_INDICATION' }, { type: 'LOCK_METAMASK' }, ] - backgroundSetLockedSpy = sinon.stub(background, 'setLocked') - backgroundSetLockedSpy.callsFake((callback) => { - callback(new Error('error')) - }) try { await store.dispatch(actions.lockMetamask()) assert.fail('Should have thrown error') } catch (error) { - assert.deepEqual(store.getActions(), expectedActions) + assert.deepStrictEqual(store.getActions(), expectedActions) } }) }) describe('#setSelectedAddress', function () { - let setSelectedAddressSpy - afterEach(function () { - setSelectedAddressSpy.restore() + sinon.restore() }) it('calls setSelectedAddress in background', async function () { - setSelectedAddressSpy = sinon - .stub(background, 'setSelectedAddress') - .callsArgWith(1, null) const store = mockStore() + const setSelectedAddressSpy = sinon.stub().callsFake((_, cb) => cb()) + + background.getApi.returns({ + setSelectedAddress: setSelectedAddressSpy, + }) + + actions._setBackgroundConnection(background.getApi()) + await store.dispatch( actions.setSelectedAddress( '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', @@ -1003,10 +1079,18 @@ describe('Actions', function () { }) it('errors when setSelectedAddress throws', async function () { - setSelectedAddressSpy = sinon - .stub(background, 'setSelectedAddress') - .callsArgWith(1, new Error('error')) const store = mockStore() + + const setSelectedAddressSpy = sinon + .stub() + .callsFake((_, cb) => cb(new Error('error'))) + + background.getApi.returns({ + setSelectedAddress: setSelectedAddressSpy, + }) + + actions._setBackgroundConnection(background.getApi()) + const expectedActions = [ { type: 'SHOW_LOADING_INDICATION', value: undefined }, { type: 'DISPLAY_WARNING', value: 'error' }, @@ -1014,38 +1098,49 @@ describe('Actions', function () { ] await store.dispatch(actions.setSelectedAddress()) - assert.deepEqual(store.getActions(), expectedActions) + assert.deepStrictEqual(store.getActions(), expectedActions) }) }) describe('#showAccountDetail', function () { - let setSelectedAddressSpy - afterEach(function () { - setSelectedAddressSpy.restore() + sinon.restore() }) it('#showAccountDetail', async function () { - setSelectedAddressSpy = sinon - .stub(background, 'setSelectedAddress') - .callsArgWith(1, null) const store = mockStore({ activeTab: {}, metamask: { alertEnabledness: {}, selectedAddress: '0x123' }, }) + const setSelectedAddressSpy = sinon.stub().callsFake((_, cb) => cb()) + + background.getApi.returns({ + setSelectedAddress: setSelectedAddressSpy, + }) + + actions._setBackgroundConnection(background.getApi()) + await store.dispatch(actions.showAccountDetail()) assert(setSelectedAddressSpy.calledOnce) }) it('displays warning if setSelectedAddress throws', async function () { - setSelectedAddressSpy = sinon - .stub(background, 'setSelectedAddress') - .callsArgWith(1, new Error('error')) const store = mockStore({ activeTab: {}, metamask: { alertEnabledness: {}, selectedAddress: '0x123' }, }) + + const setSelectedAddressSpy = sinon + .stub() + .callsFake((_, cb) => cb(new Error('error'))) + + background.getApi.returns({ + setSelectedAddress: setSelectedAddressSpy, + }) + + actions._setBackgroundConnection(background.getApi()) + const expectedActions = [ { type: 'SHOW_LOADING_INDICATION', value: undefined }, { type: 'DISPLAY_WARNING', value: 'error' }, @@ -1053,30 +1148,78 @@ describe('Actions', function () { ] await store.dispatch(actions.showAccountDetail()) - assert.deepEqual(store.getActions(), expectedActions) + assert.deepStrictEqual(store.getActions(), expectedActions) }) }) describe('#addToken', function () { - let addTokenSpy - afterEach(function () { - addTokenSpy.restore() + sinon.restore() }) it('calls addToken in background', async function () { - addTokenSpy = sinon.stub(background, 'addToken').callsArgWith(4, null) const store = mockStore() + const addTokenStub = sinon + .stub() + .callsFake((_, __, ___, ____, cb) => cb()) + + background.getApi.returns({ + addToken: addTokenStub, + }) + + actions._setBackgroundConnection(background.getApi()) + + await store.dispatch(actions.addToken()) + assert(addTokenStub.calledOnce) + }) + + it('expected actions', async function () { + const store = mockStore() + + const tokenDetails = { + address: 'tokenAddress', + symbol: 'token', + decimal: 18, + } + + const addTokenStub = sinon + .stub() + .callsFake((_, __, ___, ____, cb) => cb(null, tokenDetails)) + + background.getApi.returns({ + addToken: addTokenStub, + }) + + actions._setBackgroundConnection(background.getApi()) + + const expectedActions = [ + { type: 'SHOW_LOADING_INDICATION', value: undefined }, + { type: 'HIDE_LOADING_INDICATION' }, + { + type: 'UPDATE_TOKENS', + newTokens: tokenDetails, + }, + ] + await store.dispatch(actions.addToken()) - assert(addTokenSpy.calledOnce) + + assert.deepStrictEqual(store.getActions(), expectedActions) }) it('errors when addToken in background throws', async function () { - addTokenSpy = sinon - .stub(background, 'addToken') - .callsArgWith(4, new Error('error')) const store = mockStore() + + const addTokenStub = sinon + .stub() + .callsFake((_, __, ___, ____, cb) => cb(new Error('error'))) + + background.getApi.returns({ + addToken: addTokenStub, + }) + + actions._setBackgroundConnection(background.getApi()) + const expectedActions = [ { type: 'SHOW_LOADING_INDICATION', value: undefined }, { type: 'HIDE_LOADING_INDICATION' }, @@ -1093,26 +1236,34 @@ describe('Actions', function () { }) describe('#removeToken', function () { - let removeTokenSpy - afterEach(function () { - removeTokenSpy.restore() + sinon.restore() }) it('calls removeToken in background', async function () { - removeTokenSpy = sinon - .stub(background, 'removeToken') - .callsArgWith(1, null) const store = mockStore() + + const removeTokenStub = sinon.stub().callsFake((_, cb) => cb()) + + background.getApi.returns({ + removeToken: removeTokenStub, + }) + + actions._setBackgroundConnection(background.getApi()) + await store.dispatch(actions.removeToken()) - assert(removeTokenSpy.calledOnce) + assert(removeTokenStub.calledOnce) }) it('errors when removeToken in background fails', async function () { - removeTokenSpy = sinon - .stub(background, 'removeToken') - .callsArgWith(1, new Error('error')) const store = mockStore() + + background.getApi.returns({ + removeToken: sinon.stub().callsFake((_, cb) => cb(new Error('error'))), + }) + + actions._setBackgroundConnection(background.getApi()) + const expectedActions = [ { type: 'SHOW_LOADING_INDICATION', value: undefined }, { type: 'HIDE_LOADING_INDICATION' }, @@ -1123,149 +1274,190 @@ describe('Actions', function () { await store.dispatch(actions.removeToken()) assert.fail('Should have thrown error') } catch (_) { - assert.deepEqual(store.getActions(), expectedActions) + assert.deepStrictEqual(store.getActions(), expectedActions) } }) }) describe('#setProviderType', function () { - let setProviderTypeSpy - let store - - beforeEach(function () { - store = mockStore({ metamask: { provider: {} } }) - }) - afterEach(function () { - setProviderTypeSpy.restore() + sinon.restore() }) it('calls setProviderType', async function () { - setProviderTypeSpy = sinon - .stub(background, 'setProviderType') - .callsArgWith(1, null) + const store = mockStore() + + const setProviderTypeStub = sinon.stub().callsFake((_, cb) => cb()) + + background.getApi.returns({ + setProviderType: setProviderTypeStub, + }) + + actions._setBackgroundConnection(background.getApi()) + await store.dispatch(actions.setProviderType()) - assert(setProviderTypeSpy.calledOnce) + assert(setProviderTypeStub.calledOnce) }) it('displays warning when setProviderType throws', async function () { - setProviderTypeSpy = sinon - .stub(background, 'setProviderType') - .callsArgWith(1, new Error('error')) + const store = mockStore() + + background.getApi.returns({ + setProviderType: sinon + .stub() + .callsFake((_, cb) => cb(new Error('error'))), + }) + + actions._setBackgroundConnection(background.getApi()) + const expectedActions = [ { type: 'DISPLAY_WARNING', value: 'Had a problem changing networks!' }, ] await store.dispatch(actions.setProviderType()) - assert(setProviderTypeSpy.calledOnce) - assert.deepEqual(store.getActions(), expectedActions) + assert.deepStrictEqual(store.getActions(), expectedActions) }) }) describe('#setRpcTarget', function () { - let setRpcTargetSpy - afterEach(function () { - setRpcTargetSpy.restore() + sinon.restore() }) it('calls setRpcTarget', async function () { - setRpcTargetSpy = sinon - .stub(background, 'setCustomRpc') - .callsArgWith(4, null) const store = mockStore() + + background.setCustomRpc.callsFake((_, __, ___, ____, cb) => cb()) + + actions._setBackgroundConnection(background) + await store.dispatch(actions.setRpcTarget('http://localhost:8545')) - assert(setRpcTargetSpy.calledOnce) + assert(background.setCustomRpc.calledOnce) }) it('displays warning when setRpcTarget throws', async function () { - setRpcTargetSpy = sinon - .stub(background, 'setCustomRpc') - .callsArgWith(4, new Error('error')) const store = mockStore() + + background.setCustomRpc.callsFake((_, __, ___, ____, cb) => + cb(new Error('error')), + ) + + actions._setBackgroundConnection(background) + const expectedActions = [ { type: 'DISPLAY_WARNING', value: 'Had a problem changing networks!' }, ] await store.dispatch(actions.setRpcTarget()) - assert.deepEqual(store.getActions(), expectedActions) + assert.deepStrictEqual(store.getActions(), expectedActions) }) }) describe('#addToAddressBook', function () { it('calls setAddressBook', async function () { - const addToAddressBookSpy = sinon - .stub(background, 'setAddressBook') - .callsArgWith(4, null, true) const store = mockStore() + + const setAddressBookStub = sinon + .stub() + .callsFake((_, __, ___, ____, cb) => cb()) + + background.getApi.returns({ + setAddressBook: setAddressBookStub, + }) + + actions._setBackgroundConnection(background.getApi()) + await store.dispatch(actions.addToAddressBook('test')) - assert(addToAddressBookSpy.calledOnce) - addToAddressBookSpy.restore() + assert(setAddressBookStub.calledOnce) + sinon.restore() }) }) describe('#exportAccount', function () { - let verifyPasswordSpy, exportAccountSpy - afterEach(function () { - verifyPasswordSpy.restore() - exportAccountSpy.restore() + sinon.restore() }) it('returns expected actions for successful action', async function () { const store = mockStore() + + const testPrivKey = 'a-test-priv-key' + + const verifyPasswordStub = sinon.stub().callsFake((_, cb) => cb()) + + const exportAccountStub = sinon + .stub() + .callsFake((_, cb) => cb(null, testPrivKey)) + + background.getApi.returns({ + verifyPassword: verifyPasswordStub, + exportAccount: exportAccountStub, + }) + + actions._setBackgroundConnection(background.getApi()) + const expectedActions = [ { type: 'SHOW_LOADING_INDICATION', value: undefined }, { type: 'HIDE_LOADING_INDICATION' }, { type: 'SHOW_PRIVATE_KEY', - value: - '7ec73b91bb20f209a7ff2d32f542c3420b4fccf14abcc7840d2eff0ebcb18505', + value: testPrivKey, }, ] - verifyPasswordSpy = sinon.spy(background, 'verifyPassword') - exportAccountSpy = sinon.spy(background, 'exportAccount') - await store.dispatch( - actions.exportAccount( - password, - '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', - ), + actions.exportAccount('a-test-password', '0xAddress'), ) - assert(verifyPasswordSpy.calledOnce) - assert(exportAccountSpy.calledOnce) - assert.deepEqual(store.getActions(), expectedActions) + assert(verifyPasswordStub.calledOnce) + assert(exportAccountStub.calledOnce) + assert.deepStrictEqual(store.getActions(), expectedActions) }) it('returns action errors when first func callback errors', async function () { const store = mockStore() + + const verifyPasswordStub = sinon + .stub() + .callsFake((_, cb) => cb(new Error('error'))) + + background.getApi.returns({ + verifyPassword: verifyPasswordStub, + }) + + actions._setBackgroundConnection(background.getApi()) + const expectedActions = [ { type: 'SHOW_LOADING_INDICATION', value: undefined }, { type: 'HIDE_LOADING_INDICATION' }, { type: 'DISPLAY_WARNING', value: 'Incorrect Password.' }, ] - verifyPasswordSpy = sinon.stub(background, 'verifyPassword') - verifyPasswordSpy.callsFake((_, callback) => { - callback(new Error('error')) - }) - try { await store.dispatch( - actions.exportAccount( - password, - '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', - ), + actions.exportAccount('a-test-password', '0xAddress'), ) assert.fail('Should have thrown error') } catch (_) { - assert.deepEqual(store.getActions(), expectedActions) + assert.deepStrictEqual(store.getActions(), expectedActions) } }) it('returns action errors when second func callback errors', async function () { const store = mockStore() + + const verifyPasswordStub = sinon.stub().callsFake((_, cb) => cb()) + + const exportAccountStub = sinon + .stub() + .callsFake((_, cb) => cb(new Error('error'))) + + background.getApi.returns({ + verifyPassword: verifyPasswordStub, + exportAccount: exportAccountStub, + }) + + actions._setBackgroundConnection(background.getApi()) + const expectedActions = [ { type: 'SHOW_LOADING_INDICATION', value: undefined }, { type: 'HIDE_LOADING_INDICATION' }, @@ -1275,63 +1467,104 @@ describe('Actions', function () { }, ] - exportAccountSpy = sinon.stub(background, 'exportAccount') - exportAccountSpy.callsFake((_, callback) => { - callback(new Error('error')) - }) - try { await store.dispatch( - actions.exportAccount( - password, - '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', - ), + actions.exportAccount('a-test-password', '0xAddress'), ) assert.fail('Should have thrown error') } catch (_) { - assert.deepEqual(store.getActions(), expectedActions) + assert.deepStrictEqual(store.getActions(), expectedActions) } }) }) describe('#setAccountLabel', function () { + afterEach(function () { + sinon.restore() + }) + it('calls setAccountLabel', async function () { - const setAccountLabelSpy = sinon - .stub(background, 'setAccountLabel') - .callsArgWith(2, null) const store = mockStore() + + const setAccountLabelStub = sinon.stub().callsFake((_, __, cb) => cb()) + + background.getApi.returns({ + setAccountLabel: setAccountLabelStub, + }) + + actions._setBackgroundConnection(background.getApi()) + await store.dispatch( actions.setAccountLabel( '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', 'test', ), ) - assert(setAccountLabelSpy.calledOnce) + assert(setAccountLabelStub.calledOnce) + }) + + it('returns action errors when func callback errors', async function () { + const store = mockStore() + + background.getApi.returns({ + setAccountLabel: sinon + .stub() + .callsFake((_, __, cb) => cb(new Error('error'))), + }) + + actions._setBackgroundConnection(background.getApi()) + + const expectedActions = [ + { type: 'SHOW_LOADING_INDICATION', value: undefined }, + { type: 'HIDE_LOADING_INDICATION' }, + { type: 'DISPLAY_WARNING', value: 'error' }, + ] + + try { + await store.dispatch( + actions.setAccountLabel( + '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + 'test', + ), + ) + assert.fail('Should have thrown error') + } catch (error) { + assert.deepStrictEqual(store.getActions(), expectedActions) + } }) }) describe('#setFeatureFlag', function () { - let setFeatureFlagSpy - afterEach(function () { - setFeatureFlagSpy.restore() + sinon.restore() }) it('calls setFeatureFlag in the background', async function () { - setFeatureFlagSpy = sinon - .stub(background, 'setFeatureFlag') - .callsArgWith(2, null) const store = mockStore() + const setFeatureFlagStub = sinon.stub().callsFake((_, __, cb) => cb()) + + background.getApi.returns({ + setFeatureFlag: setFeatureFlagStub, + }) + + actions._setBackgroundConnection(background.getApi()) + await store.dispatch(actions.setFeatureFlag()) - assert(setFeatureFlagSpy.calledOnce) + assert(setFeatureFlagStub.calledOnce) }) it('errors when setFeatureFlag in background throws', async function () { - setFeatureFlagSpy = sinon - .stub(background, 'setFeatureFlag') - .callsArgWith(2, new Error('error')) const store = mockStore() + + background.getApi.returns({ + setFeatureFlag: sinon + .stub() + .callsFake((_, __, cb) => cb(new Error('error'))), + }) + + actions._setBackgroundConnection(background.getApi()) + const expectedActions = [ { type: 'SHOW_LOADING_INDICATION', value: undefined }, { type: 'HIDE_LOADING_INDICATION' }, @@ -1342,42 +1575,81 @@ describe('Actions', function () { await store.dispatch(actions.setFeatureFlag()) assert.fail('Should have thrown error') } catch (_) { - assert.deepEqual(store.getActions(), expectedActions) + assert.deepStrictEqual(store.getActions(), expectedActions) } }) }) describe('#setCompletedOnboarding', function () { + afterEach(function () { + sinon.restore() + }) + it('completes onboarding', async function () { - const completeOnboardingSpy = sinon.stub(background, 'completeOnboarding') - completeOnboardingSpy.callsFake((cb) => cb()) const store = mockStore() + const completeOnboardingStub = sinon.stub().callsFake((cb) => cb()) + + background.getApi.returns({ + completeOnboarding: completeOnboardingStub, + }) + + actions._setBackgroundConnection(background.getApi()) + await store.dispatch(actions.setCompletedOnboarding()) - assert.equal(completeOnboardingSpy.callCount, 1) - completeOnboardingSpy.restore() + assert(completeOnboardingStub.calledOnce) }) - }) - describe('#setUseBlockie', function () { - let setUseBlockieSpy + it('errors when setCompletedOnboarding in background throws', async function () { + const store = mockStore() - beforeEach(function () { - setUseBlockieSpy = sinon.stub(background, 'setUseBlockie') + background.getApi.returns({ + completeOnboarding: sinon + .stub() + .callsFake((cb) => cb(new Error('error'))), + }) + + actions._setBackgroundConnection(background.getApi()) + + const expectedActions = [ + { type: 'SHOW_LOADING_INDICATION', value: undefined }, + { type: 'DISPLAY_WARNING', value: 'error' }, + { type: 'HIDE_LOADING_INDICATION' }, + ] + + try { + await store.dispatch(actions.setCompletedOnboarding()) + assert.fail('Should have thrown error') + } catch (_) { + assert.deepStrictEqual(store.getActions(), expectedActions) + } }) + }) + describe('#setUseBlockie', function () { afterEach(function () { - setUseBlockieSpy.restore() + sinon.restore() }) - it('calls setUseBlockie in background', function () { + it('calls setUseBlockie in background', async function () { const store = mockStore() - store.dispatch(actions.setUseBlockie()) - assert(setUseBlockieSpy.calledOnce) + const setUseBlockStub = background.setUseBlockie.callsFake((_, cb) => + cb(), + ) + + actions._setBackgroundConnection(background) + + await store.dispatch(actions.setUseBlockie()) + assert(setUseBlockStub.calledOnce) }) - it('errors when setUseBlockie in background throws', function () { + it('errors when setUseBlockie in background throws', async function () { const store = mockStore() + + background.setUseBlockie.callsFake((_, cb) => cb(new Error('error'))) + + actions._setBackgroundConnection(background) + const expectedActions = [ { type: 'SHOW_LOADING_INDICATION', value: undefined }, { type: 'HIDE_LOADING_INDICATION' }, @@ -1385,18 +1657,12 @@ describe('Actions', function () { { type: 'SET_USE_BLOCKIE', value: undefined }, ] - setUseBlockieSpy.callsFake((_, callback) => { - callback(new Error('error')) - }) - - store.dispatch(actions.setUseBlockie()) - assert.deepEqual(store.getActions(), expectedActions) + await store.dispatch(actions.setUseBlockie()) + assert.deepStrictEqual(store.getActions(), expectedActions) }) }) describe('#updateCurrentLocale', function () { - let setCurrentLocaleSpy - beforeEach(function () { sinon.stub(window, 'fetch').resolves({ json: async () => enLocale, @@ -1404,84 +1670,118 @@ describe('Actions', function () { }) afterEach(function () { - setCurrentLocaleSpy.restore() - window.fetch.restore() + sinon.restore() }) it('calls expected actions', async function () { const store = mockStore() - setCurrentLocaleSpy = sinon.spy(background, 'setCurrentLocale') + + background.setCurrentLocale.callsFake((_, cb) => cb()) + + actions._setBackgroundConnection(background) const expectedActions = [ { type: 'SHOW_LOADING_INDICATION', value: undefined }, { type: 'SET_CURRENT_LOCALE', - value: { locale: 'en', messages: enLocale }, + value: { locale: 'test', messages: enLocale }, }, { type: 'HIDE_LOADING_INDICATION' }, ] - await store.dispatch(actions.updateCurrentLocale('en')) - assert(setCurrentLocaleSpy.calledOnce) - assert.deepEqual(store.getActions(), expectedActions) + await store.dispatch(actions.updateCurrentLocale('test')) + assert(background.setCurrentLocale.calledOnce) + assert.deepStrictEqual(store.getActions(), expectedActions) }) it('errors when setCurrentLocale throws', async function () { const store = mockStore() + + background.setCurrentLocale.callsFake((_, cb) => cb(new Error('error'))) + + actions._setBackgroundConnection(background) + const expectedActions = [ { type: 'SHOW_LOADING_INDICATION', value: undefined }, { type: 'DISPLAY_WARNING', value: 'error' }, { type: 'HIDE_LOADING_INDICATION' }, ] - setCurrentLocaleSpy = sinon.stub(background, 'setCurrentLocale') - setCurrentLocaleSpy.callsFake((_, callback) => { - callback(new Error('error')) - }) try { - await store.dispatch(actions.updateCurrentLocale('en')) + await store.dispatch(actions.updateCurrentLocale('test')) assert.fail('Should have thrown error') } catch (_) { - assert.deepEqual(store.getActions(), expectedActions) + assert.deepStrictEqual(store.getActions(), expectedActions) } }) }) describe('#markPasswordForgotten', function () { + afterEach(function () { + sinon.restore() + }) + it('calls markPasswordForgotten', async function () { const store = mockStore() - const markPasswordForgottenSpy = sinon - .stub(background, 'markPasswordForgotten') - .callsArg(0) + + background.markPasswordForgotten.callsFake((cb) => cb()) + + actions._setBackgroundConnection(background) await store.dispatch(actions.markPasswordForgotten()) const resultantActions = store.getActions() - assert.deepEqual(resultantActions[1], { + assert.deepStrictEqual(resultantActions[1], { type: 'FORGOT_PASSWORD', value: true, }) - assert.ok(markPasswordForgottenSpy.calledOnce) - markPasswordForgottenSpy.restore() + assert(background.markPasswordForgotten.calledOnce) + }) + + it('errors when markPasswordForgotten throws', async function () { + const store = mockStore() + + background.markPasswordForgotten.callsFake((cb) => cb(new Error('error'))) + + actions._setBackgroundConnection(background) + + const expectedActions = [ + { type: 'HIDE_LOADING_INDICATION' }, + { type: 'FORGOT_PASSWORD', value: true }, + { + type: 'UPDATE_METAMASK_STATE', + value: { + currentLocale: 'test', + selectedAddress: '0xFirstAddress', + }, + }, + ] + + try { + await store.dispatch(actions.markPasswordForgotten('test')) + assert.fail('Should have thrown error') + } catch (_) { + assert.deepStrictEqual(store.getActions(), expectedActions) + } }) }) describe('#unMarkPasswordForgotten', function () { it('calls unMarkPasswordForgotten', async function () { const store = mockStore() - const unMarkPasswordForgottenSpy = sinon - .stub(background, 'unMarkPasswordForgotten') - .callsArg(0) + + background.unMarkPasswordForgotten.callsFake((cb) => cb()) + + actions._setBackgroundConnection(background) await store.dispatch(actions.unMarkPasswordForgotten()) const resultantActions = store.getActions() - assert.deepEqual(resultantActions[0], { + assert.deepStrictEqual(resultantActions[0], { type: 'FORGOT_PASSWORD', value: false, }) - assert.ok(unMarkPasswordForgottenSpy.calledOnce) - unMarkPasswordForgottenSpy.restore() + assert(background.unMarkPasswordForgotten.calledOnce) }) }) })