1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-01 21:57:06 +01:00
metamask-extension/ui/ducks/metamask/metamask.test.js

423 lines
12 KiB
JavaScript
Raw Normal View History

import { NetworkType } from '@metamask/controller-utils';
import { NetworkStatus } from '@metamask/network-controller';
import { TransactionStatus } from '../../../shared/constants/transaction';
import * as actionConstants from '../../store/actionConstants';
import reduceMetamask, {
getBlockGasLimit,
getConversionRate,
getIsNetworkBusy,
getNativeCurrency,
getSendHexDataFeatureFlagState,
getSendToAccounts,
getUnapprovedTxs,
isNotEIP1559Network,
} from './metamask';
2018-10-10 10:12:46 +02:00
describe('MetaMask Reducers', () => {
const mockState = {
metamask: reduceMetamask(
{
isInitialized: true,
isUnlocked: true,
featureFlags: { sendHexData: true },
identities: {
'0xfdea65c8e26263f6d9a1b5de9555d2931a33b825': {
address: '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825',
name: 'Send Account 1',
},
'0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb': {
address: '0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb',
name: 'Send Account 2',
},
'0x2f8d4a878cfa04a6e60d46362f5644deab66572d': {
address: '0x2f8d4a878cfa04a6e60d46362f5644deab66572d',
name: 'Send Account 3',
},
'0xd85a4b6a394794842887b8284293d69163007bbb': {
address: '0xd85a4b6a394794842887b8284293d69163007bbb',
name: 'Send Account 4',
},
},
cachedBalances: {},
currentBlockGasLimit: '0x4c1878',
conversionRate: 1200.88200327,
nativeCurrency: 'ETH',
useCurrencyRateCheck: true,
NetworkController: Split `network` into `networkId` and `networkStatus` (#17556) The `network` store of the network controller crams two types of data into one place. It roughly tracks whether we have enough information to make requests to the network and whether the network is capable of receiving requests, but it also stores the ID of the network (as obtained via `net_version`). Generally we shouldn't be using the network ID for anything, as it has been completely replaced by chain ID, which all custom RPC endpoints have been required to support for over a year now. However, as the network ID is used in various places within the extension codebase, removing it entirely would be a non-trivial effort. So, minimally, this commit splits `network` into two stores: `networkId` and `networkStatus`. But it also expands the concept of network status. Previously, the network was in one of two states: "loading" and "not-loading". But now it can be in one of four states: - `available`: The network is able to receive and respond to requests. - `unavailable`: The network is not able to receive and respond to requests for unknown reasons. - `blocked`: The network is actively blocking requests based on the user's geolocation. (This is specific to Infura.) - `unknown`: We don't know whether the network can receive and respond to requests, either because we haven't checked or we tried to check and were unsuccessful. This commit also changes how the network status is determined — specifically, how many requests are used to determine that status, when they occur, and whether they are awaited. Previously, the network controller would make 2 to 3 requests during the course of running `lookupNetwork`. * First, if it was an Infura network, it would make a request for `eth_blockNumber` to determine whether Infura was blocking requests or not, then emit an appropriate event. This operation was not awaited. * Then, regardless of the network, it would fetch the network ID via `net_version`. This operation was awaited. * Finally, regardless of the network, it would fetch the latest block via `eth_getBlockByNumber`, then use the result to determine whether the network supported EIP-1559. This operation was awaited. Now: * One fewer request is made, specifically `eth_blockNumber`, as we don't need to make an extra request to determine whether Infura is blocking requests; we can reuse `eth_getBlockByNumber`; * All requests are awaited, which makes `lookupNetwork` run fully in-band instead of partially out-of-band; and * Both requests for `net_version` and `eth_getBlockByNumber` are performed in parallel to make `lookupNetwork` run slightly faster.
2023-03-31 00:49:12 +02:00
networkId: '5',
selectedNetworkClientId: NetworkType.goerli,
networksMetadata: {
[NetworkType.goerli]: {
EIPS: {},
status: NetworkStatus.Available,
},
},
providerConfig: {
type: 'testnet',
chainId: '0x5',
ticker: 'TestETH',
},
accounts: {
'0xfdea65c8e26263f6d9a1b5de9555d2931a33b825': {
code: '0x',
balance: '0x47c9d71831c76efe',
nonce: '0x1b',
address: '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825',
},
'0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb': {
code: '0x',
balance: '0x37452b1315889f80',
nonce: '0xa',
address: '0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb',
},
'0x2f8d4a878cfa04a6e60d46362f5644deab66572d': {
code: '0x',
balance: '0x30c9d71831c76efe',
nonce: '0x1c',
address: '0x2f8d4a878cfa04a6e60d46362f5644deab66572d',
},
'0xd85a4b6a394794842887b8284293d69163007bbb': {
code: '0x',
balance: '0x0',
nonce: '0x0',
address: '0xd85a4b6a394794842887b8284293d69163007bbb',
},
},
addressBook: {
'0x5': {
'0x06195827297c7a80a443b6894d3bdb8824b43896': {
address: '0x06195827297c7a80a443b6894d3bdb8824b43896',
name: 'Address Book Account 1',
chainId: '0x5',
},
},
},
unapprovedTxs: {
4768706228115573: {
id: 4768706228115573,
time: 1487363153561,
status: TransactionStatus.unapproved,
gasMultiplier: 1,
metamaskNetworkId: '5',
txParams: {
from: '0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb',
to: '0x18a3462427bcc9133bb46e88bcbe39cd7ef0e761',
value: '0xde0b6b3a7640000',
metamaskId: 4768706228115573,
metamaskNetworkId: '5',
gas: '0x5209',
},
txFee: '17e0186e60800',
txValue: 'de0b6b3a7640000',
maxCost: 'de234b52e4a0800',
gasPrice: '4a817c800',
},
},
},
{},
),
};
it('init state', () => {
const initState = reduceMetamask(undefined, {});
expect.anything(initState);
});
2018-10-10 10:12:46 +02:00
it('locks MetaMask', () => {
const unlockMetaMaskState = {
isUnlocked: true,
selectedAddress: 'test address',
};
2018-10-10 10:12:46 +02:00
const lockMetaMask = reduceMetamask(unlockMetaMaskState, {
type: actionConstants.LOCK_METAMASK,
});
2018-10-10 10:12:46 +02:00
expect(lockMetaMask.isUnlocked).toStrictEqual(false);
});
2018-10-10 10:12:46 +02:00
it('sets account label', () => {
2020-11-03 00:41:28 +01:00
const state = reduceMetamask(
{},
{
type: actionConstants.SET_ACCOUNT_LABEL,
value: {
account: 'test account',
label: 'test label',
},
2018-10-10 10:12:46 +02:00
},
);
2018-10-10 10:12:46 +02:00
expect(state.identities).toStrictEqual({
2020-11-03 00:41:28 +01:00
'test account': { name: 'test label' },
});
});
2018-10-10 10:12:46 +02:00
it('toggles account menu', () => {
2020-11-03 00:41:28 +01:00
const state = reduceMetamask(
{},
{
type: actionConstants.TOGGLE_ACCOUNT_MENU,
},
);
2018-10-10 10:12:46 +02:00
expect(state.isAccountMenuOpen).toStrictEqual(true);
});
2018-10-10 10:12:46 +02:00
it('toggles network menu', () => {
const state = reduceMetamask(
{},
{
type: actionConstants.TOGGLE_NETWORK_MENU,
},
);
expect(state.isNetworkMenuOpen).toStrictEqual(true);
});
it('updates value of tx by id', () => {
2018-10-10 10:12:46 +02:00
const oldState = {
currentNetworkTxList: [
{
id: 1,
txParams: 'foo',
},
],
};
2018-10-10 10:12:46 +02:00
const state = reduceMetamask(oldState, {
type: actionConstants.UPDATE_TRANSACTION_PARAMS,
2018-10-10 10:12:46 +02:00
id: 1,
value: 'bar',
});
2018-10-10 10:12:46 +02:00
expect(state.currentNetworkTxList[0].txParams).toStrictEqual('bar');
});
2018-10-10 10:12:46 +02:00
it('close welcome screen', () => {
2020-11-03 00:41:28 +01:00
const state = reduceMetamask(
{},
{
type: actionConstants.CLOSE_WELCOME_SCREEN,
},
);
2018-10-10 10:12:46 +02:00
expect(state.welcomeScreenSeen).toStrictEqual(true);
});
2018-10-10 10:12:46 +02:00
it('sets pending tokens', () => {
2018-10-10 10:12:46 +02:00
const payload = {
2020-11-03 00:41:28 +01:00
address: '0x617b3f8050a0bd94b6b1da02b4384ee5b4df13f4',
decimals: 18,
symbol: 'META',
};
2018-10-10 10:12:46 +02:00
2020-11-03 00:41:28 +01:00
const pendingTokensState = reduceMetamask(
{},
{
type: actionConstants.SET_PENDING_TOKENS,
payload,
},
);
2018-10-10 10:12:46 +02:00
expect(pendingTokensState.pendingTokens).toStrictEqual(payload);
});
2018-10-10 10:12:46 +02:00
it('clears pending tokens', () => {
const payload = {
2020-11-03 00:41:28 +01:00
address: '0x617b3f8050a0bd94b6b1da02b4384ee5b4df13f4',
decimals: 18,
symbol: 'META',
};
const pendingTokensState = {
pendingTokens: payload,
};
2018-10-10 10:12:46 +02:00
const state = reduceMetamask(pendingTokensState, {
type: actionConstants.CLEAR_PENDING_TOKENS,
});
2018-10-10 10:12:46 +02:00
expect(state.pendingTokens).toStrictEqual({});
});
Address book send plus contact list (#6914) * Style Send Header * Move Send to-row to send view and restyle * Add "Recents" group to select recipient view * Rename SendToRow to AddRecipient * Basic UI and Layout * New ENSInput component * wip - fuzzy search for input * small refactor * Add Dialog * contact list initial * initial error on invalid address * clean up edit * Click to open modal * Create AddToAddressBookModal component * Modal styling and layout * modal i18n * Add to Addressbook * ens wip * ens wip * ENS Resolution * Reset input * Send to explicit address * Happy Path Complete * Add back error checking * Reset send-to when emptying input * Add back warning object * Fix linter * Fix unit test #1 - fix import paths * Remove dead tests * One more to go * Fix all unit tests * add unit test for reducers and actions * test rendering AddRecipient * Add tests for dialog boxes in AddRecipient * Add test for validating * Fix linter * Fix e2e tests * Token send e2e fix * Style View Contact * Style edit-contact * Fix e2e * Fix from-import-beta-ui e2e spec * Make section header say "add recipient” by default * Auto-focus add recipient input * Update placeholder text * Update input title font size * Auto advance to next step if user paste a valid address * Ellipsify address when recipient is selected * Fix app header background color on desktop * Give each form row a margin of 16px * Use .container/.component naming pattern for ens-input * Auto-focus on input when add to addressbook modal is opened; Save on Enter * Fix and add unit test * Fix selectors name in e2e tests * Correct e2e test token amount for address-book-send changes * Adds e2e test for editing a transaction * Delete test/integration/lib/send-new-ui.js * Add tests for amount max button and high value error on send screen to test/e2e/metamask-ui.spec.js * lint and revert to address as object keys * add chainId based on current network to address book entry * fix test * only display contacts for the current network * Improve ENS message when not found on current network * Add error to indicate when network does not support ENS * bump gaba * address book, resolve comments * Move contact-list to its own component * De-duplicate getaddressbook selector and refactor name selection logic in contact-list-tab/ * Use contact-list component in contact-list-tab.component (i.e. in settings) * Improve/fix settings headers for popup and browser views * Lint fixes related to address book updates * Add 'My accounts' page to settings address book * Update add new contact button in settings to match floating circular design * Improve styles of view contact page * Improve styles and labels of the add-contact.component * Further lint fixes related to address book updates * Update unit tests as per address book updates * Ensure that contact list groups are sorted alphabetically * Refactor settings component to use a container for connection to redux; allow display of addressbook name in settings header * Decouple ens-input.component from send context * Add ens resolution to add contact screen in settings * Switching networks when an ens address is shown on send form removes the ens address. * Resolve send screen search for ensAddress to matching address book entry if it exists * Show resolved ens icon and address if exists (settings: add-contact.component) * Make the displayed and copied address in view-contact.component the checksummed address * Default alias state prop in AddToAddressBookModal to empty string * Use keyCode to detect enter key in AddToAddressBookModal * Ensure add-contact component properly updates after QR code detection * Fix display of all recents after clicking 'Load More' in contact list * Fix send screen contact searching after network switching * Code cleanup related to address book changes * Update unit tests for address book changes * Update ENS name not found on network message * Add ens registration error message * Cancel on edit mode takes user back to view screen * Adds support for memo to settings contact list view and edit screens * Modify designs of edit and view contact in popup environment * Update settings content list UX to show split columns in fullscreen and proper internal navigation * Correct background address book API usages in UI
2019-07-31 21:56:44 +02:00
it('disables desktop', () => {
const enabledMetaMaskState = {
desktopEnabled: true,
};
const enabledDesktopMetaMask = reduceMetamask(enabledMetaMaskState, {
type: actionConstants.FORCE_DISABLE_DESKTOP,
});
expect(enabledDesktopMetaMask.desktopEnabled).toStrictEqual(false);
});
describe('metamask state selectors', () => {
describe('getBlockGasLimit', () => {
it('should return the current block gas limit', () => {
expect(getBlockGasLimit(mockState)).toStrictEqual('0x4c1878');
});
});
describe('getConversionRate()', () => {
it('should return the eth conversion rate', () => {
expect(getConversionRate(mockState)).toStrictEqual(1200.88200327);
});
});
describe('getNativeCurrency()', () => {
it('should return nativeCurrency when useCurrencyRateCheck is true', () => {
expect(getNativeCurrency(mockState)).toStrictEqual('ETH');
});
it('should return the ticker symbol of the selected network when useCurrencyRateCheck is false', () => {
expect(
getNativeCurrency({
...mockState,
metamask: {
...mockState.metamask,
useCurrencyRateCheck: false,
},
}),
).toStrictEqual('TestETH');
});
});
describe('getSendHexDataFeatureFlagState()', () => {
it('should return the sendHexData feature flag state', () => {
expect(getSendHexDataFeatureFlagState(mockState)).toStrictEqual(true);
});
});
describe('getSendToAccounts()', () => {
it('should return an array including all the users accounts and the address book', () => {
expect(getSendToAccounts(mockState)).toStrictEqual([
{
code: '0x',
balance: '0x47c9d71831c76efe',
nonce: '0x1b',
address: '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825',
name: 'Send Account 1',
},
{
code: '0x',
balance: '0x37452b1315889f80',
nonce: '0xa',
address: '0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb',
name: 'Send Account 2',
},
{
code: '0x',
balance: '0x30c9d71831c76efe',
nonce: '0x1c',
address: '0x2f8d4a878cfa04a6e60d46362f5644deab66572d',
name: 'Send Account 3',
},
{
code: '0x',
balance: '0x0',
nonce: '0x0',
address: '0xd85a4b6a394794842887b8284293d69163007bbb',
name: 'Send Account 4',
},
{
address: '0x06195827297c7a80a443b6894d3bdb8824b43896',
name: 'Address Book Account 1',
chainId: '0x5',
},
]);
});
});
it('should return the unapproved txs', () => {
expect(getUnapprovedTxs(mockState)).toStrictEqual({
4768706228115573: {
id: 4768706228115573,
time: 1487363153561,
status: TransactionStatus.unapproved,
gasMultiplier: 1,
metamaskNetworkId: '5',
txParams: {
from: '0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb',
to: '0x18a3462427bcc9133bb46e88bcbe39cd7ef0e761',
value: '0xde0b6b3a7640000',
metamaskId: 4768706228115573,
metamaskNetworkId: '5',
gas: '0x5209',
},
txFee: '17e0186e60800',
txValue: 'de0b6b3a7640000',
maxCost: 'de234b52e4a0800',
gasPrice: '4a817c800',
},
});
});
});
describe('isNotEIP1559Network()', () => {
it('should return true if network does not supports EIP-1559', () => {
expect(
isNotEIP1559Network({
...mockState,
metamask: {
...mockState.metamask,
selectedNetworkClientId: NetworkType.mainnet,
networksMetadata: {
[NetworkType.mainnet]: {
EIPS: {
1559: false,
},
status: 'available',
},
},
},
}),
).toStrictEqual(true);
});
it('should return false if networksMetadata[selectedNetworkClientId].EIPS.1559 is not false', () => {
expect(isNotEIP1559Network(mockState)).toStrictEqual(false);
expect(
isNotEIP1559Network({
...mockState,
metamask: {
...mockState.metamask,
selectedNetworkClientId: NetworkType.mainnet,
networksMetadata: {
[NetworkType.mainnet]: {
EIPS: { 1559: true },
status: 'available',
},
},
},
}),
).toStrictEqual(false);
});
});
describe('getIsNetworkBusy', () => {
it('should return true if state.metamask.gasFeeEstimates.networkCongestion is over the "busy" threshold', () => {
expect(
getIsNetworkBusy({
metamask: { gasFeeEstimates: { networkCongestion: 0.67 } },
}),
).toBe(true);
});
it('should return true if state.metamask.gasFeeEstimates.networkCongestion is right at the "busy" threshold', () => {
expect(
getIsNetworkBusy({
metamask: { gasFeeEstimates: { networkCongestion: 0.66 } },
}),
).toBe(true);
});
it('should return false if state.metamask.gasFeeEstimates.networkCongestion is not over the "busy" threshold', () => {
expect(
getIsNetworkBusy({
metamask: { gasFeeEstimates: { networkCongestion: 0.65 } },
}),
).toBe(false);
});
});
});