1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-03 22:54:29 +01:00
metamask-extension/test/unit/ui/app/actions.spec.js
Mark Stacey 5363d6aa2a
Prevent multiple warnings for the same locale message (#7091)
* Prevent multiple warnings for the same locale message

Our i18n helper issues warnings whenever a requested message is
missing. These warnings are helpful in assisting translation efforts,
but they can be distracting otherwise. They're especially problematic
for locales that are missing many messages. My browser ended up
crashing on more than one occasion due to the sheer volume of warnings.

The warning has been updated to only be issued once per missing key.
This required updating the method to pass in the current locale. The
current locale was added to the warning itself as well, which could be
helpful for cases where a message is missing in both the current locale
and the fallback ('en').

* Change locale and localeMessages as single action

Updating the current locale and the locale messages resulted in two
renders, and during the first the state was inconsistent (it would say
the locale had changed to the new one, but still be using the old set
of locale messages). Instead the locale is now updated with one atomic
action.

This was required after adding the locale to the missing locale message
warning, as otherwise it would say the message was missing from the
wrong locale.
2019-09-06 10:47:07 -03:00

1226 lines
35 KiB
JavaScript

// Used to inspect long objects
// util.inspect({JSON}, false, null))
// const util = require('util')
const assert = require('assert')
const sinon = require('sinon')
const clone = require('clone')
const nock = require('nock')
const fetchMock = require('fetch-mock')
const configureStore = require('redux-mock-store').default
const thunk = require('redux-thunk').default
const EthQuery = require('eth-query')
const Eth = require('ethjs')
const KeyringController = require('eth-keyring-controller')
const { createTestProviderTools } = require('../../../stub/provider')
const provider = createTestProviderTools({ scaffold: {}}).provider
const enLocale = require('../../../../app/_locales/en/messages.json')
const actions = require('../../../../ui/app/store/actions')
const MetaMaskController = require('../../../../app/scripts/metamask-controller')
const firstTimeState = require('../../../unit/localhostState')
const devState = require('../../../data/2-state.json')
const middleware = [thunk]
const mockStore = configureStore(middleware)
describe('Actions', () => {
const noop = () => {}
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 () => {
metamaskController = new MetaMaskController({
provider,
keyringController: new KeyringController({}),
showUnapprovedTx: noop,
showUnconfirmedMessage: noop,
encryptor: {
encrypt: function (_, object) {
this.object = object
return Promise.resolve('mock-encrypted')
},
decrypt: function () {
return Promise.resolve(this.object)
},
},
initState: clone(firstTimeState),
})
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', () => {
let submitPasswordSpy, verifySeedPhraseSpy
afterEach(() => {
submitPasswordSpy.restore()
verifySeedPhraseSpy.restore()
})
it('calls submitPassword and verifySeedPhrase', async () => {
const store = mockStore({})
submitPasswordSpy = sinon.spy(background, 'submitPassword')
verifySeedPhraseSpy = sinon.spy(background, 'verifySeedPhrase')
return store.dispatch(actions.tryUnlockMetamask())
.then(() => {
assert(submitPasswordSpy.calledOnce)
assert(verifySeedPhraseSpy.calledOnce)
})
})
it('errors on submitPassword will fail', async () => {
const store = mockStore({})
const expectedActions = [
{ type: 'SHOW_LOADING_INDICATION', value: undefined },
{ type: 'UNLOCK_IN_PROGRESS' },
{ type: 'UNLOCK_FAILED', value: 'error in submitPassword' },
{ 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)
}
})
it('displays warning error and unlock failed when verifySeed fails', async () => {
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'))
})
try {
await store.dispatch(actions.tryUnlockMetamask('test'))
assert.fail('Should have thrown error')
} catch (_) {
const actions = store.getActions()
const warning = actions.filter(action => action.type === 'DISPLAY_WARNING')
const unlockFailed = actions.filter(action => action.type === 'UNLOCK_FAILED')
assert.deepEqual(warning, displayWarningError)
assert.deepEqual(unlockFailed, unlockFailedError)
}
})
})
describe('#createNewVaultAndRestore', () => {
let createNewVaultAndRestoreSpy
afterEach(() => {
createNewVaultAndRestoreSpy.restore()
})
it('restores new vault', async () => {
const store = mockStore({})
createNewVaultAndRestoreSpy = sinon.spy(background, 'createNewVaultAndRestore')
try {
await store.dispatch(actions.createNewVaultAndRestore())
assert.fail('Should have thrown error')
} catch (_) {
assert(createNewVaultAndRestoreSpy.calledOnce)
}
})
it('errors when callback in createNewVaultAndRestore throws', async () => {
const store = mockStore({})
const expectedActions = [
{ type: 'SHOW_LOADING_INDICATION', value: undefined },
{ type: 'DISPLAY_WARNING', value: 'error' },
{ type: 'HIDE_LOADING_INDICATION' },
]
createNewVaultAndRestoreSpy = sinon.stub(background, 'createNewVaultAndRestore')
createNewVaultAndRestoreSpy.callsFake((_, __, callback) => {
callback(new Error('error'))
})
try {
await store.dispatch(actions.createNewVaultAndRestore())
assert.fail('Should have thrown error')
} catch (_) {
assert.deepEqual(store.getActions(), expectedActions)
}
})
})
describe('#requestRevealSeedWords', () => {
let submitPasswordSpy
it('calls submitPassword in background', () => {
const store = mockStore()
submitPasswordSpy = sinon.spy(background, 'verifySeedPhrase')
return store.dispatch(actions.requestRevealSeedWords())
.then(() => {
assert(submitPasswordSpy.calledOnce)
})
})
it('displays warning error message then callback in background errors', async () => {
const store = mockStore()
const expectedActions = [
{ type: 'SHOW_LOADING_INDICATION', value: undefined },
{ type: 'HIDE_LOADING_INDICATION' },
{ type: 'DISPLAY_WARNING', value: 'error' },
]
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)
}
})
})
describe('#removeAccount', () => {
let removeAccountSpy
afterEach(() => {
removeAccountSpy.restore()
})
it('calls removeAccount in background and expect actions to show account', () => {
const store = mockStore(devState)
const expectedActions = [
{ type: 'SHOW_LOADING_INDICATION', value: undefined },
{ type: 'HIDE_LOADING_INDICATION' },
{ type: 'SHOW_ACCOUNTS_PAGE' },
]
removeAccountSpy = sinon.spy(background, 'removeAccount')
return store.dispatch(actions.removeAccount('0xe18035bf8712672935fdb4e5e431b1a0183d2dfc'))
.then(() => {
assert(removeAccountSpy.calledOnce)
assert.deepEqual(store.getActions(), expectedActions)
})
})
it('displays warning error message when removeAccount callback errors', async () => {
const store = mockStore()
const expectedActions = [
{ type: 'SHOW_LOADING_INDICATION', value: undefined },
{ type: 'HIDE_LOADING_INDICATION' },
{ type: 'DISPLAY_WARNING', value: 'error' },
]
removeAccountSpy = sinon.stub(background, 'removeAccount')
removeAccountSpy.callsFake((_, callback) => {
callback(new Error('error'))
})
try {
await store.dispatch(actions.removeAccount('0xe18035bf8712672935fdb4e5e431b1a0183d2dfc'))
assert.fail('Should have thrown error')
} catch (_) {
assert.deepEqual(store.getActions(), expectedActions)
}
})
})
describe('#addNewKeyring', () => {
let addNewKeyringSpy
beforeEach(() => {
addNewKeyringSpy = sinon.stub(background, 'addNewKeyring')
})
afterEach(() => {
addNewKeyringSpy.restore()
})
it('calls addNewKeyring', () => {
const privateKey = 'c87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3'
const store = mockStore()
store.dispatch(actions.addNewKeyring('Simple Key Pair', [ privateKey ]))
assert(addNewKeyringSpy.calledOnce)
})
it('errors then addNewKeyring in background throws', () => {
const store = mockStore()
const expectedActions = [
{ type: 'SHOW_LOADING_INDICATION', value: undefined },
{ type: 'HIDE_LOADING_INDICATION' },
{ type: 'DISPLAY_WARNING', value: 'error' },
]
addNewKeyringSpy.callsFake((_, __, callback) => {
callback(new Error('error'))
})
store.dispatch(actions.addNewKeyring())
assert.deepEqual(store.getActions(), expectedActions)
})
})
describe('#resetAccount', () => {
let resetAccountSpy
afterEach(() => {
resetAccountSpy.restore()
})
it('resets account', async () => {
const store = mockStore()
const expectedActions = [
{ type: 'SHOW_LOADING_INDICATION', value: undefined },
{ type: 'HIDE_LOADING_INDICATION' },
{ type: 'SHOW_ACCOUNTS_PAGE' },
]
resetAccountSpy = sinon.spy(background, 'resetAccount')
return store.dispatch(actions.resetAccount())
.then(() => {
assert(resetAccountSpy.calledOnce)
assert.deepEqual(store.getActions(), expectedActions)
})
})
it('throws if resetAccount throws', async () => {
const store = mockStore()
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)
}
})
})
describe('#importNewAccount', () => {
let importAccountWithStrategySpy
afterEach(() => {
importAccountWithStrategySpy.restore()
})
it('calls importAccountWithStrategies in background', () => {
const store = mockStore()
importAccountWithStrategySpy = sinon.spy(background, 'importAccountWithStrategy')
const importPrivkey = 'c87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3'
return store.dispatch(actions.importNewAccount('Private Key', [ importPrivkey ]))
.then(() => {
assert(importAccountWithStrategySpy.calledOnce)
})
})
it('displays warning error message when importAccount in background callback errors', async () => {
const store = mockStore()
const expectedActions = [
{ type: 'SHOW_LOADING_INDICATION', value: 'This may take a while, please be patient.' },
{ type: 'HIDE_LOADING_INDICATION' },
{ type: 'DISPLAY_WARNING', value: 'error' },
]
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)
}
})
})
describe('#addNewAccount', () => {
let addNewAccountSpy
afterEach(() => {
addNewAccountSpy.restore()
})
it('Adds a new account', () => {
const store = mockStore({ metamask: devState })
addNewAccountSpy = sinon.spy(background, 'addNewAccount')
return store.dispatch(actions.addNewAccount())
.then(() => {
assert(addNewAccountSpy.calledOnce)
})
})
})
describe('#setCurrentCurrency', () => {
let setCurrentCurrencySpy
beforeEach(() => {
setCurrentCurrencySpy = sinon.stub(background, 'setCurrentCurrency')
})
afterEach(() => {
setCurrentCurrencySpy.restore()
})
it('calls setCurrentCurrency', () => {
const store = mockStore()
store.dispatch(actions.setCurrentCurrency('jpy'))
assert(setCurrentCurrencySpy.calledOnce)
})
it('throws if setCurrentCurrency throws', () => {
const store = mockStore()
const expectedActions = [
{ type: 'SHOW_LOADING_INDICATION', value: undefined },
{ type: 'HIDE_LOADING_INDICATION' },
{ type: 'DISPLAY_WARNING', value: 'error' },
]
setCurrentCurrencySpy.callsFake((_, callback) => {
callback(new Error('error'))
})
store.dispatch(actions.setCurrentCurrency())
assert.deepEqual(store.getActions(), expectedActions)
})
})
describe('#signMsg', () => {
let signMessageSpy, metamaskMsgs, msgId, messages
const msgParams = {
from: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc',
data: '0x879a053d4800c6354e76c7985a865d2922c82fb5b3f4577b2fe08b998954f2e0',
}
beforeEach(() => {
metamaskController.newUnsignedMessage(msgParams, noop)
metamaskMsgs = metamaskController.messageManager.getUnapprovedMsgs()
messages = metamaskController.messageManager.messages
msgId = Object.keys(metamaskMsgs)[0]
messages[0].msgParams.metamaskId = parseInt(msgId)
})
afterEach(() => {
signMessageSpy.restore()
})
it('calls signMsg in background', () => {
const store = mockStore()
signMessageSpy = sinon.spy(background, 'signMessage')
return store.dispatch(actions.signMsg(msgParams))
.then(() => {
assert(signMessageSpy.calledOnce)
})
})
it('errors when signMessage in background throws', async () => {
const store = mockStore()
const expectedActions = [
{ type: 'SHOW_LOADING_INDICATION', value: undefined },
{ type: 'UPDATE_METAMASK_STATE', value: undefined },
{ type: 'HIDE_LOADING_INDICATION' },
{ type: 'DISPLAY_WARNING', value: 'error' },
]
signMessageSpy = sinon.stub(background, 'signMessage')
signMessageSpy.callsFake((_, callback) => {
callback(new Error('error'))
})
try {
await store.dispatch(actions.signMsg())
assert.fail('Should have thrown error')
} catch (_) {
assert.deepEqual(store.getActions(), expectedActions)
}
})
})
describe('#signPersonalMsg', () => {
let signPersonalMessageSpy, metamaskMsgs, msgId, personalMessages
const msgParams = {
from: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc',
data: '0x879a053d4800c6354e76c7985a865d2922c82fb5b3f4577b2fe08b998954f2e0',
}
beforeEach(() => {
metamaskController.newUnsignedPersonalMessage(msgParams, noop)
metamaskMsgs = metamaskController.personalMessageManager.getUnapprovedMsgs()
personalMessages = metamaskController.personalMessageManager.messages
msgId = Object.keys(metamaskMsgs)[0]
personalMessages[0].msgParams.metamaskId = parseInt(msgId)
})
afterEach(() => {
signPersonalMessageSpy.restore()
})
it('calls signPersonalMessage', () => {
const store = mockStore()
signPersonalMessageSpy = sinon.spy(background, 'signPersonalMessage')
return store.dispatch(actions.signPersonalMsg(msgParams))
.then(() => {
assert(signPersonalMessageSpy.calledOnce)
})
})
it('throws if signPersonalMessage throws', async () => {
const store = mockStore()
const expectedActions = [
{ type: 'SHOW_LOADING_INDICATION', value: undefined },
{ type: 'UPDATE_METAMASK_STATE', value: undefined },
{ type: 'HIDE_LOADING_INDICATION' },
{ type: 'DISPLAY_WARNING', value: 'error' },
]
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')
} catch (_) {
assert.deepEqual(store.getActions(), expectedActions)
}
})
})
describe('#signTx', () => {
let sendTransactionSpy
beforeEach(() => {
global.ethQuery = new EthQuery(provider)
sendTransactionSpy = sinon.stub(global.ethQuery, 'sendTransaction')
})
afterEach(() => {
sendTransactionSpy.restore()
})
it('calls sendTransaction in global ethQuery', () => {
const store = mockStore()
store.dispatch(actions.signTx())
assert(sendTransactionSpy.calledOnce)
})
it('errors in when sendTransaction throws', () => {
const store = mockStore()
const expectedActions = [
{ type: 'DISPLAY_WARNING', value: 'error' },
{ type: 'SHOW_CONF_TX_PAGE', transForward: true, id: undefined },
]
sendTransactionSpy.callsFake((_, callback) => {
callback(new Error('error'))
})
store.dispatch(actions.signTx())
assert.deepEqual(store.getActions(), expectedActions)
})
})
describe('#signTokenTx', () => {
let tokenSpy
beforeEach(() => {
global.eth = new Eth(provider)
tokenSpy = sinon.spy(global.eth, 'contract')
})
afterEach(() => {
tokenSpy.restore()
})
it('calls eth.contract', () => {
const store = mockStore()
store.dispatch(actions.signTokenTx())
assert(tokenSpy.calledOnce)
})
})
describe('#lockMetamask', () => {
let backgroundSetLockedSpy
afterEach(() => {
backgroundSetLockedSpy.restore()
})
it('calls setLocked', () => {
const store = mockStore()
backgroundSetLockedSpy = sinon.spy(background, 'setLocked')
return store.dispatch(actions.lockMetamask())
.then(() => {
assert(backgroundSetLockedSpy.calledOnce)
})
})
it('returns display warning error with value when setLocked in background callback errors', () => {
const store = mockStore()
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'))
})
return store.dispatch(actions.lockMetamask())
.then(() => {
assert.deepEqual(store.getActions(), expectedActions)
})
})
})
describe('#setSelectedAddress', () => {
let setSelectedAddressSpy
beforeEach(() => {
setSelectedAddressSpy = sinon.stub(background, 'setSelectedAddress')
})
afterEach(() => {
setSelectedAddressSpy.restore()
})
it('calls setSelectedAddress in background', () => {
const store = mockStore({ metamask: devState })
store.dispatch(actions.setSelectedAddress('0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc'))
assert(setSelectedAddressSpy.calledOnce)
})
it('errors when setSelectedAddress throws', () => {
const store = mockStore()
const expectedActions = [
{ type: 'SHOW_LOADING_INDICATION', value: undefined },
{ type: 'HIDE_LOADING_INDICATION' },
{ type: 'DISPLAY_WARNING', value: 'error' },
]
setSelectedAddressSpy.callsFake((_, callback) => {
callback(new Error('error'))
})
store.dispatch(actions.setSelectedAddress())
assert.deepEqual(store.getActions(), expectedActions)
})
})
describe('#showAccountDetail', () => {
let setSelectedAddressSpy
beforeEach(() => {
setSelectedAddressSpy = sinon.stub(background, 'setSelectedAddress')
})
afterEach(() => {
setSelectedAddressSpy.restore()
})
it('#showAccountDetail', () => {
const store = mockStore()
store.dispatch(actions.showAccountDetail())
assert(setSelectedAddressSpy.calledOnce)
})
it('displays warning if setSelectedAddress throws', () => {
const store = mockStore()
const expectedActions = [
{ type: 'SHOW_LOADING_INDICATION', value: undefined },
{ type: 'HIDE_LOADING_INDICATION' },
{ type: 'DISPLAY_WARNING', value: 'error' },
]
setSelectedAddressSpy.callsFake((_, callback) => {
callback(new Error('error'))
})
store.dispatch(actions.showAccountDetail())
assert.deepEqual(store.getActions(), expectedActions)
})
})
describe('#addToken', () => {
let addTokenSpy
beforeEach(() => {
addTokenSpy = sinon.stub(background, 'addToken')
})
afterEach(() => {
addTokenSpy.restore()
})
it('calls addToken in background', () => {
const store = mockStore()
store.dispatch(actions.addToken())
.then(() => {
assert(addTokenSpy.calledOnce)
})
})
it('errors when addToken in background throws', async () => {
const store = mockStore()
const expectedActions = [
{ type: 'SHOW_LOADING_INDICATION', value: undefined },
{ type: 'HIDE_LOADING_INDICATION' },
{ type: 'DISPLAY_WARNING', value: 'error' },
]
addTokenSpy.callsFake((_, __, ___, ____, callback) => {
callback(new Error('error'))
})
try {
await store.dispatch(actions.addToken())
assert.fail('Should have thrown error')
} catch (_) {
assert.deepEqual(store.getActions(), expectedActions)
}
})
})
describe('#removeToken', () => {
let removeTokenSpy
beforeEach(() => {
removeTokenSpy = sinon.stub(background, 'removeToken')
})
afterEach(() => {
removeTokenSpy.restore()
})
it('calls removeToken in background', () => {
const store = mockStore()
store.dispatch(actions.removeToken())
.then(() => {
assert(removeTokenSpy.calledOnce)
})
})
it('errors when removeToken in background fails', async () => {
const store = mockStore()
const expectedActions = [
{ type: 'SHOW_LOADING_INDICATION', value: undefined },
{ type: 'HIDE_LOADING_INDICATION' },
{ type: 'DISPLAY_WARNING', value: 'error' },
]
removeTokenSpy.callsFake((_, callback) => {
callback(new Error('error'))
})
try {
await store.dispatch(actions.removeToken())
assert.fail('Should have thrown error')
} catch (_) {
assert.deepEqual(store.getActions(), expectedActions)
}
})
})
describe('#setProviderType', () => {
let setProviderTypeSpy
let store
beforeEach(() => {
store = mockStore({ metamask: { provider: {} } })
setProviderTypeSpy = sinon.stub(background, 'setProviderType')
})
afterEach(() => {
setProviderTypeSpy.restore()
})
it('calls setProviderType', () => {
store.dispatch(actions.setProviderType())
assert(setProviderTypeSpy.calledOnce)
})
it('displays warning when setProviderType throws', () => {
const expectedActions = [
{ type: 'DISPLAY_WARNING', value: 'Had a problem changing networks!' },
]
setProviderTypeSpy.callsFake((_, callback) => {
callback(new Error('error'))
})
store.dispatch(actions.setProviderType())
assert(setProviderTypeSpy.calledOnce)
assert.deepEqual(store.getActions(), expectedActions)
})
})
describe('#setRpcTarget', () => {
let setRpcTargetSpy
beforeEach(() => {
setRpcTargetSpy = sinon.stub(background, 'setCustomRpc')
})
afterEach(() => {
setRpcTargetSpy.restore()
})
it('calls setRpcTarget', () => {
const store = mockStore()
store.dispatch(actions.setRpcTarget('http://localhost:8545'))
assert(setRpcTargetSpy.calledOnce)
})
it('displays warning when setRpcTarget throws', () => {
const store = mockStore()
const expectedActions = [
{ type: 'DISPLAY_WARNING', value: 'Had a problem changing networks!' },
]
setRpcTargetSpy.callsFake((_, __, ___, ____, callback) => {
callback(new Error('error'))
})
store.dispatch(actions.setRpcTarget())
assert.deepEqual(store.getActions(), expectedActions)
})
})
describe('#addToAddressBook', () => {
let addToAddressBookSpy
beforeEach(() => {
addToAddressBookSpy = sinon.stub(background, 'setAddressBook')
})
afterEach(() => {
addToAddressBookSpy.restore()
})
it('calls setAddressBook', () => {
const store = mockStore({ metamask: devState })
store.dispatch(actions.addToAddressBook('test'))
assert(addToAddressBookSpy.calledOnce)
})
})
describe('#exportAccount', () => {
let submitPasswordSpy, exportAccountSpy
afterEach(() => {
submitPasswordSpy.restore()
exportAccountSpy.restore()
})
it('returns expected actions for successful action', () => {
const store = mockStore(devState)
const expectedActions = [
{ type: 'SHOW_LOADING_INDICATION', value: undefined },
{ type: 'HIDE_LOADING_INDICATION' },
{ type: 'SHOW_PRIVATE_KEY', value: '7ec73b91bb20f209a7ff2d32f542c3420b4fccf14abcc7840d2eff0ebcb18505' },
]
submitPasswordSpy = sinon.spy(background, 'submitPassword')
exportAccountSpy = sinon.spy(background, 'exportAccount')
return store.dispatch(actions.exportAccount(password, '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc'))
.then(() => {
assert(submitPasswordSpy.calledOnce)
assert(exportAccountSpy.calledOnce)
assert.deepEqual(store.getActions(), expectedActions)
})
})
it('returns action errors when first func callback errors', async () => {
const store = mockStore(devState)
const expectedActions = [
{ type: 'SHOW_LOADING_INDICATION', value: undefined },
{ type: 'HIDE_LOADING_INDICATION' },
{ type: 'DISPLAY_WARNING', value: 'Incorrect Password.' },
]
submitPasswordSpy = sinon.stub(background, 'submitPassword')
submitPasswordSpy.callsFake((_, callback) => {
callback(new Error('error'))
})
try {
await store.dispatch(actions.exportAccount(password, '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc'))
assert.fail('Should have thrown error')
} catch (_) {
assert.deepEqual(store.getActions(), expectedActions)
}
})
it('returns action errors when second func callback errors', async () => {
const store = mockStore(devState)
const expectedActions = [
{ type: 'SHOW_LOADING_INDICATION', value: undefined },
{ type: 'HIDE_LOADING_INDICATION' },
{ type: 'DISPLAY_WARNING', value: 'Had a problem exporting the account.' },
]
exportAccountSpy = sinon.stub(background, 'exportAccount')
exportAccountSpy.callsFake((_, callback) => {
callback(new Error('error'))
})
try {
await store.dispatch(actions.exportAccount(password, '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc'))
assert.fail('Should have thrown error')
} catch (_) {
assert.deepEqual(store.getActions(), expectedActions)
}
})
})
describe('#setAccountLabel', () => {
let setAccountLabelSpy
beforeEach(() => {
setAccountLabelSpy = sinon.stub(background, 'setAccountLabel')
})
it('calls setAccountLabel', () => {
const store = mockStore()
store.dispatch(actions.setAccountLabel('0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', 'test'))
assert(setAccountLabelSpy.calledOnce)
})
})
describe('#pairUpdate', () => {
beforeEach(() => {
nock('https://shapeshift.io')
.defaultReplyHeaders({ 'access-control-allow-origin': '*' })
.get('/marketinfo/btc_eth')
.reply(200, {pair: 'BTC_ETH', rate: 25.68289016, minerFee: 0.00176, limit: 0.67748474, minimum: 0.00013569, maxLimit: 0.67758573})
nock('https://shapeshift.io')
.defaultReplyHeaders({ 'access-control-allow-origin': '*' })
.get('/coins')
.reply(200)
})
it('calls expected actions', () => {
const store = mockStore()
// issue with dispatch action in callback not showing
const expectedActions = [
{ type: 'SHOW_SUB_LOADING_INDICATION' },
{ type: 'HIDE_WARNING' },
]
store.dispatch(actions.pairUpdate('btc'))
assert.deepEqual(store.getActions(), expectedActions)
})
})
describe('#setFeatureFlag', () => {
let setFeatureFlagSpy
beforeEach(() => {
setFeatureFlagSpy = sinon.stub(background, 'setFeatureFlag')
})
afterEach(() => {
setFeatureFlagSpy.restore()
})
it('calls setFeatureFlag in the background', () => {
const store = mockStore()
store.dispatch(actions.setFeatureFlag())
assert(setFeatureFlagSpy.calledOnce)
})
it('errors when setFeatureFlag in background throws', async () => {
const store = mockStore()
const expectedActions = [
{ type: 'SHOW_LOADING_INDICATION', value: undefined },
{ type: 'HIDE_LOADING_INDICATION' },
{ type: 'DISPLAY_WARNING', value: 'error' },
]
setFeatureFlagSpy.callsFake((_, __, callback) => {
callback(new Error('error'))
})
try {
await store.dispatch(actions.setFeatureFlag())
assert.fail('Should have thrown error')
} catch (_) {
assert.deepEqual(store.getActions(), expectedActions)
}
})
})
describe('#setCompletedOnboarding', () => {
let completeOnboardingSpy
beforeEach(() => {
completeOnboardingSpy = sinon.stub(background, 'completeOnboarding')
completeOnboardingSpy.callsFake(cb => cb())
})
after(() => {
completeOnboardingSpy.restore()
})
it('completes onboarding', async () => {
const store = mockStore()
await store.dispatch(actions.setCompletedOnboarding())
assert.equal(completeOnboardingSpy.callCount, 1)
})
})
describe('#updateNetworkNonce', () => {
let getTransactionCountSpy
afterEach(() => {
getTransactionCountSpy.restore()
})
it('calls getTransactionCount', () => {
const store = mockStore()
getTransactionCountSpy = sinon.spy(global.ethQuery, 'getTransactionCount')
store.dispatch(actions.updateNetworkNonce())
.then(() => {
assert(getTransactionCountSpy.calledOnce)
})
})
it('errors when getTransactionCount throws', async () => {
const store = mockStore()
const expectedActions = [
{ type: 'DISPLAY_WARNING', value: 'error' },
]
getTransactionCountSpy = sinon.stub(global.ethQuery, 'getTransactionCount')
getTransactionCountSpy.callsFake((_, callback) => {
callback(new Error('error'))
})
try {
await store.dispatch(actions.updateNetworkNonce())
assert.fail('Should have thrown error')
} catch (_) {
assert.deepEqual(store.getActions(), expectedActions)
}
})
})
describe('#setUseBlockie', () => {
let setUseBlockieSpy
beforeEach(() => {
setUseBlockieSpy = sinon.stub(background, 'setUseBlockie')
})
afterEach(() => {
setUseBlockieSpy.restore()
})
it('calls setUseBlockie in background', () => {
const store = mockStore()
store.dispatch(actions.setUseBlockie())
assert(setUseBlockieSpy.calledOnce)
})
it('errors when setUseBlockie in background throws', () => {
const store = mockStore()
const expectedActions = [
{ type: 'SHOW_LOADING_INDICATION', value: undefined },
{ type: 'HIDE_LOADING_INDICATION' },
{ type: 'DISPLAY_WARNING', value: 'error' },
{ type: 'SET_USE_BLOCKIE', value: undefined },
]
setUseBlockieSpy.callsFake((_, callback) => {
callback(new Error('error'))
})
store.dispatch(actions.setUseBlockie())
assert.deepEqual(store.getActions(), expectedActions)
})
})
describe('#updateCurrentLocale', () => {
let setCurrentLocaleSpy
beforeEach(() => {
fetchMock.get('*', enLocale)
})
afterEach(() => {
setCurrentLocaleSpy.restore()
fetchMock.restore()
})
it('calls expected actions', () => {
const store = mockStore()
setCurrentLocaleSpy = sinon.spy(background, 'setCurrentLocale')
const expectedActions = [
{ type: 'SHOW_LOADING_INDICATION', value: undefined },
{ type: 'SET_CURRENT_LOCALE', value: { locale: 'en', messages: enLocale }},
{ type: 'HIDE_LOADING_INDICATION' },
]
return store.dispatch(actions.updateCurrentLocale('en'))
.then(() => {
assert(setCurrentLocaleSpy.calledOnce)
assert.deepEqual(store.getActions(), expectedActions)
})
})
it('calls expected actions', () => {
const store = mockStore()
const expectedActions = [
{ type: 'SHOW_LOADING_INDICATION', value: undefined },
{ type: 'HIDE_LOADING_INDICATION' },
{ type: 'DISPLAY_WARNING', value: 'error' },
]
setCurrentLocaleSpy = sinon.stub(background, 'setCurrentLocale')
setCurrentLocaleSpy.callsFake((_, callback) => {
callback(new Error('error'))
})
return store.dispatch(actions.updateCurrentLocale('en'))
.then(() => {
assert.deepEqual(store.getActions(), expectedActions)
})
})
})
describe('#markPasswordForgotten', () => {
let markPasswordForgottenSpy
beforeEach(() => {
markPasswordForgottenSpy = sinon.stub(background, 'markPasswordForgotten')
})
afterEach(() => {
markPasswordForgottenSpy.restore()
})
it('calls markPasswordForgotten', () => {
const store = mockStore()
store.dispatch(actions.markPasswordForgotten())
assert(markPasswordForgottenSpy.calledOnce)
})
})
describe('#unMarkPasswordForgotten', () => {
let unMarkPasswordForgottenSpy
beforeEach(() => {
unMarkPasswordForgottenSpy = sinon.stub(background, 'unMarkPasswordForgotten')
})
afterEach(() => {
unMarkPasswordForgottenSpy.restore()
})
it('calls unMarkPasswordForgotten', () => {
const store = mockStore()
store.dispatch(actions.unMarkPasswordForgotten())
assert(unMarkPasswordForgottenSpy.calledOnce)
})
})
})