From 556a765cc0afee5cc2a08b4b6a1b27af3411b0d0 Mon Sep 17 00:00:00 2001 From: Shane Jonas Date: Thu, 15 Feb 2024 15:53:58 -0500 Subject: [PATCH 01/74] Added generic polling hook --- app/scripts/metamask-controller.js | 6 ++ ui/hooks/usePolling.test.js | 84 +++++++++++++++++++ ui/hooks/usePolling.ts | 49 +++++++++++ .../confirm-transaction.component.js | 43 +++------- .../confirm-transaction.test.js | 12 ++- .../confirm-transaction.transaction.test.js | 5 +- ui/store/actions.ts | 25 ++++++ 7 files changed, 186 insertions(+), 38 deletions(-) create mode 100644 ui/hooks/usePolling.test.js create mode 100644 ui/hooks/usePolling.ts diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index e8f7d9f6887f..97a78cfa969f 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -3301,6 +3301,12 @@ export default class MetamaskController extends EventEmitter { ), // GasFeeController + gasFeeStartPollingByNetworkClientId: + gasFeeController.startPollingByNetworkClientId.bind(gasFeeController), + + gasFeeStopPollingByPollingToken: + gasFeeController.stopPollingByPollingToken.bind(gasFeeController), + getGasFeeEstimatesAndStartPolling: gasFeeController.getGasFeeEstimatesAndStartPolling.bind( gasFeeController, diff --git a/ui/hooks/usePolling.test.js b/ui/hooks/usePolling.test.js new file mode 100644 index 000000000000..4611d5effee3 --- /dev/null +++ b/ui/hooks/usePolling.test.js @@ -0,0 +1,84 @@ +import React from 'react'; +import { renderHook, cleanup } from '@testing-library/react-hooks'; +import { Provider } from 'react-redux'; +import configureStore from '../store/store'; +import usePolling from './usePolling'; + +describe('usePolling', () => { + // eslint-disable-next-line jest/no-done-callback + it('calls startPollingByNetworkClientId and callback option args with polling token when component instantiating the hook mounts', (done) => { + const mockStart = jest.fn().mockImplementation(() => { + return Promise.resolve('pollingToken'); + }); + const mockStop = jest.fn(); + const networkClientId = 'mainnet'; + const options = {}; + const mockState = { + metamask: {}, + }; + + const wrapper = ({ children }) => ( + <> + {children} + + ); + + renderHook( + () => { + usePolling({ + callback: (pollingToken) => { + expect(mockStart).toHaveBeenCalledWith(networkClientId, options); + expect(pollingToken).toBeDefined(); + done(); + return (_pollingToken) => { + // noop + }; + }, + startPollingByNetworkClientId: mockStart, + stopPollingByPollingToken: mockStop, + networkClientId, + options, + }); + }, + { wrapper }, + ); + }); + // eslint-disable-next-line jest/no-done-callback + it('calls the cleanup function with the correct pollingToken when unmounted', (done) => { + const mockStart = jest.fn().mockImplementation(() => { + return Promise.resolve('pollingToken'); + }); + const mockStop = jest.fn(); + const networkClientId = 'mainnet'; + const options = {}; + const mockState = { + metamask: {}, + }; + + const wrapper = ({ children }) => ( + <> + {children} + + ); + + renderHook( + () => { + usePolling({ + callback: () => { + return (_pollingToken) => { + expect(mockStop).toHaveBeenCalledWith(_pollingToken); + expect(_pollingToken).toBeDefined(); + done(); + }; + }, + startPollingByNetworkClientId: mockStart, + stopPollingByPollingToken: mockStop, + networkClientId, + options, + }); + }, + { wrapper }, + ); + cleanup(); + }); +}); diff --git a/ui/hooks/usePolling.ts b/ui/hooks/usePolling.ts new file mode 100644 index 000000000000..42a141547f84 --- /dev/null +++ b/ui/hooks/usePolling.ts @@ -0,0 +1,49 @@ +import { useEffect, useRef } from 'react'; + +type UsePollingOptions = { + callback?: (pollingToken: string) => (pollingToken: string) => void; + startPollingByNetworkClientId: ( + networkClientId: string, + options: any, + ) => Promise; + stopPollingByPollingToken: (pollingToken: string) => void; + networkClientId: string; + options?: any; +}; + +const usePolling = (usePollingOptions: UsePollingOptions) => { + const pollTokenRef = useRef(null); + const cleanupRef = useRef void)>(null); + let isMounted = false; + useEffect(() => { + isMounted = true; + + const cleanup = () => { + if (pollTokenRef.current) { + usePollingOptions.stopPollingByPollingToken(pollTokenRef.current); + cleanupRef.current?.(pollTokenRef.current); + } + }; + // Start polling when the component mounts + usePollingOptions + .startPollingByNetworkClientId( + usePollingOptions.networkClientId, + usePollingOptions.options, + ) + .then((pollToken) => { + pollTokenRef.current = pollToken; + cleanupRef.current = usePollingOptions.callback?.(pollToken) || null; + if (!isMounted) { + cleanup(); + } + }); + + // Return a cleanup function to stop polling when the component unmounts + return () => { + isMounted = false; + cleanup(); + }; + }, [usePollingOptions.networkClientId, usePollingOptions.options]); +}; + +export default usePolling; diff --git a/ui/pages/confirmations/confirm-transaction/confirm-transaction.component.js b/ui/pages/confirmations/confirm-transaction/confirm-transaction.component.js index f32867639b11..41f31a856301 100644 --- a/ui/pages/confirmations/confirm-transaction/confirm-transaction.component.js +++ b/ui/pages/confirmations/confirm-transaction/confirm-transaction.component.js @@ -37,19 +37,19 @@ import { unconfirmedTransactionsListSelector, unconfirmedTransactionsHashSelector, use4ByteResolutionSelector, + getSelectedNetworkClientId, } from '../../../selectors'; import { - disconnectGasFeeEstimatePoller, getContractMethodData, - getGasFeeEstimatesAndStartPolling, - addPollingTokenToAppState, - removePollingTokenFromAppState, setDefaultHomeActiveTabName, + gasFeeStartPollingByNetworkClientId, + gasFeeStopPollingByPollingToken, } from '../../../store/actions'; import ConfirmSignatureRequest from '../confirm-signature-request'; ///: BEGIN:ONLY_INCLUDE_IF(conf-redesign) import Confirm from '../confirm/confirm'; ///: END:ONLY_INCLUDE_IF +import usePolling from '../../../hooks/usePolling'; import ConfirmTokenTransactionSwitch from './confirm-token-transaction-switch'; const ConfirmTransaction = () => { @@ -57,14 +57,12 @@ const ConfirmTransaction = () => { const history = useHistory(); const { id: paramsTransactionId } = useParams(); - const [isMounted, setIsMounted] = useState(false); - const [pollingToken, setPollingToken] = useState(); - const mostRecentOverviewPage = useSelector(getMostRecentOverviewPage); const sendTo = useSelector(getSendTo); const unconfirmedTxsSorted = useSelector(unconfirmedTransactionsListSelector); const unconfirmedTxs = useSelector(unconfirmedTransactionsHashSelector); + const networkClientId = useSelector(getSelectedNetworkClientId); const totalUnapproved = unconfirmedTxsSorted.length || 0; const getTransaction = useCallback(() => { @@ -109,30 +107,13 @@ const ConfirmTransaction = () => { const prevParamsTransactionId = usePrevious(paramsTransactionId); const prevTransactionId = usePrevious(transactionId); - const _beforeUnload = useCallback(() => { - setIsMounted(false); - - if (pollingToken) { - disconnectGasFeeEstimatePoller(pollingToken); - removePollingTokenFromAppState(pollingToken); - } - }, [pollingToken]); + usePolling({ + startPollingByNetworkClientId: gasFeeStartPollingByNetworkClientId, + stopPollingByPollingToken: gasFeeStopPollingByPollingToken, + networkClientId: transaction.networkClientId ?? networkClientId, + }); useEffect(() => { - setIsMounted(true); - - getGasFeeEstimatesAndStartPolling().then((_pollingToken) => { - if (isMounted) { - setPollingToken(_pollingToken); - addPollingTokenToAppState(_pollingToken); - } else { - disconnectGasFeeEstimatePoller(_pollingToken); - removePollingTokenFromAppState(_pollingToken); - } - }); - - window.addEventListener('beforeunload', _beforeUnload); - if (!totalUnapproved && !sendTo) { history.replace(mostRecentOverviewPage); } else { @@ -148,10 +129,6 @@ const ConfirmTransaction = () => { } } - return () => { - _beforeUnload(); - window.removeEventListener('beforeunload', _beforeUnload); - }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); diff --git a/ui/pages/confirmations/confirm-transaction/confirm-transaction.test.js b/ui/pages/confirmations/confirm-transaction/confirm-transaction.test.js index c374316f320a..69d6206aeb09 100644 --- a/ui/pages/confirmations/confirm-transaction/confirm-transaction.test.js +++ b/ui/pages/confirmations/confirm-transaction/confirm-transaction.test.js @@ -135,6 +135,11 @@ jest.mock('../confirm-transaction-switch', () => { }); describe('Confirmation Transaction Page', () => { + beforeEach(() => { + jest + .spyOn(Actions, 'gasFeeStartPollingByNetworkClientId') + .mockResolvedValue(null); + }); it('should display the Loading component when the transaction is invalid', () => { const mockStore = configureMockStore(middleware)({ ...mockState, @@ -216,10 +221,9 @@ describe('Confirmation Transaction Page', () => { describe('initialization', () => { it('should poll for gas estimates', () => { const mockStore = configureMockStore(middleware)(mockState); - const gasEstimationPollingSpy = jest.spyOn( - Actions, - 'getGasFeeEstimatesAndStartPolling', - ); + const gasEstimationPollingSpy = jest + .spyOn(Actions, 'gasFeeStartPollingByNetworkClientId') + .mockResolvedValue(null); renderWithProvider(, mockStore); diff --git a/ui/pages/confirmations/confirm-transaction/confirm-transaction.transaction.test.js b/ui/pages/confirmations/confirm-transaction/confirm-transaction.transaction.test.js index 5be82bcb7588..4c3f9f20dc99 100644 --- a/ui/pages/confirmations/confirm-transaction/confirm-transaction.transaction.test.js +++ b/ui/pages/confirmations/confirm-transaction/confirm-transaction.transaction.test.js @@ -1,7 +1,7 @@ import React from 'react'; import configureMockStore from 'redux-mock-store'; import thunk from 'redux-thunk'; - +import * as Actions from '../../../store/actions'; import { renderWithProvider } from '../../../../test/lib/render-helpers'; import { setBackgroundConnection } from '../../../store/background-connection'; import mockState from '../../../../test/data/mock-state.json'; @@ -28,6 +28,9 @@ describe('Confirm Transaction', () => { mockState.metamask.transactions, )[0]; it('should render correct information for approve transaction with value', () => { + jest + .spyOn(Actions, 'gasFeeStartPollingByNetworkClientId') + .mockResolvedValue(null); const store = configureMockStore(middleware)({ ...mockState, confirmTransaction: { diff --git a/ui/store/actions.ts b/ui/store/actions.ts index 8be2af71284d..53d3ce7e4dbd 100644 --- a/ui/store/actions.ts +++ b/ui/store/actions.ts @@ -4238,6 +4238,31 @@ export async function removePollingTokenFromAppState(pollingToken: string) { ]); } +/** + * Informs the GasFeeController that the UI requires gas fee polling + * + * @param networkClientId - unique identifier for the network client + * @returns polling token that can be used to stop polling + */ +export function gasFeeStartPollingByNetworkClientId(networkClientId: string) { + return submitRequestToBackground('gasFeeStartPollingByNetworkClientId', [ + networkClientId, + ]); +} + +/** + * Informs the GasFeeController that the UI no longer requires gas fee polling + * for the given network client. + * If all network clients unsubscribe, the controller stops polling. + * + * @param pollingToken - Poll token received from calling startPollingByNetworkClientId + */ +export function gasFeeStopPollingByPollingToken(pollingToken: string) { + return submitRequestToBackground('gasFeeStopPollingByPollingToken', [ + pollingToken, + ]); +} + export function getGasFeeTimeEstimate( maxPriorityFeePerGas: string, maxFeePerGas: string, From 5706baa8a0835025aa4eca52e26af8161f9fd5ef Mon Sep 17 00:00:00 2001 From: Shane Jonas Date: Thu, 15 Feb 2024 17:05:07 -0500 Subject: [PATCH 02/74] Added fast stable stringify --- package.json | 1 + ui/hooks/usePolling.ts | 3 ++- yarn.lock | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index eca6edbe72e9..feec542b8245 100644 --- a/package.json +++ b/package.json @@ -333,6 +333,7 @@ "ethereumjs-util": "^7.0.10", "extension-port-stream": "^3.0.0", "fast-json-patch": "^3.1.1", + "fast-json-stable-stringify": "^2.1.0", "fuse.js": "^3.2.0", "human-standard-token-abi": "^2.0.0", "immer": "^9.0.6", diff --git a/ui/hooks/usePolling.ts b/ui/hooks/usePolling.ts index 42a141547f84..1d15bbddac77 100644 --- a/ui/hooks/usePolling.ts +++ b/ui/hooks/usePolling.ts @@ -1,4 +1,5 @@ import { useEffect, useRef } from 'react'; +import stringify from 'fast-json-stable-stringify'; type UsePollingOptions = { callback?: (pollingToken: string) => (pollingToken: string) => void; @@ -43,7 +44,7 @@ const usePolling = (usePollingOptions: UsePollingOptions) => { isMounted = false; cleanup(); }; - }, [usePollingOptions.networkClientId, usePollingOptions.options]); + }, [usePollingOptions.networkClientId, stringify(usePollingOptions.options)]); }; export default usePolling; diff --git a/yarn.lock b/yarn.lock index 609456cd3893..00c252452be7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -24268,6 +24268,7 @@ __metadata: fancy-log: "npm:^1.3.3" fast-glob: "npm:^3.2.2" fast-json-patch: "npm:^3.1.1" + fast-json-stable-stringify: "npm:^2.1.0" fs-extra: "npm:^8.1.0" fuse.js: "npm:^3.2.0" ganache: "npm:^7.9.2" From a9a23037551b66e206e250f82fce6160e4cd33c5 Mon Sep 17 00:00:00 2001 From: Shane Jonas Date: Fri, 16 Feb 2024 11:07:26 -0500 Subject: [PATCH 03/74] Removed fast stringify for normal json stringify to not deal with ESM --- ui/hooks/usePolling.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/ui/hooks/usePolling.ts b/ui/hooks/usePolling.ts index 1d15bbddac77..7698cc61e7fb 100644 --- a/ui/hooks/usePolling.ts +++ b/ui/hooks/usePolling.ts @@ -1,5 +1,4 @@ import { useEffect, useRef } from 'react'; -import stringify from 'fast-json-stable-stringify'; type UsePollingOptions = { callback?: (pollingToken: string) => (pollingToken: string) => void; @@ -44,7 +43,13 @@ const usePolling = (usePollingOptions: UsePollingOptions) => { isMounted = false; cleanup(); }; - }, [usePollingOptions.networkClientId, stringify(usePollingOptions.options)]); + }, [ + usePollingOptions.networkClientId, + JSON.stringify( + usePollingOptions.options, + Object.keys(usePollingOptions.options).sort(), + ), + ]); }; export default usePolling; From 591c9342197d2cccc5ffa6519a68a5ab20782b54 Mon Sep 17 00:00:00 2001 From: Shane Jonas Date: Fri, 16 Feb 2024 11:18:42 -0500 Subject: [PATCH 04/74] Removed fast-json-stable-stringify --- package.json | 1 - yarn.lock | 1 - 2 files changed, 2 deletions(-) diff --git a/package.json b/package.json index feec542b8245..eca6edbe72e9 100644 --- a/package.json +++ b/package.json @@ -333,7 +333,6 @@ "ethereumjs-util": "^7.0.10", "extension-port-stream": "^3.0.0", "fast-json-patch": "^3.1.1", - "fast-json-stable-stringify": "^2.1.0", "fuse.js": "^3.2.0", "human-standard-token-abi": "^2.0.0", "immer": "^9.0.6", diff --git a/yarn.lock b/yarn.lock index 00c252452be7..609456cd3893 100644 --- a/yarn.lock +++ b/yarn.lock @@ -24268,7 +24268,6 @@ __metadata: fancy-log: "npm:^1.3.3" fast-glob: "npm:^3.2.2" fast-json-patch: "npm:^3.1.1" - fast-json-stable-stringify: "npm:^2.1.0" fs-extra: "npm:^8.1.0" fuse.js: "npm:^3.2.0" ganache: "npm:^7.9.2" From d8bb41dda8590d23bf0bfc63eb045dd174d81d4d Mon Sep 17 00:00:00 2001 From: Shane Jonas Date: Fri, 16 Feb 2024 11:37:53 -0500 Subject: [PATCH 05/74] Fixed issue if usePollingOptions.options is not defined --- ui/hooks/usePolling.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ui/hooks/usePolling.ts b/ui/hooks/usePolling.ts index 7698cc61e7fb..ae64d3c73bb6 100644 --- a/ui/hooks/usePolling.ts +++ b/ui/hooks/usePolling.ts @@ -45,10 +45,11 @@ const usePolling = (usePollingOptions: UsePollingOptions) => { }; }, [ usePollingOptions.networkClientId, - JSON.stringify( - usePollingOptions.options, - Object.keys(usePollingOptions.options).sort(), - ), + usePollingOptions.options && + JSON.stringify( + usePollingOptions.options, + Object.keys(usePollingOptions.options).sort(), + ), ]); }; From cf501b9d9aa2c4a83e771b41ba504fae55e08a3e Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Fri, 16 Feb 2024 09:51:17 -0800 Subject: [PATCH 06/74] Replace useSafeGasEstimatePolling with usePolling --- .../files-to-convert.json | 1 - ui/hooks/useGasFeeEstimates.js | 13 +++-- ui/hooks/useSafeGasEstimatePolling.js | 47 ------------------- .../confirmations/hooks/useGasFeeInputs.js | 2 +- .../hooks/useIncrementedGasFees.js | 2 +- 5 files changed, 12 insertions(+), 53 deletions(-) delete mode 100644 ui/hooks/useSafeGasEstimatePolling.js diff --git a/development/ts-migration-dashboard/files-to-convert.json b/development/ts-migration-dashboard/files-to-convert.json index 0a11ad6fba86..be5e60a6a97f 100644 --- a/development/ts-migration-dashboard/files-to-convert.json +++ b/development/ts-migration-dashboard/files-to-convert.json @@ -1130,7 +1130,6 @@ "ui/hooks/useIncrementedGasFees.js", "ui/hooks/useOriginMetadata.js", "ui/hooks/usePrevious.js", - "ui/hooks/useSafeGasEstimatePolling.js", "ui/hooks/useSegmentContext.js", "ui/hooks/useShouldAnimateGasEstimations.js", "ui/hooks/useShouldShowSpeedUp.js", diff --git a/ui/hooks/useGasFeeEstimates.js b/ui/hooks/useGasFeeEstimates.js index 1cd11ccc0727..bf40c832ba71 100644 --- a/ui/hooks/useGasFeeEstimates.js +++ b/ui/hooks/useGasFeeEstimates.js @@ -6,7 +6,8 @@ import { getIsGasEstimatesLoading, getIsNetworkBusy, } from '../ducks/metamask/metamask'; -import { useSafeGasEstimatePolling } from './useSafeGasEstimatePolling'; +import usePolling from './usePolling'; +import { gasFeeStartPollingByNetworkClientId, gasFeeStopPollingByPollingToken } from '../store/actions'; /** * @typedef {object} GasEstimates @@ -27,12 +28,18 @@ import { useSafeGasEstimatePolling } from './useSafeGasEstimatePolling'; * * @returns {GasEstimates} GasEstimates object */ -export function useGasFeeEstimates() { +export function useGasFeeEstimates(networkClientId) { const gasEstimateType = useSelector(getGasEstimateType); const gasFeeEstimates = useSelector(getGasFeeEstimates, isEqual); const isGasEstimatesLoading = useSelector(getIsGasEstimatesLoading); const isNetworkBusy = useSelector(getIsNetworkBusy); - useSafeGasEstimatePolling(); + const selectedNetworkClientId = useSelector(getSelectedNetworkClientId); + + usePolling({ + startPollingByNetworkClientId: gasFeeStartPollingByNetworkClientId, + stopPollingByPollingToken: gasFeeStopPollingByPollingToken, + networkClientId: networkClientId ?? selectedNetworkClientId, + }); return { gasFeeEstimates, diff --git a/ui/hooks/useSafeGasEstimatePolling.js b/ui/hooks/useSafeGasEstimatePolling.js deleted file mode 100644 index 156f805e6737..000000000000 --- a/ui/hooks/useSafeGasEstimatePolling.js +++ /dev/null @@ -1,47 +0,0 @@ -import { useEffect } from 'react'; -import { - disconnectGasFeeEstimatePoller, - getGasFeeEstimatesAndStartPolling, - addPollingTokenToAppState, - removePollingTokenFromAppState, -} from '../store/actions'; - -/** - * Provides a reusable hook that can be used for safely updating the polling - * data in the gas fee controller. It makes a request to get estimates and - * begin polling, keeping track of the poll token for the lifetime of the hook. - * It then disconnects polling upon unmount. If the hook is unmounted while waiting - * for `getGasFeeEstimatesAndStartPolling` to resolve, the `active` flag ensures - * that a call to disconnect happens after promise resolution. - */ -export function useSafeGasEstimatePolling() { - useEffect(() => { - let active = true; - let pollToken; - - const cleanup = () => { - active = false; - if (pollToken) { - disconnectGasFeeEstimatePoller(pollToken); - removePollingTokenFromAppState(pollToken); - } - }; - - getGasFeeEstimatesAndStartPolling().then((newPollToken) => { - if (active) { - pollToken = newPollToken; - addPollingTokenToAppState(pollToken); - } else { - disconnectGasFeeEstimatePoller(newPollToken); - removePollingTokenFromAppState(pollToken); - } - }); - - window.addEventListener('beforeunload', cleanup); - - return () => { - cleanup(); - window.removeEventListener('beforeunload', cleanup); - }; - }, []); -} diff --git a/ui/pages/confirmations/hooks/useGasFeeInputs.js b/ui/pages/confirmations/hooks/useGasFeeInputs.js index 90913f8f86c3..4bbf1ee903c7 100644 --- a/ui/pages/confirmations/hooks/useGasFeeInputs.js +++ b/ui/pages/confirmations/hooks/useGasFeeInputs.js @@ -130,7 +130,7 @@ export function useGasFeeInputs( gasFeeEstimates, isGasEstimatesLoading, isNetworkBusy, - } = useGasFeeEstimates(); + } = useGasFeeEstimates(transaction.networkClientId); const userPrefersAdvancedGas = useSelector(getAdvancedInlineGasShown); diff --git a/ui/pages/confirmations/hooks/useIncrementedGasFees.js b/ui/pages/confirmations/hooks/useIncrementedGasFees.js index 319312e1b421..b4156e70ca16 100644 --- a/ui/pages/confirmations/hooks/useIncrementedGasFees.js +++ b/ui/pages/confirmations/hooks/useIncrementedGasFees.js @@ -39,7 +39,7 @@ function getHighestIncrementedFee(originalFee, currentEstimate) { * ).CustomGasSettings} Gas settings for cancellations/speed ups */ export function useIncrementedGasFees(transaction) { - const { gasFeeEstimates = {} } = useGasFeeEstimates(); + const { gasFeeEstimates = {} } = useGasFeeEstimates(transaction.networkClientId); // We memoize this value so that it can be relied upon in other hooks. const customGasSettings = useMemo(() => { From 57a0469415788af035f50e227791569795ef6154 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Fri, 16 Feb 2024 10:20:09 -0800 Subject: [PATCH 07/74] update specs --- ui/hooks/useGasFeeEstimates.js | 1 + ui/hooks/useGasFeeEstimates.test.js | 37 ++++++++++++++++++++--------- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/ui/hooks/useGasFeeEstimates.js b/ui/hooks/useGasFeeEstimates.js index bf40c832ba71..0dd94b448e01 100644 --- a/ui/hooks/useGasFeeEstimates.js +++ b/ui/hooks/useGasFeeEstimates.js @@ -8,6 +8,7 @@ import { } from '../ducks/metamask/metamask'; import usePolling from './usePolling'; import { gasFeeStartPollingByNetworkClientId, gasFeeStopPollingByPollingToken } from '../store/actions'; +import { getSelectedNetworkClientId } from '../selectors'; /** * @typedef {object} GasEstimates diff --git a/ui/hooks/useGasFeeEstimates.test.js b/ui/hooks/useGasFeeEstimates.test.js index a76633c112a0..21530ab102da 100644 --- a/ui/hooks/useGasFeeEstimates.test.js +++ b/ui/hooks/useGasFeeEstimates.test.js @@ -7,19 +7,17 @@ import { getGasFeeEstimates, getIsGasEstimatesLoading, } from '../ducks/metamask/metamask'; -import { checkNetworkAndAccountSupports1559 } from '../selectors'; +import { checkNetworkAndAccountSupports1559, getSelectedNetworkClientId } from '../selectors'; import { - disconnectGasFeeEstimatePoller, - getGasFeeEstimatesAndStartPolling, + gasFeeStopPollingByPollingToken, + gasFeeStartPollingByNetworkClientId, } from '../store/actions'; import { useGasFeeEstimates } from './useGasFeeEstimates'; jest.mock('../store/actions', () => ({ - disconnectGasFeeEstimatePoller: jest.fn(), - getGasFeeEstimatesAndStartPolling: jest.fn(), - addPollingTokenToAppState: jest.fn(), - removePollingTokenFromAppState: jest.fn(), + gasFeeStopPollingByPollingToken: jest.fn(), + gasFeeStartPollingByNetworkClientId: jest.fn(), })); jest.mock('react-redux', () => { @@ -51,6 +49,9 @@ const generateUseSelectorRouter = DEFAULT_OPTS.checkNetworkAndAccountSupports1559 ); } + if (selector === getSelectedNetworkClientId) { + return 'selectedNetworkClientId'; + } if (selector === getGasEstimateType) { return opts.gasEstimateType ?? DEFAULT_OPTS.gasEstimateType; } @@ -68,12 +69,12 @@ describe('useGasFeeEstimates', () => { beforeEach(() => { jest.clearAllMocks(); tokens = []; - getGasFeeEstimatesAndStartPolling.mockImplementation(() => { + gasFeeStartPollingByNetworkClientId.mockImplementation(() => { const token = createRandomId(); tokens.push(token); return Promise.resolve(token); }); - disconnectGasFeeEstimatePoller.mockImplementation((token) => { + gasFeeStopPollingByPollingToken.mockImplementation((token) => { tokens = tokens.filter((tkn) => tkn !== token); }); }); @@ -90,11 +91,25 @@ describe('useGasFeeEstimates', () => { expect(tokens).toHaveLength(1); const expectedToken = tokens[0]; await cleanup(); - expect(getGasFeeEstimatesAndStartPolling).toHaveBeenCalledTimes(1); - expect(disconnectGasFeeEstimatePoller).toHaveBeenCalledWith(expectedToken); + expect(gasFeeStartPollingByNetworkClientId).toHaveBeenCalledTimes(1); + expect(gasFeeStopPollingByPollingToken).toHaveBeenCalledWith(expectedToken); expect(tokens).toHaveLength(0); }); + it('polls the selected networkClientId by default', () => { + useSelector.mockImplementation(generateUseSelectorRouter()); + renderHook(() => useGasFeeEstimates()); + expect(gasFeeStartPollingByNetworkClientId).toHaveBeenCalledTimes(1); + expect(gasFeeStartPollingByNetworkClientId).toHaveBeenCalledWith('selectedNetworkClientId', undefined) + }); + + it('polls the passed in networkClientId when provided', () => { + useSelector.mockImplementation(generateUseSelectorRouter()); + renderHook(() => useGasFeeEstimates('networkClientId1')); + expect(gasFeeStartPollingByNetworkClientId).toHaveBeenCalledTimes(1); + expect(gasFeeStartPollingByNetworkClientId).toHaveBeenCalledWith('networkClientId1', undefined) + }); + it('works with LEGACY gas prices', () => { useSelector.mockImplementation( generateUseSelectorRouter({ From 3d484525bbedeaadc23ac407f8f3140943756741 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Fri, 16 Feb 2024 13:47:01 -0800 Subject: [PATCH 08/74] update useGasFeeEstimates to use usePolling hook --- app/scripts/metamask-controller.js | 4 + ui/ducks/metamask/metamask.js | 51 ++++- ui/hooks/useGasFeeEstimates.js | 53 +++-- ui/hooks/useGasFeeEstimates.test.js | 183 +++++++++++------- .../hooks/useIncrementedGasFees.js | 4 +- ui/selectors/selectors.js | 5 +- ui/store/actions.ts | 21 +- 7 files changed, 227 insertions(+), 94 deletions(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index eefb4440d6cf..2244b84bbe51 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -2823,6 +2823,10 @@ export default class MetamaskController extends EventEmitter { this.networkController.getEIP1559Compatibility.bind( this.networkController, ), + getNetworkConfigurationByNetworkClientId: + this.networkController.getNetworkConfigurationByNetworkClientId.bind( + this.networkController, + ), // PreferencesController setSelectedAddress: (address) => { const account = this.accountsController.getAccountByAddress(address); diff --git a/ui/ducks/metamask/metamask.js b/ui/ducks/metamask/metamask.js index ed4dd3bb9947..9b35a47c310b 100644 --- a/ui/ducks/metamask/metamask.js +++ b/ui/ducks/metamask/metamask.js @@ -331,12 +331,14 @@ export function isNotEIP1559Network(state) { * Function returns true if network details are fetched and it is found to support EIP-1559 * * @param state + * @param networkClientId */ -export function isEIP1559Network(state) { +export function isEIP1559Network(state, networkClientId) { const selectedNetworkClientId = getSelectedNetworkClientId(state); return ( - state.metamask.networksMetadata?.[selectedNetworkClientId].EIPS[1559] === - true + state.metamask.networksMetadata?.[ + networkClientId ?? selectedNetworkClientId + ].EIPS[1559] === true ); } @@ -352,6 +354,19 @@ export function getEstimatedGasFeeTimeBounds(state) { return state.metamask.estimatedGasFeeTimeBounds; } +export function getGasEstimateTypeByChainId(state, chainId) { + return state.metamask.gasFeeEstimatesByChainId[chainId]?.gasEstimateType; +} + +export function getGasFeeEstimatesByChainId(state, chainId) { + return state.metamask.gasFeeEstimatesByChainId[chainId]?.gasFeeEstimates; +} + +export function getEstimatedGasFeeTimeBoundsByChainId(state, chainId) { + return state.metamask.gasFeeEstimatesByChainId[chainId] + ?.estimatedGasFeeTimeBounds; +} + export function getIsGasEstimatesLoading(state) { const networkAndAccountSupports1559 = checkNetworkAndAccountSupports1559(state); @@ -372,11 +387,41 @@ export function getIsGasEstimatesLoading(state) { return isGasEstimatesLoading; } +export function getIsGasEstimatesLoadingByChainId( + state, + { chainId, networkClientId }, +) { + const networkAndAccountSupports1559 = checkNetworkAndAccountSupports1559( + state, + networkClientId, + ); + const gasEstimateType = getGasEstimateTypeByChainId(state, chainId); + + // We consider the gas estimate to be loading if the gasEstimateType is + // 'NONE' or if the current gasEstimateType cannot be supported by the current + // network + const isEIP1559TolerableEstimateType = + gasEstimateType === GasEstimateTypes.feeMarket || + gasEstimateType === GasEstimateTypes.ethGasPrice; + const isGasEstimatesLoading = + gasEstimateType === GasEstimateTypes.none || + (networkAndAccountSupports1559 && !isEIP1559TolerableEstimateType) || + (!networkAndAccountSupports1559 && + gasEstimateType === GasEstimateTypes.feeMarket); + + return isGasEstimatesLoading; +} + export function getIsNetworkBusy(state) { const gasFeeEstimates = getGasFeeEstimates(state); return gasFeeEstimates?.networkCongestion >= NetworkCongestionThresholds.busy; } +export function getIsNetworkBusyByChainId(state, chainId) { + const gasFeeEstimates = getGasFeeEstimatesByChainId(state, chainId); + return gasFeeEstimates?.networkCongestion >= NetworkCongestionThresholds.busy; +} + export function getCompletedOnboarding(state) { return state.metamask.completedOnboarding; } diff --git a/ui/hooks/useGasFeeEstimates.js b/ui/hooks/useGasFeeEstimates.js index 0dd94b448e01..3f97c8e54529 100644 --- a/ui/hooks/useGasFeeEstimates.js +++ b/ui/hooks/useGasFeeEstimates.js @@ -1,14 +1,19 @@ import isEqual from 'lodash/isEqual'; import { useSelector } from 'react-redux'; +import { useEffect, useState } from 'react'; import { - getGasEstimateType, - getGasFeeEstimates, - getIsGasEstimatesLoading, - getIsNetworkBusy, + getGasEstimateTypeByChainId, + getGasFeeEstimatesByChainId, + getIsGasEstimatesLoadingByChainId, + getIsNetworkBusyByChainId, } from '../ducks/metamask/metamask'; -import usePolling from './usePolling'; -import { gasFeeStartPollingByNetworkClientId, gasFeeStopPollingByPollingToken } from '../store/actions'; +import { + gasFeeStartPollingByNetworkClientId, + gasFeeStopPollingByPollingToken, + getNetworkConfigurationByNetworkClientId, +} from '../store/actions'; import { getSelectedNetworkClientId } from '../selectors'; +import usePolling from './usePolling'; /** * @typedef {object} GasEstimates @@ -27,19 +32,43 @@ import { getSelectedNetworkClientId } from '../selectors'; * GasFeeController that it is done requiring new gas estimates. Also checks * the returned gas estimate for validity on the current network. * + * @param _networkClientId * @returns {GasEstimates} GasEstimates object */ -export function useGasFeeEstimates(networkClientId) { - const gasEstimateType = useSelector(getGasEstimateType); - const gasFeeEstimates = useSelector(getGasFeeEstimates, isEqual); - const isGasEstimatesLoading = useSelector(getIsGasEstimatesLoading); - const isNetworkBusy = useSelector(getIsNetworkBusy); +export function useGasFeeEstimates(_networkClientId) { const selectedNetworkClientId = useSelector(getSelectedNetworkClientId); + const networkClientId = _networkClientId ?? selectedNetworkClientId; + + const [chainId, setChainId] = useState(''); + + const gasEstimateType = useSelector((state) => + getGasEstimateTypeByChainId(state, chainId), + ); + const gasFeeEstimates = useSelector( + (state) => getGasFeeEstimatesByChainId(state, chainId), + isEqual, + ); + const isGasEstimatesLoading = useSelector((state) => + getIsGasEstimatesLoadingByChainId(state, { chainId, networkClientId }), + ); + const isNetworkBusy = useSelector((state) => + getIsNetworkBusyByChainId(state, chainId), + ); + + useEffect(() => { + getNetworkConfigurationByNetworkClientId(networkClientId).then( + (networkConfig) => { + if (networkConfig) { + setChainId(networkConfig.chainId); + } + }, + ); + }, [networkClientId]); usePolling({ startPollingByNetworkClientId: gasFeeStartPollingByNetworkClientId, stopPollingByPollingToken: gasFeeStopPollingByPollingToken, - networkClientId: networkClientId ?? selectedNetworkClientId, + networkClientId, }); return { diff --git a/ui/hooks/useGasFeeEstimates.test.js b/ui/hooks/useGasFeeEstimates.test.js index 21530ab102da..0187ac793bbe 100644 --- a/ui/hooks/useGasFeeEstimates.test.js +++ b/ui/hooks/useGasFeeEstimates.test.js @@ -1,23 +1,49 @@ -import { cleanup, renderHook } from '@testing-library/react-hooks'; +import { renderHook, act } from '@testing-library/react-hooks'; import { useSelector } from 'react-redux'; import { GasEstimateTypes } from '../../shared/constants/gas'; -import createRandomId from '../../shared/modules/random-id'; import { - getGasEstimateType, - getGasFeeEstimates, - getIsGasEstimatesLoading, + getGasEstimateTypeByChainId, + getGasFeeEstimatesByChainId, + getIsGasEstimatesLoadingByChainId, + getIsNetworkBusyByChainId, } from '../ducks/metamask/metamask'; -import { checkNetworkAndAccountSupports1559, getSelectedNetworkClientId } from '../selectors'; import { - gasFeeStopPollingByPollingToken, gasFeeStartPollingByNetworkClientId, + gasFeeStopPollingByPollingToken, + getNetworkConfigurationByNetworkClientId, } from '../store/actions'; import { useGasFeeEstimates } from './useGasFeeEstimates'; +import usePolling from './usePolling'; + +jest.mock('./usePolling', () => jest.fn()); jest.mock('../store/actions', () => ({ - gasFeeStopPollingByPollingToken: jest.fn(), - gasFeeStartPollingByNetworkClientId: jest.fn(), + getNetworkConfigurationByNetworkClientId: jest.fn(), +})); + +jest.mock('../ducks/metamask/metamask', () => ({ + getGasEstimateTypeByChainId: jest + .fn() + .mockReturnValue('getGasEstimateTypeByChainId'), + getGasFeeEstimatesByChainId: jest + .fn() + .mockReturnValue('getGasFeeEstimatesByChainId'), + getIsGasEstimatesLoadingByChainId: jest + .fn() + .mockReturnValue('getIsGasEstimatesLoadingByChainId'), + getIsNetworkBusyByChainId: jest + .fn() + .mockReturnValue('getIsNetworkBusyByChainId'), +})); + +jest.mock('../selectors', () => ({ + checkNetworkAndAccountSupports1559: jest + .fn() + .mockReturnValue('checkNetworkAndAccountSupports1559'), + getSelectedNetworkClientId: jest + .fn() + .mockReturnValue('getSelectedNetworkClientId'), })); jest.mock('react-redux', () => { @@ -40,93 +66,105 @@ const DEFAULT_OPTS = { isGasEstimatesLoading: true, }; +const MOCK_STATE = {}; + const generateUseSelectorRouter = (opts = DEFAULT_OPTS) => (selector) => { - if (selector === checkNetworkAndAccountSupports1559) { + const selectorId = selector(MOCK_STATE); + if (selectorId === 'checkNetworkAndAccountSupports1559') { return ( opts.checkNetworkAndAccountSupports1559 ?? DEFAULT_OPTS.checkNetworkAndAccountSupports1559 ); } - if (selector === getSelectedNetworkClientId) { + if (selectorId === 'getSelectedNetworkClientId') { return 'selectedNetworkClientId'; } - if (selector === getGasEstimateType) { + if (selectorId === 'getGasEstimateTypeByChainId') { return opts.gasEstimateType ?? DEFAULT_OPTS.gasEstimateType; } - if (selector === getGasFeeEstimates) { + if (selectorId === 'getGasFeeEstimatesByChainId') { return opts.gasFeeEstimates ?? DEFAULT_OPTS.gasFeeEstimates; } - if (selector === getIsGasEstimatesLoading) { + if (selectorId === 'getIsGasEstimatesLoadingByChainId') { return opts.isGasEstimatesLoading ?? DEFAULT_OPTS.isGasEstimatesLoading; } return undefined; }; describe('useGasFeeEstimates', () => { - let tokens = []; beforeEach(() => { jest.clearAllMocks(); - tokens = []; - gasFeeStartPollingByNetworkClientId.mockImplementation(() => { - const token = createRandomId(); - tokens.push(token); - return Promise.resolve(token); - }); - gasFeeStopPollingByPollingToken.mockImplementation((token) => { - tokens = tokens.filter((tkn) => tkn !== token); - }); - }); + getNetworkConfigurationByNetworkClientId.mockImplementation( + (networkClientId) => { + if (!networkClientId) { + return Promise.resolve(undefined); + } - it('registers with the controller', () => { - useSelector.mockImplementation(generateUseSelectorRouter()); - renderHook(() => useGasFeeEstimates()); - expect(tokens).toHaveLength(1); + return Promise.resolve({ + chainId: '0xa', + }); + }, + ); }); - it('clears token with the controller on unmount', async () => { + it('polls the selected networkClientId by default', async () => { useSelector.mockImplementation(generateUseSelectorRouter()); - renderHook(() => useGasFeeEstimates()); - expect(tokens).toHaveLength(1); - const expectedToken = tokens[0]; - await cleanup(); - expect(gasFeeStartPollingByNetworkClientId).toHaveBeenCalledTimes(1); - expect(gasFeeStopPollingByPollingToken).toHaveBeenCalledWith(expectedToken); - expect(tokens).toHaveLength(0); + await act(async () => { + renderHook(() => useGasFeeEstimates()); + }); + expect(usePolling).toHaveBeenCalledWith({ + startPollingByNetworkClientId: gasFeeStartPollingByNetworkClientId, + stopPollingByPollingToken: gasFeeStopPollingByPollingToken, + networkClientId: 'selectedNetworkClientId', + }); }); - it('polls the selected networkClientId by default', () => { + it('polls the passed in networkClientId when provided', async () => { useSelector.mockImplementation(generateUseSelectorRouter()); - renderHook(() => useGasFeeEstimates()); - expect(gasFeeStartPollingByNetworkClientId).toHaveBeenCalledTimes(1); - expect(gasFeeStartPollingByNetworkClientId).toHaveBeenCalledWith('selectedNetworkClientId', undefined) + await act(async () => { + renderHook(() => useGasFeeEstimates('networkClientId1')); + }); + expect(usePolling).toHaveBeenCalledWith({ + startPollingByNetworkClientId: gasFeeStartPollingByNetworkClientId, + stopPollingByPollingToken: gasFeeStopPollingByPollingToken, + networkClientId: 'networkClientId1', + }); }); - it('polls the passed in networkClientId when provided', () => { + it('reads state with the right chainId and networkClientId', async () => { useSelector.mockImplementation(generateUseSelectorRouter()); - renderHook(() => useGasFeeEstimates('networkClientId1')); - expect(gasFeeStartPollingByNetworkClientId).toHaveBeenCalledTimes(1); - expect(gasFeeStartPollingByNetworkClientId).toHaveBeenCalledWith('networkClientId1', undefined) + + await act(async () => + renderHook(() => useGasFeeEstimates('networkClientId1')), + ); + expect(getGasEstimateTypeByChainId).toHaveBeenCalledWith(MOCK_STATE, '0xa'); + expect(getGasFeeEstimatesByChainId).toHaveBeenCalledWith(MOCK_STATE, '0xa'); + expect(getIsGasEstimatesLoadingByChainId).toHaveBeenCalledWith(MOCK_STATE, { + chainId: '0xa', + networkClientId: 'networkClientId1', + }); + expect(getIsNetworkBusyByChainId).toHaveBeenCalledWith(MOCK_STATE, '0xa'); }); - it('works with LEGACY gas prices', () => { + it('works with LEGACY gas prices', async () => { useSelector.mockImplementation( generateUseSelectorRouter({ isGasEstimatesLoading: false, }), ); - const { - result: { current }, - } = renderHook(() => useGasFeeEstimates()); - expect(current).toMatchObject({ + + let hook; + await act(async () => (hook = renderHook(() => useGasFeeEstimates()))); + expect(hook.result.current).toMatchObject({ gasFeeEstimates: DEFAULT_OPTS.gasFeeEstimates, gasEstimateType: GasEstimateTypes.legacy, isGasEstimatesLoading: false, }); }); - it('works with ETH_GASPRICE gas prices', () => { + it('works with ETH_GASPRICE gas prices', async () => { const gasFeeEstimates = { gasPrice: '10' }; useSelector.mockImplementation( generateUseSelectorRouter({ @@ -136,17 +174,16 @@ describe('useGasFeeEstimates', () => { }), ); - const { - result: { current }, - } = renderHook(() => useGasFeeEstimates()); - expect(current).toMatchObject({ + let hook; + await act(async () => (hook = renderHook(() => useGasFeeEstimates()))); + expect(hook.result.current).toMatchObject({ gasFeeEstimates, gasEstimateType: GasEstimateTypes.ethGasPrice, isGasEstimatesLoading: false, }); }); - it('works with FEE_MARKET gas prices', () => { + it('works with FEE_MARKET gas prices', async () => { const gasFeeEstimates = { low: { minWaitTimeEstimate: 180000, @@ -177,17 +214,16 @@ describe('useGasFeeEstimates', () => { }), ); - const { - result: { current }, - } = renderHook(() => useGasFeeEstimates()); - expect(current).toMatchObject({ + let hook; + await act(async () => (hook = renderHook(() => useGasFeeEstimates()))); + expect(hook.result.current).toMatchObject({ gasFeeEstimates, gasEstimateType: GasEstimateTypes.feeMarket, isGasEstimatesLoading: false, }); }); - it('indicates that gas estimates are loading when gasEstimateType is NONE', () => { + it('indicates that gas estimates are loading when gasEstimateType is NONE', async () => { useSelector.mockImplementation( generateUseSelectorRouter({ gasEstimateType: GasEstimateTypes.none, @@ -195,17 +231,16 @@ describe('useGasFeeEstimates', () => { }), ); - const { - result: { current }, - } = renderHook(() => useGasFeeEstimates()); - expect(current).toMatchObject({ + let hook; + await act(async () => (hook = renderHook(() => useGasFeeEstimates()))); + expect(hook.result.current).toMatchObject({ gasFeeEstimates: {}, gasEstimateType: GasEstimateTypes.none, isGasEstimatesLoading: true, }); }); - it('indicates that gas estimates are loading when gasEstimateType is not FEE_MARKET or ETH_GASPRICE, but network supports EIP-1559', () => { + it('indicates that gas estimates are loading when gasEstimateType is not FEE_MARKET or ETH_GASPRICE, but network supports EIP-1559', async () => { useSelector.mockImplementation( generateUseSelectorRouter({ checkNetworkAndAccountSupports1559: true, @@ -216,17 +251,16 @@ describe('useGasFeeEstimates', () => { }), ); - const { - result: { current }, - } = renderHook(() => useGasFeeEstimates()); - expect(current).toMatchObject({ + let hook; + await act(async () => (hook = renderHook(() => useGasFeeEstimates()))); + expect(hook.result.current).toMatchObject({ gasFeeEstimates: { gasPrice: '10' }, gasEstimateType: GasEstimateTypes.legacy, isGasEstimatesLoading: true, }); }); - it('indicates that gas estimates are loading when gasEstimateType is FEE_MARKET but network does not support EIP-1559', () => { + it('indicates that gas estimates are loading when gasEstimateType is FEE_MARKET but network does not support EIP-1559', async () => { const gasFeeEstimates = { low: { minWaitTimeEstimate: 180000, @@ -256,10 +290,9 @@ describe('useGasFeeEstimates', () => { }), ); - const { - result: { current }, - } = renderHook(() => useGasFeeEstimates()); - expect(current).toMatchObject({ + let hook; + await act(async () => (hook = renderHook(() => useGasFeeEstimates()))); + expect(hook.result.current).toMatchObject({ gasFeeEstimates, gasEstimateType: GasEstimateTypes.feeMarket, isGasEstimatesLoading: true, diff --git a/ui/pages/confirmations/hooks/useIncrementedGasFees.js b/ui/pages/confirmations/hooks/useIncrementedGasFees.js index b4156e70ca16..68556c216f53 100644 --- a/ui/pages/confirmations/hooks/useIncrementedGasFees.js +++ b/ui/pages/confirmations/hooks/useIncrementedGasFees.js @@ -39,7 +39,9 @@ function getHighestIncrementedFee(originalFee, currentEstimate) { * ).CustomGasSettings} Gas settings for cancellations/speed ups */ export function useIncrementedGasFees(transaction) { - const { gasFeeEstimates = {} } = useGasFeeEstimates(transaction.networkClientId); + const { gasFeeEstimates = {} } = useGasFeeEstimates( + transaction.networkClientId, + ); // We memoize this value so that it can be relied upon in other hooks. const customGasSettings = useMemo(() => { diff --git a/ui/selectors/selectors.js b/ui/selectors/selectors.js index 50434c17d9e2..d9f24ee4ba8b 100644 --- a/ui/selectors/selectors.js +++ b/ui/selectors/selectors.js @@ -182,9 +182,10 @@ export function getCurrentKeyring(state) { * both of them support EIP-1559. * * @param state + * @param networkClientId */ -export function checkNetworkAndAccountSupports1559(state) { - const networkSupports1559 = isEIP1559Network(state); +export function checkNetworkAndAccountSupports1559(state, networkClientId) { + const networkSupports1559 = isEIP1559Network(state, networkClientId); return networkSupports1559; } diff --git a/ui/store/actions.ts b/ui/store/actions.ts index 53d3ce7e4dbd..62c4053d3694 100644 --- a/ui/store/actions.ts +++ b/ui/store/actions.ts @@ -31,7 +31,10 @@ import { TransactionParams, TransactionType, } from '@metamask/transaction-controller'; -import { NetworkClientId } from '@metamask/network-controller'; +import { + NetworkClientId, + NetworkConfiguration, +} from '@metamask/network-controller'; import { getMethodDataAsync } from '../helpers/utils/transactions.util'; import switchDirection from '../../shared/lib/switch-direction'; import { @@ -4766,6 +4769,22 @@ export async function getCurrentNetworkEIP1559Compatibility(): Promise< return networkEIP1559Compatibility; } +export async function getNetworkConfigurationByNetworkClientId( + networkClientId: NetworkClientId, +): Promise { + let networkConfiguration; + try { + networkConfiguration = + await submitRequestToBackground( + 'getNetworkConfigurationByNetworkClientId', + [networkClientId], + ); + } catch (error) { + console.error(error); + } + return networkConfiguration; +} + export function updateProposedNames( request: UpdateProposedNamesRequest, ): ThunkAction< From cabd6dbf4390a9b536911dd151b497bb215f2578 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Fri, 16 Feb 2024 13:53:17 -0800 Subject: [PATCH 09/74] fix undefined dereference estimatedBaseFee --- ui/pages/confirmations/hooks/useGasEstimates.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/pages/confirmations/hooks/useGasEstimates.js b/ui/pages/confirmations/hooks/useGasEstimates.js index a277bdff4d5d..769d1175fb13 100644 --- a/ui/pages/confirmations/hooks/useGasEstimates.js +++ b/ui/pages/confirmations/hooks/useGasEstimates.js @@ -76,7 +76,7 @@ export function useGasEstimates({ maxPriorityFeePerGas: decGWEIToHexWEI( maxPriorityFeePerGas || maxFeePerGas || gasPrice || '0', ), - baseFeePerGas: decGWEIToHexWEI(gasFeeEstimates.estimatedBaseFee ?? '0'), + baseFeePerGas: decGWEIToHexWEI(gasFeeEstimates?.estimatedBaseFee ?? '0'), }; } else { gasSettings = { From 3ec134edf8d3e4a8d57aecad33748be236a4f010 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Fri, 16 Feb 2024 15:41:05 -0800 Subject: [PATCH 10/74] Fix base-fee-input --- .tool-versions | 1 + test/data/mock-state.json | 32 +++++++ .../base-fee-input/base-fee-input.js | 25 ++--- .../base-fee-input/base-fee-input.test.js | 91 +++++++++++-------- .../confirmations/hooks/useGasEstimates.js | 5 +- 5 files changed, 103 insertions(+), 51 deletions(-) create mode 100644 .tool-versions diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 000000000000..38b76b57c456 --- /dev/null +++ b/.tool-versions @@ -0,0 +1 @@ +nodejs 20.8.1 diff --git a/test/data/mock-state.json b/test/data/mock-state.json index 06ab82c99d9f..32a4fe3ad582 100644 --- a/test/data/mock-state.json +++ b/test/data/mock-state.json @@ -43,6 +43,38 @@ "participateInMetaMetrics": false, "gasEstimateType": "fee-market", "showBetaHeader": false, + "gasFeeEstimatesByChainId": { + "0x5": { + "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", + "historicalBaseFeeRange": ["28.533098435", "70.351148354"], + "baseFeeTrend": "up", + "latestPriorityFeeRange": ["1", "40"], + "historicalPriorityFeeRange": ["0.1458417", "700.156384646"], + "priorityFeeTrend": "down", + "networkCongestion": 0.90625 + } + } + }, "gasFeeEstimates": { "low": { "minWaitTimeEstimate": 180000, diff --git a/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/base-fee-input/base-fee-input.js b/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/base-fee-input/base-fee-input.js index 3fc739b0cd1b..30a4e06b606b 100644 --- a/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/base-fee-input/base-fee-input.js +++ b/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/base-fee-input/base-fee-input.js @@ -59,23 +59,24 @@ const BaseFeeInput = () => { } = useAdvancedGasFeePopoverContext(); const { estimatedBaseFee, historicalBaseFeeRange, baseFeeTrend } = - gasFeeEstimates; + gasFeeEstimates ?? {}; + const [baseFeeError, setBaseFeeError] = useState(); const { currency, numberOfDecimals } = useUserPreferencedCurrency(PRIMARY); const advancedGasFeeValues = useSelector(getAdvancedGasFeeValues); - const [baseFee, setBaseFee] = useState(() => { - if ( - estimateUsed !== PriorityLevels.custom && - advancedGasFeeValues?.maxBaseFee && - editGasMode !== EditGasModes.swaps - ) { - return advancedGasFeeValues.maxBaseFee; - } - - return maxFeePerGas; - }); + const defaultBaseFee = + estimateUsed !== PriorityLevels.custom && + advancedGasFeeValues?.maxBaseFee && + editGasMode !== EditGasModes.swaps + ? advancedGasFeeValues.maxBaseFee + : maxFeePerGas; + + const [baseFee, setBaseFee] = useState(defaultBaseFee); + useEffect(() => { + setBaseFee(defaultBaseFee); + }, [defaultBaseFee, setBaseFee]); const [baseFeeInPrimaryCurrency] = useCurrencyDisplay( decGWEIToHexWEI(baseFee * gasLimit), diff --git a/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/base-fee-input/base-fee-input.test.js b/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/base-fee-input/base-fee-input.test.js index e89cbdf54bb4..ab5fa150579f 100644 --- a/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/base-fee-input/base-fee-input.test.js +++ b/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/base-fee-input/base-fee-input.test.js @@ -1,6 +1,7 @@ import React from 'react'; import { fireEvent, screen } from '@testing-library/react'; +import { act } from 'react-dom/test-utils'; import { EditGasModes, GasEstimateTypes, @@ -16,15 +17,16 @@ import AdvancedGasFeeGasLimit from '../../advanced-gas-fee-gas-limit'; import BaseFeeInput from './base-fee-input'; jest.mock('../../../../../../store/actions', () => ({ - disconnectGasFeeEstimatePoller: jest.fn(), - getGasFeeEstimatesAndStartPolling: jest + gasFeeStartPollingByNetworkClientId: jest .fn() - .mockImplementation(() => Promise.resolve()), - addPollingTokenToAppState: jest.fn(), - removePollingTokenFromAppState: jest.fn(), + .mockResolvedValue('pollingToken'), + gasFeeStopPollingByPollingToken: jest.fn(), + getNetworkConfigurationByNetworkClientId: jest + .fn() + .mockResolvedValue({ chainId: '0x5' }), })); -const render = (txProps, contextProps) => { +const render = async (txProps, contextProps) => { const store = configureStore({ metamask: { ...mockState.metamask, @@ -34,40 +36,55 @@ const render = (txProps, contextProps) => { balance: '0x1F4', }, }, - advancedGasFee: { maxBaseFee: 100 }, + advancedGasFee: { '0x5': { maxBaseFee: 100 } }, featureFlags: { advancedInlineGas: true }, gasFeeEstimates: mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, + gasFeeEstimatesByChainId: { + ...mockState.metamask.gasFeeEstimatesByChainId, + '0x5': { + ...mockState.metamask.gasFeeEstimatesByChainId['0x5'], + gasFeeEstimates: + mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, + }, + }, }, }); - return renderWithProvider( - - - - - - , - store, + let result; + + await act( + async () => + (result = renderWithProvider( + + + + + + , + store, + )), ); + + return result; }; describe('BaseFeeInput', () => { - it('should renders advancedGasFee.baseFee value if current estimate used is not custom', () => { - render({ + it('should renders advancedGasFee.baseFee value if current estimate used is not custom', async () => { + await render({ userFeeLevel: 'high', }); expect(document.getElementsByTagName('input')[0]).toHaveValue(100); }); - it('should not use advancedGasFee.baseFee value for swaps', () => { - render( + it('should not use advancedGasFee.baseFee value for swaps', async () => { + await render( { userFeeLevel: 'high', }, @@ -82,8 +99,8 @@ describe('BaseFeeInput', () => { ); }); - it('should renders baseFee values from transaction if current estimate used is custom', () => { - render({ + it('should renders baseFee values from transaction if current estimate used is custom', async () => { + await render({ txParams: { maxFeePerGas: '0x2E90EDD000', }, @@ -91,8 +108,8 @@ describe('BaseFeeInput', () => { expect(document.getElementsByTagName('input')[0]).toHaveValue(200); }); - it('should show current value of estimatedBaseFee in users primary currency in right side of input box', () => { - render({ + it('should show current value of estimatedBaseFee in users primary currency in right side of input box', async () => { + await render({ txParams: { gas: '0x5208', maxFeePerGas: '0x2E90EDD000', @@ -101,18 +118,18 @@ describe('BaseFeeInput', () => { expect(screen.queryByText('≈ 0.0042 ETH')).toBeInTheDocument(); }); - it('should show current value of estimatedBaseFee in subtext', () => { - render(); + it('should show current value of estimatedBaseFee in subtext', async () => { + await render(); expect(screen.queryByText('50 GWEI')).toBeInTheDocument(); }); - it('should show 12hr range value in subtext', () => { - render(); + it('should show 12hr range value in subtext', async () => { + await render(); expect(screen.queryByText('50 - 100 GWEI')).toBeInTheDocument(); }); - it('should show error if base fee is less than suggested low value', () => { - render({ + it('should show error if base fee is less than suggested low value', async () => { + await render({ txParams: { maxFeePerGas: '0x174876E800', }, @@ -128,8 +145,8 @@ describe('BaseFeeInput', () => { }); }); - it('should show error if base if is more than suggested high value', () => { - render({ + it('should show error if base if is more than suggested high value', async () => { + await render({ txParams: { maxFeePerGas: '0x174876E800', }, diff --git a/ui/pages/confirmations/hooks/useGasEstimates.js b/ui/pages/confirmations/hooks/useGasEstimates.js index 769d1175fb13..083c084689a6 100644 --- a/ui/pages/confirmations/hooks/useGasEstimates.js +++ b/ui/pages/confirmations/hooks/useGasEstimates.js @@ -53,8 +53,9 @@ export function useGasEstimates({ transaction, }) { const supportsEIP1559 = - useSelector(checkNetworkAndAccountSupports1559) && - !isLegacyTransaction(transaction?.txParams); + useSelector((state) => + checkNetworkAndAccountSupports1559(state, transaction?.networkClientId), + ) && !isLegacyTransaction(transaction?.txParams); const { currency: primaryCurrency, From 9a641c93cfcb2fb0cab51297b00546b41ad0865b Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Fri, 16 Feb 2024 15:54:23 -0800 Subject: [PATCH 11/74] jsdoc --- ui/ducks/metamask/metamask.js | 2 +- ui/hooks/useGasFeeEstimates.js | 2 +- ui/selectors/selectors.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/ducks/metamask/metamask.js b/ui/ducks/metamask/metamask.js index 9b35a47c310b..71924dbdd7bc 100644 --- a/ui/ducks/metamask/metamask.js +++ b/ui/ducks/metamask/metamask.js @@ -331,7 +331,7 @@ export function isNotEIP1559Network(state) { * Function returns true if network details are fetched and it is found to support EIP-1559 * * @param state - * @param networkClientId + * @param networkClientId - The optional network client ID to check for EIP-1559 support. Defaults to the currently selected network. */ export function isEIP1559Network(state, networkClientId) { const selectedNetworkClientId = getSelectedNetworkClientId(state); diff --git a/ui/hooks/useGasFeeEstimates.js b/ui/hooks/useGasFeeEstimates.js index 3f97c8e54529..b58a2654815b 100644 --- a/ui/hooks/useGasFeeEstimates.js +++ b/ui/hooks/useGasFeeEstimates.js @@ -32,7 +32,7 @@ import usePolling from './usePolling'; * GasFeeController that it is done requiring new gas estimates. Also checks * the returned gas estimate for validity on the current network. * - * @param _networkClientId + * @param _networkClientId - The optional network client ID to get gas fee estimates for. Defaults to the currently selected network. * @returns {GasEstimates} GasEstimates object */ export function useGasFeeEstimates(_networkClientId) { diff --git a/ui/selectors/selectors.js b/ui/selectors/selectors.js index d9f24ee4ba8b..3b8c5115b812 100644 --- a/ui/selectors/selectors.js +++ b/ui/selectors/selectors.js @@ -182,7 +182,7 @@ export function getCurrentKeyring(state) { * both of them support EIP-1559. * * @param state - * @param networkClientId + * @param networkClientId - The optional network client ID to check network and account for EIP-1559 support */ export function checkNetworkAndAccountSupports1559(state, networkClientId) { const networkSupports1559 = isEIP1559Network(state, networkClientId); From cd086c4e9de4169aef2c5f7bf557d7c774479bff Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Fri, 16 Feb 2024 15:54:37 -0800 Subject: [PATCH 12/74] remove .tool-versions --- .tool-versions | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .tool-versions diff --git a/.tool-versions b/.tool-versions deleted file mode 100644 index 38b76b57c456..000000000000 --- a/.tool-versions +++ /dev/null @@ -1 +0,0 @@ -nodejs 20.8.1 From 6398d0617391aed52b431cdb0bf58dc6bf913a93 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 20 Feb 2024 10:00:32 -0800 Subject: [PATCH 13/74] fix advanced-gas-fee-gas-limit.test.js --- .../advanced-gas-fee-gas-limit.test.js | 52 +++++++++++++------ 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-gas-limit/advanced-gas-fee-gas-limit.test.js b/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-gas-limit/advanced-gas-fee-gas-limit.test.js index 51e0c5ed9c6d..4c3c49f294a7 100644 --- a/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-gas-limit/advanced-gas-fee-gas-limit.test.js +++ b/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-gas-limit/advanced-gas-fee-gas-limit.test.js @@ -11,17 +11,21 @@ import configureStore from '../../../../../store/store'; import { AdvancedGasFeePopoverContextProvider } from '../context'; import AdvancedGasFeeGasLimit from './advanced-gas-fee-gas-limit'; +import { act } from 'react-dom/test-utils'; jest.mock('../../../../../store/actions', () => ({ - disconnectGasFeeEstimatePoller: jest.fn(), - getGasFeeEstimatesAndStartPolling: jest + gasFeeStartPollingByNetworkClientId: jest .fn() - .mockImplementation(() => Promise.resolve()), - addPollingTokenToAppState: jest.fn(), - removePollingTokenFromAppState: jest.fn(), + .mockResolvedValue('pollingToken'), + gasFeeStopPollingByPollingToken: jest.fn(), + getNetworkConfigurationByNetworkClientId: jest + .fn() + .mockResolvedValue({ chainId: '0x5' }), })); -const render = (contextProps) => { + + +const render = async (contextProps) => { const store = configureStore({ metamask: { ...mockState.metamask, @@ -31,14 +35,26 @@ const render = (contextProps) => { balance: '0x1F4', }, }, - advancedGasFee: { priorityFee: 100 }, + advancedGasFee: { '0x5': { priorityFee: 100 } }, featureFlags: { advancedInlineGas: true }, gasFeeEstimates: mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, + gasFeeEstimatesByChainId: { + ...mockState.metamask.gasFeeEstimatesByChainId, + '0x5': { + ...mockState.metamask.gasFeeEstimatesByChainId['0x5'], + gasFeeEstimates: + mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, + }, + }, }, }); - return renderWithProvider( + let result; + + await act( + async () => + result = renderWithProvider( { , store, - ); + )) + + return result; }; describe('AdvancedGasFeeGasLimit', () => { - it('should show GasLimit from transaction', () => { - render(); + it('should show GasLimit from transaction', async () => { + await render(); expect(screen.getByText('21000')).toBeInTheDocument(); }); - it('should show input when edit link is clicked', () => { - render(); + it('should show input when edit link is clicked', async () => { + await render(); expect(document.getElementsByTagName('input')).toHaveLength(0); fireEvent.click(screen.queryByText('Edit')); expect(document.getElementsByTagName('input')[0]).toHaveValue(21000); }); - it('should show error if gas limit is not in range', () => { - render(); + it('should show error if gas limit is not in range', async () => { + await render(); fireEvent.click(screen.queryByText('Edit')); fireEvent.change(document.getElementsByTagName('input')[0], { target: { value: 20000 }, @@ -96,8 +114,8 @@ describe('AdvancedGasFeeGasLimit', () => { ).not.toBeInTheDocument(); }); - it('should validate gas limit against minimumGasLimit it is passed to context', () => { - render({ minimumGasLimit: '0x7530' }); + it('should validate gas limit against minimumGasLimit it is passed to context', async () => { + await render({ minimumGasLimit: '0x7530' }); fireEvent.click(screen.queryByText('Edit')); fireEvent.change(document.getElementsByTagName('input')[0], { target: { value: 25000 }, From c99ff3b3f416b86e0e6ecb71fffc9206652c750b Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 20 Feb 2024 10:13:16 -0800 Subject: [PATCH 14/74] Fix priority fee --- .../priority-fee-input/priority-fee-input.js | 25 +++++++++++-------- .../priority-fee-input.test.js | 11 ++++---- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/priority-fee-input/priority-fee-input.js b/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/priority-fee-input/priority-fee-input.js index 70ee1d913b44..8ec87783bf38 100644 --- a/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/priority-fee-input/priority-fee-input.js +++ b/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/priority-fee-input/priority-fee-input.js @@ -57,19 +57,22 @@ const PriorityFeeInput = () => { latestPriorityFeeRange, historicalPriorityFeeRange, priorityFeeTrend, - } = gasFeeEstimates; + } = gasFeeEstimates ?? {}; const [priorityFeeError, setPriorityFeeError] = useState(); - const [priorityFee, setPriorityFee] = useState(() => { - if ( - estimateUsed !== PriorityLevels.custom && - advancedGasFeeValues?.priorityFee && - editGasMode !== EditGasModes.swaps - ) { - return advancedGasFeeValues.priorityFee; - } - return maxPriorityFeePerGas; - }); + + const defaultPriorityFee = + estimateUsed !== PriorityLevels.custom && + advancedGasFeeValues?.priorityFee && + editGasMode !== EditGasModes.swaps + ? advancedGasFeeValues.priorityFee + : maxPriorityFeePerGas; + + + const [priorityFee, setPriorityFee] = useState(defaultPriorityFee); + useEffect(() => { + setPriorityFee(defaultPriorityFee); + }, [defaultPriorityFee, setPriorityFee]); const { currency, numberOfDecimals } = useUserPreferencedCurrency(PRIMARY); diff --git a/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/priority-fee-input/priority-fee-input.test.js b/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/priority-fee-input/priority-fee-input.test.js index 6aa3cac2531e..eafe65b10fc0 100644 --- a/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/priority-fee-input/priority-fee-input.test.js +++ b/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/priority-fee-input/priority-fee-input.test.js @@ -17,12 +17,13 @@ import { CHAIN_IDS } from '../../../../../../../shared/constants/network'; import PriorityfeeInput from './priority-fee-input'; jest.mock('../../../../../../store/actions', () => ({ - disconnectGasFeeEstimatePoller: jest.fn(), - getGasFeeEstimatesAndStartPolling: jest + gasFeeStartPollingByNetworkClientId: jest .fn() - .mockImplementation(() => Promise.resolve()), - addPollingTokenToAppState: jest.fn(), - removePollingTokenFromAppState: jest.fn(), + .mockResolvedValue('pollingToken'), + gasFeeStopPollingByPollingToken: jest.fn(), + getNetworkConfigurationByNetworkClientId: jest + .fn() + .mockResolvedValue({ chainId: '0x5' }), })); const render = (txProps, contextProps) => { From db00da5ebf118973aa497d03249b20329267fd67 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 20 Feb 2024 10:13:26 -0800 Subject: [PATCH 15/74] fix base fee import act --- .../base-fee-input/base-fee-input.test.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/base-fee-input/base-fee-input.test.js b/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/base-fee-input/base-fee-input.test.js index ab5fa150579f..67a15399f301 100644 --- a/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/base-fee-input/base-fee-input.test.js +++ b/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/base-fee-input/base-fee-input.test.js @@ -1,7 +1,6 @@ import React from 'react'; -import { fireEvent, screen } from '@testing-library/react'; +import { act, fireEvent, screen } from '@testing-library/react'; -import { act } from 'react-dom/test-utils'; import { EditGasModes, GasEstimateTypes, From 40bf680304408e25e21a4e4c649a9a650ba6268c Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 20 Feb 2024 10:13:45 -0800 Subject: [PATCH 16/74] fix advanced fee --- .../advanced-gas-fee-defaults.test.js | 59 ++++++++++++------- 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-defaults/advanced-gas-fee-defaults.test.js b/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-defaults/advanced-gas-fee-defaults.test.js index 7365d6a81cf4..845e0669335a 100644 --- a/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-defaults/advanced-gas-fee-defaults.test.js +++ b/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-defaults/advanced-gas-fee-defaults.test.js @@ -1,5 +1,5 @@ import React from 'react'; -import { fireEvent, screen } from '@testing-library/react'; +import { act, fireEvent, screen } from '@testing-library/react'; import { EditGasModes, @@ -21,18 +21,19 @@ import AdvancedGasFeeDefaults from './advanced-gas-fee-defaults'; const TEXT_SELECTOR = 'Save these values as my default for the Goerli network.'; jest.mock('../../../../../store/actions', () => ({ - disconnectGasFeeEstimatePoller: jest.fn(), - getGasFeeEstimatesAndStartPolling: jest + gasFeeStartPollingByNetworkClientId: jest .fn() - .mockImplementation(() => Promise.resolve()), - addPollingTokenToAppState: jest.fn(), - removePollingTokenFromAppState: jest.fn(), + .mockResolvedValue('pollingToken'), + gasFeeStopPollingByPollingToken: jest.fn(), + getNetworkConfigurationByNetworkClientId: jest + .fn() + .mockResolvedValue({ chainId: '0x5' }), setAdvancedGasFee: jest.fn(), updateEventFragment: jest.fn(), createTransactionEventFragment: jest.fn(), })); -const render = (defaultGasParams, contextParams) => { +const render = async (defaultGasParams, contextParams) => { const store = configureStore({ metamask: { ...mockState.metamask, @@ -46,9 +47,22 @@ const render = (defaultGasParams, contextParams) => { featureFlags: { advancedInlineGas: true }, gasFeeEstimates: mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, + gasFeeEstimatesByChainId: { + ...mockState.metamask.gasFeeEstimatesByChainId, + '0x5': { + ...mockState.metamask.gasFeeEstimatesByChainId['0x5'], + gasFeeEstimates: + mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, + }, + }, }, }); - return renderWithProvider( + + let result; + + await act( + async () => + result = renderWithProvider( { , store, - ); + )) + + return result; }; + describe('AdvancedGasFeeDefaults', () => { - it('should renders correct message when the default is not set', () => { - render({ advancedGasFee: {} }); + it('should renders correct message when the default is not set', async () => { + await render({ advancedGasFee: {} }); expect(screen.queryByText(TEXT_SELECTOR)).toBeInTheDocument(); }); - it('should renders correct message when the default values are set', () => { - render({ + it('should renders correct message when the default values are set', async () => { + await render({ advancedGasFee: { [CHAIN_IDS.GOERLI]: { maxBaseFee: 50, priorityFee: 2 }, }, }); expect(screen.queryByText(TEXT_SELECTOR)).toBeInTheDocument(); }); - it('should renders correct message when the default values are set and the maxBaseFee values are updated', () => { - render({ + it('should renders correct message when the default values are set and the maxBaseFee values are updated', async () => { + await render({ advancedGasFee: { [CHAIN_IDS.GOERLI]: { maxBaseFee: 50, priorityFee: 2 }, }, @@ -91,8 +108,8 @@ describe('AdvancedGasFeeDefaults', () => { expect(screen.queryByText(TEXT_SELECTOR)).toBeInTheDocument(); expect(screen.queryByText(TEXT_SELECTOR)).toBeInTheDocument(); }); - it('should renders correct message when the default values are set and the priorityFee values are updated', () => { - render({ + it('should renders correct message when the default values are set and the priorityFee values are updated', async () => { + await render({ advancedGasFee: { [CHAIN_IDS.GOERLI]: { maxBaseFee: 50, priorityFee: 2 }, }, @@ -107,8 +124,8 @@ describe('AdvancedGasFeeDefaults', () => { expect(screen.queryByText(TEXT_SELECTOR)).toBeInTheDocument(); }); - it('should call action setAdvancedGasFee when checkbox or label text is clicked', () => { - render({ + it('should call action setAdvancedGasFee when checkbox or label text is clicked', async () => { + await render({ advancedGasFee: { [CHAIN_IDS.GOERLI]: { maxBaseFee: 50, priorityFee: 2 }, }, @@ -124,8 +141,8 @@ describe('AdvancedGasFeeDefaults', () => { expect(mock).toHaveBeenCalledTimes(2); }); - it('should not render option to set default gas options in a swaps transaction', () => { - render({}, { editGasMode: EditGasModes.swaps }); + it('should not render option to set default gas options in a swaps transaction', async () => { + await render({}, { editGasMode: EditGasModes.swaps }); expect( document.querySelector('input[type=checkbox]'), ).not.toBeInTheDocument(); From 31733873e4c1ca43c52eac51d8b43e4bf7e637ed Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 20 Feb 2024 10:17:04 -0800 Subject: [PATCH 17/74] fix priority fee input --- .../advanced-gas-fee-gas-limit.test.js | 3 +- .../priority-fee-input.test.js | 54 ++++++++++++------- 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-gas-limit/advanced-gas-fee-gas-limit.test.js b/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-gas-limit/advanced-gas-fee-gas-limit.test.js index 4c3c49f294a7..0ead69e8d376 100644 --- a/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-gas-limit/advanced-gas-fee-gas-limit.test.js +++ b/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-gas-limit/advanced-gas-fee-gas-limit.test.js @@ -1,5 +1,5 @@ import React from 'react'; -import { fireEvent, screen } from '@testing-library/react'; +import { act, fireEvent, screen } from '@testing-library/react'; import { GasEstimateTypes } from '../../../../../../shared/constants/gas'; import { renderWithProvider } from '../../../../../../test/lib/render-helpers'; @@ -11,7 +11,6 @@ import configureStore from '../../../../../store/store'; import { AdvancedGasFeePopoverContextProvider } from '../context'; import AdvancedGasFeeGasLimit from './advanced-gas-fee-gas-limit'; -import { act } from 'react-dom/test-utils'; jest.mock('../../../../../store/actions', () => ({ gasFeeStartPollingByNetworkClientId: jest diff --git a/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/priority-fee-input/priority-fee-input.test.js b/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/priority-fee-input/priority-fee-input.test.js index eafe65b10fc0..3ff89c456592 100644 --- a/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/priority-fee-input/priority-fee-input.test.js +++ b/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/priority-fee-input/priority-fee-input.test.js @@ -1,5 +1,5 @@ import React from 'react'; -import { fireEvent, screen } from '@testing-library/react'; +import { act, fireEvent, screen } from '@testing-library/react'; import { EditGasModes, @@ -26,7 +26,7 @@ jest.mock('../../../../../../store/actions', () => ({ .mockResolvedValue({ chainId: '0x5' }), })); -const render = (txProps, contextProps) => { +const render = async (txProps, contextProps) => { const store = configureStore({ metamask: { ...mockState.metamask, @@ -40,10 +40,22 @@ const render = (txProps, contextProps) => { featureFlags: { advancedInlineGas: true }, gasFeeEstimates: mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, + gasFeeEstimatesByChainId: { + ...mockState.metamask.gasFeeEstimatesByChainId, + '0x5': { + ...mockState.metamask.gasFeeEstimatesByChainId['0x5'], + gasFeeEstimates: + mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, + }, + }, }, }); - return renderWithProvider( + let result; + + await act( + async () => + result = renderWithProvider( { , store, - ); + )) + + return result; }; describe('PriorityfeeInput', () => { - it('should renders advancedGasFee.priorityfee value if current estimate used is not custom', () => { - render({ + it('should renders advancedGasFee.priorityfee value if current estimate used is not custom', async () => { + await render({ userFeeLevel: 'high', }); expect(document.getElementsByTagName('input')[0]).toHaveValue(100); }); - it('should not use advancedGasFee.priorityfee value for swaps', () => { - render( + it('should not use advancedGasFee.priorityfee value for swaps', async () => { + await render( { userFeeLevel: 'high', }, @@ -84,8 +98,8 @@ describe('PriorityfeeInput', () => { ); }); - it('should renders priorityfee value from transaction if current estimate used is custom', () => { - render({ + it('should renders priorityfee value from transaction if current estimate used is custom', async () => { + await render({ txParams: { maxPriorityFeePerGas: '0x77359400', }, @@ -93,13 +107,13 @@ describe('PriorityfeeInput', () => { expect(document.getElementsByTagName('input')[0]).toHaveValue(2); }); - it('should show current priority fee range in subtext', () => { - render(); + it('should show current priority fee range in subtext', async () => { + await render(); expect(screen.queryByText('1 - 20 GWEI')).toBeInTheDocument(); }); - it('should show current value of priority fee in users primary currency in right side of input box', () => { - render({ + it('should show current value of priority fee in users primary currency in right side of input box', async () => { + await render({ txParams: { gas: '0x5208', maxPriorityFeePerGas: '0x77359400', @@ -108,13 +122,13 @@ describe('PriorityfeeInput', () => { expect(screen.queryByText('≈ 0.000042 ETH')).toBeInTheDocument(); }); - it('should show 12hr range value in subtext', () => { - render(); + it('should show 12hr range value in subtext', async () => { + await render(); expect(screen.queryByText('2 - 125 GWEI')).toBeInTheDocument(); }); - it('should not show error if value entered is 0', () => { - render({ + it('should not show error if value entered is 0', async () => { + await render({ txParams: { maxPriorityFeePerGas: '0x174876E800', }, @@ -130,8 +144,8 @@ describe('PriorityfeeInput', () => { ).not.toBeInTheDocument(); }); - it('should not show the error if priority fee is 0', () => { - render({ + it('should not show the error if priority fee is 0', async () => { + await render({ txParams: { maxPriorityFeePerGas: '0x0', }, From b2d3f31c7b7aefa1b6e2536459fac6375bf4a39c Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 20 Feb 2024 10:18:18 -0800 Subject: [PATCH 18/74] fix gas fee popover --- .../advanced-gas-fee-popover.test.js | 49 ++++++++++++------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-popover.test.js b/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-popover.test.js index 09ca4ba261a4..3d9dafb1d144 100644 --- a/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-popover.test.js +++ b/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-popover.test.js @@ -1,5 +1,5 @@ import React from 'react'; -import { fireEvent, screen } from '@testing-library/react'; +import { act, fireEvent, screen } from '@testing-library/react'; import { GasEstimateTypes } from '../../../../../shared/constants/gas'; import { renderWithProvider } from '../../../../../test/lib/render-helpers'; @@ -12,12 +12,13 @@ import configureStore from '../../../../store/store'; import AdvancedGasFeePopover from './advanced-gas-fee-popover'; jest.mock('../../../../store/actions', () => ({ - disconnectGasFeeEstimatePoller: jest.fn(), - getGasFeeEstimatesAndStartPolling: jest + gasFeeStartPollingByNetworkClientId: jest .fn() - .mockImplementation(() => Promise.resolve()), - addPollingTokenToAppState: jest.fn(), - removePollingTokenFromAppState: jest.fn(), + .mockResolvedValue('pollingToken'), + gasFeeStopPollingByPollingToken: jest.fn(), + getNetworkConfigurationByNetworkClientId: jest + .fn() + .mockResolvedValue({ chainId: '0x5' }), createTransactionEventFragment: jest.fn(), })); @@ -28,7 +29,7 @@ jest.mock('../../../../contexts/transaction-modal', () => ({ }), })); -const render = () => { +const render = async () => { const store = configureStore({ metamask: { ...mockState.metamask, @@ -41,10 +42,22 @@ const render = () => { featureFlags: { advancedInlineGas: true }, gasFeeEstimates: mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, + gasFeeEstimatesByChainId: { + ...mockState.metamask.gasFeeEstimatesByChainId, + '0x5': { + ...mockState.metamask.gasFeeEstimatesByChainId['0x5'], + gasFeeEstimates: + mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, + }, + }, }, }); - return renderWithProvider( + let result; + + await act( + async () => + result = renderWithProvider( { , store, - ); + )) + + return result; }; describe('AdvancedGasFeePopover', () => { - it('should renders save button enabled by default', () => { - render(); + it('should renders save button enabled by default', async () => { + await render(); expect(screen.queryByRole('button', { name: 'Save' })).not.toBeDisabled(); }); - it('should enable save button if priority fee 0 is entered', () => { - render(); + it('should enable save button if priority fee 0 is entered', async () => { + await render(); fireEvent.change(document.getElementsByTagName('input')[1], { target: { value: 0 }, }); expect(screen.queryByRole('button', { name: 'Save' })).toBeEnabled(); }); - it('should disable save button if priority fee entered is greater than base fee', () => { - render(); + it('should disable save button if priority fee entered is greater than base fee', async () => { + await render(); fireEvent.change(document.getElementsByTagName('input')[1], { target: { value: 100000 }, }); expect(screen.queryByRole('button', { name: 'Save' })).toBeDisabled(); }); - it('should disable save button if gas limit beyond range is entered', () => { - render(); + it('should disable save button if gas limit beyond range is entered', async () => { + await render(); fireEvent.click(screen.queryByText('Edit')); fireEvent.change(document.getElementsByTagName('input')[3], { target: { value: 0 }, From b3160b819ec873b9ff0fb6247dac1329126748d4 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 20 Feb 2024 10:19:04 -0800 Subject: [PATCH 19/74] lint --- .../advanced-gas-fee-defaults.test.js | 43 +++++++++--------- .../advanced-gas-fee-gas-limit.test.js | 43 +++++++++--------- .../priority-fee-input/priority-fee-input.js | 12 +++-- .../priority-fee-input.test.js | 45 ++++++++++--------- .../advanced-gas-fee-popover.test.js | 39 ++++++++-------- 5 files changed, 91 insertions(+), 91 deletions(-) diff --git a/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-defaults/advanced-gas-fee-defaults.test.js b/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-defaults/advanced-gas-fee-defaults.test.js index 845e0669335a..b5b389829748 100644 --- a/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-defaults/advanced-gas-fee-defaults.test.js +++ b/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-defaults/advanced-gas-fee-defaults.test.js @@ -47,14 +47,14 @@ const render = async (defaultGasParams, contextParams) => { featureFlags: { advancedInlineGas: true }, gasFeeEstimates: mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, - gasFeeEstimatesByChainId: { - ...mockState.metamask.gasFeeEstimatesByChainId, - '0x5': { - ...mockState.metamask.gasFeeEstimatesByChainId['0x5'], - gasFeeEstimates: - mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, - }, + gasFeeEstimatesByChainId: { + ...mockState.metamask.gasFeeEstimatesByChainId, + '0x5': { + ...mockState.metamask.gasFeeEstimatesByChainId['0x5'], + gasFeeEstimates: + mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, }, + }, }, }); @@ -62,20 +62,21 @@ const render = async (defaultGasParams, contextParams) => { await act( async () => - result = renderWithProvider( - - - - - - , - store, - )) + (result = renderWithProvider( + + + + + + , + store, + )), + ); return result; }; diff --git a/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-gas-limit/advanced-gas-fee-gas-limit.test.js b/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-gas-limit/advanced-gas-fee-gas-limit.test.js index 0ead69e8d376..bba6d4c5aba8 100644 --- a/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-gas-limit/advanced-gas-fee-gas-limit.test.js +++ b/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-gas-limit/advanced-gas-fee-gas-limit.test.js @@ -22,8 +22,6 @@ jest.mock('../../../../../store/actions', () => ({ .mockResolvedValue({ chainId: '0x5' }), })); - - const render = async (contextProps) => { const store = configureStore({ metamask: { @@ -39,13 +37,13 @@ const render = async (contextProps) => { gasFeeEstimates: mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, gasFeeEstimatesByChainId: { - ...mockState.metamask.gasFeeEstimatesByChainId, - '0x5': { - ...mockState.metamask.gasFeeEstimatesByChainId['0x5'], - gasFeeEstimates: - mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, - }, + ...mockState.metamask.gasFeeEstimatesByChainId, + '0x5': { + ...mockState.metamask.gasFeeEstimatesByChainId['0x5'], + gasFeeEstimates: + mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, }, + }, }, }); @@ -53,20 +51,21 @@ const render = async (contextProps) => { await act( async () => - result = renderWithProvider( - - - - - , - store, - )) + (result = renderWithProvider( + + + + + , + store, + )), + ); return result; }; diff --git a/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/priority-fee-input/priority-fee-input.js b/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/priority-fee-input/priority-fee-input.js index 8ec87783bf38..a35f118e0f04 100644 --- a/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/priority-fee-input/priority-fee-input.js +++ b/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/priority-fee-input/priority-fee-input.js @@ -60,14 +60,12 @@ const PriorityFeeInput = () => { } = gasFeeEstimates ?? {}; const [priorityFeeError, setPriorityFeeError] = useState(); - const defaultPriorityFee = - estimateUsed !== PriorityLevels.custom && - advancedGasFeeValues?.priorityFee && - editGasMode !== EditGasModes.swaps - ? advancedGasFeeValues.priorityFee - : maxPriorityFeePerGas; - + estimateUsed !== PriorityLevels.custom && + advancedGasFeeValues?.priorityFee && + editGasMode !== EditGasModes.swaps + ? advancedGasFeeValues.priorityFee + : maxPriorityFeePerGas; const [priorityFee, setPriorityFee] = useState(defaultPriorityFee); useEffect(() => { diff --git a/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/priority-fee-input/priority-fee-input.test.js b/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/priority-fee-input/priority-fee-input.test.js index 3ff89c456592..7133da22a075 100644 --- a/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/priority-fee-input/priority-fee-input.test.js +++ b/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/priority-fee-input/priority-fee-input.test.js @@ -40,14 +40,14 @@ const render = async (txProps, contextProps) => { featureFlags: { advancedInlineGas: true }, gasFeeEstimates: mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, - gasFeeEstimatesByChainId: { - ...mockState.metamask.gasFeeEstimatesByChainId, - '0x5': { - ...mockState.metamask.gasFeeEstimatesByChainId['0x5'], - gasFeeEstimates: - mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, - }, + gasFeeEstimatesByChainId: { + ...mockState.metamask.gasFeeEstimatesByChainId, + '0x5': { + ...mockState.metamask.gasFeeEstimatesByChainId['0x5'], + gasFeeEstimates: + mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, }, + }, }, }); @@ -55,21 +55,22 @@ const render = async (txProps, contextProps) => { await act( async () => - result = renderWithProvider( - - - - - - , - store, - )) + (result = renderWithProvider( + + + + + + , + store, + )), + ); return result; }; diff --git a/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-popover.test.js b/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-popover.test.js index 3d9dafb1d144..488b044513c3 100644 --- a/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-popover.test.js +++ b/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-popover.test.js @@ -42,14 +42,14 @@ const render = async () => { featureFlags: { advancedInlineGas: true }, gasFeeEstimates: mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, - gasFeeEstimatesByChainId: { - ...mockState.metamask.gasFeeEstimatesByChainId, - '0x5': { - ...mockState.metamask.gasFeeEstimatesByChainId['0x5'], - gasFeeEstimates: - mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, - }, + gasFeeEstimatesByChainId: { + ...mockState.metamask.gasFeeEstimatesByChainId, + '0x5': { + ...mockState.metamask.gasFeeEstimatesByChainId['0x5'], + gasFeeEstimates: + mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, }, + }, }, }); @@ -57,19 +57,20 @@ const render = async () => { await act( async () => - result = renderWithProvider( - - - , - store, - )) + (result = renderWithProvider( + + + , + store, + )), + ); - return result; + return result; }; describe('AdvancedGasFeePopover', () => { From 1dc268834855024d3b2a6f40380709dd16d9395d Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 20 Feb 2024 10:39:23 -0800 Subject: [PATCH 20/74] WIP gas-details-item.test.js --- .../gas-details-item/gas-details-item.test.js | 89 ++++++++++++------- 1 file changed, 58 insertions(+), 31 deletions(-) diff --git a/ui/pages/confirmations/components/gas-details-item/gas-details-item.test.js b/ui/pages/confirmations/components/gas-details-item/gas-details-item.test.js index 2d3321c8596e..eff620570853 100644 --- a/ui/pages/confirmations/components/gas-details-item/gas-details-item.test.js +++ b/ui/pages/confirmations/components/gas-details-item/gas-details-item.test.js @@ -1,5 +1,5 @@ import React from 'react'; -import { screen, waitFor } from '@testing-library/react'; +import { act, screen, waitFor } from '@testing-library/react'; import { GasEstimateTypes } from '../../../../../shared/constants/gas'; import mockEstimates from '../../../../../test/data/mock-estimates.json'; @@ -11,15 +11,17 @@ import configureStore from '../../../../store/store'; import GasDetailsItem from './gas-details-item'; jest.mock('../../../../store/actions', () => ({ - disconnectGasFeeEstimatePoller: jest.fn(), - getGasFeeEstimatesAndStartPolling: jest + gasFeeStartPollingByNetworkClientId: jest .fn() - .mockImplementation(() => Promise.resolve()), - addPollingTokenToAppState: jest.fn(), + .mockResolvedValue('pollingToken'), + gasFeeStopPollingByPollingToken: jest.fn(), + getNetworkConfigurationByNetworkClientId: jest + .fn() + .mockResolvedValue({ chainId: '0x5' }), getGasFeeTimeEstimate: jest.fn().mockImplementation(() => Promise.resolve()), })); -const render = ({ contextProps } = {}) => { +const render = async ({ contextProps } = {}) => { const store = configureStore({ metamask: { ...mockState.metamask, @@ -33,31 +35,46 @@ const render = ({ contextProps } = {}) => { useNativeCurrencyAsPrimaryCurrency: true, }, gasFeeEstimates: mockEstimates[GasEstimateTypes.feeMarket], + gasFeeEstimatesByChainId: { + ...mockState.metamask.gasFeeEstimatesByChainId, + '0x5': { + ...mockState.metamask.gasFeeEstimatesByChainId['0x5'], + gasFeeEstimates: + mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, + }, + }, ...contextProps, }, }); - return renderWithProvider( - - - , - store, + let result; + + await act( + async () => + (result = renderWithProvider( + + + , + store, + )), ); + + return result; }; describe('GasDetailsItem', () => { it('should render label', async () => { - render(); + await render(); await waitFor(() => { expect(screen.queryAllByText('Market')[0]).toBeInTheDocument(); expect(screen.queryByText('Max fee:')).toBeInTheDocument(); @@ -66,7 +83,7 @@ describe('GasDetailsItem', () => { }); it('should show warning icon if estimates are high', async () => { - render({ + await render({ contextProps: { transaction: { txParams: {}, userFeeLevel: 'high' } }, }); await waitFor(() => { @@ -75,13 +92,23 @@ describe('GasDetailsItem', () => { }); it('should show warning icon if dapp estimates are high', async () => { - render({ + await render({ contextProps: { gasFeeEstimates: { high: { suggestedMaxPriorityFeePerGas: '1', }, }, + gasFeeEstimatesByChainId: { + ...mockState.metamask.gasFeeEstimatesByChainId, + '0x5': { + gasFeeEstimates: { + high: { + suggestedMaxPriorityFeePerGas: '1', + }, + }, + }, + }, transaction: { txParams: { gas: '0x52081', @@ -101,7 +128,7 @@ describe('GasDetailsItem', () => { }); it('should not show warning icon if estimates are not high', async () => { - render({ + await render({ contextProps: { transaction: { txParams: {}, userFeeLevel: 'low' } }, }); await waitFor(() => { @@ -109,8 +136,8 @@ describe('GasDetailsItem', () => { }); }); - it('should return null if there is simulationError and user has not acknowledged gasMissing warning', () => { - const { container } = render({ + it('should return null if there is simulationError and user has not acknowledged gasMissing warning', async () => { + const { container } = await render({ contextProps: { transaction: { txParams: {}, @@ -123,7 +150,7 @@ describe('GasDetailsItem', () => { }); it('should not return null even if there is simulationError if user acknowledged gasMissing warning', async () => { - render(); + await render(); await waitFor(() => { expect(screen.queryAllByText('Market')[0]).toBeInTheDocument(); expect(screen.queryByText('Max fee:')).toBeInTheDocument(); @@ -132,7 +159,7 @@ describe('GasDetailsItem', () => { }); it('should render gas fee details', async () => { - render(); + await render(); await waitFor(() => { expect(screen.queryAllByTitle('0.0000315 ETH').length).toBeGreaterThan(0); expect(screen.queryAllByText('ETH').length).toBeGreaterThan(0); @@ -140,7 +167,7 @@ describe('GasDetailsItem', () => { }); it('should render gas fee details if maxPriorityFeePerGas is 0', async () => { - render({ + await render({ contextProps: { transaction: { txParams: { @@ -160,7 +187,7 @@ describe('GasDetailsItem', () => { }); it('should render gas fee details if maxPriorityFeePerGas is undefined', async () => { - render({ + await render({ contextProps: { transaction: { txParams: { From af58cc94d9e8a4ebbdec62903195b68143af48e1 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 20 Feb 2024 12:29:14 -0800 Subject: [PATCH 21/74] WIP --- ui/hooks/useGasFeeEstimates.js | 24 +++++++++---------- .../gas-details-item/gas-details-item.test.js | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/ui/hooks/useGasFeeEstimates.js b/ui/hooks/useGasFeeEstimates.js index b58a2654815b..d15649b7182b 100644 --- a/ui/hooks/useGasFeeEstimates.js +++ b/ui/hooks/useGasFeeEstimates.js @@ -42,28 +42,28 @@ export function useGasFeeEstimates(_networkClientId) { const [chainId, setChainId] = useState(''); const gasEstimateType = useSelector((state) => - getGasEstimateTypeByChainId(state, chainId), + getGasEstimateTypeByChainId(state, '0x5'), ); const gasFeeEstimates = useSelector( (state) => getGasFeeEstimatesByChainId(state, chainId), isEqual, ); const isGasEstimatesLoading = useSelector((state) => - getIsGasEstimatesLoadingByChainId(state, { chainId, networkClientId }), + getIsGasEstimatesLoadingByChainId(state, { chainId: '0x5', networkClientId }), ); const isNetworkBusy = useSelector((state) => - getIsNetworkBusyByChainId(state, chainId), + getIsNetworkBusyByChainId(state, '0x5'), ); - useEffect(() => { - getNetworkConfigurationByNetworkClientId(networkClientId).then( - (networkConfig) => { - if (networkConfig) { - setChainId(networkConfig.chainId); - } - }, - ); - }, [networkClientId]); + // useEffect(() => { + // getNetworkConfigurationByNetworkClientId(networkClientId).then( + // (networkConfig) => { + // if (networkConfig) { + // setChainId(networkConfig.chainId); + // } + // }, + // ); + // }, [networkClientId]); usePolling({ startPollingByNetworkClientId: gasFeeStartPollingByNetworkClientId, diff --git a/ui/pages/confirmations/components/gas-details-item/gas-details-item.test.js b/ui/pages/confirmations/components/gas-details-item/gas-details-item.test.js index eff620570853..e21773792de0 100644 --- a/ui/pages/confirmations/components/gas-details-item/gas-details-item.test.js +++ b/ui/pages/confirmations/components/gas-details-item/gas-details-item.test.js @@ -158,7 +158,7 @@ describe('GasDetailsItem', () => { }); }); - it('should render gas fee details', async () => { + it.only('should render gas fee details', async () => { await render(); await waitFor(() => { expect(screen.queryAllByTitle('0.0000315 ETH').length).toBeGreaterThan(0); From 2e7db99322246b7275751af0679b5d4ba6925a27 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 20 Feb 2024 14:51:19 -0800 Subject: [PATCH 22/74] Fix specs --- .../__snapshots__/confirm-gas-display.test.js.snap | 6 +++--- .../confirm-gas-display/confirm-gas-display.test.js | 2 +- .../gas-details-item/gas-details-item.test.js | 10 ++++------ .../transaction-detail.component.test.js | 2 +- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/ui/pages/confirmations/components/confirm-gas-display/__snapshots__/confirm-gas-display.test.js.snap b/ui/pages/confirmations/components/confirm-gas-display/__snapshots__/confirm-gas-display.test.js.snap index a798793d2c62..b3f464b168a5 100644 --- a/ui/pages/confirmations/components/confirm-gas-display/__snapshots__/confirm-gas-display.test.js.snap +++ b/ui/pages/confirmations/components/confirm-gas-display/__snapshots__/confirm-gas-display.test.js.snap @@ -87,16 +87,16 @@ exports[`ConfirmGasDisplay should match snapshot 1`] = `

