From 2c462b1014933e51ea77e350d8da79203756ebd6 Mon Sep 17 00:00:00 2001 From: Sylva Elendu Date: Wed, 26 Jul 2023 17:48:11 +0100 Subject: [PATCH] chore: Custom Gas Modal Component (#6287) * custom gas modal component * failing snapshot * validate for error txn with data * initialbackgroundstate in unit test --- .../CustomGasModal/CustomGasModal.styles.ts | 15 + .../UI/CustomGasModal/CustomGasModal.test.tsx | 140 ++ .../UI/CustomGasModal/CustomGasModal.tsx | 200 +++ .../UI/CustomGasModal/CustomGasModal.types.ts | 39 + .../CustomGasModal.test.tsx.snap | 1356 +++++++++++++++++ app/components/UI/CustomGasModal/index.ts | 1 + .../UI/EditGasFeeLegacyUpdate/types.ts | 6 +- .../Views/SendFlow/Confirm/index.js | 322 +--- app/constants/test-ids.js | 2 + app/util/test/renderWithProvider.tsx | 38 +- 10 files changed, 1856 insertions(+), 263 deletions(-) create mode 100644 app/components/UI/CustomGasModal/CustomGasModal.styles.ts create mode 100644 app/components/UI/CustomGasModal/CustomGasModal.test.tsx create mode 100644 app/components/UI/CustomGasModal/CustomGasModal.tsx create mode 100644 app/components/UI/CustomGasModal/CustomGasModal.types.ts create mode 100644 app/components/UI/CustomGasModal/__snapshots__/CustomGasModal.test.tsx.snap create mode 100644 app/components/UI/CustomGasModal/index.ts diff --git a/app/components/UI/CustomGasModal/CustomGasModal.styles.ts b/app/components/UI/CustomGasModal/CustomGasModal.styles.ts new file mode 100644 index 00000000000..7002e7d4fd3 --- /dev/null +++ b/app/components/UI/CustomGasModal/CustomGasModal.styles.ts @@ -0,0 +1,15 @@ +import { StyleSheet } from 'react-native'; + +const createStyles = () => + StyleSheet.create({ + bottomModal: { + justifyContent: 'flex-end', + margin: 0, + }, + keyboardAwareWrapper: { + flex: 1, + justifyContent: 'flex-end', + }, + }); + +export default createStyles; diff --git a/app/components/UI/CustomGasModal/CustomGasModal.test.tsx b/app/components/UI/CustomGasModal/CustomGasModal.test.tsx new file mode 100644 index 00000000000..9a751fd47d3 --- /dev/null +++ b/app/components/UI/CustomGasModal/CustomGasModal.test.tsx @@ -0,0 +1,140 @@ +import React from 'react'; + +import { fireEvent } from '@testing-library/react-native'; + +import Engine from '../../../core/Engine'; +import initialBackgroundState from '../../../util/test/initial-background-state.json'; +import renderWithProvider from '../../../util/test/renderWithProvider'; +import CustomGasModal from './'; + +Engine.init({}); +jest.mock('@react-navigation/native', () => ({ + useNavigation: () => ({ + navigation: {}, + }), + createNavigatorFactory: () => ({}), +})); + +jest.mock('react-native-keyboard-aware-scroll-view', () => { + const KeyboardAwareScrollView = jest.requireActual('react-native').ScrollView; + return { KeyboardAwareScrollView }; +}); + +const gasSelected = 'high'; + +const mockInitialState = { + settings: {}, + transaction: { + selectedAsset: {}, + transaction: { + gas: '0x0', + gasPrice: '0x0', + data: '0x0', + }, + }, + engine: { + backgroundState: { + ...initialBackgroundState, + }, + }, +}; + +jest.mock('react-redux', () => ({ + ...jest.requireActual('react-redux'), + useSelector: (fn: any) => fn(mockInitialState), +})); + +const mockedAction = jest.fn(); +const updateGasState = jest.fn(); +const eip1559GasData = { + maxFeePerGas: '0x0', + maxPriorityFeePerGas: '0x1', + suggestedMaxFeePerGas: '0x2', + suggestedMaxPriorityFeePerGas: '0x3', + suggestedGasLimit: '0x4', +}; +const eip1559GasTxn = { + suggestedGasLimit: '0x5', + totalMaxHex: '0x6', +}; + +const legacyGasData = { + legacyGasLimit: '', + suggestedGasPrice: '', +}; + +const customGasModalSharedProps = { + gasSelected, + onChange: mockedAction, + onCancel: mockedAction, + isAnimating: false, + onlyGas: false, + validateAmount: mockedAction, + updateGasState, + onGasChanged: (gas: string) => mockedAction(gas), + onGasCanceled: (gas: string) => mockedAction(gas), +}; + +describe('CustomGasModal', () => { + it('should render correctly', () => { + const wrapper = renderWithProvider( + , + { state: mockInitialState }, + false, + ); + expect(wrapper).toMatchSnapshot(); + }); + + it('should contain gas price if legacy', async () => { + const { findByText } = renderWithProvider( + , + { state: mockInitialState }, + false, + ); + + expect(await findByText('Gas price')).toBeDefined(); + expect(await findByText('Gas limit must be at least 21000')).toBeDefined(); + }); + + it('should contain gas fee if EIP1559 if legacy is false', () => { + const { queryByText } = renderWithProvider( + , + { state: mockInitialState }, + false, + ); + + expect(queryByText('Max fee')).toBeDefined(); + }); + + it('should call updateParentState when saved', () => { + const { getByText } = renderWithProvider( + , + { state: mockInitialState }, + false, + ); + + const saveButton = getByText('Save'); + + fireEvent.press(saveButton); + expect(updateGasState).toHaveBeenCalled(); + }); +}); diff --git a/app/components/UI/CustomGasModal/CustomGasModal.tsx b/app/components/UI/CustomGasModal/CustomGasModal.tsx new file mode 100644 index 00000000000..991c6420b8b --- /dev/null +++ b/app/components/UI/CustomGasModal/CustomGasModal.tsx @@ -0,0 +1,200 @@ +import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view'; +import Modal from 'react-native-modal'; +import { useSelector } from 'react-redux'; + +import { selectChainId } from '../../../selectors/networkController'; +import { useAppThemeFromContext } from '../../../util/theme'; +import EditGasFee1559 from '../../UI/EditGasFee1559Update'; +import EditGasFeeLegacy from '../../UI/EditGasFeeLegacyUpdate'; +import createStyles from './CustomGasModal.styles'; +import { CustomGasModalProps } from './CustomGasModal.types'; + +const CustomGasModal = ({ + gasSelected, + animateOnChange, + isAnimating, + onlyGas, + validateAmount, + legacy, + legacyGasData, + EIP1559GasData, + EIP1559GasTxn, + onGasChanged, + onGasCanceled, + updateGasState, +}: CustomGasModalProps) => { + const { colors } = useAppThemeFromContext(); + const styles = createStyles(); + const transaction = useSelector((state: any) => state.transaction); + const gasFeeEstimate = useSelector( + (state: any) => + state.engine.backgroundState.GasFeeController.gasFeeEstimates, + ); + const primaryCurrency = useSelector( + (state: any) => state.settings.primaryCurrency, + ); + const chainId = useSelector((state: any) => selectChainId(state)); + const selectedAsset = useSelector( + (state: any) => state.transaction.selectedAsset, + ); + const gasEstimateType = useSelector( + (state: any) => + state.engine.backgroundState.GasFeeController.gasEstimateType, + ); + + const [selectedGas, setSelectedGas] = useState(gasSelected); + const [eip1559Txn, setEIP1559Txn] = useState(EIP1559GasTxn); + const [legacyGasObj, setLegacyGasObj] = useState(legacyGasData); + const [eip1559GasObj, setEIP1559GasObj] = useState(EIP1559GasData); + const [isViewAnimating, setIsViewAnimating] = useState(false); + const [error, setError] = useState(''); + + useEffect(() => { + setIsViewAnimating(isAnimating); + }, [isAnimating]); + + const onGasAnimationStart = useCallback(() => setIsViewAnimating(true), []); + const onGasAnimationEnd = useCallback(() => setIsViewAnimating(false), []); + + const getGasAnalyticsParams = () => ({ + active_currency: { value: selectedAsset.symbol, anonymous: true }, + gas_estimate_type: gasEstimateType, + }); + + const onChangeGas = (gasValue: string) => { + setSelectedGas(gasValue); + onGasChanged(selectedGas); + }; + + const onCancelGas = () => { + onGasCanceled(selectedGas); + }; + + const updatedTransactionFrom = useMemo( + () => ({ + ...transaction, + data: transaction?.transaction?.data, + from: transaction?.transaction?.from, + }), + [transaction], + ); + + const onSaveLegacyGasOption = useCallback( + (gasTxn, gasObj, gasSelect) => { + gasTxn.error = validateAmount({ + transaction: updatedTransactionFrom, + total: gasTxn.totalHex, + }); + setLegacyGasObj(gasObj); + setError(gasTxn?.error); + updateGasState({ gasTxn, gasObj, gasSelect, txnType: legacy }); + }, + [validateAmount, updatedTransactionFrom, legacy, updateGasState], + ); + + const onSaveEIP1559GasOption = useCallback( + (gasTxn, gasObj) => { + gasTxn.error = validateAmount({ + transaction: updatedTransactionFrom, + total: gasTxn.totalMaxHex, + }); + + setEIP1559Txn(gasTxn); + setEIP1559GasObj(gasObj); + setError(gasTxn?.error); + updateGasState({ + gasTxn, + gasObj, + gasSelect: selectedGas, + txnType: legacy, + }); + }, + [ + validateAmount, + selectedGas, + updatedTransactionFrom, + legacy, + updateGasState, + ], + ); + + const legacyGasObject = { + legacyGasLimit: legacyGasObj?.legacyGasLimit, + suggestedGasPrice: legacyGasObj?.suggestedGasPrice, + }; + + const eip1559GasObject = { + suggestedMaxFeePerGas: + eip1559GasObj?.suggestedMaxFeePerGas || + eip1559GasObj?.[selectedGas]?.suggestedMaxFeePerGas, + suggestedMaxPriorityFeePerGas: + eip1559GasObj?.suggestedMaxPriorityFeePerGas || + gasFeeEstimate[selectedGas]?.suggestedMaxPriorityFeePerGas, + suggestedGasLimit: + eip1559GasObj?.suggestedGasLimit || eip1559Txn?.suggestedGasLimit, + }; + + return ( + + + {legacy ? ( + + ) : ( + + )} + + + ); +}; + +export default CustomGasModal; diff --git a/app/components/UI/CustomGasModal/CustomGasModal.types.ts b/app/components/UI/CustomGasModal/CustomGasModal.types.ts new file mode 100644 index 00000000000..639889523b9 --- /dev/null +++ b/app/components/UI/CustomGasModal/CustomGasModal.types.ts @@ -0,0 +1,39 @@ +export interface CustomGasModalProps { + gasSelected: string; + onChange: (gas: string) => void; + onCancel: () => void; + animateOnChange?: boolean; + isAnimating: any; + onlyGas: boolean; + validateAmount: ({ + transaction, + total, + }: { + transaction: any; + total: string; + }) => void; + legacy: boolean; + legacyGasData?: { + legacyGasLimit: string; + suggestedGasPrice: string; + }; + EIP1559GasData?: { + maxFeePerGas: string; + maxPriorityFeePerGas: string; + suggestedMaxFeePerGas: string; + suggestedMaxPriorityFeePerGas: string; + suggestedGasLimit: string; + }; + EIP1559GasTxn?: { + suggestedGasLimit: string; + totalMaxHex: string; + }; + onGasChanged: (gas: string) => void; + onGasCanceled: (gas: string) => void; + updateGasState: (state: { + gasTxn: any; + gasObj: any; + gasSelect: string; + txnType: boolean; + }) => void; +} diff --git a/app/components/UI/CustomGasModal/__snapshots__/CustomGasModal.test.tsx.snap b/app/components/UI/CustomGasModal/__snapshots__/CustomGasModal.test.tsx.snap new file mode 100644 index 00000000000..0953fe2d162 --- /dev/null +++ b/app/components/UI/CustomGasModal/__snapshots__/CustomGasModal.test.tsx.snap @@ -0,0 +1,1356 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CustomGasModal should render correctly 1`] = ` + + + + + + + + + + + + + +  + + + + Edit gas fee + + +  + + + + + + + + + ~ + + + + + + + + 0 ETH + + + + + + + + + + + Gas limit + + + + +  + + + + + + + + +  + + + + + + + + + + +  + + + + + + +  + + + Gas limit must be at least 21000 + + + + + + + + + + Gas price + + + + +  + + + + + + + + +  + + + + + + + GWEI + + + + + + +  + + + + + + + + + + + + + Save + + + + + + + + + + + + +`; diff --git a/app/components/UI/CustomGasModal/index.ts b/app/components/UI/CustomGasModal/index.ts new file mode 100644 index 00000000000..3aa4dbc4bb5 --- /dev/null +++ b/app/components/UI/CustomGasModal/index.ts @@ -0,0 +1 @@ +export { default } from './CustomGasModal'; diff --git a/app/components/UI/EditGasFeeLegacyUpdate/types.ts b/app/components/UI/EditGasFeeLegacyUpdate/types.ts index 1b465b9cc6e..a3f742d962b 100644 --- a/app/components/UI/EditGasFeeLegacyUpdate/types.ts +++ b/app/components/UI/EditGasFeeLegacyUpdate/types.ts @@ -41,7 +41,7 @@ export interface EditGasFeeLegacyUpdateProps { /** * Warning message to show */ - warning: any | undefined; + warning?: any; /** * Ignore option array */ @@ -49,11 +49,11 @@ export interface EditGasFeeLegacyUpdateProps { /** * Extend options object. Object has option keys and properties will be spread */ - extendOptions: any; + extendOptions?: any; /** * Recommended object with type and render function */ - recommended: any; + recommended?: any; /** * Estimate option to compare with for too low warning */ diff --git a/app/components/Views/SendFlow/Confirm/index.js b/app/components/Views/SendFlow/Confirm/index.js index e98a9ca3506..264233c17d5 100644 --- a/app/components/Views/SendFlow/Confirm/index.js +++ b/app/components/Views/SendFlow/Confirm/index.js @@ -9,7 +9,6 @@ import { ActivityIndicator, Platform, } from 'react-native'; -import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view'; import { connect } from 'react-redux'; import { getSendFlowTitle } from '../../../UI/Navbar'; import PropTypes from 'prop-types'; @@ -20,11 +19,9 @@ import { weiToFiat, balanceToFiat, isDecimal, - fromWei, hexToBN, BNToHex, } from '../../../../util/number'; - import { getTicker, decodeTransferData, @@ -68,8 +65,6 @@ import { removeFavoriteCollectible } from '../../../../actions/collectibles'; import { SafeAreaView } from 'react-native-safe-area-context'; import AccountFromToInfoCard from '../../../UI/AccountFromToInfoCard'; import TransactionReview from '../../../UI/TransactionReview/TransactionReviewEIP1559Update'; -import EditGasFee1559 from '../../../UI/EditGasFee1559Update'; -import EditGasFeeLegacy from '../../../UI/EditGasFeeLegacyUpdate'; import CustomNonce from '../../../UI/CustomNonce'; import AppConstants from '../../../../core/AppConstants'; import { @@ -105,10 +100,14 @@ import generateTestId from '../../../../../wdio/utils/generateTestId'; import { COMFIRM_TXN_AMOUNT } from '../../../../../wdio/screen-objects/testIDs/Screens/TransactionConfirm.testIds'; import { isNetworkBuyNativeTokenSupported } from '../../../UI/Ramp/utils'; import { getRampNetworks } from '../../../../reducers/fiatOrders'; +import CustomGasModal from '../../../UI/CustomGasModal'; +import { + TXN_CONFIRM_SCREEN, + TXN_CONFIRM_SEND_BUTTON, +} from '../../../../constants/test-ids'; const EDIT = 'edit'; const EDIT_NONCE = 'edit_nonce'; -const EDIT_EIP1559 = 'edit_eip1559'; const REVIEW = 'review'; const POLLING_INTERVAL_ESTIMATED_L1_FEE = 30000; @@ -236,11 +235,8 @@ class Confirm extends PureComponent { errorMessage: undefined, mode: REVIEW, gasSelected: AppConstants.GAS_OPTIONS.MEDIUM, - gasSelectedTemp: AppConstants.GAS_OPTIONS.MEDIUM, stopUpdateGas: false, advancedGasInserted: false, - gasSpeedSelected: AppConstants.GAS_OPTIONS.MEDIUM, - suggestedGasLimit: undefined, EIP1559GasTransaction: {}, EIP1559GasObject: {}, legacyGasObject: {}, @@ -286,18 +282,6 @@ class Confirm extends PureComponent { } }; - getGasAnalyticsParams = () => { - try { - const { selectedAsset, gasEstimateType } = this.props; - return { - active_currency: { value: selectedAsset.symbol, anonymous: true }, - gas_estimate_type: gasEstimateType, - }; - } catch (error) { - return {}; - } - }; - updateNavBar = () => { const { navigation, route, resetTransaction } = this.props; const colors = this.context.colors || mockTheme.colors; @@ -358,7 +342,13 @@ class Confirm extends PureComponent { }; componentDidMount = async () => { - const { chainId } = this.props; + const { + chainId, + showCustomNonce, + navigation, + providerType, + isPaymentRequest, + } = this.props; this.updateNavBar(); this.getGasLimit(); @@ -372,8 +362,6 @@ class Confirm extends PureComponent { this.getAnalyticsParams(), ); - const { showCustomNonce, navigation, providerType, isPaymentRequest } = - this.props; showCustomNonce && (await this.setNetworkNonce()); navigation.setParams({ providerType, isPaymentRequest }); this.parseTransactionDataHeader(); @@ -396,6 +384,9 @@ class Confirm extends PureComponent { selectedAsset, } = this.props; this.updateNavBar(); + + if (this.state?.closeModal) this.toggleConfirmationModal(REVIEW); + const { errorMessage, fromSelectedAddress } = this.state; const valueChanged = prevProps.transactionState.transaction.value !== value; const fromAddressChanged = @@ -427,9 +418,6 @@ class Confirm extends PureComponent { const gasSelected = gasEstimateTypeChanged ? AppConstants.GAS_OPTIONS.MEDIUM : this.state.gasSelected; - const gasSelectedTemp = gasEstimateTypeChanged - ? AppConstants.GAS_OPTIONS.MEDIUM - : this.state.gasSelectedTemp; if ( (!this.state.stopUpdateGas && !this.state.advancedGasInserted) || @@ -442,25 +430,19 @@ class Confirm extends PureComponent { gasEstimationReady: true, animateOnChange: true, gasSelected, - gasSelectedTemp, }, () => { this.setState({ animateOnChange: false }); }, ); } else if (this.props.gasEstimateType !== GAS_ESTIMATE_TYPES.NONE) { - const suggestedGasLimit = fromWei(gas, 'wei'); - this.setError(this.state.legacyGasTransaction.error); - // eslint-disable-next-line react/no-did-update-set-state this.setState( { gasEstimationReady: true, animateOnChange: true, gasSelected, - gasSelectedTemp, - suggestedGasLimit, }, () => { this.setState({ animateOnChange: false }); @@ -476,12 +458,9 @@ class Confirm extends PureComponent { this.scrollView = ref; }; - review = () => { - this.onModeChange(REVIEW); - }; - - edit = (MODE) => { + toggleConfirmationModal = (MODE) => { this.onModeChange(MODE); + this.setState({ closeModal: false }); }; onModeChange = (mode) => { @@ -573,25 +552,6 @@ class Confirm extends PureComponent { }); }; - handleSetGasSpeed = (speed) => { - this.setState({ gasSpeedSelected: speed }); - }; - - validateGas = () => { - const { accounts } = this.props; - const { gas, gasPrice, value, from } = - this.props.transactionState.transaction; - let errorMessage; - const totalGas = gas.mul(gasPrice); - const valueBN = hexToBN(value); - const balanceBN = hexToBN(accounts[from].balance); - if (valueBN.add(totalGas).gt(balanceBN)) { - errorMessage = strings('transaction.insufficient'); - this.setState({ errorMessage }); - } - return errorMessage; - }; - prepareTransactionToSend = () => { const { transactionState: { transaction }, @@ -661,7 +621,7 @@ class Confirm extends PureComponent { transaction: { value }, }, } = this.props; - const selectedAddress = transaction.from; + const selectedAddress = transaction?.from; let weiBalance, weiInput, error; if (isDecimal(value)) { @@ -830,167 +790,6 @@ class Confirm extends PureComponent { this.setState({ hexDataModalVisible: !hexDataModalVisible }); }; - cancelGasEdition = () => { - this.setState({ - stopUpdateGas: false, - gasSelectedTemp: this.state.gasSelected, - }); - this.review(); - }; - - saveGasEdition = (EIP1559GasTransaction, EIP1559GasObject) => { - const { transaction } = this.props; - EIP1559GasTransaction.error = this.validateAmount({ - transaction, - total: EIP1559GasTransaction.totalMaxHex, - }); - - this.setState({ EIP1559GasTransaction, EIP1559GasObject }); - - this.review(); - }; - - saveGasEditionLegacy = ( - legacyGasTransaction, - legacyGasObject, - gasSelected, - ) => { - const { transaction } = this.props; - - legacyGasTransaction.error = this.validateAmount({ - transaction, - total: legacyGasTransaction.totalHex, - }); - this.setState({ - gasSelected, - gasSelectedTemp: gasSelected, - advancedGasInserted: !gasSelected, - stopUpdateGas: false, - legacyGasTransaction, - legacyGasObject, - }); - this.review(); - }; - - renderCustomGasModalEIP1559 = () => { - const { primaryCurrency, chainId, gasFeeEstimates } = this.props; - const { - gasSelected, - isAnimating, - animateOnChange, - EIP1559GasObject, - EIP1559GasTransaction, - } = this.state; - - const selectedGasObject = { - suggestedMaxFeePerGas: - EIP1559GasObject.suggestedMaxFeePerGas || - gasFeeEstimates[gasSelected]?.suggestedMaxFeePerGas, - suggestedMaxPriorityFeePerGas: - EIP1559GasObject.suggestedMaxPriorityFeePerGas || - gasFeeEstimates[gasSelected]?.suggestedMaxPriorityFeePerGas, - suggestedGasLimit: - EIP1559GasObject.suggestedGasLimit || - EIP1559GasTransaction.suggestedGasLimit, - }; - - const colors = this.context.colors || mockTheme.colors; - const styles = createStyles(colors); - - return ( - - - - - - ); - }; - - renderCustomGasModalLegacy = () => { - const { primaryCurrency, chainId, gasEstimateType, gasFeeEstimates } = - this.props; - const { legacyGasObject, gasSelected, isAnimating, animateOnChange } = - this.state; - - const selectedGasObject = { - legacyGasLimit: legacyGasObject?.legacyGasLimit, - suggestedGasPrice: legacyGasObject?.suggestedGasPrice, - }; - - const colors = this.context.colors || mockTheme.colors; - const styles = createStyles(colors); - - return ( - - - - - - ); - }; - renderCustomNonceModal = () => { const { setNonce } = this.props; const { proposedNonce, nonce } = this.props.transaction; @@ -998,7 +797,7 @@ class Confirm extends PureComponent { this.review()} + close={() => this.toggleConfirmationModal(REVIEW)} save={setNonce} /> ); @@ -1083,21 +882,6 @@ class Confirm extends PureComponent { }); }; - updateGasSelected = (selected) => { - this.setState({ - stopUpdateGas: !selected, - gasSelectedTemp: selected, - gasSelected: selected, - }); - }; - - calculateTempGasFeeLegacy = (selected) => { - this.setState({ - stopUpdateGas: !selected, - gasSelectedTemp: selected, - }); - }; - onUpdatingValuesStart = () => { this.setState({ isAnimating: true }); }; @@ -1112,6 +896,37 @@ class Confirm extends PureComponent { }); }; + onGasChanged = (gasValue) => { + this.setState({ gasSelected: gasValue }); + }; + + onGasCanceled = (gasValue) => { + this.setState({ + stopUpdateGas: false, + gasSelectedTemp: gasValue, + closeModal: true, + }); + }; + + updateGasState = ({ gasTxn, gasObj, gasSelect, txnType }) => { + this.setState({ + gasSelectedTemp: gasSelect, + gasSelected: gasSelect, + closeModal: true, + ...(txnType + ? { + legacyGasTransaction: gasTxn, + legacyGasObject: gasObj, + advancedGasInserted: !gasSelect, + stopUpdateGas: false, + } + : { + EIP1559GasTransaction: gasTxn, + EIP1559GasObject: gasObj, + }), + }); + }; + render = () => { const { selectedAsset, paymentRequest } = this.props.transactionState; const { @@ -1136,10 +951,13 @@ class Confirm extends PureComponent { isAnimating, animateOnChange, multiLayerL1FeeTotal, + gasSelected, + EIP1559GasObject, + EIP1559GasTransaction, + legacyGasObject, } = this.state; const colors = this.context.colors || mockTheme.colors; const styles = createStyles(colors); - const showFeeMarket = !gasEstimateType || gasEstimateType === GAS_ESTIMATE_TYPES.FEE_MARKET || @@ -1157,7 +975,7 @@ class Confirm extends PureComponent { this.edit(!showFeeMarket ? EDIT : EDIT_EIP1559)} + onEdit={() => this.toggleConfirmationModal(EDIT)} onUpdatingValuesStart={this.onUpdatingValuesStart} onUpdatingValuesEnd={this.onUpdatingValuesEnd} animateOnChange={animateOnChange} isAnimating={isAnimating} gasEstimationReady={gasEstimationReady} chainId={chainId} - gasObject={ - !showFeeMarket - ? this.state.legacyGasObject - : this.state.EIP1559GasObject - } + gasObject={!showFeeMarket ? legacyGasObject : EIP1559GasObject} updateTransactionState={this.updateTransactionState} legacy={!showFeeMarket} onlyGas={false} multiLayerL1FeeTotal={multiLayerL1FeeTotal} /> + {mode === EDIT && ( + + )} {showCustomNonce && ( this.edit(EDIT_NONCE)} + onNonceEdit={() => this.toggleConfirmationModal(EDIT_NONCE)} /> )} @@ -1284,7 +1114,7 @@ class Confirm extends PureComponent { } containerStyle={styles.buttonNext} onPress={this.onNext} - testID={'txn-confirm-send-button'} + testID={TXN_CONFIRM_SEND_BUTTON} > {transactionConfirmed ? ( @@ -1295,9 +1125,7 @@ class Confirm extends PureComponent { )} - {mode === EDIT && this.renderCustomGasModalLegacy()} {mode === EDIT_NONCE && this.renderCustomNonceModal()} - {mode === EDIT_EIP1559 && this.renderCustomGasModalEIP1559()} {this.renderHexDataModal()} ); diff --git a/app/constants/test-ids.js b/app/constants/test-ids.js index 89167a62d4d..47c79decc37 100644 --- a/app/constants/test-ids.js +++ b/app/constants/test-ids.js @@ -101,3 +101,5 @@ export const SIGNATURE_MODAL_CANCEL_BUTTON_ID = // Advanced Settings export const ADVANCED_SETTINGS_CONTAINER_ID = 'advanced-settings'; export const ETH_SIGN_SWITCH_ID = 'eth-sign-switch'; +export const TXN_CONFIRM_SCREEN = 'txn-confirm-screen'; +export const TXN_CONFIRM_SEND_BUTTON = 'txn-confirm-send-button'; diff --git a/app/util/test/renderWithProvider.tsx b/app/util/test/renderWithProvider.tsx index 6374122a0b3..5071b789ad7 100644 --- a/app/util/test/renderWithProvider.tsx +++ b/app/util/test/renderWithProvider.tsx @@ -1,18 +1,20 @@ -import { NavigationContainer } from '@react-navigation/native'; import React from 'react'; import { Provider } from 'react-redux'; + +import { NavigationContainer } from '@react-navigation/native'; +import { + createStackNavigator, + StackNavigationOptions, +} from '@react-navigation/stack'; import { - RenderHookResult, render, renderHook, + RenderHookResult, } from '@testing-library/react-native'; + import { mockTheme, ThemeContext } from '../theme'; -import configureStore from './configureStore'; import { Theme } from '../theme/models'; -import { - createStackNavigator, - StackNavigationOptions, -} from '@react-navigation/stack'; +import configureStore from './configureStore'; interface ProviderValues { state?: Record; @@ -22,18 +24,28 @@ interface ProviderValues { export default function renderWithProvider( component: React.ReactElement, providerValues?: ProviderValues, + includeNavigationContainer = true, ) { const { state = {}, theme = mockTheme } = providerValues ?? {}; const store = configureStore(state); - const AllProviders = ({ children }: { children: React.ReactElement }) => ( - - - {children} - - + const InnerProvider = ({ children }: { children: React.ReactElement }) => ( + + {children} + ); + const AllProviders = ({ children }: { children: React.ReactElement }) => { + if (includeNavigationContainer) { + return ( + + {children} + + ); + } + return {children}; + }; + return render(component, { wrapper: AllProviders }); }