1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-27 04:46:10 +01:00
metamask-extension/ui/pages/confirm-transaction-base/transaction-alerts/transaction-alerts.test.js
Elliot Winkler 7b963cabd7
Alert users when the network is busy (#12268)
When a lot of transactions are occurring on the network, such as during
an NFT drop, it drives gas fees up. When this happens, we want to not
only inform the user about this, but also dissuade them from using a
higher gas fee (as we have proved in testing that high gas fees can
cause bidding wars and exacerbate the situation).

The method for determining whether the network is "busy" is already
handled by GasFeeController, which exposes a `networkCongestion`
property within the gas fee estimate data. If this number exceeds 0.66 —
meaning that the current base fee is above the 66th percentile among the
base fees over the last several days — then we determine that the
network is "busy".
2022-01-07 12:18:02 -07:00

308 lines
10 KiB
JavaScript

import React from 'react';
import { fireEvent } from '@testing-library/react';
import { renderWithProvider } from '../../../../test/jest';
import { submittedPendingTransactionsSelector } from '../../../selectors/transactions';
import { useGasFeeContext } from '../../../contexts/gasFee';
import configureStore from '../../../store/store';
import TransactionAlerts from './transaction-alerts';
jest.mock('../../../selectors/transactions', () => {
return {
...jest.requireActual('../../../selectors/transactions'),
submittedPendingTransactionsSelector: jest.fn(),
};
});
jest.mock('../../../contexts/gasFee');
function render({
componentProps = {},
useGasFeeContextValue = {},
submittedPendingTransactionsSelectorValue = null,
}) {
useGasFeeContext.mockReturnValue(useGasFeeContextValue);
submittedPendingTransactionsSelector.mockReturnValue(
submittedPendingTransactionsSelectorValue,
);
const store = configureStore({});
return renderWithProvider(<TransactionAlerts {...componentProps} />, store);
}
describe('TransactionAlerts', () => {
describe('when supportsEIP1559V2 from useGasFeeContext is truthy', () => {
describe('if hasSimulationError from useGasFeeContext is true', () => {
it('informs the user that a simulation of the transaction failed', () => {
const { getByText } = render({
useGasFeeContextValue: {
supportsEIP1559V2: true,
hasSimulationError: true,
},
});
expect(
getByText(
'We were not able to estimate gas. There might be an error in the contract and this transaction may fail.',
),
).toBeInTheDocument();
});
describe('if the user has not acknowledged the failure', () => {
it('offers the user an option to bypass the warning', () => {
const { getByText } = render({
useGasFeeContextValue: {
supportsEIP1559V2: true,
hasSimulationError: true,
},
});
expect(getByText('I want to proceed anyway')).toBeInTheDocument();
});
it('calls setUserAcknowledgedGasMissing if the user bypasses the warning', () => {
const setUserAcknowledgedGasMissing = jest.fn();
const { getByText } = render({
useGasFeeContextValue: {
supportsEIP1559V2: true,
hasSimulationError: true,
},
componentProps: { setUserAcknowledgedGasMissing },
});
fireEvent.click(getByText('I want to proceed anyway'));
expect(setUserAcknowledgedGasMissing).toHaveBeenCalled();
});
});
describe('if the user has already acknowledged the failure', () => {
it('does not offer the user an option to bypass the warning', () => {
const { queryByText } = render({
useGasFeeContextValue: {
supportsEIP1559V2: true,
hasSimulationError: true,
},
componentProps: { userAcknowledgedGasMissing: true },
});
expect(
queryByText('I want to proceed anyway'),
).not.toBeInTheDocument();
});
});
});
describe('if hasSimulationError from useGasFeeContext is falsy', () => {
it('does not inform the user that a simulation of the transaction failed', () => {
const { queryByText } = render({
useGasFeeContextValue: {
supportsEIP1559V2: true,
},
});
expect(
queryByText(
'We were not able to estimate gas. There might be an error in the contract and this transaction may fail.',
),
).not.toBeInTheDocument();
});
});
describe('if the length of pendingTransactions is 1', () => {
it('informs the user that they have a pending transaction', () => {
const { getByText } = render({
useGasFeeContextValue: { supportsEIP1559V2: true },
submittedPendingTransactionsSelectorValue: [{ some: 'transaction' }],
});
expect(
getByText('You have (1) pending transaction.'),
).toBeInTheDocument();
});
});
describe('if the length of pendingTransactions is more than 1', () => {
it('informs the user that they have pending transactions', () => {
const { getByText } = render({
useGasFeeContextValue: { supportsEIP1559V2: true },
submittedPendingTransactionsSelectorValue: [
{ some: 'transaction' },
{ some: 'transaction' },
],
});
expect(
getByText('You have (2) pending transactions.'),
).toBeInTheDocument();
});
});
describe('if the length of pendingTransactions is 0', () => {
it('does not inform the user that they have pending transactions', () => {
const { queryByText } = render({
useGasFeeContextValue: { supportsEIP1559V2: true },
submittedPendingTransactionsSelectorValue: [],
});
expect(
queryByText('You have (0) pending transactions.'),
).not.toBeInTheDocument();
});
});
describe('if balanceError from useGasFeeContext is true', () => {
it('informs the user that they have insufficient funds', () => {
const { getByText } = render({
useGasFeeContextValue: {
supportsEIP1559V2: true,
balanceError: true,
},
});
expect(getByText('Insufficient funds.')).toBeInTheDocument();
});
});
describe('if balanceError from useGasFeeContext is falsy', () => {
it('does not inform the user that they have insufficient funds', () => {
const { queryByText } = render({
useGasFeeContextValue: {
supportsEIP1559V2: true,
balanceError: false,
},
});
expect(queryByText('Insufficient funds.')).not.toBeInTheDocument();
});
});
describe('if estimateUsed from useGasFeeContext is "low"', () => {
it('informs the user that the current transaction is queued', () => {
const { getByText } = render({
useGasFeeContextValue: {
supportsEIP1559V2: true,
estimateUsed: 'low',
},
});
expect(
getByText(
'Future transactions will queue after this one. This price was last seen was some time ago.',
),
).toBeInTheDocument();
});
});
describe('if estimateUsed from useGasFeeContext is not "low"', () => {
it('does not inform the user that the current transaction is queued', () => {
const { queryByText } = render({
useGasFeeContextValue: {
supportsEIP1559V2: true,
estimateUsed: 'something_else',
},
});
expect(
queryByText(
'Future transactions will queue after this one. This price was last seen was some time ago.',
),
).not.toBeInTheDocument();
});
});
describe('if isNetworkBusy from useGasFeeContext is truthy', () => {
it('informs the user that the network is busy', () => {
const { getByText } = render({
useGasFeeContextValue: {
supportsEIP1559V2: true,
isNetworkBusy: true,
},
});
expect(
getByText(
'Network is busy. Gas prices are high and estimates are less accurate.',
),
).toBeInTheDocument();
});
});
describe('if isNetworkBusy from useGasFeeContext is falsy', () => {
it('does not inform the user that the network is busy', () => {
const { queryByText } = render({
useGasFeeContextValue: {
supportsEIP1559V2: true,
isNetworkBusy: false,
},
});
expect(
queryByText(
'Network is busy. Gas prices are high and estimates are less accurate.',
),
).not.toBeInTheDocument();
});
});
});
describe('when supportsEIP1559V2 from useGasFeeContext is falsy', () => {
describe('if hasSimulationError from useGasFeeContext is true', () => {
it('does not inform the user that a simulation of the transaction failed', () => {
const { queryByText } = render({
useGasFeeContextValue: {
supportsEIP1559V2: false,
hasSimulationError: true,
},
});
expect(
queryByText(
'We were not able to estimate gas. There might be an error in the contract and this transaction may fail.',
),
).not.toBeInTheDocument();
});
});
describe('if the length of pendingTransactions is at least 1', () => {
it('informs the user that they have a pending transaction', () => {
const { queryByText } = render({
useGasFeeContextValue: { supportsEIP1559V2: false },
submittedPendingTransactionsSelectorValue: [{ some: 'transaction' }],
});
expect(
queryByText('You have (1) pending transaction.'),
).not.toBeInTheDocument();
});
});
describe('if balanceError from useGasFeeContext is true', () => {
it('informs the user that they have insufficient funds', () => {
const { queryByText } = render({
useGasFeeContextValue: {
supportsEIP1559V2: false,
balanceError: true,
},
});
expect(queryByText('Insufficient funds.')).not.toBeInTheDocument();
});
});
describe('if estimateUsed from useGasFeeContext is "low"', () => {
it('informs the user that the current transaction is queued', () => {
const { queryByText } = render({
useGasFeeContextValue: {
supportsEIP1559V2: false,
estimateUsed: 'low',
},
});
expect(
queryByText(
'Future transactions will queue after this one. This price was last seen was some time ago.',
),
).not.toBeInTheDocument();
});
});
describe('if isNetworkBusy from useGasFeeContext is truthy', () => {
it('does not inform the user that the network is busy', () => {
const { queryByText } = render({
useGasFeeContextValue: {
supportsEIP1559V2: false,
isNetworkBusy: true,
},
});
expect(
queryByText(
'Network is busy. Gas prices are high and estimates are less accurate.',
),
).not.toBeInTheDocument();
});
});
});
});