- Advanced + Unknown processing time

~ - 1 sec +

diff --git a/ui/pages/confirmations/components/confirm-gas-display/confirm-gas-display.test.js b/ui/pages/confirmations/components/confirm-gas-display/confirm-gas-display.test.js index 296b90d1503c..484c602fcbcd 100644 --- a/ui/pages/confirmations/components/confirm-gas-display/confirm-gas-display.test.js +++ b/ui/pages/confirmations/components/confirm-gas-display/confirm-gas-display.test.js @@ -36,7 +36,7 @@ const render = ({ transactionProp = {}, contextProps = {} } = {}) => { preferences: { useNativeCurrencyAsPrimaryCurrency: true, }, - gasFeeEstimates: mockEstimates[GasEstimateTypes.feeMarket], + gasFeeEstimates: mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, }, }); diff --git a/ui/pages/confirmations/components/gas-details-item/gas-details-item.test.js b/ui/pages/confirmations/components/gas-details-item/gas-details-item.test.js index 2d3321c8596e..2d3496b3c164 100644 --- a/ui/pages/confirmations/components/gas-details-item/gas-details-item.test.js +++ b/ui/pages/confirmations/components/gas-details-item/gas-details-item.test.js @@ -32,7 +32,7 @@ const render = ({ contextProps } = {}) => { preferences: { useNativeCurrencyAsPrimaryCurrency: true, }, - gasFeeEstimates: mockEstimates[GasEstimateTypes.feeMarket], + gasFeeEstimates: mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, ...contextProps, }, }); @@ -42,8 +42,6 @@ const render = ({ contextProps } = {}) => { transaction={{ txParams: { gas: '0x5208', - maxFeePerGas: '0x59682f10', - maxPriorityFeePerGas: '0x59682f00', }, userFeeLevel: 'medium', }} @@ -134,7 +132,7 @@ describe('GasDetailsItem', () => { it('should render gas fee details', async () => { render(); await waitFor(() => { - expect(screen.queryAllByTitle('0.0000315 ETH').length).toBeGreaterThan(0); + expect(screen.queryAllByTitle('0.00147 ETH').length).toBeGreaterThan(0); expect(screen.queryAllByText('ETH').length).toBeGreaterThan(0); }); }); @@ -154,7 +152,7 @@ describe('GasDetailsItem', () => { }, }); await waitFor(() => { - expect(screen.queryAllByTitle('0.0000315 ETH').length).toBeGreaterThan(0); + expect(screen.queryAllByTitle('0.001113 ETH').length).toBeGreaterThan(0); expect(screen.queryAllByText('ETH').length).toBeGreaterThan(0); }); }); @@ -173,7 +171,7 @@ describe('GasDetailsItem', () => { }, }); await waitFor(() => { - expect(screen.queryAllByTitle('0.0000315 ETH').length).toBeGreaterThan(0); + expect(screen.queryAllByTitle('0.001113 ETH').length).toBeGreaterThan(0); expect(screen.queryAllByText('ETH').length).toBeGreaterThan(0); }); }); diff --git a/ui/pages/confirmations/components/transaction-detail/transaction-detail.component.test.js b/ui/pages/confirmations/components/transaction-detail/transaction-detail.component.test.js index b9434e18a0f6..af94d90d2daa 100644 --- a/ui/pages/confirmations/components/transaction-detail/transaction-detail.component.test.js +++ b/ui/pages/confirmations/components/transaction-detail/transaction-detail.component.test.js @@ -31,7 +31,7 @@ const render = ({ componentProps, contextProps } = {}) => { balance: '0x1F4', }, }, - gasFeeEstimates: mockEstimates[GasEstimateTypes.feeMarket], + gasFeeEstimates: mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, }, }); From be2afe8f924891690b534ced83e0b00e7b8eb0ad Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 20 Feb 2024 14:53:11 -0800 Subject: [PATCH 23/74] lint --- .../components/confirm-gas-display/confirm-gas-display.test.js | 3 ++- .../components/gas-details-item/gas-details-item.test.js | 3 ++- .../transaction-detail/transaction-detail.component.test.js | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/ui/pages/confirmations/components/confirm-gas-display/confirm-gas-display.test.js b/ui/pages/confirmations/components/confirm-gas-display/confirm-gas-display.test.js index 484c602fcbcd..deecbf007783 100644 --- a/ui/pages/confirmations/components/confirm-gas-display/confirm-gas-display.test.js +++ b/ui/pages/confirmations/components/confirm-gas-display/confirm-gas-display.test.js @@ -36,7 +36,8 @@ const render = ({ transactionProp = {}, contextProps = {} } = {}) => { preferences: { useNativeCurrencyAsPrimaryCurrency: true, }, - gasFeeEstimates: mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, + gasFeeEstimates: + mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, }, }); diff --git a/ui/pages/confirmations/components/gas-details-item/gas-details-item.test.js b/ui/pages/confirmations/components/gas-details-item/gas-details-item.test.js index 2d3496b3c164..02071860835e 100644 --- a/ui/pages/confirmations/components/gas-details-item/gas-details-item.test.js +++ b/ui/pages/confirmations/components/gas-details-item/gas-details-item.test.js @@ -32,7 +32,8 @@ const render = ({ contextProps } = {}) => { preferences: { useNativeCurrencyAsPrimaryCurrency: true, }, - gasFeeEstimates: mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, + gasFeeEstimates: + mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, ...contextProps, }, }); diff --git a/ui/pages/confirmations/components/transaction-detail/transaction-detail.component.test.js b/ui/pages/confirmations/components/transaction-detail/transaction-detail.component.test.js index af94d90d2daa..1e1fa3804429 100644 --- a/ui/pages/confirmations/components/transaction-detail/transaction-detail.component.test.js +++ b/ui/pages/confirmations/components/transaction-detail/transaction-detail.component.test.js @@ -31,7 +31,8 @@ const render = ({ componentProps, contextProps } = {}) => { balance: '0x1F4', }, }, - gasFeeEstimates: mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, + gasFeeEstimates: + mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, }, }); From a9b0dc699031d44559a57433af2b521705e2e423 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 20 Feb 2024 14:57:16 -0800 Subject: [PATCH 24/74] missed one --- .../components/edit-gas-fee-button/edit-gas-fee-button.test.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui/pages/confirmations/components/edit-gas-fee-button/edit-gas-fee-button.test.js b/ui/pages/confirmations/components/edit-gas-fee-button/edit-gas-fee-button.test.js index 922b1eae7fb0..d0c351809e64 100644 --- a/ui/pages/confirmations/components/edit-gas-fee-button/edit-gas-fee-button.test.js +++ b/ui/pages/confirmations/components/edit-gas-fee-button/edit-gas-fee-button.test.js @@ -35,7 +35,8 @@ const render = ({ componentProps, contextProps } = {}) => { balance: '0x1F4', }, }, - gasFeeEstimates: mockEstimates[GasEstimateTypes.feeMarket], + gasFeeEstimates: + mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, }, }); From aef952038c3ec7451833419d646ea4ca6a0b8933 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 20 Feb 2024 15:12:31 -0800 Subject: [PATCH 25/74] restore useGasFeeEstimates --- ui/hooks/useGasFeeEstimates.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/ui/hooks/useGasFeeEstimates.js b/ui/hooks/useGasFeeEstimates.js index 31ce0c26cb38..92612ff63691 100644 --- a/ui/hooks/useGasFeeEstimates.js +++ b/ui/hooks/useGasFeeEstimates.js @@ -42,7 +42,7 @@ export function useGasFeeEstimates(_networkClientId) { const [chainId, setChainId] = useState(''); const gasEstimateType = useSelector((state) => - getGasEstimateTypeByChainId(state, '0x5'), + getGasEstimateTypeByChainId(state, chainId), ); const gasFeeEstimates = useSelector( (state) => getGasFeeEstimatesByChainId(state, chainId), @@ -50,23 +50,23 @@ export function useGasFeeEstimates(_networkClientId) { ); const isGasEstimatesLoading = useSelector((state) => getIsGasEstimatesLoadingByChainId(state, { - chainId: '0x5', + chainId, networkClientId, }), ); const isNetworkBusy = useSelector((state) => - getIsNetworkBusyByChainId(state, '0x5'), + getIsNetworkBusyByChainId(state, chainId), ); - // useEffect(() => { - // getNetworkConfigurationByNetworkClientId(networkClientId).then( - // (networkConfig) => { - // if (networkConfig) { - // setChainId(networkConfig.chainId); - // } - // }, - // ); - // }, [networkClientId]); + useEffect(() => { + getNetworkConfigurationByNetworkClientId(networkClientId).then( + (networkConfig) => { + if (networkConfig) { + setChainId(networkConfig.chainId); + } + }, + ); + }, [networkClientId]); usePolling({ startPollingByNetworkClientId: gasFeeStartPollingByNetworkClientId, From c0339b81459f2102633a70ea5bdb07631ca1d649 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Tue, 20 Feb 2024 15:12:39 -0800 Subject: [PATCH 26/74] fix gas-details-item act --- .../gas-details-item/gas-details-item.test.js | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/ui/pages/confirmations/components/gas-details-item/gas-details-item.test.js b/ui/pages/confirmations/components/gas-details-item/gas-details-item.test.js index da271eb40950..60f0cba4d7b5 100644 --- a/ui/pages/confirmations/components/gas-details-item/gas-details-item.test.js +++ b/ui/pages/confirmations/components/gas-details-item/gas-details-item.test.js @@ -50,21 +50,22 @@ const render = async ({ contextProps } = {}) => { let result; - await act(async () => - renderWithProvider( - - - , - store, - ), + await act( + async () => + (result = renderWithProvider( + + + , + store, + )), ); return result; From ffb7ab40c54661ab104036bd5754046523b14b72 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Wed, 21 Feb 2024 09:28:11 -0800 Subject: [PATCH 27/74] Fix useGasItemFeeDetails gasFeeEstimates undefined reference --- .../edit-gas-fee-popover/edit-gas-item/useGasItemFeeDetails.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/pages/confirmations/components/edit-gas-fee-popover/edit-gas-item/useGasItemFeeDetails.js b/ui/pages/confirmations/components/edit-gas-fee-popover/edit-gas-item/useGasItemFeeDetails.js index bfe35be4ad04..3e78d5ac05fc 100644 --- a/ui/pages/confirmations/components/edit-gas-fee-popover/edit-gas-item/useGasItemFeeDetails.js +++ b/ui/pages/confirmations/components/edit-gas-fee-popover/edit-gas-item/useGasItemFeeDetails.js @@ -79,7 +79,7 @@ export const useGasItemFeeDetails = (priorityLevel) => { maxPriorityFeePerGas, }); - if (gasFeeEstimates[priorityLevel]) { + if (gasFeeEstimates?.[priorityLevel]) { minWaitTime = priorityLevel === PriorityLevels.high ? gasFeeEstimates?.high.minWaitTimeEstimate From c20fb28aa67147b368efbbf0894dd6a90e8696ff Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Wed, 21 Feb 2024 09:55:36 -0800 Subject: [PATCH 28/74] Fix base-fee-input.test.js --- .../base-fee-input/base-fee-input.test.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/base-fee-input/base-fee-input.test.js b/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/base-fee-input/base-fee-input.test.js index 66efaa22403a..c3413ddc0a0b 100644 --- a/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/base-fee-input/base-fee-input.test.js +++ b/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/base-fee-input/base-fee-input.test.js @@ -138,8 +138,8 @@ describe('BaseFeeInput', () => { ); }); - it('should show current value of estimatedBaseFee in users primary currency in right side of input box', () => { - render({ + it('should show current value of estimatedBaseFee in users primary currency in right side of input box', async () => { + await render({ txParams: { gas: '0x5208', maxFeePerGas: '0x2E90EDD000', @@ -196,8 +196,8 @@ describe('BaseFeeInput', () => { }); describe('updateBaseFee', () => { - it('updates base fee correctly', () => { - const { getByTestId } = render(); + it('updates base fee correctly', async () => { + const { getByTestId } = await render(); const input = getByTestId('base-fee-input'); fireEvent.change(input, { target: { value: '1' } }); @@ -205,8 +205,8 @@ describe('BaseFeeInput', () => { expect(input.value).toBe('1'); }); - it('handles low numbers', () => { - const { getByTestId } = render(); + it('handles low numbers', async () => { + const { getByTestId } = await render(); const input = getByTestId('base-fee-input'); fireEvent.change(input, { target: { value: LOW_BASE_FEE } }); From 18e5801fc56a8b21fb4965f243f2af1293a69422 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Wed, 21 Feb 2024 10:20:01 -0800 Subject: [PATCH 29/74] fix priority-fee-input.test.js --- .../priority-fee-input/priority-fee-input.test.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/priority-fee-input/priority-fee-input.test.js b/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/priority-fee-input/priority-fee-input.test.js index 40b6df46d408..1378e89c84b3 100644 --- a/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/priority-fee-input/priority-fee-input.test.js +++ b/ui/pages/confirmations/components/advanced-gas-fee-popover/advanced-gas-fee-inputs/priority-fee-input/priority-fee-input.test.js @@ -179,8 +179,8 @@ describe('PriorityfeeInput', () => { }); describe('updatePriorityFee', () => { - it('updates base fee correctly', () => { - const { getByTestId } = render(); + it('updates base fee correctly', async () => { + const { getByTestId } = await render(); const input = getByTestId('priority-fee-input'); fireEvent.change(input, { target: { value: '1' } }); @@ -188,8 +188,8 @@ describe('PriorityfeeInput', () => { expect(input.value).toBe('1'); }); - it('handles low numbers', () => { - const { getByTestId } = render(); + it('handles low numbers', async () => { + const { getByTestId } = await render(); const input = getByTestId('priority-fee-input'); fireEvent.change(input, { target: { value: LOW_PRIORITY_FEE } }); From 55a76ab474a479cffa36147ef1057344fed0836c Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Wed, 21 Feb 2024 10:43:20 -0800 Subject: [PATCH 30/74] fix transaction-detail.component.test.js --- .../transaction-detail.component.test.js | 61 ++++++++++++------- 1 file changed, 39 insertions(+), 22 deletions(-) diff --git a/ui/pages/confirmations/components/transaction-detail/transaction-detail.component.test.js b/ui/pages/confirmations/components/transaction-detail/transaction-detail.component.test.js index 1e1fa3804429..5a5d7431c2d0 100644 --- a/ui/pages/confirmations/components/transaction-detail/transaction-detail.component.test.js +++ b/ui/pages/confirmations/components/transaction-detail/transaction-detail.component.test.js @@ -1,5 +1,5 @@ import React from 'react'; -import { screen } from '@testing-library/react'; +import { act, screen } from '@testing-library/react'; import { TransactionEnvelopeType } from '@metamask/transaction-controller'; import { GasEstimateTypes } from '../../../../../shared/constants/gas'; @@ -13,15 +13,17 @@ import configureStore from '../../../../store/store'; import TransactionDetail from './transaction-detail.component'; jest.mock('../../../../store/actions', () => ({ - disconnectGasFeeEstimatePoller: jest.fn(), - getGasFeeEstimatesAndStartPolling: jest + gasFeeStartPollingByNetworkClientId: jest .fn() - .mockImplementation(() => Promise.resolve()), - addPollingTokenToAppState: jest.fn(), + .mockResolvedValue('pollingToken'), + gasFeeStopPollingByPollingToken: jest.fn(), + getNetworkConfigurationByNetworkClientId: jest + .fn() + .mockResolvedValue({ chainId: '0x5' }), createTransactionEventFragment: jest.fn(), })); -const render = ({ componentProps, contextProps } = {}) => { +const render = async ({ componentProps, contextProps } = {}) => { const store = configureStore({ metamask: { ...mockState.metamask, @@ -33,33 +35,48 @@ const render = ({ componentProps, contextProps } = {}) => { }, gasFeeEstimates: mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, + gasFeeEstimatesByChainId: { + ...mockState.metamask.gasFeeEstimatesByChainId, + '0x5': { + ...mockState.metamask.gasFeeEstimatesByChainId['0x5'], + gasFeeEstimates: + mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, + }, + }, }, }); - return renderWithProvider( - - { - console.log('on edit'); - }} - rows={[]} - userAcknowledgedGasMissing - {...componentProps} - /> - , - store, + let result; + + await act( + async () => + (result = renderWithProvider( + + { + console.log('on edit'); + }} + rows={[]} + userAcknowledgedGasMissing + {...componentProps} + /> + , + store, + )), ); + + return result; }; describe('TransactionDetail', () => { - it('should render edit link with text low if low gas estimates are selected', () => { - render({ contextProps: { transaction: { userFeeLevel: 'low' } } }); + it('should render edit link with text low if low gas estimates are selected', async () => { + await render({ contextProps: { transaction: { userFeeLevel: 'low' } } }); expect(screen.queryByText('🐢')).toBeInTheDocument(); expect(screen.queryByText('Low')).toBeInTheDocument(); }); - it('should render edit link with text edit for legacy transactions', () => { - render({ + it('should render edit link with text edit for legacy transactions', async () => { + await render({ contextProps: { transaction: { userFeeLevel: 'low', From 35b7f78b3b702f4afb066b10e11ce5fbede1459e Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Wed, 21 Feb 2024 10:56:55 -0800 Subject: [PATCH 31/74] Fix ui/pages/swaps test --- ui/ducks/metamask/metamask.js | 6 +++--- ui/pages/swaps/index.test.js | 13 +++++++++++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/ui/ducks/metamask/metamask.js b/ui/ducks/metamask/metamask.js index 71924dbdd7bc..26e1883d2bf6 100644 --- a/ui/ducks/metamask/metamask.js +++ b/ui/ducks/metamask/metamask.js @@ -355,15 +355,15 @@ export function getEstimatedGasFeeTimeBounds(state) { } export function getGasEstimateTypeByChainId(state, chainId) { - return state.metamask.gasFeeEstimatesByChainId[chainId]?.gasEstimateType; + return state.metamask.gasFeeEstimatesByChainId?.[chainId]?.gasEstimateType; } export function getGasFeeEstimatesByChainId(state, chainId) { - return state.metamask.gasFeeEstimatesByChainId[chainId]?.gasFeeEstimates; + return state.metamask.gasFeeEstimatesByChainId?.[chainId]?.gasFeeEstimates; } export function getEstimatedGasFeeTimeBoundsByChainId(state, chainId) { - return state.metamask.gasFeeEstimatesByChainId[chainId] + return state.metamask.gasFeeEstimatesByChainId?.[chainId] ?.estimatedGasFeeTimeBounds; } diff --git a/ui/pages/swaps/index.test.js b/ui/pages/swaps/index.test.js index 3844631bc892..ddd867bc62d4 100644 --- a/ui/pages/swaps/index.test.js +++ b/ui/pages/swaps/index.test.js @@ -21,8 +21,13 @@ setBackgroundConnection({ setSwapsLiveness: jest.fn(() => true), setSwapsTokens: jest.fn(), setSwapsTxGasPrice: jest.fn(), - disconnectGasFeeEstimatePoller: jest.fn(), - getGasFeeEstimatesAndStartPolling: jest.fn(), + gasFeeStartPollingByNetworkClientId: jest + .fn() + .mockResolvedValue('pollingToken'), + gasFeeStopPollingByPollingToken: jest.fn(), + getNetworkConfigurationByNetworkClientId: jest + .fn() + .mockResolvedValue({ chainId: '0x1' }), }); describe('Swap', () => { @@ -49,6 +54,10 @@ describe('Swap', () => { .get('/networks/1/tokens') .reply(200, MOCKS.TOKENS_GET_RESPONSE); + nock(CONSTANTS.METASWAP_BASE_URL) + .get('/networks/1/tokens?includeBlockedTokens=true') + .reply(200, MOCKS.TOKENS_GET_RESPONSE); + featureFlagsNock = nock(CONSTANTS.METASWAP_BASE_URL) .get('/featureFlags') .reply(200, MOCKS.createFeatureFlagsResponse()); From 2293f79f1014069d0e72441fa1b1f0457d5c0924 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Wed, 21 Feb 2024 11:18:28 -0800 Subject: [PATCH 32/74] fix transaction-list-item-details.component.test.js --- ...action-list-item-details.component.test.js | 148 ++++++++---------- 1 file changed, 64 insertions(+), 84 deletions(-) diff --git a/ui/components/app/transaction-list-item-details/transaction-list-item-details.component.test.js b/ui/components/app/transaction-list-item-details/transaction-list-item-details.component.test.js index 793dec26db85..092464decc55 100644 --- a/ui/components/app/transaction-list-item-details/transaction-list-item-details.component.test.js +++ b/ui/components/app/transaction-list-item-details/transaction-list-item-details.component.test.js @@ -1,7 +1,7 @@ import React from 'react'; import configureMockStore from 'redux-mock-store'; import thunk from 'redux-thunk'; -import { waitFor } from '@testing-library/react'; +import { act, waitFor } from '@testing-library/react'; import { TransactionStatus } from '@metamask/transaction-controller'; import { GAS_LIMITS } from '../../../../shared/constants/gas'; import { renderWithProvider } from '../../../../test/lib/render-helpers'; @@ -10,8 +10,13 @@ import TransactionListItemDetails from '.'; jest.mock('../../../store/actions.ts', () => ({ tryReverseResolveAddress: () => jest.fn(), - getGasFeeEstimatesAndStartPolling: jest.fn().mockResolvedValue(), - addPollingTokenToAppState: jest.fn(), + gasFeeStartPollingByNetworkClientId: jest + .fn() + .mockResolvedValue('pollingToken'), + gasFeeStopPollingByPollingToken: jest.fn(), + getNetworkConfigurationByNetworkClientId: jest + .fn() + .mockResolvedValue({ chainId: '0x5' }), })); let mockGetCustodianTransactionDeepLink = jest.fn(); @@ -22,34 +27,34 @@ jest.mock('../../../store/institutional/institution-background', () => ({ }), })); -describe('TransactionListItemDetails Component', () => { - const transaction = { - history: [], - id: 1, - status: TransactionStatus.confirmed, - txParams: { - from: '0x1', - gas: GAS_LIMITS.SIMPLE, - gasPrice: '0x3b9aca00', - nonce: '0xa4', - to: '0x2', - value: '0x2386f26fc10000', - }, - metadata: { - note: 'some note', - }, - custodyId: '1', - }; - - const transactionGroup = { - transactions: [transaction], - primaryTransaction: transaction, - initialTransaction: transaction, +const transaction = { + history: [], + id: 1, + status: TransactionStatus.confirmed, + txParams: { + from: '0x1', + gas: GAS_LIMITS.SIMPLE, + gasPrice: '0x3b9aca00', nonce: '0xa4', - hasRetried: false, - hasCancelled: false, - }; - + to: '0x2', + value: '0x2386f26fc10000', + }, + metadata: { + note: 'some note', + }, + custodyId: '1', +}; + +const transactionGroup = { + transactions: [transaction], + primaryTransaction: transaction, + initialTransaction: transaction, + nonce: '0xa4', + hasRetried: false, + hasCancelled: false, +}; + +const render = async (overrideProps) => { const rpcPrefs = { blockExplorerUrl: 'https://customblockexplorer.com/', }; @@ -69,70 +74,52 @@ describe('TransactionListItemDetails Component', () => { transactionStatus: () =>
, blockExplorerLinkText, rpcPrefs, + ...overrideProps, }; - it('should render title with title prop', async () => { - const mockStore = configureMockStore([thunk])(mockState); + const mockStore = configureMockStore([thunk])(mockState); + + let result; - const { queryByText } = renderWithProvider( - , - mockStore, - ); + await act( + async () => + (result = renderWithProvider( + , + mockStore, + )), + ); + + return result; +}; + +describe('TransactionListItemDetails Component', () => { + it('should render title with title prop', async () => { + const { queryByText } = await render(); await waitFor(() => { - expect(queryByText(props.title)).toBeInTheDocument(); + expect(queryByText('Test Transaction Details')).toBeInTheDocument(); }); }); describe('Retry button', () => { - it('should render retry button with showRetry prop', () => { - const retryProps = { - ...props, - showRetry: true, - }; - - const mockStore = configureMockStore([thunk])(mockState); - - const { queryByTestId } = renderWithProvider( - , - mockStore, - ); + it('should render retry button with showRetry prop', async () => { + const { queryByTestId } = await render({ showRetry: true }); expect(queryByTestId('rety-button')).toBeInTheDocument(); }); }); describe('Cancel button', () => { - it('should render cancel button with showCancel prop', () => { - const retryProps = { - ...props, - showCancel: true, - }; - - const mockStore = configureMockStore([thunk])(mockState); - - const { queryByTestId } = renderWithProvider( - , - mockStore, - ); + it('should render cancel button with showCancel prop', async () => { + const { queryByTestId } = await render({ showCancel: true }); expect(queryByTestId('cancel-button')).toBeInTheDocument(); }); }); describe('Speedup button', () => { - it('should render speedup button with showSpeedUp prop', () => { - const retryProps = { - ...props, - showSpeedUp: true, - }; - - const mockStore = configureMockStore([thunk])(mockState); - - const { queryByTestId } = renderWithProvider( - , - mockStore, - ); + it('should render speedup button with showSpeedUp prop', async () => { + const { queryByTestId } = await render({ showSpeedUp: true }); expect(queryByTestId('speedup-button')).toBeInTheDocument(); }); @@ -144,9 +131,7 @@ describe('TransactionListItemDetails Component', () => { .fn() .mockReturnValue({ url: 'https://url.com' }); - const mockStore = configureMockStore([thunk])(mockState); - - renderWithProvider(, mockStore); + await render({ showCancel: true }); await waitFor(() => { const custodianViewButton = document.querySelector( @@ -173,15 +158,10 @@ describe('TransactionListItemDetails Component', () => { primaryTransaction: newTransaction, initialTransaction: newTransaction, }; - const mockStore = configureMockStore([thunk])(mockState); - const { queryByText } = renderWithProvider( - , - mockStore, - ); + const { queryByText } = await render({ + transactionGroup: newTransactionGroup, + }); await waitFor(() => { expect(queryByText('some note')).toBeInTheDocument(); From 112397685474c2b1fe49455493c7e98921e8bfd5 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Wed, 21 Feb 2024 11:36:46 -0800 Subject: [PATCH 33/74] fix send-content.component.test.js --- .../send-content.component.test.js | 239 +++++++----------- 1 file changed, 86 insertions(+), 153 deletions(-) diff --git a/ui/pages/confirmations/send/send-content/send-content.component.test.js b/ui/pages/confirmations/send/send-content/send-content.component.test.js index 88c6fb270cce..ccfa8769c7f0 100644 --- a/ui/pages/confirmations/send/send-content/send-content.component.test.js +++ b/ui/pages/confirmations/send/send-content/send-content.component.test.js @@ -1,5 +1,5 @@ import React from 'react'; -import { waitFor } from '@testing-library/react'; +import { act, waitFor } from '@testing-library/react'; import configureMockStore from 'redux-mock-store'; import { renderWithProvider } from '../../../../../test/lib/render-helpers'; @@ -13,10 +13,13 @@ import { useIsOriginalNativeTokenSymbol } from '../../../../hooks/useIsOriginalN import SendContent from '.'; jest.mock('../../../../store/actions', () => ({ - disconnectGasFeeEstimatePoller: jest.fn(), - getGasFeeEstimatesAndStartPolling: jest.fn().mockResolvedValue(), - addPollingTokenToAppState: jest.fn(), - removePollingTokenFromAppState: jest.fn(), + gasFeeStartPollingByNetworkClientId: jest + .fn() + .mockResolvedValue('pollingToken'), + gasFeeStopPollingByPollingToken: jest.fn(), + getNetworkConfigurationByNetworkClientId: jest + .fn() + .mockResolvedValue({ chainId: '0x5' }), createTransactionEventFragment: jest.fn(), getGasFeeTimeEstimate: jest.fn().mockResolvedValue('unknown'), getTokenSymbol: jest.fn().mockResolvedValue('ETH'), @@ -28,31 +31,41 @@ jest.mock('../../../../hooks/useIsOriginalNativeTokenSymbol', () => { }; }); -describe('SendContent Component', () => { - useIsOriginalNativeTokenSymbol.mockReturnValue(true); - describe('render', () => { - const mockStore = configureMockStore()({ - ...mockSendState, - metamask: { - ...mockSendState.metamask, - providerConfig: { - chainId: CHAIN_IDS.GOERLI, - nickname: GOERLI_DISPLAY_NAME, - type: NETWORK_TYPES.GOERLI, - }, +const render = async (props, overrideStoreState) => { + const mockStore = configureMockStore()({ + ...mockSendState, + metamask: { + ...mockSendState.metamask, + providerConfig: { + chainId: CHAIN_IDS.GOERLI, + nickname: GOERLI_DISPLAY_NAME, + type: NETWORK_TYPES.GOERLI, }, - }); + }, + ...overrideStoreState, + }); + + let result; + await act( + async () => + (result = renderWithProvider(, mockStore)), + ); + + return result; +}; + +describe('SendContent Component', () => { + beforeEach(() => { + useIsOriginalNativeTokenSymbol.mockReturnValue(true); + }); + + describe('render', () => { it('should match snapshot', async () => { - const props = { + const { container } = await render({ gasIsExcessive: false, showHexData: true, - }; - - const { container } = renderWithProvider( - , - mockStore, - ); + }); await waitFor(() => { expect(container).toMatchSnapshot(); @@ -61,78 +74,47 @@ describe('SendContent Component', () => { }); describe('SendHexDataRow', () => { - const tokenAssetState = { - ...mockSendState, - send: { - ...mockSendState.send, - draftTransactions: { - '1-tx': { - ...mockSendState.send.draftTransactions['1-tx'], - asset: { - balance: '0x3635c9adc5dea00000', - details: { - address: '0xAddress', - decimals: 18, - symbol: 'TST', - balance: '1', - standard: 'ERC20', - }, - error: null, - type: 'TOKEN', - }, - }, - }, - }, - metamask: { - ...mockSendState.metamask, - providerConfig: { - chainId: CHAIN_IDS.GOERLI, - nickname: GOERLI_DISPLAY_NAME, - type: NETWORK_TYPES.GOERLI, - }, - }, - }; - it('should not render the SendHexDataRow if props.showHexData is false', async () => { - const props = { + const { queryByText } = await render({ gasIsExcessive: false, showHexData: false, - }; - - const mockStore = configureMockStore()({ - ...mockSendState, - metamask: { - ...mockSendState.metamask, - providerConfig: { - chainId: CHAIN_IDS.GOERLI, - nickname: GOERLI_DISPLAY_NAME, - type: NETWORK_TYPES.GOERLI, - }, - }, }); - const { queryByText } = renderWithProvider( - , - mockStore, - ); - await waitFor(() => { expect(queryByText('Hex data:')).not.toBeInTheDocument(); }); }); it('should not render the SendHexDataRow if the asset type is TOKEN (ERC-20)', async () => { - const props = { - gasIsExcessive: false, - showHexData: true, + const tokenAssetState = { + send: { + ...mockSendState.send, + draftTransactions: { + '1-tx': { + ...mockSendState.send.draftTransactions['1-tx'], + asset: { + balance: '0x3635c9adc5dea00000', + details: { + address: '0xAddress', + decimals: 18, + symbol: 'TST', + balance: '1', + standard: 'ERC20', + }, + error: null, + type: 'TOKEN', + }, + }, + }, + }, }; - // Use token draft transaction asset - const mockState = configureMockStore()(tokenAssetState); - - const { queryByText } = renderWithProvider( - , - mockState, + const { queryByText } = await render( + { + gasIsExcessive: false, + showHexData: true, + }, + tokenAssetState, ); await waitFor(() => { @@ -143,28 +125,11 @@ describe('SendContent Component', () => { describe('Gas Error', () => { it('should show gas warning when gasIsExcessive prop is true.', async () => { - const props = { + const { queryByTestId } = await render({ gasIsExcessive: true, showHexData: false, - }; - - const mockStore = configureMockStore()({ - ...mockSendState, - metamask: { - ...mockSendState.metamask, - providerConfig: { - chainId: CHAIN_IDS.GOERLI, - nickname: GOERLI_DISPLAY_NAME, - type: NETWORK_TYPES.GOERLI, - }, - }, }); - const { queryByTestId } = renderWithProvider( - , - mockStore, - ); - const gasWarning = queryByTestId('gas-warning-message'); await waitFor(() => { @@ -173,13 +138,7 @@ describe('SendContent Component', () => { }); it('should show gas warning for none gasEstimateType in state', async () => { - const props = { - gasIsExcessive: false, - showHexData: false, - }; - const noGasPriceState = { - ...mockSendState, metamask: { ...mockSendState.metamask, gasEstimateType: 'none', @@ -191,11 +150,12 @@ describe('SendContent Component', () => { }, }; - const mockStore = configureMockStore()(noGasPriceState); - - const { queryByTestId } = renderWithProvider( - , - mockStore, + const { queryByTestId } = await render( + { + gasIsExcessive: false, + showHexData: false, + }, + noGasPriceState, ); const gasWarning = queryByTestId('gas-warning-message'); @@ -208,13 +168,7 @@ describe('SendContent Component', () => { describe('Recipient Warning', () => { it('should show recipient warning with knownAddressRecipient state in draft transaction state', async () => { - const props = { - gasIsExcessive: false, - showHexData: false, - }; - const knownRecipientWarningState = { - ...mockSendState, send: { ...mockSendState.send, draftTransactions: { @@ -238,11 +192,12 @@ describe('SendContent Component', () => { }, }; - const mockStore = configureMockStore()(knownRecipientWarningState); - - const { queryByTestId } = renderWithProvider( - , - mockStore, + const { queryByTestId } = await render( + { + gasIsExcessive: false, + showHexData: false, + }, + knownRecipientWarningState, ); const sendWarning = queryByTestId('send-warning'); @@ -255,13 +210,7 @@ describe('SendContent Component', () => { describe('Assert Error', () => { it('should render dialog error with asset error in draft transaction state', async () => { - const props = { - gasIsExcessive: false, - showHexData: false, - }; - const assertErrorState = { - ...mockSendState, send: { ...mockSendState.send, draftTransactions: { @@ -285,11 +234,12 @@ describe('SendContent Component', () => { }, }; - const mockStore = configureMockStore()(assertErrorState); - - const { queryByTestId } = renderWithProvider( - , - mockStore, + const { queryByTestId } = await render( + { + gasIsExcessive: false, + showHexData: false, + }, + assertErrorState, ); const dialogMessage = queryByTestId('dialog-message'); @@ -302,29 +252,12 @@ describe('SendContent Component', () => { describe('Warning', () => { it('should display warning dialog message from warning prop', async () => { - const props = { + const { queryByTestId } = await render({ gasIsExcessive: false, showHexData: false, warning: 'warning', - }; - - const mockStore = configureMockStore()({ - ...mockSendState, - metamask: { - ...mockSendState.metamask, - providerConfig: { - chainId: CHAIN_IDS.GOERLI, - nickname: GOERLI_DISPLAY_NAME, - type: NETWORK_TYPES.GOERLI, - }, - }, }); - const { queryByTestId } = renderWithProvider( - , - mockStore, - ); - const dialogMessage = queryByTestId('dialog-message'); await waitFor(() => { From f565236c4f9f9cfd086a7f385b82def543543ce9 Mon Sep 17 00:00:00 2001 From: Shane Jonas Date: Wed, 21 Feb 2024 14:48:26 -0500 Subject: [PATCH 34/74] Get confirmation container container tests passing and remove act warnings --- .../confirm-page-container-container.test.js | 74 ++++++++++++------- 1 file changed, 49 insertions(+), 25 deletions(-) diff --git a/ui/pages/confirmations/components/confirm-page-container/confirm-page-container-container.test.js b/ui/pages/confirmations/components/confirm-page-container/confirm-page-container-container.test.js index 4a515fad6b45..eb38c48a510c 100644 --- a/ui/pages/confirmations/components/confirm-page-container/confirm-page-container-container.test.js +++ b/ui/pages/confirmations/components/confirm-page-container/confirm-page-container-container.test.js @@ -163,6 +163,13 @@ jest.mock('../../../../store/actions', () => ({ getGasFeeEstimatesAndStartPolling: jest .fn() .mockImplementation(() => Promise.resolve()), + getNetworkConfigurationByNetworkClientId: jest.fn().mockImplementation(() => { + return Promise.resolve({ chainId: '0x5' }); + }), + gasFeeStartPollingByNetworkClientId: jest.fn().mockImplementation(() => { + return Promise.resolve('pollingToken'); + }), + gasFeeStopPollingByPollingToken: jest.fn(), addPollingTokenToAppState: jest.fn(), })); @@ -197,9 +204,11 @@ describe('Confirm Page Container Container Test', () => { }); describe('Render and simulate button clicks', () => { - beforeEach(() => { + beforeEach(async () => { const store = configureMockStore()(mockedState); - renderWithProvider(, store); + await act(async () => { + renderWithProvider(, store); + }); }); it('should render a confirm page container component', () => { @@ -244,7 +253,7 @@ describe('Confirm Page Container Container Test', () => { }); describe(`when type is '${TransactionType.tokenMethodSetApprovalForAll}'`, () => { - it('should display warning modal with total token balance', () => { + it('should display warning modal with total token balance', async () => { const mockValue12AsHexString = '0x0c'; // base-10 representation = 12 TokenUtil.fetchTokenBalance.mockImplementation(() => { @@ -253,16 +262,18 @@ describe('Confirm Page Container Container Test', () => { setMockedTransactionType(TransactionType.tokenMethodSetApprovalForAll); const store = configureMockStore()(mockedState); - renderWithProvider( - , - store, - ); + await act(async () => { + renderWithProvider( + , + store, + ); + }); - act(() => { + await act(async () => { const confirmButton = screen.getByTestId('page-container-footer-next'); fireEvent.click(confirmButton); }); @@ -281,25 +292,36 @@ describe('Confirm Page Container Container Test', () => { describe('Rendering NetworkAccountBalanceHeader', () => { const store = configureMockStore()(mockState); - it('should render NetworkAccountBalanceHeader if displayAccountBalanceHeader is true', () => { - const { getByText } = renderWithProvider( - , - store, - ); + it('should render NetworkAccountBalanceHeader if displayAccountBalanceHeader is true', async () => { + let result; + await act(async () => { + result = renderWithProvider( + , + store, + ); + }); + const { getByText } = result; expect(getByText('Balance')).toBeInTheDocument(); }); - it('should not render NetworkAccountBalanceHeader if displayAccountBalanceHeader is false', () => { - const { queryByText } = renderWithProvider( - , - store, - ); - expect(queryByText('Balance')).toBeNull(); + it('should not render NetworkAccountBalanceHeader if displayAccountBalanceHeader is false', async () => { + let result; + await act(async () => { + result = renderWithProvider( + , + store, + ); + }); + const { queryByText } = result; + expect(queryByText('Balance')).toBe(null); }); }); describe('Contact/AddressBook name should appear in recipient header', () => { - it('should not show add to address dialog if recipient is in contact list and should display contact name', () => { + it('should not show add to address dialog if recipient is in contact list and should display contact name', async () => { const addressBookName = 'test save name'; const addressBook = { @@ -320,7 +342,9 @@ describe('Confirm Page Container Container Test', () => { const store = configureMockStore()(mockState); - renderWithProvider(, store); + await act(async () => { + renderWithProvider(, store); + }); // Does not display new address dialog banner const newAccountDetectDialog = screen.queryByText( From 00f30a6d31fd5faf7583791e61d9e8cbdedb704c Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Wed, 21 Feb 2024 13:22:03 -0800 Subject: [PATCH 35/74] remove snapshot --- .../send-content.component.test.js.snap | 291 ------------------ 1 file changed, 291 deletions(-) delete mode 100644 ui/pages/confirmations/send/send-content/__snapshots__/send-content.component.test.js.snap diff --git a/ui/pages/confirmations/send/send-content/__snapshots__/send-content.component.test.js.snap b/ui/pages/confirmations/send/send-content/__snapshots__/send-content.component.test.js.snap deleted file mode 100644 index cb4204841623..000000000000 --- a/ui/pages/confirmations/send/send-content/__snapshots__/send-content.component.test.js.snap +++ /dev/null @@ -1,291 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`SendContent Component render should match snapshot 1`] = ` -
-
-
-
-
- Asset: -
-
-
-
-
-
-
-
-
-
-
- - Balance: - -
- - 0 - - - ETH - -
-
-
- -
-
-
-
-
-
-
- Amount: - -
-
-
-
-
-
- -
- ETH -
-
-
- No conversion rate available -
-
- -
-
-
-
-
-
-
- Hex data: -
-
-
-