1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 09:52:26 +01:00

Remove nodeify (#13003)

The `nodeify` utility is no longer needed for the background API.
Instead each method is assumed to be either synchronous or Promise-
returning.

The error handling was updated to at least log the error in the case
where a method fall fails after the connection is broken.
This commit is contained in:
Mark Stacey 2021-12-08 18:06:53 -03:30 committed by GitHub
parent a7da8333a0
commit 5076e5057f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 311 additions and 637 deletions

View File

@ -31,6 +31,7 @@ describe('preferences controller', function () {
.callsFake(() => ({ type: 'mainnet' })); .callsFake(() => ({ type: 'mainnet' }));
preferencesController = new PreferencesController({ preferencesController = new PreferencesController({
initLangCode: 'en_US',
migrateAddressBookState, migrateAddressBookState,
network, network,
provider, provider,
@ -41,6 +42,30 @@ describe('preferences controller', function () {
sinon.restore(); sinon.restore();
}); });
describe('useBlockie', function () {
it('defaults useBlockie to false', function () {
assert.equal(preferencesController.store.getState().useBlockie, false);
});
it('setUseBlockie to true', function () {
preferencesController.setUseBlockie(true);
assert.equal(preferencesController.store.getState().useBlockie, true);
});
});
describe('setCurrentLocale', function () {
it('checks the default currentLocale', function () {
const { currentLocale } = preferencesController.store.getState();
assert.equal(currentLocale, 'en_US');
});
it('sets current locale in preferences controller', function () {
preferencesController.setCurrentLocale('ja');
const { currentLocale } = preferencesController.store.getState();
assert.equal(currentLocale, 'ja');
});
});
describe('setAddresses', function () { describe('setAddresses', function () {
it('should keep a map of addresses to names and addresses in the store', function () { it('should keep a map of addresses to names and addresses in the store', function () {
preferencesController.setAddresses(['0xda22le', '0x7e57e2']); preferencesController.setAddresses(['0xda22le', '0x7e57e2']);

View File

@ -1,7 +1,7 @@
import { ethErrors, serializeError } from 'eth-rpc-errors'; import { ethErrors, serializeError } from 'eth-rpc-errors';
const createMetaRPCHandler = (api, outStream) => { const createMetaRPCHandler = (api, outStream) => {
return (data) => { return async (data) => {
if (outStream._writableState.ended) { if (outStream._writableState.ended) {
return; return;
} }
@ -15,24 +15,35 @@ const createMetaRPCHandler = (api, outStream) => {
}); });
return; return;
} }
api[data.method](...data.params, (err, result) => {
if (outStream._writableState.ended) { let result;
return; let error;
try {
result = await api[data.method](...data.params);
} catch (err) {
error = err;
}
if (outStream._writableState.ended) {
if (error) {
console.error(error);
} }
if (err) { return;
outStream.write({ }
jsonrpc: '2.0',
error: serializeError(err, { shouldIncludeStack: true }), if (error) {
id: data.id, outStream.write({
}); jsonrpc: '2.0',
} else { error: serializeError(error, { shouldIncludeStack: true }),
outStream.write({ id: data.id,
jsonrpc: '2.0', });
result, } else {
id: data.id, outStream.write({
}); jsonrpc: '2.0',
} result,
}); id: data.id,
});
}
}; };
}; };

View File

@ -16,11 +16,11 @@ describe('createMetaRPCHandler', () => {
params: ['bar'], params: ['bar'],
}); });
}); });
it('can write the response to the outstream when api callback is called', () => { it('can write the response to the outstream', () => {
const api = { const api = {
foo: (param1, cb) => { foo: (param1) => {
expect(param1).toStrictEqual('bar'); expect(param1).toStrictEqual('bar');
cb(null, 'foobarbaz'); return 'foobarbaz';
}, },
}; };
const streamTest = createThoughStream(); const streamTest = createThoughStream();
@ -35,11 +35,31 @@ describe('createMetaRPCHandler', () => {
streamTest.end(); streamTest.end();
}); });
}); });
it('can write the error to the outstream when api callback is called with an error', () => { it('can write an async response to the outstream', () => {
const api = { const api = {
foo: (param1, cb) => { foo: async (param1) => {
expect(param1).toStrictEqual('bar'); expect(param1).toStrictEqual('bar');
cb(new Error('foo-error')); await new Promise((resolve) => setTimeout(() => resolve(), 100));
return 'foobarbaz';
},
};
const streamTest = createThoughStream();
const handler = createMetaRPCHandler(api, streamTest);
handler({
id: 1,
method: 'foo',
params: ['bar'],
});
streamTest.on('data', (data) => {
expect(data.result).toStrictEqual('foobarbaz');
streamTest.end();
});
});
it('can write the error to the outstream when method throws an error', () => {
const api = {
foo: (param1) => {
expect(param1).toStrictEqual('bar');
throw new Error('foo-error');
}, },
}; };
const streamTest = createThoughStream(); const streamTest = createThoughStream();
@ -56,9 +76,9 @@ describe('createMetaRPCHandler', () => {
}); });
it('can not throw an error for writing an error after end', () => { it('can not throw an error for writing an error after end', () => {
const api = { const api = {
foo: (param1, cb) => { foo: (param1) => {
expect(param1).toStrictEqual('bar'); expect(param1).toStrictEqual('bar');
cb(new Error('foo-error')); throw new Error('foo-error');
}, },
}; };
const streamTest = createThoughStream(); const streamTest = createThoughStream();
@ -74,11 +94,11 @@ describe('createMetaRPCHandler', () => {
}); });
it('can not throw an error for write after end', () => { it('can not throw an error for write after end', () => {
const api = { const api = {
foo: (param1, cb) => { foo: (param1) => {
expect(param1).toStrictEqual('bar'); expect(param1).toStrictEqual('bar');
cb(undefined, { return {
foo: 'bar', foo: 'bar',
}); };
}, },
}; };
const streamTest = createThoughStream(); const streamTest = createThoughStream();

View File

@ -1,55 +0,0 @@
import promiseToCallback from 'promise-to-callback';
const callbackNoop = function (err) {
if (err) {
throw err;
}
};
/**
* A generator that returns a function which, when passed a promise, can treat that promise as a node style callback.
* The prime advantage being that callbacks are better for error handling.
*
* @param {Function} fn - The function to handle as a callback.
* @param {Object} context - The context in which the function is to be called,
* most often a `this` reference.
*
*/
export function nodeify(fn, context) {
return function (...args) {
const lastArg = args[args.length - 1];
const lastArgIsCallback = typeof lastArg === 'function';
let callback;
if (lastArgIsCallback) {
callback = lastArg;
args.pop();
} else {
callback = callbackNoop;
}
// call the provided function and ensure result is a promise
let result;
try {
result = Promise.resolve(fn.apply(context, args));
} catch (err) {
result = Promise.reject(err);
}
// wire up promise resolution to callback
promiseToCallback(result)(callback);
};
}
/**
* Returns a new object where every function property is nodeified, and every
* non-function property is unmodified.
*
* @param {Record<string, unknown>} obj - The object whose function values to
* `nodeify`.
* @param {Object} context - The context in which the function is to be called.
*/
export function nodeifyObject(obj, context) {
return Object.entries(obj).reduce((nodeified, [key, value]) => {
nodeified[key] =
typeof value === 'function' ? nodeify(value, context) : value;
return nodeified;
}, {});
}

View File

@ -1,85 +0,0 @@
import { nodeify, nodeifyObject } from './nodeify';
describe('nodeify', () => {
const getObject = () => {
return {
foo: 'bar',
promiseFunc(a) {
const solution = this.foo + a;
return Promise.resolve(solution);
},
};
};
it('should retain original context', () => {
const obj = getObject();
const nodified = nodeify(obj.promiseFunc, obj);
nodified('baz', (_, res) => {
expect(res).toStrictEqual('barbaz');
});
});
it('no callback - should allow the last argument to not be a function', async () => {
const obj = getObject();
const nodified = nodeify(obj.promiseFunc, obj);
await expect(() => {
nodified('baz');
}).not.toThrow();
});
it('sync functions - returns value', async () => {
const nodified = nodeify(() => 42);
nodified((_, result) => {
expect(42).toStrictEqual(result);
});
});
it('sync functions - handles errors', () => {
const nodified = nodeify(() => {
throw new Error('boom!');
});
nodified((err, _) => {
expect(err.message).toStrictEqual('boom!');
});
});
describe('nodeifyObject', () => {
it('nodeifies every function of an object', async () => {
const obj = {
notFunction: 'bar',
syncFunction: () => 'hello',
asyncFunction: async () => 'goodbye',
};
const nodeified = nodeifyObject(obj, null);
expect(nodeified.notFunction).toStrictEqual(obj.notFunction);
await Promise.all([
new Promise((resolve, reject) => {
nodeified.syncFunction((err, result) => {
if (err) {
reject(
new Error(`should not have thrown any error: ${err.message}`),
);
return;
}
expect(result).toStrictEqual('hello');
resolve();
});
}),
new Promise((resolve, reject) => {
nodeified.asyncFunction((err, result) => {
if (err) {
reject(
new Error(`should not have thrown any error: ${err.message}`),
);
return;
}
expect(result).toStrictEqual('goodbye');
resolve();
});
}),
]);
});
});
});

View File

@ -86,7 +86,6 @@ import TypedMessageManager from './lib/typed-message-manager';
import TransactionController from './controllers/transactions'; import TransactionController from './controllers/transactions';
import DetectTokensController from './controllers/detect-tokens'; import DetectTokensController from './controllers/detect-tokens';
import SwapsController from './controllers/swaps'; import SwapsController from './controllers/swaps';
import { nodeify, nodeifyObject } from './lib/nodeify';
import accountImporter from './account-import-strategies'; import accountImporter from './account-import-strategies';
import seedPhraseVerifier from './lib/seed-phrase-verifier'; import seedPhraseVerifier from './lib/seed-phrase-verifier';
import MetaMetricsController from './controllers/metametrics'; import MetaMetricsController from './controllers/metametrics';
@ -985,485 +984,400 @@ export default class MetamaskController extends EventEmitter {
*/ */
getApi() { getApi() {
const { const {
addressBookController,
alertController, alertController,
approvalController, approvalController,
appStateController,
collectiblesController,
collectibleDetectionController,
currencyRateController,
detectTokensController,
ensController,
gasFeeController,
keyringController, keyringController,
metaMetricsController, metaMetricsController,
networkController, networkController,
notificationController,
onboardingController, onboardingController,
permissionController, permissionController,
preferencesController, preferencesController,
qrHardwareKeyring,
swapsController, swapsController,
threeBoxController, threeBoxController,
txController,
tokensController, tokensController,
collectiblesController, txController,
} = this; } = this;
return { return {
// etc // etc
getState: (cb) => cb(null, this.getState()), getState: this.getState.bind(this),
setCurrentCurrency: nodeify( setCurrentCurrency: currencyRateController.setCurrentCurrency.bind(
this.currencyRateController.setCurrentCurrency.bind( currencyRateController,
this.currencyRateController,
),
), ),
setUseBlockie: this.setUseBlockie.bind(this), setUseBlockie: preferencesController.setUseBlockie.bind(
setUseNonceField: this.setUseNonceField.bind(this), preferencesController,
setUsePhishDetect: this.setUsePhishDetect.bind(this),
setUseTokenDetection: nodeify(
this.preferencesController.setUseTokenDetection,
this.preferencesController,
), ),
setUseCollectibleDetection: nodeify( setUseNonceField: preferencesController.setUseNonceField.bind(
this.preferencesController.setUseCollectibleDetection, preferencesController,
this.preferencesController,
), ),
setOpenSeaEnabled: nodeify( setUsePhishDetect: preferencesController.setUsePhishDetect.bind(
this.preferencesController.setOpenSeaEnabled, preferencesController,
this.preferencesController, ),
setUseTokenDetection: preferencesController.setUseTokenDetection.bind(
preferencesController,
),
setUseCollectibleDetection: preferencesController.setUseCollectibleDetection.bind(
preferencesController,
),
setOpenSeaEnabled: preferencesController.setOpenSeaEnabled.bind(
preferencesController,
),
setIpfsGateway: preferencesController.setIpfsGateway.bind(
preferencesController,
),
setParticipateInMetaMetrics: metaMetricsController.setParticipateInMetaMetrics.bind(
metaMetricsController,
),
setCurrentLocale: preferencesController.setCurrentLocale.bind(
preferencesController,
), ),
setIpfsGateway: this.setIpfsGateway.bind(this),
setParticipateInMetaMetrics: this.setParticipateInMetaMetrics.bind(this),
setCurrentLocale: this.setCurrentLocale.bind(this),
markPasswordForgotten: this.markPasswordForgotten.bind(this), markPasswordForgotten: this.markPasswordForgotten.bind(this),
unMarkPasswordForgotten: this.unMarkPasswordForgotten.bind(this), unMarkPasswordForgotten: this.unMarkPasswordForgotten.bind(this),
safelistPhishingDomain: this.safelistPhishingDomain.bind(this), safelistPhishingDomain: this.safelistPhishingDomain.bind(this),
getRequestAccountTabIds: (cb) => cb(null, this.getRequestAccountTabIds()), getRequestAccountTabIds: this.getRequestAccountTabIds,
getOpenMetamaskTabsIds: (cb) => cb(null, this.getOpenMetamaskTabsIds()), getOpenMetamaskTabsIds: this.getOpenMetamaskTabsIds,
// primary HD keyring management // primary HD keyring management
addNewAccount: nodeify(this.addNewAccount, this), addNewAccount: this.addNewAccount.bind(this),
verifySeedPhrase: nodeify(this.verifySeedPhrase, this), verifySeedPhrase: this.verifySeedPhrase.bind(this),
resetAccount: nodeify(this.resetAccount, this), resetAccount: this.resetAccount.bind(this),
removeAccount: nodeify(this.removeAccount, this), removeAccount: this.removeAccount.bind(this),
importAccountWithStrategy: nodeify(this.importAccountWithStrategy, this), importAccountWithStrategy: this.importAccountWithStrategy.bind(this),
// hardware wallets // hardware wallets
connectHardware: nodeify(this.connectHardware, this), connectHardware: this.connectHardware.bind(this),
forgetDevice: nodeify(this.forgetDevice, this), forgetDevice: this.forgetDevice.bind(this),
checkHardwareStatus: nodeify(this.checkHardwareStatus, this), checkHardwareStatus: this.checkHardwareStatus.bind(this),
unlockHardwareWalletAccount: nodeify( unlockHardwareWalletAccount: this.unlockHardwareWalletAccount.bind(this),
this.unlockHardwareWalletAccount, setLedgerTransportPreference: this.setLedgerTransportPreference.bind(
this, this,
), ),
setLedgerTransportPreference: nodeify( attemptLedgerTransportCreation: this.attemptLedgerTransportCreation.bind(
this.setLedgerTransportPreference,
this, this,
), ),
attemptLedgerTransportCreation: nodeify( establishLedgerTransportPreference: this.establishLedgerTransportPreference.bind(
this.attemptLedgerTransportCreation,
this,
),
establishLedgerTransportPreference: nodeify(
this.establishLedgerTransportPreference,
this, this,
), ),
// qr hardware devices // qr hardware devices
submitQRHardwareCryptoHDKey: nodeify( submitQRHardwareCryptoHDKey: qrHardwareKeyring.submitCryptoHDKey.bind(
this.qrHardwareKeyring.submitCryptoHDKey, qrHardwareKeyring,
this.qrHardwareKeyring,
), ),
submitQRHardwareCryptoAccount: nodeify( submitQRHardwareCryptoAccount: qrHardwareKeyring.submitCryptoAccount.bind(
this.qrHardwareKeyring.submitCryptoAccount, qrHardwareKeyring,
this.qrHardwareKeyring,
), ),
cancelSyncQRHardware: nodeify( cancelSyncQRHardware: qrHardwareKeyring.cancelSync.bind(
this.qrHardwareKeyring.cancelSync, qrHardwareKeyring,
this.qrHardwareKeyring,
), ),
submitQRHardwareSignature: nodeify( submitQRHardwareSignature: qrHardwareKeyring.submitSignature.bind(
this.qrHardwareKeyring.submitSignature, qrHardwareKeyring,
this.qrHardwareKeyring,
), ),
cancelQRHardwareSignRequest: nodeify( cancelQRHardwareSignRequest: qrHardwareKeyring.cancelSignRequest.bind(
this.qrHardwareKeyring.cancelSignRequest, qrHardwareKeyring,
this.qrHardwareKeyring,
), ),
// mobile // mobile
fetchInfoToSync: nodeify(this.fetchInfoToSync, this), fetchInfoToSync: this.fetchInfoToSync.bind(this),
// vault management // vault management
submitPassword: nodeify(this.submitPassword, this), submitPassword: this.submitPassword.bind(this),
verifyPassword: nodeify(this.verifyPassword, this), verifyPassword: this.verifyPassword.bind(this),
// network management // network management
setProviderType: nodeify( setProviderType: networkController.setProviderType.bind(
networkController.setProviderType,
networkController, networkController,
), ),
rollbackToPreviousProvider: nodeify( rollbackToPreviousProvider: networkController.rollbackToPreviousProvider.bind(
networkController.rollbackToPreviousProvider,
networkController, networkController,
), ),
setCustomRpc: nodeify(this.setCustomRpc, this), setCustomRpc: this.setCustomRpc.bind(this),
updateAndSetCustomRpc: nodeify(this.updateAndSetCustomRpc, this), updateAndSetCustomRpc: this.updateAndSetCustomRpc.bind(this),
delCustomRpc: nodeify(this.delCustomRpc, this), delCustomRpc: this.delCustomRpc.bind(this),
// PreferencesController // PreferencesController
setSelectedAddress: nodeify( setSelectedAddress: preferencesController.setSelectedAddress.bind(
preferencesController.setSelectedAddress,
preferencesController, preferencesController,
), ),
addToken: nodeify(tokensController.addToken, tokensController), addToken: tokensController.addToken.bind(tokensController),
rejectWatchAsset: nodeify( rejectWatchAsset: tokensController.rejectWatchAsset.bind(
tokensController.rejectWatchAsset,
tokensController, tokensController,
), ),
acceptWatchAsset: nodeify( acceptWatchAsset: tokensController.acceptWatchAsset.bind(
tokensController.acceptWatchAsset,
tokensController, tokensController,
), ),
updateTokenType: nodeify( updateTokenType: tokensController.updateTokenType.bind(tokensController),
tokensController.updateTokenType, removeToken: tokensController.removeAndIgnoreToken.bind(tokensController),
tokensController, setAccountLabel: preferencesController.setAccountLabel.bind(
),
removeToken: nodeify(
tokensController.removeAndIgnoreToken,
tokensController,
),
setAccountLabel: nodeify(
preferencesController.setAccountLabel,
preferencesController, preferencesController,
), ),
setFeatureFlag: nodeify( setFeatureFlag: preferencesController.setFeatureFlag.bind(
preferencesController.setFeatureFlag,
preferencesController, preferencesController,
), ),
setPreference: nodeify( setPreference: preferencesController.setPreference.bind(
preferencesController.setPreference,
preferencesController, preferencesController,
), ),
addKnownMethodData: nodeify( addKnownMethodData: preferencesController.addKnownMethodData.bind(
preferencesController.addKnownMethodData,
preferencesController, preferencesController,
), ),
setDismissSeedBackUpReminder: nodeify( setDismissSeedBackUpReminder: preferencesController.setDismissSeedBackUpReminder.bind(
this.preferencesController.setDismissSeedBackUpReminder, preferencesController,
this.preferencesController,
), ),
setAdvancedGasFee: nodeify( setAdvancedGasFee: preferencesController.setAdvancedGasFee.bind(
preferencesController.setAdvancedGasFee,
preferencesController, preferencesController,
), ),
// CollectiblesController // CollectiblesController
addCollectible: nodeify( addCollectible: collectiblesController.addCollectible.bind(
collectiblesController.addCollectible,
collectiblesController, collectiblesController,
), ),
addCollectibleVerifyOwnership: nodeify( addCollectibleVerifyOwnership: collectiblesController.addCollectibleVerifyOwnership.bind(
collectiblesController.addCollectibleVerifyOwnership,
collectiblesController, collectiblesController,
), ),
removeAndIgnoreCollectible: nodeify( removeAndIgnoreCollectible: collectiblesController.removeAndIgnoreCollectible.bind(
collectiblesController.removeAndIgnoreCollectible,
collectiblesController, collectiblesController,
), ),
removeCollectible: nodeify( removeCollectible: collectiblesController.removeCollectible.bind(
collectiblesController.removeCollectible,
collectiblesController, collectiblesController,
), ),
// AddressController // AddressController
setAddressBook: nodeify( setAddressBook: addressBookController.set.bind(addressBookController),
this.addressBookController.set, removeFromAddressBook: addressBookController.delete.bind(
this.addressBookController, addressBookController,
),
removeFromAddressBook: nodeify(
this.addressBookController.delete,
this.addressBookController,
), ),
// AppStateController // AppStateController
setLastActiveTime: nodeify( setLastActiveTime: appStateController.setLastActiveTime.bind(
this.appStateController.setLastActiveTime, appStateController,
this.appStateController,
), ),
setDefaultHomeActiveTabName: nodeify( setDefaultHomeActiveTabName: appStateController.setDefaultHomeActiveTabName.bind(
this.appStateController.setDefaultHomeActiveTabName, appStateController,
this.appStateController,
), ),
setConnectedStatusPopoverHasBeenShown: nodeify( setConnectedStatusPopoverHasBeenShown: appStateController.setConnectedStatusPopoverHasBeenShown.bind(
this.appStateController.setConnectedStatusPopoverHasBeenShown, appStateController,
this.appStateController,
), ),
setRecoveryPhraseReminderHasBeenShown: nodeify( setRecoveryPhraseReminderHasBeenShown: appStateController.setRecoveryPhraseReminderHasBeenShown.bind(
this.appStateController.setRecoveryPhraseReminderHasBeenShown, appStateController,
this.appStateController,
), ),
setRecoveryPhraseReminderLastShown: nodeify( setRecoveryPhraseReminderLastShown: appStateController.setRecoveryPhraseReminderLastShown.bind(
this.appStateController.setRecoveryPhraseReminderLastShown, appStateController,
this.appStateController,
), ),
setShowTestnetMessageInDropdown: nodeify( setShowTestnetMessageInDropdown: appStateController.setShowTestnetMessageInDropdown.bind(
this.appStateController.setShowTestnetMessageInDropdown, appStateController,
this.appStateController,
), ),
// EnsController // EnsController
tryReverseResolveAddress: nodeify( tryReverseResolveAddress: ensController.reverseResolveAddress.bind(
this.ensController.reverseResolveAddress, ensController,
this.ensController,
), ),
// KeyringController // KeyringController
setLocked: nodeify(this.setLocked, this), setLocked: this.setLocked.bind(this),
createNewVaultAndKeychain: nodeify(this.createNewVaultAndKeychain, this), createNewVaultAndKeychain: this.createNewVaultAndKeychain.bind(this),
createNewVaultAndRestore: nodeify(this.createNewVaultAndRestore, this), createNewVaultAndRestore: this.createNewVaultAndRestore.bind(this),
exportAccount: nodeify( exportAccount: keyringController.exportAccount.bind(keyringController),
keyringController.exportAccount,
keyringController,
),
// txController // txController
cancelTransaction: nodeify(txController.cancelTransaction, txController), cancelTransaction: txController.cancelTransaction.bind(txController),
updateTransaction: nodeify(txController.updateTransaction, txController), updateTransaction: txController.updateTransaction.bind(txController),
updateAndApproveTransaction: nodeify( updateAndApproveTransaction: txController.updateAndApproveTransaction.bind(
txController.updateAndApproveTransaction,
txController, txController,
), ),
createCancelTransaction: nodeify(this.createCancelTransaction, this), createCancelTransaction: this.createCancelTransaction.bind(this),
createSpeedUpTransaction: nodeify(this.createSpeedUpTransaction, this), createSpeedUpTransaction: this.createSpeedUpTransaction.bind(this),
estimateGas: nodeify(this.estimateGas, this), estimateGas: this.estimateGas.bind(this),
getNextNonce: nodeify(this.getNextNonce, this), getNextNonce: this.getNextNonce.bind(this),
addUnapprovedTransaction: nodeify( addUnapprovedTransaction: txController.addUnapprovedTransaction.bind(
txController.addUnapprovedTransaction,
txController, txController,
), ),
// messageManager // messageManager
signMessage: nodeify(this.signMessage, this), signMessage: this.signMessage.bind(this),
cancelMessage: this.cancelMessage.bind(this), cancelMessage: this.cancelMessage.bind(this),
// personalMessageManager // personalMessageManager
signPersonalMessage: nodeify(this.signPersonalMessage, this), signPersonalMessage: this.signPersonalMessage.bind(this),
cancelPersonalMessage: this.cancelPersonalMessage.bind(this), cancelPersonalMessage: this.cancelPersonalMessage.bind(this),
// typedMessageManager // typedMessageManager
signTypedMessage: nodeify(this.signTypedMessage, this), signTypedMessage: this.signTypedMessage.bind(this),
cancelTypedMessage: this.cancelTypedMessage.bind(this), cancelTypedMessage: this.cancelTypedMessage.bind(this),
// decryptMessageManager // decryptMessageManager
decryptMessage: nodeify(this.decryptMessage, this), decryptMessage: this.decryptMessage.bind(this),
decryptMessageInline: nodeify(this.decryptMessageInline, this), decryptMessageInline: this.decryptMessageInline.bind(this),
cancelDecryptMessage: this.cancelDecryptMessage.bind(this), cancelDecryptMessage: this.cancelDecryptMessage.bind(this),
// EncryptionPublicKeyManager // EncryptionPublicKeyManager
encryptionPublicKey: nodeify(this.encryptionPublicKey, this), encryptionPublicKey: this.encryptionPublicKey.bind(this),
cancelEncryptionPublicKey: this.cancelEncryptionPublicKey.bind(this), cancelEncryptionPublicKey: this.cancelEncryptionPublicKey.bind(this),
// onboarding controller // onboarding controller
setSeedPhraseBackedUp: nodeify( setSeedPhraseBackedUp: onboardingController.setSeedPhraseBackedUp.bind(
onboardingController.setSeedPhraseBackedUp,
onboardingController, onboardingController,
), ),
completeOnboarding: nodeify( completeOnboarding: onboardingController.completeOnboarding.bind(
onboardingController.completeOnboarding,
onboardingController, onboardingController,
), ),
setFirstTimeFlowType: nodeify( setFirstTimeFlowType: onboardingController.setFirstTimeFlowType.bind(
onboardingController.setFirstTimeFlowType,
onboardingController, onboardingController,
), ),
// alert controller // alert controller
setAlertEnabledness: nodeify( setAlertEnabledness: alertController.setAlertEnabledness.bind(
alertController.setAlertEnabledness,
alertController, alertController,
), ),
setUnconnectedAccountAlertShown: nodeify( setUnconnectedAccountAlertShown: alertController.setUnconnectedAccountAlertShown.bind(
alertController.setUnconnectedAccountAlertShown,
alertController, alertController,
), ),
setWeb3ShimUsageAlertDismissed: nodeify( setWeb3ShimUsageAlertDismissed: alertController.setWeb3ShimUsageAlertDismissed.bind(
alertController.setWeb3ShimUsageAlertDismissed,
alertController, alertController,
), ),
// 3Box // 3Box
setThreeBoxSyncingPermission: nodeify( setThreeBoxSyncingPermission: threeBoxController.setThreeBoxSyncingPermission.bind(
threeBoxController.setThreeBoxSyncingPermission,
threeBoxController, threeBoxController,
), ),
restoreFromThreeBox: nodeify( restoreFromThreeBox: threeBoxController.restoreFromThreeBox.bind(
threeBoxController.restoreFromThreeBox,
threeBoxController, threeBoxController,
), ),
setShowRestorePromptToFalse: nodeify( setShowRestorePromptToFalse: threeBoxController.setShowRestorePromptToFalse.bind(
threeBoxController.setShowRestorePromptToFalse,
threeBoxController, threeBoxController,
), ),
getThreeBoxLastUpdated: nodeify( getThreeBoxLastUpdated: threeBoxController.getLastUpdated.bind(
threeBoxController.getLastUpdated,
threeBoxController, threeBoxController,
), ),
turnThreeBoxSyncingOn: nodeify( turnThreeBoxSyncingOn: threeBoxController.turnThreeBoxSyncingOn.bind(
threeBoxController.turnThreeBoxSyncingOn,
threeBoxController, threeBoxController,
), ),
initializeThreeBox: nodeify(this.initializeThreeBox, this), initializeThreeBox: this.initializeThreeBox.bind(this),
// permissions // permissions
removePermissionsFor: permissionController.revokePermissions.bind( removePermissionsFor: permissionController.revokePermissions.bind(
permissionController, permissionController,
), ),
approvePermissionsRequest: nodeify( approvePermissionsRequest: permissionController.acceptPermissionsRequest.bind(
permissionController.acceptPermissionsRequest,
permissionController, permissionController,
), ),
rejectPermissionsRequest: nodeify( rejectPermissionsRequest: permissionController.rejectPermissionsRequest.bind(
permissionController.rejectPermissionsRequest,
permissionController, permissionController,
), ),
...nodeifyObject(getPermissionBackgroundApiMethods(permissionController)), ...getPermissionBackgroundApiMethods(permissionController),
// swaps // swaps
fetchAndSetQuotes: nodeify( fetchAndSetQuotes: swapsController.fetchAndSetQuotes.bind(
swapsController.fetchAndSetQuotes,
swapsController, swapsController,
), ),
setSelectedQuoteAggId: nodeify( setSelectedQuoteAggId: swapsController.setSelectedQuoteAggId.bind(
swapsController.setSelectedQuoteAggId,
swapsController, swapsController,
), ),
resetSwapsState: nodeify( resetSwapsState: swapsController.resetSwapsState.bind(swapsController),
swapsController.resetSwapsState, setSwapsTokens: swapsController.setSwapsTokens.bind(swapsController),
clearSwapsQuotes: swapsController.clearSwapsQuotes.bind(swapsController),
setApproveTxId: swapsController.setApproveTxId.bind(swapsController),
setTradeTxId: swapsController.setTradeTxId.bind(swapsController),
setSwapsTxGasPrice: swapsController.setSwapsTxGasPrice.bind(
swapsController, swapsController,
), ),
setSwapsTokens: nodeify(swapsController.setSwapsTokens, swapsController), setSwapsTxGasLimit: swapsController.setSwapsTxGasLimit.bind(
clearSwapsQuotes: nodeify(
swapsController.clearSwapsQuotes,
swapsController, swapsController,
), ),
setApproveTxId: nodeify(swapsController.setApproveTxId, swapsController), setSwapsTxMaxFeePerGas: swapsController.setSwapsTxMaxFeePerGas.bind(
setTradeTxId: nodeify(swapsController.setTradeTxId, swapsController),
setSwapsTxGasPrice: nodeify(
swapsController.setSwapsTxGasPrice,
swapsController, swapsController,
), ),
setSwapsTxGasLimit: nodeify( setSwapsTxMaxFeePriorityPerGas: swapsController.setSwapsTxMaxFeePriorityPerGas.bind(
swapsController.setSwapsTxGasLimit,
swapsController, swapsController,
), ),
setSwapsTxMaxFeePerGas: nodeify( safeRefetchQuotes: swapsController.safeRefetchQuotes.bind(
swapsController.setSwapsTxMaxFeePerGas,
swapsController, swapsController,
), ),
setSwapsTxMaxFeePriorityPerGas: nodeify( stopPollingForQuotes: swapsController.stopPollingForQuotes.bind(
swapsController.setSwapsTxMaxFeePriorityPerGas,
swapsController, swapsController,
), ),
safeRefetchQuotes: nodeify( setBackgroundSwapRouteState: swapsController.setBackgroundSwapRouteState.bind(
swapsController.safeRefetchQuotes,
swapsController, swapsController,
), ),
stopPollingForQuotes: nodeify( resetPostFetchState: swapsController.resetPostFetchState.bind(
swapsController.stopPollingForQuotes,
swapsController, swapsController,
), ),
setBackgroundSwapRouteState: nodeify( setSwapsErrorKey: swapsController.setSwapsErrorKey.bind(swapsController),
swapsController.setBackgroundSwapRouteState, setInitialGasEstimate: swapsController.setInitialGasEstimate.bind(
swapsController, swapsController,
), ),
resetPostFetchState: nodeify( setCustomApproveTxData: swapsController.setCustomApproveTxData.bind(
swapsController.resetPostFetchState,
swapsController, swapsController,
), ),
setSwapsErrorKey: nodeify( setSwapsLiveness: swapsController.setSwapsLiveness.bind(swapsController),
swapsController.setSwapsErrorKey, setSwapsUserFeeLevel: swapsController.setSwapsUserFeeLevel.bind(
swapsController, swapsController,
), ),
setInitialGasEstimate: nodeify( setSwapsQuotesPollingLimitEnabled: swapsController.setSwapsQuotesPollingLimitEnabled.bind(
swapsController.setInitialGasEstimate,
swapsController,
),
setCustomApproveTxData: nodeify(
swapsController.setCustomApproveTxData,
swapsController,
),
setSwapsLiveness: nodeify(
swapsController.setSwapsLiveness,
swapsController,
),
setSwapsUserFeeLevel: nodeify(
swapsController.setSwapsUserFeeLevel,
swapsController,
),
setSwapsQuotesPollingLimitEnabled: nodeify(
swapsController.setSwapsQuotesPollingLimitEnabled,
swapsController, swapsController,
), ),
// MetaMetrics // MetaMetrics
trackMetaMetricsEvent: nodeify( trackMetaMetricsEvent: metaMetricsController.trackEvent.bind(
metaMetricsController.trackEvent,
metaMetricsController, metaMetricsController,
), ),
trackMetaMetricsPage: nodeify( trackMetaMetricsPage: metaMetricsController.trackPage.bind(
metaMetricsController.trackPage,
metaMetricsController, metaMetricsController,
), ),
// approval controller // approval controller
resolvePendingApproval: nodeify( resolvePendingApproval: approvalController.accept.bind(
approvalController.accept,
approvalController,
),
rejectPendingApproval: nodeify(
approvalController.reject,
approvalController, approvalController,
), ),
rejectPendingApproval: approvalController.reject.bind(approvalController),
// Notifications // Notifications
updateViewedNotifications: nodeify( updateViewedNotifications: notificationController.updateViewed.bind(
this.notificationController.updateViewed, notificationController,
this.notificationController,
), ),
// GasFeeController // GasFeeController
getGasFeeEstimatesAndStartPolling: nodeify( getGasFeeEstimatesAndStartPolling: gasFeeController.getGasFeeEstimatesAndStartPolling.bind(
this.gasFeeController.getGasFeeEstimatesAndStartPolling, gasFeeController,
this.gasFeeController,
), ),
disconnectGasFeeEstimatePoller: nodeify( disconnectGasFeeEstimatePoller: gasFeeController.disconnectPoller.bind(
this.gasFeeController.disconnectPoller, gasFeeController,
this.gasFeeController,
), ),
getGasFeeTimeEstimate: nodeify( getGasFeeTimeEstimate: gasFeeController.getTimeEstimate.bind(
this.gasFeeController.getTimeEstimate, gasFeeController,
this.gasFeeController,
), ),
addPollingTokenToAppState: nodeify( addPollingTokenToAppState: appStateController.addPollingToken.bind(
this.appStateController.addPollingToken, appStateController,
this.appStateController,
), ),
removePollingTokenFromAppState: nodeify( removePollingTokenFromAppState: appStateController.removePollingToken.bind(
this.appStateController.removePollingToken, appStateController,
this.appStateController,
), ),
// DetectTokenController // DetectTokenController
detectNewTokens: nodeify( detectNewTokens: detectTokensController.detectNewTokens.bind(
this.detectTokensController.detectNewTokens, detectTokensController,
this.detectTokensController,
), ),
// DetectCollectibleController // DetectCollectibleController
detectCollectibles: process.env.COLLECTIBLES_V1 detectCollectibles: process.env.COLLECTIBLES_V1
? nodeify( ? collectibleDetectionController.detectCollectibles.bind(
this.collectibleDetectionController.detectCollectibles, collectibleDetectionController,
this.collectibleDetectionController,
) )
: null, : null,
}; };
@ -2175,13 +2089,10 @@ export default class MetamaskController extends EventEmitter {
* *
* @param {string} msgId - The id of the message to cancel. * @param {string} msgId - The id of the message to cancel.
*/ */
cancelMessage(msgId, cb) { cancelMessage(msgId) {
const { messageManager } = this; const { messageManager } = this;
messageManager.rejectMsg(msgId); messageManager.rejectMsg(msgId);
if (!cb || typeof cb !== 'function') { return this.getState();
return;
}
cb(null, this.getState());
} }
// personal_sign methods: // personal_sign methods:
@ -2240,15 +2151,11 @@ export default class MetamaskController extends EventEmitter {
/** /**
* Used to cancel a personal_sign type message. * Used to cancel a personal_sign type message.
* @param {string} msgId - The ID of the message to cancel. * @param {string} msgId - The ID of the message to cancel.
* @param {Function} cb - The callback function called with a full state update.
*/ */
cancelPersonalMessage(msgId, cb) { cancelPersonalMessage(msgId) {
const messageManager = this.personalMessageManager; const messageManager = this.personalMessageManager;
messageManager.rejectMsg(msgId); messageManager.rejectMsg(msgId);
if (!cb || typeof cb !== 'function') { return this.getState();
return;
}
cb(null, this.getState());
} }
// eth_decrypt methods // eth_decrypt methods
@ -2332,15 +2239,11 @@ export default class MetamaskController extends EventEmitter {
/** /**
* Used to cancel a eth_decrypt type message. * Used to cancel a eth_decrypt type message.
* @param {string} msgId - The ID of the message to cancel. * @param {string} msgId - The ID of the message to cancel.
* @param {Function} cb - The callback function called with a full state update.
*/ */
cancelDecryptMessage(msgId, cb) { cancelDecryptMessage(msgId) {
const messageManager = this.decryptMessageManager; const messageManager = this.decryptMessageManager;
messageManager.rejectMsg(msgId); messageManager.rejectMsg(msgId);
if (!cb || typeof cb !== 'function') { return this.getState();
return;
}
cb(null, this.getState());
} }
// eth_getEncryptionPublicKey methods // eth_getEncryptionPublicKey methods
@ -2437,15 +2340,11 @@ export default class MetamaskController extends EventEmitter {
/** /**
* Used to cancel a eth_getEncryptionPublicKey type message. * Used to cancel a eth_getEncryptionPublicKey type message.
* @param {string} msgId - The ID of the message to cancel. * @param {string} msgId - The ID of the message to cancel.
* @param {Function} cb - The callback function called with a full state update.
*/ */
cancelEncryptionPublicKey(msgId, cb) { cancelEncryptionPublicKey(msgId) {
const messageManager = this.encryptionPublicKeyManager; const messageManager = this.encryptionPublicKeyManager;
messageManager.rejectMsg(msgId); messageManager.rejectMsg(msgId);
if (!cb || typeof cb !== 'function') { return this.getState();
return;
}
cb(null, this.getState());
} }
// eth_signTypedData methods // eth_signTypedData methods
@ -2507,15 +2406,11 @@ export default class MetamaskController extends EventEmitter {
/** /**
* Used to cancel a eth_signTypedData type message. * Used to cancel a eth_signTypedData type message.
* @param {string} msgId - The ID of the message to cancel. * @param {string} msgId - The ID of the message to cancel.
* @param {Function} cb - The callback function called with a full state update.
*/ */
cancelTypedMessage(msgId, cb) { cancelTypedMessage(msgId) {
const messageManager = this.typedMessageManager; const messageManager = this.typedMessageManager;
messageManager.rejectMsg(msgId); messageManager.rejectMsg(msgId);
if (!cb || typeof cb !== 'function') { return this.getState();
return;
}
cb(null, this.getState());
} }
/** /**
@ -2613,20 +2508,18 @@ export default class MetamaskController extends EventEmitter {
* Allows a user to begin the seed phrase recovery process. * Allows a user to begin the seed phrase recovery process.
* @param {Function} cb - A callback function called when complete. * @param {Function} cb - A callback function called when complete.
*/ */
markPasswordForgotten(cb) { markPasswordForgotten() {
this.preferencesController.setPasswordForgotten(true); this.preferencesController.setPasswordForgotten(true);
this.sendUpdate(); this.sendUpdate();
cb();
} }
/** /**
* Allows a user to end the seed phrase recovery process. * Allows a user to end the seed phrase recovery process.
* @param {Function} cb - A callback function called when complete. * @param {Function} cb - A callback function called when complete.
*/ */
unMarkPasswordForgotten(cb) { unMarkPasswordForgotten() {
this.preferencesController.setPasswordForgotten(false); this.preferencesController.setPasswordForgotten(false);
this.sendUpdate(); this.sendUpdate();
cb();
} }
//============================================================================= //=============================================================================
@ -3320,74 +3213,6 @@ export default class MetamaskController extends EventEmitter {
await this.threeBoxController.init(); await this.threeBoxController.init();
} }
/**
* Sets whether or not to use the blockie identicon format.
* @param {boolean} val - True for bockie, false for jazzicon.
* @param {Function} cb - A callback function called when complete.
*/
setUseBlockie(val, cb) {
try {
this.preferencesController.setUseBlockie(val);
cb(null);
return;
} catch (err) {
cb(err);
// eslint-disable-next-line no-useless-return
return;
}
}
/**
* Sets whether or not to use the nonce field.
* @param {boolean} val - True for nonce field, false for not nonce field.
* @param {Function} cb - A callback function called when complete.
*/
setUseNonceField(val, cb) {
try {
this.preferencesController.setUseNonceField(val);
cb(null);
return;
} catch (err) {
cb(err);
// eslint-disable-next-line no-useless-return
return;
}
}
/**
* Sets whether or not to use phishing detection.
* @param {boolean} val
* @param {Function} cb
*/
setUsePhishDetect(val, cb) {
try {
this.preferencesController.setUsePhishDetect(val);
cb(null);
return;
} catch (err) {
cb(err);
// eslint-disable-next-line no-useless-return
return;
}
}
/**
* Sets the IPFS gateway to use for ENS content resolution.
* @param {string} val - the host of the gateway to set
* @param {Function} cb - A callback function called when complete.
*/
setIpfsGateway(val, cb) {
try {
this.preferencesController.setIpfsGateway(val);
cb(null);
return;
} catch (err) {
cb(err);
// eslint-disable-next-line no-useless-return
return;
}
}
/** /**
* Sets the Ledger Live preference to use for Ledger hardware wallet support * Sets the Ledger Live preference to use for Ledger hardware wallet support
* @param {bool} bool - the value representing if the users wants to use Ledger Live * @param {bool} bool - the value representing if the users wants to use Ledger Live
@ -3411,42 +3236,6 @@ export default class MetamaskController extends EventEmitter {
return undefined; return undefined;
} }
/**
* Sets whether or not the user will have usage data tracked with MetaMetrics
* @param {boolean} bool - True for users that wish to opt-in, false for users that wish to remain out.
* @param {Function} cb - A callback function called when complete.
*/
setParticipateInMetaMetrics(bool, cb) {
try {
const metaMetricsId = this.metaMetricsController.setParticipateInMetaMetrics(
bool,
);
cb(null, metaMetricsId);
return;
} catch (err) {
cb(err);
// eslint-disable-next-line no-useless-return
return;
}
}
/**
* A method for setting a user's current locale, affecting the language rendered.
* @param {string} key - Locale identifier.
* @param {Function} cb - A callback function called when complete.
*/
setCurrentLocale(key, cb) {
try {
const direction = this.preferencesController.setCurrentLocale(key);
cb(null, direction);
return;
} catch (err) {
cb(err);
// eslint-disable-next-line no-useless-return
return;
}
}
/** /**
* A method for initializing storage the first time. * A method for initializing storage the first time.
* @param {Object} initState - The default state to initialize with. * @param {Object} initState - The default state to initialize with.

View File

@ -33,22 +33,32 @@ const firstTimeState = {
const ganacheServer = new Ganache(); const ganacheServer = new Ganache();
const threeBoxSpies = { const threeBoxSpies = {
init: sinon.stub(),
getThreeBoxSyncingState: sinon.stub().returns(true),
turnThreeBoxSyncingOn: sinon.stub(),
_registerUpdates: sinon.spy(), _registerUpdates: sinon.spy(),
init: sinon.stub(),
getLastUpdated: sinon.stub(),
getThreeBoxSyncingState: sinon.stub().returns(true),
restoreFromThreeBox: sinon.stub(),
setShowRestorePromptToFalse: sinon.stub(),
setThreeBoxSyncingPermission: sinon.stub(),
turnThreeBoxSyncingOn: sinon.stub(),
}; };
class ThreeBoxControllerMock { class ThreeBoxControllerMock {
constructor() { constructor() {
this._registerUpdates = threeBoxSpies._registerUpdates;
this.init = threeBoxSpies.init;
this.getLastUpdated = threeBoxSpies.getLastUpdated;
this.getThreeBoxSyncingState = threeBoxSpies.getThreeBoxSyncingState;
this.restoreFromThreeBox = threeBoxSpies.restoreFromThreeBox;
this.setShowRestorePromptToFalse =
threeBoxSpies.setShowRestorePromptToFalse;
this.setThreeBoxSyncingPermission =
threeBoxSpies.setThreeBoxSyncingPermission;
this.store = { this.store = {
subscribe: () => undefined, subscribe: () => undefined,
getState: () => ({}), getState: () => ({}),
}; };
this.init = threeBoxSpies.init;
this.getThreeBoxSyncingState = threeBoxSpies.getThreeBoxSyncingState;
this.turnThreeBoxSyncingOn = threeBoxSpies.turnThreeBoxSyncingOn; this.turnThreeBoxSyncingOn = threeBoxSpies.turnThreeBoxSyncingOn;
this._registerUpdates = threeBoxSpies._registerUpdates;
} }
} }
@ -423,35 +433,10 @@ describe('MetaMaskController', function () {
}); });
describe('#getApi', function () { describe('#getApi', function () {
it('getState', function (done) { it('getState', function () {
let state;
const getApi = metamaskController.getApi(); const getApi = metamaskController.getApi();
getApi.getState((err, res) => { const state = getApi.getState();
if (err) {
done(err);
} else {
state = res;
}
});
assert.deepEqual(state, metamaskController.getState()); assert.deepEqual(state, metamaskController.getState());
done();
});
});
describe('preferencesController', function () {
it('defaults useBlockie to false', function () {
assert.equal(
metamaskController.preferencesController.store.getState().useBlockie,
false,
);
});
it('setUseBlockie to true', function () {
metamaskController.setUseBlockie(true, noop);
assert.equal(
metamaskController.preferencesController.store.getState().useBlockie,
true,
);
}); });
}); });
@ -813,21 +798,6 @@ describe('MetaMaskController', function () {
}); });
}); });
describe('#setCurrentLocale', function () {
it('checks the default currentLocale', function () {
const preferenceCurrentLocale = metamaskController.preferencesController.store.getState()
.currentLocale;
assert.equal(preferenceCurrentLocale, 'en_US');
});
it('sets current locale in preferences controller', function () {
metamaskController.setCurrentLocale('ja', noop);
const preferenceCurrentLocale = metamaskController.preferencesController.store.getState()
.currentLocale;
assert.equal(preferenceCurrentLocale, 'ja');
});
});
describe('#newUnsignedMessage', function () { describe('#newUnsignedMessage', function () {
let msgParams, metamaskMsgs, messages, msgId; let msgParams, metamaskMsgs, messages, msgId;

View File

@ -1485,23 +1485,20 @@ describe('Actions', () => {
it('calls setUseBlockie in background', async () => { it('calls setUseBlockie in background', async () => {
const store = mockStore(); const store = mockStore();
const setUseBlockieStub = sinon.stub().callsFake((_, cb) => cb());
const setUseBlockStub = background.setUseBlockie.callsFake((_, cb) => actions._setBackgroundConnection({ setUseBlockie: setUseBlockieStub });
cb(),
);
actions._setBackgroundConnection(background);
await store.dispatch(actions.setUseBlockie()); await store.dispatch(actions.setUseBlockie());
expect(setUseBlockStub.callCount).toStrictEqual(1); expect(setUseBlockieStub.callCount).toStrictEqual(1);
}); });
it('errors when setUseBlockie in background throws', async () => { it('errors when setUseBlockie in background throws', async () => {
const store = mockStore(); const store = mockStore();
const setUseBlockieStub = sinon.stub().callsFake((_, cb) => {
cb(new Error('error'));
});
background.setUseBlockie.callsFake((_, cb) => cb(new Error('error'))); actions._setBackgroundConnection({ setUseBlockie: setUseBlockieStub });
actions._setBackgroundConnection(background);
const expectedActions = [ const expectedActions = [
{ type: 'SHOW_LOADING_INDICATION', value: undefined }, { type: 'SHOW_LOADING_INDICATION', value: undefined },
@ -1528,10 +1525,10 @@ describe('Actions', () => {
it('calls expected actions', async () => { it('calls expected actions', async () => {
const store = mockStore(); const store = mockStore();
const setCurrentLocaleStub = sinon.stub().callsFake((_, cb) => cb());
background.setCurrentLocale.callsFake((_, cb) => cb()); actions._setBackgroundConnection({
setCurrentLocale: setCurrentLocaleStub,
actions._setBackgroundConnection(background); });
const expectedActions = [ const expectedActions = [
{ type: 'SHOW_LOADING_INDICATION', value: undefined }, { type: 'SHOW_LOADING_INDICATION', value: undefined },
@ -1543,16 +1540,18 @@ describe('Actions', () => {
]; ];
await store.dispatch(actions.updateCurrentLocale('test')); await store.dispatch(actions.updateCurrentLocale('test'));
expect(background.setCurrentLocale.callCount).toStrictEqual(1); expect(setCurrentLocaleStub.callCount).toStrictEqual(1);
expect(store.getActions()).toStrictEqual(expectedActions); expect(store.getActions()).toStrictEqual(expectedActions);
}); });
it('errors when setCurrentLocale throws', async () => { it('errors when setCurrentLocale throws', async () => {
const store = mockStore(); const store = mockStore();
const setCurrentLocaleStub = sinon
background.setCurrentLocale.callsFake((_, cb) => cb(new Error('error'))); .stub()
.callsFake((_, cb) => cb(new Error('error')));
actions._setBackgroundConnection(background); actions._setBackgroundConnection({
setCurrentLocale: setCurrentLocaleStub,
});
const expectedActions = [ const expectedActions = [
{ type: 'SHOW_LOADING_INDICATION', value: undefined }, { type: 'SHOW_LOADING_INDICATION', value: undefined },