1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-22 09:57:02 +01:00

Legacy transactions to use old transaction flow (#12782)

This commit is contained in:
Jyoti Puri 2021-11-29 21:38:24 +05:30 committed by GitHub
parent e8b7fcf8dc
commit 0e0e7ac830
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 264 additions and 95 deletions

View File

@ -0,0 +1,27 @@
{
"fee-market": {
"gasEstimateType": "fee-market",
"gasFeeEstimates": {
"low": {
"minWaitTimeEstimate": 180000,
"maxWaitTimeEstimate": 300000,
"suggestedMaxPriorityFeePerGas": "3",
"suggestedMaxFeePerGas": "53"
},
"medium": {
"minWaitTimeEstimate": 15000,
"maxWaitTimeEstimate": 60000,
"suggestedMaxPriorityFeePerGas": "7",
"suggestedMaxFeePerGas": "70"
},
"high": {
"minWaitTimeEstimate": 0,
"maxWaitTimeEstimate": 15000,
"suggestedMaxPriorityFeePerGas": "10",
"suggestedMaxFeePerGas": "100"
},
"estimatedBaseFee": "50"
},
"estimatedGasFeeTimeBounds": {}
}
}

View File

@ -7,9 +7,6 @@ import ActionableMessage from '../../../ui/actionable-message/actionable-message
import { PageContainerFooter } from '../../../ui/page-container';
import { ConfirmPageContainerSummary, ConfirmPageContainerWarning } from '.';
// eslint-disable-next-line prefer-destructuring
const EIP_1559_V2 = process.env.EIP_1559_V2;
export default class ConfirmPageContainerContent extends Component {
static contextTypes = {
t: PropTypes.func.isRequired,
@ -42,7 +39,8 @@ export default class ConfirmPageContainerContent extends Component {
hideUserAcknowledgedGasMissing: PropTypes.bool,
unapprovedTxCount: PropTypes.number,
rejectNText: PropTypes.string,
hideTitle: PropTypes.boolean,
hideTitle: PropTypes.bool,
supportsEIP1559V2: PropTypes.bool,
};
renderContent() {
@ -101,6 +99,7 @@ export default class ConfirmPageContainerContent extends Component {
hideTitle,
setUserAcknowledgedGasMissing,
hideUserAcknowledgedGasMissing,
supportsEIP1559V2,
} = this.props;
const primaryAction = hideUserAcknowledgedGasMissing
@ -141,7 +140,9 @@ export default class ConfirmPageContainerContent extends Component {
hideTitle={hideTitle}
/>
{this.renderContent()}
{!EIP_1559_V2 && !hasSimulationError && (errorKey || errorMessage) && (
{!supportsEIP1559V2 &&
!hasSimulationError &&
(errorKey || errorMessage) && (
<div className="confirm-page-container-content__error-container">
<ErrorMessage errorMessage={errorMessage} errorKey={errorKey} />
</div>

View File

@ -41,6 +41,8 @@ describe('Confirm Page Container Content', () => {
});
it('render ConfirmPageContainer component with simulation error', async () => {
process.env.EIP_1559_V2 = false;
const { queryByText, getByText } = renderWithProvider(
<ConfirmPageContainerContent {...props} />,
store,

View File

@ -3,9 +3,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import Identicon from '../../../../ui/identicon';
// eslint-disable-next-line prefer-destructuring
const EIP_1559_V2 = process.env.EIP_1559_V2;
import { useGasFeeContext } from '../../../../../contexts/gasFee';
const ConfirmPageContainerSummary = (props) => {
const {
@ -21,6 +19,8 @@ const ConfirmPageContainerSummary = (props) => {
hideTitle,
} = props;
const { supportsEIP1559V2 } = useGasFeeContext();
return (
<div className={classnames('confirm-page-container-summary', className)}>
{origin === 'metamask' ? null : (
@ -48,7 +48,7 @@ const ConfirmPageContainerSummary = (props) => {
</div>
) : null}
</div>
{!hideSubtitle && !EIP_1559_V2 && (
{!hideSubtitle && !supportsEIP1559V2 && (
<div className="confirm-page-container-summary__subtitle">
{subtitleComponent}
</div>

View File

@ -1,24 +1,25 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import SenderToRecipient from '../../ui/sender-to-recipient';
import { PageContainerFooter } from '../../ui/page-container';
import EditGasPopover from '../edit-gas-popover';
import { EDIT_GAS_MODES } from '../../../../shared/constants/gas';
import { GasFeeContextProvider } from '../../../contexts/gasFee';
import ErrorMessage from '../../ui/error-message';
import { TRANSACTION_TYPES } from '../../../../shared/constants/transaction';
import { PageContainerFooter } from '../../ui/page-container';
import Dialog from '../../ui/dialog';
import ErrorMessage from '../../ui/error-message';
import SenderToRecipient from '../../ui/sender-to-recipient';
import AdvancedGasFeePopover from '../advanced-gas-fee-popover';
import EditGasFeePopover from '../edit-gas-fee-popover';
import EditGasFeePopover from '../edit-gas-fee-popover/edit-gas-fee-popover';
import EditGasPopover from '../edit-gas-popover';
import {
ConfirmPageContainerHeader,
ConfirmPageContainerContent,
ConfirmPageContainerNavigation,
} from '.';
// eslint-disable-next-line prefer-destructuring
const EIP_1559_V2 = process.env.EIP_1559_V2;
export default class ConfirmPageContainer extends Component {
static contextTypes = {
t: PropTypes.func,
@ -77,6 +78,7 @@ export default class ConfirmPageContainer extends Component {
showAddToAddressBookModal: PropTypes.func,
contact: PropTypes.object,
isOwnedAccount: PropTypes.bool,
supportsEIP1559V2: PropTypes.bool,
};
render() {
@ -127,6 +129,7 @@ export default class ConfirmPageContainer extends Component {
showAddToAddressBookModal,
contact = {},
isOwnedAccount,
supportsEIP1559V2,
} = this.props;
const showAddToAddressDialog =
@ -208,6 +211,7 @@ export default class ConfirmPageContainer extends Component {
origin={origin}
ethGasPriceWarning={ethGasPriceWarning}
hideTitle={hideTitle}
supportsEIP1559V2={supportsEIP1559V2}
/>
)}
{shouldDisplayWarning && (
@ -230,7 +234,7 @@ export default class ConfirmPageContainer extends Component {
)}
</PageContainerFooter>
)}
{editingGas && !EIP_1559_V2 && (
{editingGas && !supportsEIP1559V2 && (
<EditGasPopover
mode={EDIT_GAS_MODES.MODIFY_IN_PLACE}
onClose={handleCloseEditGas}

View File

@ -28,8 +28,6 @@ import { useGasFeeContext } from '../../../contexts/gasFee';
// Once we reach this second threshold, we switch to minutes as a unit
const SECOND_CUTOFF = 90;
// eslint-disable-next-line prefer-destructuring
const EIP_1559_V2 = process.env.EIP_1559_V2;
// Shows "seconds" as unit of time if under SECOND_CUTOFF, otherwise "minutes"
const toHumanReadableTime = (milliseconds = 1, t) => {
@ -50,7 +48,7 @@ export default function GasTiming({
const [customEstimatedTime, setCustomEstimatedTime] = useState(null);
const t = useContext(I18nContext);
const { estimateUsed } = useGasFeeContext();
const { estimateUsed, supportsEIP1559V2 } = useGasFeeContext();
// If the user has chosen a value lower than the low gas fee estimate,
// We'll need to use the useEffect hook below to make a call to calculate
@ -97,7 +95,7 @@ export default function GasTiming({
]);
let unknownProcessingTimeText;
if (EIP_1559_V2) {
if (supportsEIP1559V2) {
unknownProcessingTimeText = t('editGasTooLow');
} else {
unknownProcessingTimeText = (
@ -155,7 +153,7 @@ export default function GasTiming({
]);
}
} else {
if (!EIP_1559_V2 || estimateUsed === 'low') {
if (!supportsEIP1559V2 || estimateUsed === 'low') {
attitude = 'negative';
}
// If the user has chosen a value less than our low estimate,
@ -176,7 +174,7 @@ export default function GasTiming({
}
}
// code below needs to cleaned-up once EIP_1559_V2 flag is removed
else if (EIP_1559_V2) {
else if (supportsEIP1559V2) {
text = t('gasTimingNegative', [
toHumanReadableTime(low.maxWaitTimeEstimate, t),
]);
@ -199,8 +197,8 @@ export default function GasTiming({
<Typography
variant={TYPOGRAPHY.H7}
className={classNames('gas-timing', {
[`gas-timing--${attitude}`]: attitude && !EIP_1559_V2,
[`gas-timing--${attitude}-V2`]: attitude && EIP_1559_V2,
[`gas-timing--${attitude}`]: attitude && !supportsEIP1559V2,
[`gas-timing--${attitude}-V2`]: attitude && supportsEIP1559V2,
})}
>
{text}

View File

@ -16,9 +16,6 @@ export default function TransactionDetail({
onEdit,
userAcknowledgedGasMissing,
}) {
// eslint-disable-next-line prefer-destructuring
const EIP_1559_V2 = process.env.EIP_1559_V2;
const t = useI18nContext();
const {
gasLimit,
@ -26,11 +23,12 @@ export default function TransactionDetail({
estimateUsed,
maxFeePerGas,
maxPriorityFeePerGas,
supportsEIP1559V2,
transaction,
} = useGasFeeContext();
const { openModal } = useTransactionModalContext();
if (EIP_1559_V2 && estimateUsed) {
if (supportsEIP1559V2 && estimateUsed) {
const editEnabled = !hasSimulationError || userAcknowledgedGasMissing;
if (!editEnabled) return null;

View File

@ -1,9 +1,13 @@
import React from 'react';
import { screen } from '@testing-library/react';
import { ETH } from '../../../helpers/constants/common';
import { GAS_ESTIMATE_TYPES } from '../../../../shared/constants/gas';
import { TRANSACTION_ENVELOPE_TYPES } from '../../../../shared/constants/transaction';
import { GasFeeContextProvider } from '../../../contexts/gasFee';
import { renderWithProvider } from '../../../../test/jest';
import mockEstimates from '../../../../test/data/mock-estimates.json';
import mockState from '../../../../test/data/mock-state.json';
import configureStore from '../../../store/store';
import TransactionDetail from './transaction-detail.component';
@ -19,20 +23,14 @@ jest.mock('../../../store/actions', () => ({
const render = ({ componentProps, contextProps } = {}) => {
const store = configureStore({
metamask: {
nativeCurrency: ETH,
preferences: {
useNativeCurrencyAsPrimaryCurrency: true,
},
provider: {},
cachedBalances: {},
...mockState.metamask,
accounts: {
'0xAddress': {
address: '0xAddress',
balance: '0x176e5b6f173ebe66',
[mockState.metamask.selectedAddress]: {
address: mockState.metamask.selectedAddress,
balance: '0x1F4',
},
},
selectedAddress: '0xAddress',
featureFlags: { advancedInlineGas: true },
gasFeeEstimates: mockEstimates[GAS_ESTIMATE_TYPES.FEE_MARKET],
},
});
@ -129,4 +127,17 @@ describe('TransactionDetail', () => {
expect(screen.queryByRole('button')).toBeInTheDocument();
expect(screen.queryByText('Low')).toBeInTheDocument();
});
it('should render edit link with text edit for legacy transactions', () => {
render({
contextProps: {
transaction: {
userFeeLevel: 'low',
txParams: { type: TRANSACTION_ENVELOPE_TYPES.LEGACY },
},
},
});
expect(screen.queryByText('🐢')).not.toBeInTheDocument();
expect(screen.queryByText('Edit')).toBeInTheDocument();
});
});

View File

@ -74,6 +74,10 @@ export function useGasFeeInputs(
minimumGasLimit = '0x5208',
editGasMode = EDIT_GAS_MODES.MODIFY_IN_PLACE,
) {
// eslint-disable-next-line prefer-destructuring
const EIP_1559_V2_ENABLED =
process.env.EIP_1559_V2 === true || process.env.EIP_1559_V2 === 'true';
const supportsEIP1559 =
useSelector(checkNetworkAndAccountSupports1559) &&
!isLegacyTransaction(transaction?.txParams);
@ -304,6 +308,7 @@ export function useGasFeeInputs(
hasGasErrors,
hasSimulationError,
supportsEIP1559,
supportsEIP1559V2: supportsEIP1559 && EIP_1559_V2_ENABLED,
updateTransactionUsingGasFeeEstimates,
};
}

View File

@ -316,4 +316,38 @@ describe('useGasFeeInputs', () => {
expect(result.current.estimatedMinimumFiat).toBe('');
});
});
describe('supportsEIP1559V2', () => {
beforeEach(() => {
configureEIP1559();
useSelector.mockImplementation(
generateUseSelectorRouter({
checkNetworkAndAccountSupports1559Response: true,
}),
);
process.env.EIP_1559_V2 = true;
});
afterEach(() => {
process.env.EIP_1559_V2 = false;
});
it('return true for fee_market transaction type', () => {
const { result } = renderHook(() =>
useGasFeeInputs(null, {
txParams: { type: TRANSACTION_ENVELOPE_TYPES.FEE_MARKET },
}),
);
expect(result.current.supportsEIP1559V2).toBe(true);
});
it('return false for legacy transaction type', () => {
const { result } = renderHook(() =>
useGasFeeInputs(null, {
txParams: { type: TRANSACTION_ENVELOPE_TYPES.LEGACY },
}),
);
expect(result.current.supportsEIP1559V2).toBe(false);
});
});
});

View File

@ -26,7 +26,10 @@ import {
TRANSACTION_STATUSES,
} from '../../../shared/constants/transaction';
import { getMethodName } from '../../helpers/utils/metrics';
import { getTransactionTypeTitle } from '../../helpers/utils/transactions.util';
import {
getTransactionTypeTitle,
isLegacyTransaction,
} from '../../helpers/utils/transactions.util';
import { toBuffer } from '../../../shared/modules/buffer-utils';
import { TransactionModalContextProvider } from '../../contexts/transaction-modal';
@ -57,7 +60,8 @@ import GasDetailsItem from './gas-details-item';
import TransactionAlerts from './transaction-alerts';
// eslint-disable-next-line prefer-destructuring
const EIP_1559_V2 = process.env.EIP_1559_V2;
const EIP_1559_V2_ENABLED =
process.env.EIP_1559_V2 === true || process.env.EIP_1559_V2 === 'true';
const renderHeartBeatIfNotInTest = () =>
process.env.IN_TEST === 'true' ? null : <LoadingHeartBeat />;
@ -420,7 +424,9 @@ export default class ConfirmTransactionBase extends Component {
) : null;
const renderGasDetailsItem = () => {
return EIP_1559_V2 ? (
return EIP_1559_V2_ENABLED &&
supportsEIP1559 &&
!isLegacyTransaction(txData) ? (
<GasDetailsItem
key="gas_details"
hexMaximumTransactionFee={hexMaximumTransactionFee}
@ -571,14 +577,12 @@ export default class ConfirmTransactionBase extends Component {
return (
<div className="confirm-page-container-content__details">
{EIP_1559_V2 && (
<TransactionAlerts
setUserAcknowledgedGasMissing={() =>
this.setUserAcknowledgedGasMissing()
}
userAcknowledgedGasMissing={userAcknowledgedGasMissing}
/>
)}
<TransactionDetail
disabled={isDisabled()}
userAcknowledgedGasMissing={userAcknowledgedGasMissing}
@ -949,6 +953,7 @@ export default class ConfirmTransactionBase extends Component {
gasFeeIsCustom,
nativeCurrency,
hardwareWalletRequiresConnection,
supportsEIP1559,
} = this.props;
const {
submitting,
@ -1046,6 +1051,11 @@ export default class ConfirmTransactionBase extends Component {
editingGas={editingGas}
handleCloseEditGas={() => this.handleCloseEditGas()}
currentTransaction={txData}
supportsEIP1559V2={
EIP_1559_V2_ENABLED &&
supportsEIP1559 &&
!isLegacyTransaction(txData)
}
/>
</TransactionModalContextProvider>
);

View File

@ -27,11 +27,10 @@ const GasDetailsItem = ({
maxFeePerGas,
maxPriorityFeePerGas,
userAcknowledgedGasMissing,
txData,
useNativeCurrencyAsPrimaryCurrency,
}) => {
const t = useI18nContext();
const { estimateUsed, hasSimulationError } = useGasFeeContext();
const { estimateUsed, hasSimulationError, transaction } = useGasFeeContext();
if (hasSimulationError && !userAcknowledgedGasMissing) return null;
@ -124,10 +123,10 @@ const GasDetailsItem = ({
subTitle={
<GasTiming
maxPriorityFeePerGas={hexWEIToDecGWEI(
maxPriorityFeePerGas || txData.txParams.maxPriorityFeePerGas,
maxPriorityFeePerGas || transaction.txParams.maxPriorityFeePerGas,
)}
maxFeePerGas={hexWEIToDecGWEI(
maxFeePerGas || txData.txParams.maxFeePerGas,
maxFeePerGas || transaction.txParams.maxFeePerGas,
)}
/>
}
@ -142,7 +141,6 @@ GasDetailsItem.propTypes = {
maxFeePerGas: PropTypes.string,
maxPriorityFeePerGas: PropTypes.string,
userAcknowledgedGasMissing: PropTypes.bool.isRequired,
txData: PropTypes.object,
useNativeCurrencyAsPrimaryCurrency: PropTypes.bool,
};

View File

@ -37,12 +37,8 @@ const render = ({ componentProps, contextProps } = {}) => {
});
return renderWithProvider(
<GasFeeContextProvider {...contextProps}>
<GasDetailsItem
txData={{ txParams: {} }}
userAcknowledgedGasMissing={false}
{...componentProps}
/>
<GasFeeContextProvider transaction={{ txParams: {} }} {...contextProps}>
<GasDetailsItem userAcknowledgedGasMissing={false} {...componentProps} />
</GasFeeContextProvider>,
store,
);
@ -60,14 +56,18 @@ describe('GasDetailsItem', () => {
});
it('should show warning icon if estimates are high', async () => {
render({ contextProps: { defaultEstimateToUse: 'high' } });
render({
contextProps: { transaction: { txParams: {}, userFeeLevel: 'high' } },
});
await waitFor(() => {
expect(screen.queryByText('⚠ Max fee:')).toBeInTheDocument();
});
});
it('should not show warning icon if estimates are not high', async () => {
render({ contextProps: { defaultEstimateToUse: 'low' } });
render({
contextProps: { transaction: { txParams: {}, userFeeLevel: 'low' } },
});
await waitFor(() => {
expect(screen.queryByText('Max fee:')).toBeInTheDocument();
});
@ -76,8 +76,11 @@ describe('GasDetailsItem', () => {
it('should return null if there is simulationError and user has not acknowledged gasMissing warning', () => {
const { container } = render({
contextProps: {
defaultEstimateToUse: 'low',
transaction: { simulationFails: true },
transaction: {
txParams: {},
simulationFails: true,
userFeeLevel: 'low',
},
},
});
expect(container.innerHTML).toHaveLength(0);

View File

@ -16,10 +16,17 @@ const TransactionAlerts = ({
userAcknowledgedGasMissing,
setUserAcknowledgedGasMissing,
}) => {
const { balanceError, estimateUsed, hasSimulationError } = useGasFeeContext();
const {
balanceError,
estimateUsed,
hasSimulationError,
supportsEIP1559V2,
} = useGasFeeContext();
const pendingTransactions = useSelector(submittedPendingTransactionsSelector);
const t = useI18nContext();
if (!supportsEIP1559V2) return null;
return (
<div className="transaction-alerts">
{hasSimulationError && (

View File

@ -1,9 +1,14 @@
import React from 'react';
import { screen } from '@testing-library/react';
import { fireEvent, screen } from '@testing-library/react';
import { ETH } from '../../../helpers/constants/common';
import { TRANSACTION_STATUSES } from '../../../../shared/constants/transaction';
import { GAS_ESTIMATE_TYPES } from '../../../../shared/constants/gas';
import {
TRANSACTION_ENVELOPE_TYPES,
TRANSACTION_STATUSES,
} from '../../../../shared/constants/transaction';
import { renderWithProvider } from '../../../../test/lib/render-helpers';
import mockEstimates from '../../../../test/data/mock-estimates.json';
import mockState from '../../../../test/data/mock-state.json';
import { GasFeeContextProvider } from '../../../contexts/gasFee';
import configureStore from '../../../store/store';
@ -17,44 +22,54 @@ jest.mock('../../../store/actions', () => ({
addPollingTokenToAppState: jest.fn(),
}));
const render = ({ props, state } = {}) => {
const render = ({ componentProps, transactionProps, state }) => {
const store = configureStore({
metamask: {
nativeCurrency: ETH,
preferences: {
useNativeCurrencyAsPrimaryCurrency: true,
},
provider: {},
cachedBalances: {},
...mockState.metamask,
accounts: {
'0xAddress': {
address: '0xAddress',
[mockState.metamask.selectedAddress]: {
address: mockState.metamask.selectedAddress,
balance: '0x1F4',
},
},
selectedAddress: '0xAddress',
gasFeeEstimates: mockEstimates[GAS_ESTIMATE_TYPES.FEE_MARKET],
...state,
},
});
return renderWithProvider(
<GasFeeContextProvider {...props}>
<TransactionAlerts />
<GasFeeContextProvider
transaction={{
txParams: {
type: TRANSACTION_ENVELOPE_TYPES.FEE_MARKET,
},
...transactionProps,
}}
>
<TransactionAlerts {...componentProps} />
</GasFeeContextProvider>,
store,
);
};
describe('TransactionAlerts', () => {
beforeEach(() => {
process.env.EIP_1559_V2 = true;
});
afterEach(() => {
process.env.EIP_1559_V2 = false;
});
it('should returning warning message for low gas estimate', () => {
render({ props: { transaction: { userFeeLevel: 'low' } } });
render({ transactionProps: { userFeeLevel: 'low' } });
expect(
document.getElementsByClassName('actionable-message--warning'),
).toHaveLength(1);
});
it('should return null for gas estimate other than low', () => {
render({ props: { transaction: { userFeeLevel: 'high' } } });
render({ transactionProps: { userFeeLevel: 'high' } });
expect(
document.getElementsByClassName('actionable-message--warning'),
).toHaveLength(0);
@ -62,8 +77,9 @@ describe('TransactionAlerts', () => {
it('should not show insufficient balance message if transaction value is less than balance', () => {
render({
props: {
transaction: { userFeeLevel: 'high', txParams: { value: '0x64' } },
transactionProps: {
userFeeLevel: 'high',
txParams: { value: '0x64' },
},
});
expect(screen.queryByText('Insufficient funds.')).not.toBeInTheDocument();
@ -71,8 +87,9 @@ describe('TransactionAlerts', () => {
it('should show insufficient balance message if transaction value is more than balance', () => {
render({
props: {
transaction: { userFeeLevel: 'high', txParams: { value: '0x5208' } },
transactionProps: {
userFeeLevel: 'high',
txParams: { value: '0x5208' },
},
});
expect(screen.queryByText('Insufficient funds.')).toBeInTheDocument();
@ -86,7 +103,7 @@ describe('TransactionAlerts', () => {
id: 0,
time: 0,
txParams: {
from: '0xAddress',
from: mockState.metamask.selectedAddress,
to: '0xRecipient',
},
status: TRANSACTION_STATUSES.SUBMITTED,
@ -98,4 +115,58 @@ describe('TransactionAlerts', () => {
screen.queryByText('You have (1) pending transaction.'),
).toBeInTheDocument();
});
describe('SimulationError Message', () => {
it('should show simulation error message along with option to proceed anyway if transaction.simulationFails is true', () => {
render({ transactionProps: { simulationFails: true } });
expect(
screen.queryByText(
'We were not able to estimate gas. There might be an error in the contract and this transaction may fail.',
),
).toBeInTheDocument();
expect(
screen.queryByText('I want to proceed anyway'),
).toBeInTheDocument();
});
it('should not show options to acknowledge gas-missing warning if component prop userAcknowledgedGasMissing is already true', () => {
render({
componentProps: {
userAcknowledgedGasMissing: true,
},
transactionProps: { simulationFails: true },
});
expect(
screen.queryByText(
'We were not able to estimate gas. There might be an error in the contract and this transaction may fail.',
),
).toBeInTheDocument();
expect(
screen.queryByText('I want to proceed anyway'),
).not.toBeInTheDocument();
});
it('should call prop setUserAcknowledgedGasMissing if option to acknowledge gas-missing warning is clicked', () => {
const setUserAcknowledgedGasMissing = jest.fn();
render({
componentProps: {
setUserAcknowledgedGasMissing,
},
transactionProps: { simulationFails: true },
});
fireEvent.click(screen.queryByText('I want to proceed anyway'));
expect(setUserAcknowledgedGasMissing).toHaveBeenCalledTimes(1);
});
it('should return null for legacy transactions', () => {
const { container } = render({
transactionProps: {
txParams: {
type: TRANSACTION_ENVELOPE_TYPES.LEGACY,
},
},
});
expect(container.firstChild).toBeNull();
});
});
});