From 7d00d0577fe8fa78842c0954a8b1a26182e8df58 Mon Sep 17 00:00:00 2001 From: "runway-github[bot]" <73448015+runway-github[bot]@users.noreply.github.com> Date: Thu, 7 Nov 2024 23:07:43 +0000 Subject: [PATCH] temp+fix: Add migration to fix NotificationServicesController bug (#12219) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** The purpose of this PR is to fix an error apparently caused by a missing `NotificationServicesController` property on the `state.engine.backgroundState` ## **Related issues** Fixes: #12207 ## **Manual testing steps** Although we didn't pinpoint what was causing the `NotificationServicesController` to be missing, this code fills in the data if it is missing. ## **Screenshots/Recordings** n/a ### **Before** n/a ### **After** n/a ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --------- Co-authored-by: sethkfman <10342624+sethkfman@users.noreply.github.com> --- .android.env.example | 2 +- .depcheckrc.yml | 7 + .detoxrc.js | 9 +- .eslintrc.js | 6 - .github/CODEOWNERS | 3 - .github/workflows/add-team-label.yml | 6 +- .github/workflows/bump-version-name.yml | 30 + .github/workflows/create-release-draft.yml | 29 - .github/workflows/create-release-pr.yml | 21 +- .../workflows/update-latest-build-version.yml | 51 - .gitignore | 7 - .ios.env.example | 2 +- .iyarc | 3 + .js.env.example | 14 +- .storybook/storybook.requires.js | 2 +- .vscode/settings.json | 4 +- CHANGELOG.md | 109 +- README.md | 26 +- android/app/build.gradle | 4 +- android/app/google-services-example.json | 32 +- .../notification/helpers/index.test.tsx | 63 - app/actions/notification/helpers/index.ts | 64 +- app/actions/onboarding/index.ts | 6 +- app/actions/settings/index.js | 7 - .../CellSelectWithMenu.stories.tsx | 12 - .../CellSelectWithMenu.styles.ts | 3 - .../CellSelectWithMenu/CellSelectWithMenu.tsx | 25 +- .../CellSelectWithMenu.test.tsx.snap | 33 +- .../ContractBoxBase/ContractBoxBase.tsx | 29 +- .../ContractBoxBase.test.tsx.snap | 17 +- .../ListItemMultiSelectButton.stories.tsx | 27 +- .../ListItemMultiSelectButton.styles.ts | 2 +- .../ListItemMultiSelectButton.tsx | 2 +- .../ListItemMultiSelectButton.types.ts | 13 - .../ListItemMultiSelectButton.test.tsx.snap | 2 +- .../AggregatedPercentage.constants.ts | 2 - .../AggregatedPercentage.test.tsx | 22 - .../AggregatedPercentage.tsx | 43 +- .../AggregatedPercentage.test.tsx.snap | 2 - .../variants/AvatarIcon/AvatarIcon.test.tsx | 6 +- .../__snapshots__/AvatarIcon.test.tsx.snap | 22 +- .../variants/ButtonLink/ButtonLink.test.tsx | 10 +- .../__snapshots__/ButtonLink.test.tsx.snap | 46 +- .../foundation/CellBase/CellBase.types.ts | 5 - .../Form/TextField/foundation/Input/Input.tsx | 4 +- .../Input/__snapshots__/Input.test.tsx.snap | 2 +- .../Pickers/PickerBase/PickerBase.stories.tsx | 57 - .../Pickers/PickerBase/PickerBase.styles.ts | 12 +- .../Pickers/PickerBase/PickerBase.test.tsx | 68 +- .../Pickers/PickerBase/PickerBase.tsx | 9 +- .../Pickers/PickerBase/PickerBase.types.ts | 16 +- .../components/Pickers/PickerBase/README.md | 56 +- .../__snapshots__/PickerBase.test.tsx.snap | 6 +- .../PickerNetwork/PickerNetwork.stories.tsx | 10 +- .../PickerNetwork/PickerNetwork.styles.ts | 3 - .../PickerNetwork/PickerNetwork.test.tsx | 34 +- .../Pickers/PickerNetwork/PickerNetwork.tsx | 35 +- .../PickerNetwork/PickerNetwork.types.ts | 4 - .../Pickers/PickerNetwork/README.md | 40 +- .../__snapshots__/PickerNetwork.test.tsx.snap | 46 +- .../components/Texts/SensitiveText/README.md | 57 - .../SensitiveText/SensitiveText.stories.tsx | 89 - .../SensitiveText/SensitiveText.test.tsx | 116 - .../Texts/SensitiveText/SensitiveText.tsx | 39 - .../SensitiveText/SensitiveText.types.ts | 47 - .../__snapshots__/SensitiveText.test.tsx.snap | 19 - .../components/Texts/SensitiveText/index.ts | 3 - .../ApprovalModal/ApprovalModal.test.tsx | 6 +- .../__snapshots__/ApprovalModal.test.tsx.snap | 125 +- app/components/Base/DetailsModal.js | 2 +- app/components/Base/RemoteImage/index.js | 37 +- .../Base/RemoteImage/index.test.tsx | 18 +- app/components/Nav/App/index.js | 517 ++--- app/components/Nav/Main/MainNavigator.js | 23 +- app/components/Nav/Main/index.js | 22 +- .../Nav/Main/useConnectionHandler.test.ts | 137 -- .../__snapshots__/index.test.tsx.snap | 1 - app/components/UI/AccountApproval/index.js | 6 +- .../AccountSelector.test.tsx | 8 +- .../AccountSelectorList.styles.ts | 1 - .../AccountSelectorList.tsx | 69 +- .../AccountSelector.test.tsx.snap | 90 +- .../__snapshots__/index.test.tsx.snap | 35 +- .../AnimatedTransactionModal/index.test.tsx | 20 +- .../UI/AssetElement/index.constants.ts | 2 - app/components/UI/AssetElement/index.test.tsx | 31 - app/components/UI/AssetElement/index.tsx | 32 +- app/components/UI/AssetList/index.test.tsx | 6 +- .../UI/AssetOverview/AssetOverview.tsx | 10 +- .../UI/AssetOverview/Balance/Balance.tsx | 6 +- .../Balance/__snapshots__/index.test.tsx.snap | 3 - .../UI/AssetOverview/Price/Price.tsx | 4 +- .../AssetOverview/PriceChart/PriceChart.tsx | 1 - .../StakingEarnings.styles.tsx | 2 +- .../StakingEarnings/StakingEarnings.test.tsx | 32 + .../StakingEarnings.test.tsx.snap | 8 +- .../AssetOverview/StakingEarnings/index.tsx | 123 ++ .../TokenDetails/TokenDetails.tsx | 18 +- .../TokenDetailsList/TokenDetailsList.tsx | 3 +- .../__snapshots__/AssetOverview.test.tsx.snap | 136 +- .../__snapshots__/index.test.tsx.snap | 134 +- .../UI/BlockingActionModal/index.test.tsx | 6 +- app/components/UI/BrowserBottomBar/index.js | 22 +- .../UI/CollectibleContracts/index.test.tsx | 4 +- app/components/UI/DeleteWalletModal/index.tsx | 2 +- .../__snapshots__/index.test.tsx.snap | 24 +- app/components/UI/EditGasFee1559/index.js | 279 +-- .../__snapshots__/index.test.tsx.snap | 2 - app/components/UI/EditGasFeeLegacy/index.js | 173 +- .../EnableAutomaticSecurityChecksModal.tsx | 19 +- .../UI/ManageNetworks/ManageNetworks.tsx | 2 +- .../__snapshots__/ManageNetworks.test.js.snap | 48 +- app/components/UI/Navbar/index.js | 28 +- app/components/UI/NetworkInfo/index.tsx | 2 +- .../UI/NetworkModal/NetworkAdded/index.tsx | 6 +- .../UI/NetworkModal/NetworkDetails/index.tsx | 6 +- .../__snapshots__/index.test.tsx.snap | 48 +- app/components/UI/NetworkModal/index.tsx | 6 +- .../NetworkSelectorList.styles.ts | 5 +- .../NetworkSelectorList.tsx | 9 +- .../NetworkSelectorList.types.ts | 2 +- .../NetworkVerificationInfo.tsx | 26 +- .../NetworkVerificationInfo.test.tsx.snap | 50 +- .../__snapshots__/index.test.jsx.snap | 1741 --------------- .../UI/Notification/BaseNotification/index.js | 9 +- .../BaseNotification/index.test.jsx | 47 - .../List/__snapshots__/index.test.tsx.snap | 120 +- .../UI/Notification/List/index.test.tsx | 175 +- app/components/UI/Notification/List/index.tsx | 26 +- .../__snapshots__/index.test.tsx.snap | 478 +--- app/components/UI/PaymentRequest/index.js | 2 +- .../UI/PaymentRequest/index.test.tsx | 200 +- .../UI/PaymentRequestSuccess/index.js | 2 +- .../PermissionsSummary.test.tsx | 18 - .../PermissionsSummary/PermissionsSummary.tsx | 181 +- .../PermissionsSummary.types.ts | 10 - .../PermissionsSummary.test.tsx.snap | 822 +++---- .../__snapshots__/BuildQuote.test.tsx.snap | 4 +- .../NetworkSwitcher.test.tsx.snap | 48 +- .../Ramp/Views/Settings/ActivationKeyForm.tsx | 1 - .../ActivationKeyForm.test.tsx.snap | 2 +- app/components/UI/ReceiveRequest/index.js | 2 +- .../__snapshots__/index.test.tsx.snap | 70 +- .../UI/ReusableModal/index.test.tsx | 19 +- app/components/UI/Screen/index.test.tsx | 6 +- .../SimulationDetails/AssetPill/AssetPill.tsx | 2 +- .../__snapshots__/index.test.tsx.snap | 96 +- app/components/UI/SliderButton/index.test.tsx | 6 +- .../__snapshots__/index.test.tsx.snap | 155 +- .../UI/SlippageSlider/index.test.tsx | 6 +- .../StakeConfirmationView.test.tsx | 28 +- .../StakeConfirmationView.tsx | 30 +- .../StakeConfirmationView.types.ts | 3 - .../StakeConfirmationView.test.tsx.snap | 304 +-- .../StakeInputView/StakeInputView.test.tsx | 76 +- .../Views/StakeInputView/StakeInputView.tsx | 60 +- .../StakeInputView.test.tsx.snap | 55 +- .../UnstakeConfirmationView.styles.ts | 23 - .../UnstakeConfirmationView.test.tsx | 87 - .../UnstakeConfirmationView.tsx | 56 - .../UnstakeConfirmationView.types.ts | 10 - .../UnstakeConfirmationView.test.tsx.snap | 1291 ----------- .../UnstakeInputView.test.tsx | 43 +- .../UnstakeInputView/UnstakeInputView.tsx | 39 +- .../UnstakeInputView.types.ts | 9 - .../UnstakeInputView.test.tsx.snap | 47 +- app/components/UI/Stake/__mocks__/mockData.ts | 138 -- .../components/EstimatedAnnualRewardsCard.tsx | 26 +- .../LearnMoreModal.test.tsx.snap | 2 +- .../Stake/components/LearnMoreModal/index.tsx | 11 - .../MaxInputModal/MaxInputModal.styles.ts | 23 - .../MaxInputModal/MaxInputModal.test.tsx | 67 - .../__snapshots__/MaxInputModal.test.tsx.snap | 656 ------ .../Stake/components/MaxInputModal/index.tsx | 79 - .../UI/Stake/components/QuickAmounts.tsx | 47 +- .../StakeButton/StakeButton.test.tsx | 86 - .../StakingBalance/StakingBalance.test.tsx | 108 +- .../StakingBalance/StakingBalance.tsx | 103 +- .../ClaimBanner/ClaimBanner.test.tsx | 63 - .../ClaimBanner/ClaimBanner.tsx | 72 +- .../__snapshots__/ClaimBanner.test.tsx.snap | 103 - .../UnstakeBanner/utils/index.test.ts | 2 +- .../StakingButtons/StakingButtons.tsx | 52 +- .../StakingBalance/StakingCta/StakingCta.tsx | 14 +- .../StakingBalance.test.tsx.snap | 158 +- .../components/StakingBalance/mockData.ts | 75 + .../AccountCard/AccountCard.types.ts | 5 - .../__snapshots__/AccountCard.test.tsx.snap | 748 ------- .../AccountHeaderCard.styles.ts} | 0 .../AccountHeaderCard.test.tsx} | 26 +- .../AccountHeaderCard.tsx} | 35 +- .../AccountHeaderCard.types.ts | 3 + .../AccountHeaderCard.test.tsx.snap | 623 ++++++ .../ConfirmationFooter.test.tsx | 40 +- .../ConfirmationFooter/ConfirmationFooter.tsx | 5 +- .../ConfirmationFooter.types.ts | 6 - .../FooterButtonGroup.test.tsx | 116 +- .../FooterButtonGroup/FooterButtonGroup.tsx | 107 +- .../FooterButtonGroup.types.ts | 9 - .../FooterButtonGroup.test.tsx.snap | 184 +- .../ConfirmationFooter.test.tsx.snap | 5 +- .../ContractTag/ContractTag.test.tsx | 7 +- .../ContractTag/ContractTag.tsx | 28 +- .../ContractTag/ContractTag.types.ts | 2 - .../__snapshots__/ContractTag.test.tsx.snap | 140 +- .../EstimatedGasCard.styles.ts | 39 + .../EstimatedGasCard.test.tsx | 67 + .../EstimatedGasCard/EstimatedGasCard.tsx | 69 + .../EstimatedGasCard.types.ts | 4 + .../EstimatedGasCard.test.tsx.snap | 419 ++++ .../EstimatedGasFeeTooltipContent.styles.ts | 13 + .../EstimatedGasFeeTooltipContent.test.tsx | 53 + .../EstimatedGasFeeTooltipContent.tsx | 43 + ...stimatedGasFeeTooltipContent.test.tsx.snap | 67 + .../RewardsCard/RewardsCard.test.tsx | 8 +- .../RewardsCard/RewardsCard.tsx | 3 +- .../TokenValueStack.test.tsx.snap | 2 +- .../UnstakeTimeCard/UnstakeTimeCard.styles.ts | 12 - .../UnstakeTimeCard/UnstakeTimeCard.test.tsx | 31 - .../UnstakeTimeCard/UnstakeTimeCard.tsx | 36 - .../UnstakeTimeCard.test.tsx.snap | 155 -- .../YouReceiveCard/YouReceiveCard.styles.ts | 38 - .../YouReceiveCard/YouReceiveCard.test.tsx | 38 - .../YouReceiveCard/YouReceiveCard.tsx | 70 - .../YouReceiveCard/YouReceiveCard.types.ts | 4 - .../YouReceiveCard.test.tsx.snap | 229 -- .../StakingEarnings/StakingEarnings.test.tsx | 77 - .../components/StakingEarnings/index.tsx | 183 -- .../UI/Stake/hooks/useBalance.test.tsx | 144 -- app/components/UI/Stake/hooks/useBalance.ts | 37 +- .../UI/Stake/hooks/useInputHandler.ts | 183 -- .../Stake/hooks/usePoolStakedClaim/index.ts | 135 -- .../usePoolStakedClaim.test.tsx | 146 -- .../usePoolStakedClaim.types.ts | 1 - .../Stake/hooks/usePoolStakedClaim/utils.ts | 65 - .../Stake/hooks/usePoolStakedDeposit/index.ts | 85 - .../usePoolStakedDeposit.test.tsx | 127 -- .../Stake/hooks/usePoolStakedUnstake/index.ts | 75 - .../usePoolStakedUnstake.test.tsx | 133 -- .../UI/Stake/hooks/usePooledStakes.test.tsx | 217 -- .../UI/Stake/hooks/usePooledStakes.ts | 120 - .../UI/Stake/hooks/useStakeContext.ts | 10 - .../UI/Stake/hooks/useStakingChain.test.tsx | 59 - .../UI/Stake/hooks/useStakingChain.ts | 16 - .../Stake/hooks/useStakingEarnings.test.tsx | 101 - .../UI/Stake/hooks/useStakingEarnings.ts | 56 - .../hooks/useStakingEligibility.test.tsx | 128 -- .../UI/Stake/hooks/useStakingEligibility.ts | 52 - .../UI/Stake/hooks/useStakingGasFee.test.tsx | 162 -- .../UI/Stake/hooks/useStakingGasFee.ts | 94 - .../UI/Stake/hooks/useStakingInput.ts | 183 +- .../UI/Stake/hooks/useUnstakingInput.ts | 48 - .../UI/Stake/hooks/useVaultData.test.tsx | 105 - app/components/UI/Stake/hooks/useVaultData.ts | 59 - app/components/UI/Stake/routes/index.tsx | 55 +- .../stakeSdkProvider.test.tsx.snap | 21 - .../UI/Stake/sdk/stakeSdkProvider.test.tsx | 67 - .../UI/Stake/sdk/stakeSdkProvider.tsx | 81 - app/components/UI/Swaps/QuotesView.js | 20 +- .../UI/Swaps/components/InfoModal.tsx | 8 +- app/components/UI/Tabs/TabCountIcon/index.js | 5 +- app/components/UI/Tabs/index.js | 15 +- .../PortfolioBalance/index.constants.ts | 2 - .../TokenList/PortfolioBalance/index.test.tsx | 98 - .../TokenList/PortfolioBalance/index.tsx | 99 +- .../TokenList}/StakeButton/index.tsx | 33 +- .../TokenList/TokenListFooter/index.tsx | 6 +- .../Tokens/TokenList/TokenListItem/index.tsx | 12 +- app/components/UI/Tokens/TokenList/index.tsx | 24 +- .../TokenSortBottomSheet.test.tsx | 131 -- .../TokenSortBottomSheet.tsx | 104 - .../UI/Tokens/TokensBottomSheet/index.ts | 8 - .../Tokens/__snapshots__/index.test.tsx.snap | 391 +--- app/components/UI/Tokens/index.test.tsx | 146 +- app/components/UI/Tokens/index.tsx | 155 +- app/components/UI/Tokens/styles.ts | 35 - ...eriveBalanceFromAssetMarketDetails.test.ts | 2 - .../deriveBalanceFromAssetMarketDetails.ts | 2 +- app/components/UI/Tokens/util/sortAssets.ts | 13 +- .../__snapshots__/index.test.tsx.snap | 185 +- app/components/UI/TransactionHeader/index.js | 7 +- .../UI/TransactionHeader/index.test.tsx | 83 +- app/components/UI/Transactions/index.js | 3 +- .../UI/WalletAction/WalletAction.styles.ts | 3 - .../UI/WalletAction/WalletAction.tsx | 60 +- .../UI/WalletAction/WalletAction.types.ts | 19 +- .../UI/WarningAlert/WarningAlert.test.tsx | 10 +- .../__snapshots__/WarningAlert.test.tsx.snap | 204 +- .../__snapshots__/index.test.tsx.snap | 608 +---- .../UI/WhatsNewModal/index.test.tsx | 42 +- .../Views/AccountActions/AccountActions.tsx | 62 +- .../Views/AccountConnect/AccountConnect.tsx | 162 +- .../AccountConnectMultiSelector.styles.ts | 3 +- .../AccountConnectMultiSelector.tsx | 103 +- .../AccountConnectMultiSelector.types.ts | 2 - .../AccountConnectSingle.tsx | 7 +- .../AccountPermissions/AccountPermissions.tsx | 236 +- .../AccountPermissionsConnected.tsx | 2 +- .../AccountPermissionsRevoke.tsx | 2 +- .../AccountPermissions.test.tsx.snap | 50 +- .../__snapshots__/index.test.tsx.snap | 390 +--- .../Views/AddBookmark/index.test.tsx | 30 +- .../Asset/__snapshots__/index.test.js.snap | 1 + .../AssetDetailsActions.test.tsx | 107 +- .../AssetDetailsActions.tsx | 41 +- .../AssetDetailsActions.test.tsx.snap | 143 +- app/components/Views/Browser/index.js | 5 +- app/components/Views/BrowserTab/index.js | 14 + app/components/Views/ChoosePassword/index.js | 4 +- .../Views/EditAccountName/EditAccountName.tsx | 2 - .../EditAccountName.test.tsx.snap | 4 +- .../__snapshots__/index.test.tsx.snap | 174 +- .../Views/EnterPasswordSimple/index.test.tsx | 39 +- .../Views/LedgerConnect/Scan.test.tsx | 45 - app/components/Views/LedgerConnect/Scan.tsx | 8 +- app/components/Views/Login/index.js | 76 +- .../NFTAutoDetectionModal.tsx | 46 +- .../__snapshots__/TestScreen2.test.js.snap | 309 +-- .../Views/NavigationUnitTest/index.js | 80 +- .../NetworkConnectMultiSelector.tsx | 196 +- .../NetworkConnectMultiSelector.types.ts | 4 - .../NetworkSelector/NetworkSelector.test.tsx | 2 +- .../Views/NetworkSelector/NetworkSelector.tsx | 2 +- .../NetworkSelector.test.tsx.snap | 12 +- .../Badge/__snapshots__/index.test.tsx.snap | 2 +- .../Details/Fields/NetworkFeeField.test.tsx | 56 +- .../Details/Fields/NetworkFeeField.tsx | 100 +- .../Fields/Skeletons/NetworkFeeField.tsx | 34 - .../Details/Fields/TransactionField.test.tsx | 53 - .../Details/Fields/TransactionField.tsx | 7 +- .../NetworkFeeField.test.tsx.snap | 2 +- .../Footers/BlockExplorerFooter.test.tsx | 89 - .../Details/Footers/BlockExplorerFooter.tsx | 7 +- .../Details/__snapshots__/index.test.tsx.snap | 75 +- .../Notifications/Details/index.test.tsx | 31 +- .../Views/Notifications/Details/index.tsx | 14 +- .../__snapshots__/index.test.tsx.snap | 37 +- .../DefaultSettings/index.styles.ts | 7 - .../DefaultSettings/index.tsx | 18 +- .../__snapshots__/index.test.tsx.snap | 2 +- .../__snapshots__/index.test.tsx.snap | 48 +- .../__snapshots__/index.test.js.snap | 1 - .../Views/OnboardingSuccess/index.styles.ts | 1 - .../__snapshots__/index.test.tsx.snap | 120 +- .../Views/PickComponent/index.test.tsx | 28 +- app/components/Views/Quiz/SRPQuiz/SRPQuiz.tsx | 2 +- app/components/Views/ResetPassword/index.js | 3 +- .../FiatOnTestnetsFriction.tsx | 6 +- .../__snapshots__/index.test.tsx.snap | 2 +- .../Settings/ExperimentalSettings/index.tsx | 14 +- .../Views/Settings/GeneralSettings/index.js | 2 +- .../Settings/GeneralSettings/index.test.tsx | 2 +- .../AccountsList.test.tsx | 88 - .../NotificationsSettings/AccountsList.tsx | 53 - .../NotificationOptionToggle/index.tsx | 8 +- .../NotificationsSettings.styles.ts | 9 +- .../__snapshots__/AccountsList.test.tsx.snap | 520 ----- .../Settings/NotificationsSettings/index.tsx | 69 +- .../Sections/ClearCookiesSection.tsx | 6 +- .../SecuritySettings/SecuritySettings.tsx | 29 +- .../SecuritySettings.test.tsx.snap | 3 +- app/components/Views/Settings/index.test.tsx | 2 +- .../SmartTransactionStatus.tsx | 12 +- .../SmartTranactionsOptInModal.tsx | 20 +- .../KeyringSnapRemovalWarning.constants.ts | 9 - .../KeyringSnapRemovalWarning.styles.ts | 43 - .../KeyringSnapRemovalWarning.tsx | 226 -- .../Snaps/KeyringSnapRemovalWarning/index.ts | 3 - .../test/KeyringSnapRemovalWarning.test.tsx | 337 --- .../Views/Snaps/SnapSettings/SnapSettings.tsx | 168 +- .../SnapSettings/test/SnapSettings.test.tsx | 419 +--- .../KeyringAccountListItem.constants.ts | 4 - .../KeyringAccountListItem.styles.ts | 36 - .../KeyringAccountListItem.tsx | 74 - .../KeyringAccountListItem/index.ts | 3 - .../test/KeyringAccountListItem.test.tsx | 42 - .../Views/TooltipModal/ToolTipModal.styles.ts | 1 - .../__snapshots__/index.test.js.snap | 32 + .../Views/TransactionsView/index.test.js | 18 + .../Wallet/__snapshots__/index.test.tsx.snap | 50 +- app/components/Views/Wallet/index.test.tsx | 47 +- app/components/Views/Wallet/index.tsx | 95 +- .../WalletActions/WalletActions.test.tsx | 53 +- .../Views/WalletActions/WalletActions.tsx | 162 +- .../Views/confirmations/Approval/index.js | 6 +- .../__snapshots__/Confirm.test.tsx.snap | 2 +- .../Views/confirmations/Send/index.js | 2 +- .../CustomGasModal.test.tsx.snap | 1 - .../confirmations/SendFlow/Confirm/index.js | 2 +- .../ApproveTransactionHeader.test.tsx | 28 - .../ApproveTransactionHeader.tsx | 5 +- .../ApproveTransactionReview/index.js | 2 +- .../AccountNetworkInfoCollapsed.tsx | 12 +- .../AccountNetworkInfoCollapsed.test.tsx.snap | 2 +- .../AccountNetworkInfoExpanded.tsx | 16 +- .../AccountNetworkInfoExpanded.test.tsx.snap | 58 +- .../AccountNetworkInfo.test.tsx.snap | 2 +- .../Info/PersonalSign/PersonalSign.tsx | 4 +- .../components/EditGasFee1559Update/index.tsx | 1 - .../EditGasFeeLegacyUpdate.test.tsx.snap | 1 - .../EditGasFeeLegacyUpdate/index.tsx | 3 +- .../components/PersonalSign/PersonalSign.tsx | 4 +- .../components/SignatureRequest/index.js | 6 +- .../components/TransactionReview/index.js | 16 +- .../components/TypedSign/index.js | 4 +- .../components/TypedSign/index.test.tsx | 16 +- .../components/UI/InfoRow/InfoRow.stories.tsx | 6 +- .../UI/InfoRow/InfoValue/DisplayURL/index.ts | 1 - .../InfoURL.styles.ts} | 0 .../InfoURL.test.tsx} | 8 +- .../DisplayURL.tsx => InfoURL/InfoURL.tsx} | 10 +- .../__snapshots__/InfoURL.test.tsx.snap} | 2 +- .../UI/InfoRow/InfoValue/InfoURL/index.ts | 1 + .../InfoValue/{Network => InfoURL}/style.ts | 0 .../InfoValue/Network/Network.styles.ts | 24 - .../InfoValue/Network/Network.test.tsx | 33 - .../UI/InfoRow/InfoValue/Network/Network.tsx | 37 - .../__snapshots__/Network.test.tsx.snap | 59 - .../UI/InfoRow/InfoValue/Network/index.ts | 1 - .../components/WatchAssetRequest/index.js | 2 +- .../hooks/useNetworkInfo.test.ts | 47 - .../confirmations/hooks/useNetworkInfo.ts | 40 - .../hooks/Ledger/useBluetoothDevices.test.ts | 61 - .../hooks/Ledger/useBluetoothDevices.ts | 55 +- .../hooks/useCheckMultiRpcModal/index.ts | 1 - .../useCheckMultiRpcModal.test.ts | 93 - .../useCheckMultiRpcModal.ts | 38 - .../useCheckNftAutoDetectionModal/index.ts | 1 - .../useCheckNftAutoDetectionModal.test.ts | 76 - .../useCheckNftAutoDetectionModal.ts | 42 - app/constants/navigation/Routes.ts | 2 - app/constants/permissions.ts | 1 - app/constants/transaction.ts | 4 - app/core/Analytics/MetaMetrics.events.ts | 36 - app/core/AppConstants.ts | 6 +- app/core/BackgroundBridge/BackgroundBridge.js | 8 +- app/core/Encryptor/Encryptor.test.ts | 6 +- app/core/Encryptor/lib.test.ts | 43 +- app/core/{Engine.test.ts => Engine.test.js} | 221 +- app/core/Engine.ts | 515 ++--- app/core/EngineService/EngineService.ts | 12 +- app/core/NotificationManager.js | 52 +- app/core/NotificationsManager.test.ts | 15 +- app/core/Permissions/constants.ts | 1 - app/core/Permissions/specifications.js | 100 +- app/core/Permissions/specifications.test.js | 8 +- .../RPCMethods/RPCMethodMiddleware.test.ts | 27 +- app/core/RPCMethods/RPCMethodMiddleware.ts | 43 +- .../RPCMethods/lib/ethereum-chain-utils.js | 310 --- .../RPCMethods/wallet_addEthereumChain.js | 275 ++- .../wallet_addEthereumChain.test.js | 201 +- .../RPCMethods/wallet_switchEthereumChain.js | 124 +- .../wallet_switchEthereumChain.test.js | 188 -- .../handlers/handleConnectionReady.test.ts | 335 +++ app/core/SecureKeychain.js | 30 +- app/core/SecureKeychain.test.ts | 202 -- .../SnapKeyring/utils/getAccountsBySnapId.ts | 17 - app/core/Snaps/SnapBridge.ts | 8 +- app/core/redux/slices/notifications/index.ts | 9 +- app/images/ape-network.png | Bin 42185 -> 0 bytes app/images/ape-token.png | Bin 51726 -> 0 bytes app/images/gravity.png | Bin 80926 -> 0 bytes app/images/image-icons.js | 4 - app/lib/ens-ipfs/resolver.js | 4 +- app/lib/ppom/security-alerts-api.ts | 5 +- app/reducers/collectibles/index.js | 8 +- app/selectors/accountTrackerController.ts | 8 +- ...accountTrackerControllerReRenders.test.tsx | 6 +- app/selectors/accountsController.ts | 22 +- app/selectors/networkController.ts | 4 +- app/selectors/notifications/index.tsx | 8 +- app/selectors/preferencesController.ts | 14 +- app/selectors/selectedNetworkController.ts | 8 +- app/selectors/tokenRatesController.ts | 4 +- app/selectors/types.ts | 8 +- app/store/migrations/029.ts | 4 +- app/store/migrations/031.ts | 4 +- app/store/migrations/052.ts | 38 +- app/store/migrations/057.test.ts | 197 ++ app/store/migrations/057.ts | 84 +- app/store/migrations/058.test.ts | 40 +- app/store/migrations/058.ts | 41 +- app/store/migrations/059.test.ts | 164 -- app/store/migrations/059.ts | 67 - app/store/migrations/index.ts | 2 - app/store/migrations/util/index.tsx | 1 - app/util/address/index.test.ts | 12 - app/util/address/index.ts | 11 - app/util/browser/webViewFocus.test.ts | 74 + app/util/browser/webViewFocus.ts | 32 + app/util/navigation/useConnectionHandler.tsx | 41 - app/util/networks/customNetworks.tsx | 3 - app/util/networks/index.js | 3 - .../notifications/androidChannels.test.ts | 12 +- app/util/notifications/androidChannels.ts | 12 +- app/util/notifications/constants/triggers.ts | 7 - app/util/notifications/hooks/index.test.ts | 109 + app/util/notifications/hooks/index.test.tsx | 100 - app/util/notifications/hooks/index.ts | 76 +- .../hooks/useAccountSyncing.test.tsx | 102 - .../notifications/hooks/useAccountSyncing.ts | 32 - .../notifications/hooks/useNotifications.ts | 19 +- .../notifications/hooks/useProfileSyncing.ts | 1 + .../hooks/usePushNotifications.ts | 52 - .../hooks/useSwitchNotifications.test.tsx | 134 +- .../hooks/useSwitchNotifications.ts | 104 +- .../hooks/useUpdateAccountSetting.tsx | 12 +- app/util/notifications/methods/common.test.ts | 22 +- app/util/notifications/methods/common.ts | 77 +- .../notifications/methods/fcmHelper.test.ts | 83 + app/util/notifications/methods/fcmHelper.ts | 99 + app/util/notifications/methods/index.ts | 1 + .../notification-states/index.test.tsx | 42 - .../notification-states/index.ts | 14 +- .../notification-states/node-guard.test.ts | 49 - .../notification-states/node-guard.ts | 7 +- .../notifications/services/FCMService.test.ts | 135 -- app/util/notifications/services/FCMService.ts | 65 - .../services/NotificationService.test.ts | 120 +- .../services/NotificationService.ts | 50 +- .../settings/storage/constants.ts | 8 +- .../settings/storage/contants.test.ts | 1 - .../notifications/types/notification/index.ts | 35 +- app/util/number/index.js | 2 +- app/util/regex/index.test.ts | 8 +- app/util/regex/index.ts | 4 +- .../sentry/__snapshots__/utils.test.ts.snap | 2 +- app/util/sentry/tags/index.ts | 6 + app/util/sentry/utils.test.ts | 2 +- app/util/smart-transactions/index.test.ts | 145 -- app/util/smart-transactions/index.ts | 53 +- app/util/test/accountsControllerTestUtils.ts | 31 - app/util/test/initial-background-state.json | 15 +- app/util/test/network.ts | 1 + app/util/test/testSetup.js | 33 - app/util/transactions/index.js | 57 +- app/util/transactions/index.test.ts | 21 +- attribution.txt | 1968 ++++++++--------- bitrise.yml | 43 +- e2e/api-mocking/mock-config/mock-events.js | 57 - .../mock-config/mockUrlCollection.json | 3 - .../mock-responses/gas-api-responses.json | 36 - e2e/api-mocking/mock-server.js | 81 - e2e/api-specs/ConfirmationsRejectionRule.js | 14 +- e2e/fixtures/fixture-builder.js | 3 +- e2e/fixtures/utils.js | 6 - e2e/mockServer/mockServer.js | 40 + e2e/mockServer/mockUrlCollection.json | 7 + e2e/pages/AccountListView.js | 11 +- .../{Transactions => }/ActivitiesView.js | 10 +- e2e/pages/Browser/BrowserView.js | 21 +- e2e/pages/Browser/SigningBottomSheet.js | 35 - e2e/pages/EditAccountNameView.js | 20 +- .../EnableAutomaticSecurityChecksView.js | 25 + .../Network/NetworkApprovalBottomSheet.js | 27 - e2e/pages/Ramps/BuildQuoteView.js | 14 - e2e/pages/Ramps/SelectPaymentMethodView.js | 7 +- e2e/pages/Ramps/SelectRegionView.js | 2 +- e2e/pages/Ramps/SellGetStartedView.js | 15 - .../Receive/PaymentRequestQrBottomSheet.js | 19 - e2e/pages/Receive/SendLinkView.js | 33 - e2e/pages/{Receive => }/RequestPaymentView.js | 6 +- e2e/pages/Send/AmountView.js | 9 +- e2e/pages/Send/TransactionConfirmView.js | 6 +- e2e/pages/SendLinkView.js | 34 + .../Advanced/FiatOnTestnetsBottomSheet.js | 17 - .../Contacts/DeleteContactBottomSheet.js | 28 - e2e/pages/Settings/NetworksView.js | 2 +- e2e/pages/TokenOverview.js | 117 +- .../Transactions/AssetWatchBottomSheet.js | 15 - e2e/pages/modals/AccountActionsModal.js | 13 - e2e/pages/modals/AssetWatchModal.js | 21 + .../AutoLockModal.js | 6 +- .../ConnectModal.js} | 22 +- .../ConnectedAccountsModal.js | 2 +- .../ContractApprovalModal.js} | 26 +- e2e/pages/modals/DeleteContactModal.js | 28 + .../DeleteWalletModal.js | 6 +- .../DetailsModal.js} | 6 +- .../EnableAutomaticSecurityChecksView.js | 19 - e2e/pages/modals/FiatOnTestnetsModal.js | 17 + .../NetworkAddedModal.js} | 20 +- e2e/pages/modals/NetworkApprovalModal.js | 28 + .../NetworkEducationModal.js | 6 +- .../{Network => modals}/NetworkListModal.js | 3 +- .../RequestPaymentModal.js | 4 +- e2e/pages/modals/SigningModal.js | 35 + .../{Browser => modals}/SpamFilterModal.js | 2 +- .../SrpQuizModal.js | 6 +- .../TransactionProtectionModal.js | 2 +- e2e/pages/modals/WalletActionsModal.js | 8 - e2e/pages/wallet/WalletView.js | 14 +- .../ActivitiesView.selectors.js | 2 +- .../Browser/BrowserView.selectors.js | 10 +- e2e/selectors/EditGasView.selectors.js | 1 - .../Modals/AccountActionsModal.selectors.js | 5 +- .../AssetWatcher.selectors.js | 0 .../AutoLockModal.selectors.js | 2 +- e2e/selectors/Modals/CellModal.selectors.js | 1 - .../ConnectAccountModal.selectors.js} | 5 +- .../ConnectedAccountModal.selectors.js | 1 - .../ContractApprovalModal.selectors.js} | 4 +- .../DeleteContactModal.selectors.js} | 4 +- .../DeleteWalletModal.selectors.js | 2 +- ...EnableAutomaticSecurityChecks.selectors.js | 4 - .../FiatOnTestnetsModal.selectors.js} | 2 +- .../NetworkAddedModal.selectors.js} | 4 +- .../NetworkApprovalModal.selectors.js} | 2 +- .../NetworkEducationModal.selectors.js | 0 .../NetworkListModal.selectors.js | 0 .../Modals/RequestPaymentModal.selectors.js | 6 + .../SigningModal.selectors.js} | 2 +- .../SpamFilterModal.selectors.js | 0 .../SrpQuizModal.selectors.js | 2 +- .../TransactionDetailsModal.selectors.js | 1 + .../TransactionProtectionModal.selectors.js | 0 e2e/selectors/Ramps/BuildQuote.selectors.js | 2 - .../Receive/RequestPaymentModal.selectors.js | 3 - .../RequestPaymentView.selectors.js | 1 + .../{Receive => }/SendLinkView.selectors.js | 0 .../ClearCookiesSection.selectors.js | 3 + e2e/selectors/TokenOverview.selectors.js | 21 - .../TransactionConfirmView.selectors.js | 1 + e2e/selectors/TransactionReview.selectors.js | 3 - .../wallet/ImportTokenView.selectors.js | 1 + e2e/selectors/wallet/WalletView.selectors.js | 5 - e2e/specs/accounts/auto-lock.spec.js | 2 +- .../accounts/change-account-name.spec.js | 2 +- .../accounts/import-wallet-account.spec.js | 2 +- .../reveal-secret-recovery-phrase.spec.js | 4 +- e2e/specs/assets/import-tokens.spec.js | 16 +- ...mock.spec.js => advanced-gas-fees.spec.js} | 28 +- .../approve-custom-erc20.spec.js | 16 +- .../approve-default-erc20.spec.js | 18 +- .../increase-allowance-erc20.spec.js | 16 +- .../send-erc20-with-dapp.spec.js | 2 +- e2e/specs/confirmations/send-erc721.spec.js | 2 +- .../set-approve-for-all-erc721.spec.js | 10 +- .../signatures/personal-sign.spec.js | 18 +- .../signatures/typed-sign-v3.spec.js | 16 +- .../signatures/typed-sign-v4.spec.js | 16 +- .../signatures/typed-sign.spec.js | 18 +- .../suggestedGasApi.mock.spec.js | 97 - e2e/specs/networks/add-custom-rpc.spec.js | 4 +- .../networks/add-popular-networks.spec.js | 12 +- .../networks/connect-test-network.spec.js | 4 +- e2e/specs/networks/networks-search.spec.js | 2 +- .../notifications/account-syncing/mockData.js | 12 - ...c-after-adding-custom-name-account.spec.js | 98 - .../sync-after-onboarding.spec.js | 67 - e2e/specs/notifications/utils/constants.js | 7 - e2e/specs/notifications/utils/helpers.js | 10 - e2e/specs/notifications/utils/mocks.js | 83 - .../userStorageMockttpController.js | 171 -- .../userStorageMockttpController.test.js | 305 --- .../onboarding-wizard-opt-in.spec.js | 4 +- .../permission-system-delete-wallet.spec.js | 6 +- ...ssion-system-revoke-single-account.spec.js | 4 +- ...-system-revoking-multiple-accounts.spec.js | 4 +- e2e/specs/quarantine/deeplinks.failing.js | 32 +- ...ystem-removing-imported-account.failing.js | 24 +- .../portfolio-connect-account.failing.js} | 8 +- .../quarantine/swap-token-chart.failing.js | 22 +- .../term-of-use.broken.js} | 9 +- e2e/specs/ramps/offramp.spec.js | 76 - e2e/specs/ramps/onramp.spec.js | 15 +- e2e/specs/settings/addressbook-tests.spec.js | 6 +- e2e/specs/settings/delete-wallet.spec.js | 2 +- e2e/specs/settings/fiat-on-testnets.spec.js | 8 +- .../swaps/swap-action-regression.spec.js | 20 +- e2e/specs/swaps/swap-action-smoke.spec.js | 18 +- e2e/specs/swaps/token-details.spec.js | 32 +- e2e/specs/wallet/request-token-flow.spec.js | 13 +- e2e/specs/wallet/send-ERC-token.spec.js | 6 +- e2e/specs/wallet/start-exploring.spec.js | 4 +- e2e/specs/wallet/suggestedGasApi.mock.spec.js | 90 + e2e/tags.js | 4 - e2e/viewHelper.js | 20 +- index.js | 4 +- .../GoogleService-Info-example.plist | 30 - ios/GoogleServices/GoogleService-Info.plist | 26 - ios/MetaMask.xcodeproj/project.pbxproj | 32 +- .../xcschemes/MetaMask-QA.xcscheme | 20 +- .../xcshareddata/xcschemes/MetaMask.xcscheme | 20 +- ios/MetaMask/AppDelegate.h | 1 - ios/MetaMask/AppDelegate.m | 3 +- ios/Podfile.lock | 6 + jest.config.js | 2 +- locales/languages/en.json | 140 +- package.json | 47 +- .../@metamask+approval-controller+7.0.2.patch | 404 ++++ ...tamask+preferences-controller+13.0.3.patch | 13 + ...ets-controllers++multiformats+13.3.0.patch | 12 - .../@metamask+assets-controllers+32.0.0.patch | 1181 ++++++++++ .../@metamask+assets-controllers+39.0.0.patch | 531 ----- patches/@metamask+ethjs-contract+0.4.1.patch | 13 - patches/@metamask+ethjs-query+0.7.1.patch | 13 - ...@metamask+post-message-stream+8.1.0.patch} | 4 +- ...tamask+preferences-controller+11.0.0.patch | 241 ++ ...tamask+preferences-controller+13.1.0.patch | 229 -- ...etox+20.27.5.patch => detox+20.23.1.patch} | 0 patches/ethjs-contract+0.2.3.patch | 13 + patches/ethjs-query+0.3.8.patch | 13 + scripts/build.sh | 27 +- scripts/bump-version.sh | 47 + scripts/create-release-draft.sh | 45 - scripts/create-release-pr.sh | 69 +- scripts/generate-attributions/package.json | 2 +- scripts/set-build-version.sh | 123 -- scripts/set-semvar-version.sh | 113 - shim.js | 2 +- sonar-project.properties | 2 +- .../BrowserObject/AddressBarScreen.js | 6 +- .../BrowserObject/BrowserScreen.js | 1 + .../BrowserObject/MultiTabScreen.js | 16 +- .../EnableSecurityChecksScreen.js | 9 +- .../Modals/AccountApprovalModal.js | 22 +- .../Modals/ConnectedAccountsModal.js | 9 +- .../screen-objects/Modals/NetworkListModal.js | 2 +- .../Modals/TransactionProtectionModal.js | 2 +- wdio/screen-objects/RequestTokenScreen.js | 15 +- wdio/screen-objects/SendLinkScreen.js | 9 +- wdio/screen-objects/TokenOverviewScreen.js | 18 +- .../BrowserScreen/AddressBar.testIds.js | 6 + .../BrowserScreen/BrowserScreen.testIds.js | 22 + .../testIDs/BrowserScreen/MultiTab.testIds.js | 7 + .../AccountApprovalModal.testIds.js | 5 + .../AccountListComponent.testIds.js | 3 + .../ConnectedAccountsModal.testIds.js | 8 + ...leAutomaticSecurityChecksScreen.testIds.js | 4 + .../testIDs/Screens/RequestToken.testIds.js | 8 + .../Screens/TokenOverviewScreen.testIds.js | 9 + wdio/step-definitions/send-flow.steps.js | 1 + yarn.lock | 1025 ++++++--- 734 files changed, 11954 insertions(+), 30949 deletions(-) create mode 100644 .github/workflows/bump-version-name.yml delete mode 100644 .github/workflows/create-release-draft.yml delete mode 100644 .github/workflows/update-latest-build-version.yml delete mode 100644 app/actions/notification/helpers/index.test.tsx delete mode 100644 app/component-library/components-temp/Price/AggregatedPercentage/AggregatedPercentage.constants.ts delete mode 100644 app/component-library/components/Pickers/PickerBase/PickerBase.stories.tsx delete mode 100644 app/component-library/components/Texts/SensitiveText/README.md delete mode 100644 app/component-library/components/Texts/SensitiveText/SensitiveText.stories.tsx delete mode 100644 app/component-library/components/Texts/SensitiveText/SensitiveText.test.tsx delete mode 100644 app/component-library/components/Texts/SensitiveText/SensitiveText.tsx delete mode 100644 app/component-library/components/Texts/SensitiveText/SensitiveText.types.ts delete mode 100644 app/component-library/components/Texts/SensitiveText/__snapshots__/SensitiveText.test.tsx.snap delete mode 100644 app/component-library/components/Texts/SensitiveText/index.ts delete mode 100644 app/components/Nav/Main/useConnectionHandler.test.ts delete mode 100644 app/components/UI/AssetElement/index.constants.ts rename app/components/UI/{Stake/components => AssetOverview}/StakingEarnings/StakingEarnings.styles.tsx (92%) create mode 100644 app/components/UI/AssetOverview/StakingEarnings/StakingEarnings.test.tsx rename app/components/UI/{Stake/components => AssetOverview}/StakingEarnings/__snapshots__/StakingEarnings.test.tsx.snap (98%) create mode 100644 app/components/UI/AssetOverview/StakingEarnings/index.tsx delete mode 100644 app/components/UI/Notification/BaseNotification/__snapshots__/index.test.jsx.snap delete mode 100644 app/components/UI/Notification/BaseNotification/index.test.jsx delete mode 100644 app/components/UI/Stake/Views/UnstakeConfirmationView/UnstakeConfirmationView.styles.ts delete mode 100644 app/components/UI/Stake/Views/UnstakeConfirmationView/UnstakeConfirmationView.test.tsx delete mode 100644 app/components/UI/Stake/Views/UnstakeConfirmationView/UnstakeConfirmationView.tsx delete mode 100644 app/components/UI/Stake/Views/UnstakeConfirmationView/UnstakeConfirmationView.types.ts delete mode 100644 app/components/UI/Stake/Views/UnstakeConfirmationView/__snapshots__/UnstakeConfirmationView.test.tsx.snap delete mode 100644 app/components/UI/Stake/Views/UnstakeInputView/UnstakeInputView.types.ts delete mode 100644 app/components/UI/Stake/__mocks__/mockData.ts delete mode 100644 app/components/UI/Stake/components/MaxInputModal/MaxInputModal.styles.ts delete mode 100644 app/components/UI/Stake/components/MaxInputModal/MaxInputModal.test.tsx delete mode 100644 app/components/UI/Stake/components/MaxInputModal/__snapshots__/MaxInputModal.test.tsx.snap delete mode 100644 app/components/UI/Stake/components/MaxInputModal/index.tsx delete mode 100644 app/components/UI/Stake/components/StakeButton/StakeButton.test.tsx delete mode 100644 app/components/UI/Stake/components/StakingBalance/StakingBanners/ClaimBanner/ClaimBanner.test.tsx delete mode 100644 app/components/UI/Stake/components/StakingBalance/StakingBanners/ClaimBanner/__snapshots__/ClaimBanner.test.tsx.snap create mode 100644 app/components/UI/Stake/components/StakingBalance/mockData.ts delete mode 100644 app/components/UI/Stake/components/StakingConfirmation/AccountCard/AccountCard.types.ts delete mode 100644 app/components/UI/Stake/components/StakingConfirmation/AccountCard/__snapshots__/AccountCard.test.tsx.snap rename app/components/UI/Stake/components/StakingConfirmation/{AccountCard/AccountCard.styles.ts => AccountHeaderCard/AccountHeaderCard.styles.ts} (100%) rename app/components/UI/Stake/components/StakingConfirmation/{AccountCard/AccountCard.test.tsx => AccountHeaderCard/AccountHeaderCard.test.tsx} (75%) rename app/components/UI/Stake/components/StakingConfirmation/{AccountCard/AccountCard.tsx => AccountHeaderCard/AccountHeaderCard.tsx} (68%) create mode 100644 app/components/UI/Stake/components/StakingConfirmation/AccountHeaderCard/AccountHeaderCard.types.ts create mode 100644 app/components/UI/Stake/components/StakingConfirmation/AccountHeaderCard/__snapshots__/AccountHeaderCard.test.tsx.snap delete mode 100644 app/components/UI/Stake/components/StakingConfirmation/ConfirmationFooter/ConfirmationFooter.types.ts delete mode 100644 app/components/UI/Stake/components/StakingConfirmation/ConfirmationFooter/FooterButtonGroup/FooterButtonGroup.types.ts create mode 100644 app/components/UI/Stake/components/StakingConfirmation/EstimatedGasCard/EstimatedGasCard.styles.ts create mode 100644 app/components/UI/Stake/components/StakingConfirmation/EstimatedGasCard/EstimatedGasCard.test.tsx create mode 100644 app/components/UI/Stake/components/StakingConfirmation/EstimatedGasCard/EstimatedGasCard.tsx create mode 100644 app/components/UI/Stake/components/StakingConfirmation/EstimatedGasCard/EstimatedGasCard.types.ts create mode 100644 app/components/UI/Stake/components/StakingConfirmation/EstimatedGasCard/__snapshots__/EstimatedGasCard.test.tsx.snap create mode 100644 app/components/UI/Stake/components/StakingConfirmation/EstimatedGasFeeTooltipContent/EstimatedGasFeeTooltipContent.styles.ts create mode 100644 app/components/UI/Stake/components/StakingConfirmation/EstimatedGasFeeTooltipContent/EstimatedGasFeeTooltipContent.test.tsx create mode 100644 app/components/UI/Stake/components/StakingConfirmation/EstimatedGasFeeTooltipContent/EstimatedGasFeeTooltipContent.tsx create mode 100644 app/components/UI/Stake/components/StakingConfirmation/EstimatedGasFeeTooltipContent/__snapshots__/EstimatedGasFeeTooltipContent.test.tsx.snap delete mode 100644 app/components/UI/Stake/components/StakingConfirmation/UnstakeTimeCard/UnstakeTimeCard.styles.ts delete mode 100644 app/components/UI/Stake/components/StakingConfirmation/UnstakeTimeCard/UnstakeTimeCard.test.tsx delete mode 100644 app/components/UI/Stake/components/StakingConfirmation/UnstakeTimeCard/UnstakeTimeCard.tsx delete mode 100644 app/components/UI/Stake/components/StakingConfirmation/UnstakeTimeCard/__snapshots__/UnstakeTimeCard.test.tsx.snap delete mode 100644 app/components/UI/Stake/components/StakingConfirmation/YouReceiveCard/YouReceiveCard.styles.ts delete mode 100644 app/components/UI/Stake/components/StakingConfirmation/YouReceiveCard/YouReceiveCard.test.tsx delete mode 100644 app/components/UI/Stake/components/StakingConfirmation/YouReceiveCard/YouReceiveCard.tsx delete mode 100644 app/components/UI/Stake/components/StakingConfirmation/YouReceiveCard/YouReceiveCard.types.ts delete mode 100644 app/components/UI/Stake/components/StakingConfirmation/YouReceiveCard/__snapshots__/YouReceiveCard.test.tsx.snap delete mode 100644 app/components/UI/Stake/components/StakingEarnings/StakingEarnings.test.tsx delete mode 100644 app/components/UI/Stake/components/StakingEarnings/index.tsx delete mode 100644 app/components/UI/Stake/hooks/useBalance.test.tsx delete mode 100644 app/components/UI/Stake/hooks/useInputHandler.ts delete mode 100644 app/components/UI/Stake/hooks/usePoolStakedClaim/index.ts delete mode 100644 app/components/UI/Stake/hooks/usePoolStakedClaim/usePoolStakedClaim.test.tsx delete mode 100644 app/components/UI/Stake/hooks/usePoolStakedClaim/usePoolStakedClaim.types.ts delete mode 100644 app/components/UI/Stake/hooks/usePoolStakedClaim/utils.ts delete mode 100644 app/components/UI/Stake/hooks/usePoolStakedDeposit/index.ts delete mode 100644 app/components/UI/Stake/hooks/usePoolStakedDeposit/usePoolStakedDeposit.test.tsx delete mode 100644 app/components/UI/Stake/hooks/usePoolStakedUnstake/index.ts delete mode 100644 app/components/UI/Stake/hooks/usePoolStakedUnstake/usePoolStakedUnstake.test.tsx delete mode 100644 app/components/UI/Stake/hooks/usePooledStakes.test.tsx delete mode 100644 app/components/UI/Stake/hooks/usePooledStakes.ts delete mode 100644 app/components/UI/Stake/hooks/useStakeContext.ts delete mode 100644 app/components/UI/Stake/hooks/useStakingChain.test.tsx delete mode 100644 app/components/UI/Stake/hooks/useStakingChain.ts delete mode 100644 app/components/UI/Stake/hooks/useStakingEarnings.test.tsx delete mode 100644 app/components/UI/Stake/hooks/useStakingEarnings.ts delete mode 100644 app/components/UI/Stake/hooks/useStakingEligibility.test.tsx delete mode 100644 app/components/UI/Stake/hooks/useStakingEligibility.ts delete mode 100644 app/components/UI/Stake/hooks/useStakingGasFee.test.tsx delete mode 100644 app/components/UI/Stake/hooks/useStakingGasFee.ts delete mode 100644 app/components/UI/Stake/hooks/useUnstakingInput.ts delete mode 100644 app/components/UI/Stake/hooks/useVaultData.test.tsx delete mode 100644 app/components/UI/Stake/hooks/useVaultData.ts delete mode 100644 app/components/UI/Stake/sdk/__snapshots__/stakeSdkProvider.test.tsx.snap delete mode 100644 app/components/UI/Stake/sdk/stakeSdkProvider.test.tsx delete mode 100644 app/components/UI/Stake/sdk/stakeSdkProvider.tsx delete mode 100644 app/components/UI/Tokens/TokenList/PortfolioBalance/index.constants.ts rename app/components/UI/{Stake/components => Tokens/TokenList}/StakeButton/index.tsx (74%) delete mode 100644 app/components/UI/Tokens/TokensBottomSheet/TokenSortBottomSheet.test.tsx delete mode 100644 app/components/UI/Tokens/TokensBottomSheet/TokenSortBottomSheet.tsx delete mode 100644 app/components/UI/Tokens/TokensBottomSheet/index.ts delete mode 100644 app/components/Views/Notifications/Details/Fields/Skeletons/NetworkFeeField.tsx delete mode 100644 app/components/Views/Notifications/Details/Fields/TransactionField.test.tsx delete mode 100644 app/components/Views/Notifications/Details/Footers/BlockExplorerFooter.test.tsx delete mode 100644 app/components/Views/Settings/NotificationsSettings/AccountsList.test.tsx delete mode 100644 app/components/Views/Settings/NotificationsSettings/AccountsList.tsx delete mode 100644 app/components/Views/Settings/NotificationsSettings/__snapshots__/AccountsList.test.tsx.snap delete mode 100644 app/components/Views/Snaps/KeyringSnapRemovalWarning/KeyringSnapRemovalWarning.constants.ts delete mode 100644 app/components/Views/Snaps/KeyringSnapRemovalWarning/KeyringSnapRemovalWarning.styles.ts delete mode 100644 app/components/Views/Snaps/KeyringSnapRemovalWarning/KeyringSnapRemovalWarning.tsx delete mode 100644 app/components/Views/Snaps/KeyringSnapRemovalWarning/index.ts delete mode 100644 app/components/Views/Snaps/KeyringSnapRemovalWarning/test/KeyringSnapRemovalWarning.test.tsx delete mode 100644 app/components/Views/Snaps/components/KeyringAccountListItem/KeyringAccountListItem.constants.ts delete mode 100644 app/components/Views/Snaps/components/KeyringAccountListItem/KeyringAccountListItem.styles.ts delete mode 100644 app/components/Views/Snaps/components/KeyringAccountListItem/KeyringAccountListItem.tsx delete mode 100644 app/components/Views/Snaps/components/KeyringAccountListItem/index.ts delete mode 100644 app/components/Views/Snaps/components/KeyringAccountListItem/test/KeyringAccountListItem.test.tsx create mode 100644 app/components/Views/TransactionsView/__snapshots__/index.test.js.snap create mode 100644 app/components/Views/TransactionsView/index.test.js delete mode 100644 app/components/Views/confirmations/components/UI/InfoRow/InfoValue/DisplayURL/index.ts rename app/components/Views/confirmations/components/UI/InfoRow/InfoValue/{DisplayURL/DisplayURL.styles.ts => InfoURL/InfoURL.styles.ts} (100%) rename app/components/Views/confirmations/components/UI/InfoRow/InfoValue/{DisplayURL/DisplayURL.test.tsx => InfoURL/InfoURL.test.tsx} (59%) rename app/components/Views/confirmations/components/UI/InfoRow/InfoValue/{DisplayURL/DisplayURL.tsx => InfoURL/InfoURL.tsx} (81%) rename app/components/Views/confirmations/components/UI/InfoRow/InfoValue/{DisplayURL/__snapshots__/DisplayURL.test.tsx.snap => InfoURL/__snapshots__/InfoURL.test.tsx.snap} (87%) create mode 100644 app/components/Views/confirmations/components/UI/InfoRow/InfoValue/InfoURL/index.ts rename app/components/Views/confirmations/components/UI/InfoRow/InfoValue/{Network => InfoURL}/style.ts (100%) delete mode 100644 app/components/Views/confirmations/components/UI/InfoRow/InfoValue/Network/Network.styles.ts delete mode 100644 app/components/Views/confirmations/components/UI/InfoRow/InfoValue/Network/Network.test.tsx delete mode 100644 app/components/Views/confirmations/components/UI/InfoRow/InfoValue/Network/Network.tsx delete mode 100644 app/components/Views/confirmations/components/UI/InfoRow/InfoValue/Network/__snapshots__/Network.test.tsx.snap delete mode 100644 app/components/Views/confirmations/components/UI/InfoRow/InfoValue/Network/index.ts delete mode 100644 app/components/Views/confirmations/hooks/useNetworkInfo.test.ts delete mode 100644 app/components/Views/confirmations/hooks/useNetworkInfo.ts delete mode 100644 app/components/hooks/Ledger/useBluetoothDevices.test.ts delete mode 100644 app/components/hooks/useCheckMultiRpcModal/index.ts delete mode 100644 app/components/hooks/useCheckMultiRpcModal/useCheckMultiRpcModal.test.ts delete mode 100644 app/components/hooks/useCheckMultiRpcModal/useCheckMultiRpcModal.ts delete mode 100644 app/components/hooks/useCheckNftAutoDetectionModal/index.ts delete mode 100644 app/components/hooks/useCheckNftAutoDetectionModal/useCheckNftAutoDetectionModal.test.ts delete mode 100644 app/components/hooks/useCheckNftAutoDetectionModal/useCheckNftAutoDetectionModal.ts rename app/core/{Engine.test.ts => Engine.test.js} (50%) delete mode 100644 app/core/RPCMethods/lib/ethereum-chain-utils.js create mode 100644 app/core/SDKConnect/handlers/handleConnectionReady.test.ts delete mode 100644 app/core/SecureKeychain.test.ts delete mode 100644 app/core/SnapKeyring/utils/getAccountsBySnapId.ts delete mode 100644 app/images/ape-network.png delete mode 100644 app/images/ape-token.png delete mode 100644 app/images/gravity.png create mode 100644 app/store/migrations/057.test.ts delete mode 100644 app/store/migrations/059.test.ts delete mode 100644 app/store/migrations/059.ts create mode 100644 app/util/browser/webViewFocus.test.ts create mode 100644 app/util/browser/webViewFocus.ts delete mode 100644 app/util/navigation/useConnectionHandler.tsx create mode 100644 app/util/notifications/hooks/index.test.ts delete mode 100644 app/util/notifications/hooks/index.test.tsx delete mode 100644 app/util/notifications/hooks/useAccountSyncing.test.tsx delete mode 100644 app/util/notifications/hooks/useAccountSyncing.ts delete mode 100644 app/util/notifications/hooks/usePushNotifications.ts create mode 100644 app/util/notifications/methods/fcmHelper.test.ts create mode 100644 app/util/notifications/methods/fcmHelper.ts delete mode 100644 app/util/notifications/notification-states/index.test.tsx delete mode 100644 app/util/notifications/notification-states/node-guard.test.ts delete mode 100644 app/util/notifications/services/FCMService.test.ts delete mode 100644 app/util/notifications/services/FCMService.ts delete mode 100644 e2e/api-mocking/mock-config/mock-events.js delete mode 100644 e2e/api-mocking/mock-config/mockUrlCollection.json delete mode 100644 e2e/api-mocking/mock-responses/gas-api-responses.json delete mode 100644 e2e/api-mocking/mock-server.js create mode 100644 e2e/mockServer/mockServer.js create mode 100644 e2e/mockServer/mockUrlCollection.json rename e2e/pages/{Transactions => }/ActivitiesView.js (73%) delete mode 100644 e2e/pages/Browser/SigningBottomSheet.js create mode 100644 e2e/pages/EnableAutomaticSecurityChecksView.js delete mode 100644 e2e/pages/Network/NetworkApprovalBottomSheet.js delete mode 100644 e2e/pages/Ramps/SellGetStartedView.js delete mode 100644 e2e/pages/Receive/PaymentRequestQrBottomSheet.js delete mode 100644 e2e/pages/Receive/SendLinkView.js rename e2e/pages/{Receive => }/RequestPaymentView.js (86%) create mode 100644 e2e/pages/SendLinkView.js delete mode 100644 e2e/pages/Settings/Advanced/FiatOnTestnetsBottomSheet.js delete mode 100644 e2e/pages/Settings/Contacts/DeleteContactBottomSheet.js delete mode 100644 e2e/pages/Transactions/AssetWatchBottomSheet.js create mode 100644 e2e/pages/modals/AssetWatchModal.js rename e2e/pages/{Settings/SecurityAndPrivacy => modals}/AutoLockModal.js (57%) rename e2e/pages/{Browser/ConnectBottomSheet.js => modals/ConnectModal.js} (68%) rename e2e/pages/{Browser => modals}/ConnectedAccountsModal.js (95%) rename e2e/pages/{Browser/ContractApprovalBottomSheet.js => modals/ContractApprovalModal.js} (60%) create mode 100644 e2e/pages/modals/DeleteContactModal.js rename e2e/pages/{Settings/SecurityAndPrivacy => modals}/DeleteWalletModal.js (83%) rename e2e/pages/{Transactions/TransactionDetailsModal.js => modals/DetailsModal.js} (87%) delete mode 100644 e2e/pages/modals/EnableAutomaticSecurityChecksView.js create mode 100644 e2e/pages/modals/FiatOnTestnetsModal.js rename e2e/pages/{Network/NetworkAddedBottomSheet.js => modals/NetworkAddedModal.js} (55%) create mode 100644 e2e/pages/modals/NetworkApprovalModal.js rename e2e/pages/{Network => modals}/NetworkEducationModal.js (86%) rename e2e/pages/{Network => modals}/NetworkListModal.js (95%) rename e2e/pages/{Receive => modals}/RequestPaymentModal.js (84%) create mode 100644 e2e/pages/modals/SigningModal.js rename e2e/pages/{Browser => modals}/SpamFilterModal.js (82%) rename e2e/pages/{Settings/SecurityAndPrivacy => modals}/SrpQuizModal.js (96%) rename e2e/pages/{Transactions => modals}/TransactionProtectionModal.js (90%) rename e2e/selectors/{Transactions => }/ActivitiesView.selectors.js (90%) rename e2e/selectors/{Transactions => Modals}/AssetWatcher.selectors.js (100%) rename e2e/selectors/{Settings/SecurityAndPrivacy => Modals}/AutoLockModal.selectors.js (64%) rename e2e/selectors/{Browser/ConnectAccountBottomSheet.selectors.js => Modals/ConnectAccountModal.selectors.js} (74%) rename e2e/selectors/{Browser => Modals}/ConnectedAccountModal.selectors.js (91%) rename e2e/selectors/{Browser/ContractApprovalBottomSheet.selectors.js => Modals/ContractApprovalModal.selectors.js} (79%) rename e2e/selectors/{Settings/Contacts/DeleteContactBottomSheet.selectors.js => Modals/DeleteContactModal.selectors.js} (56%) rename e2e/selectors/{Settings/SecurityAndPrivacy => Modals}/DeleteWalletModal.selectors.js (89%) delete mode 100644 e2e/selectors/Modals/EnableAutomaticSecurityChecks.selectors.js rename e2e/selectors/{Settings/Advanced/FiatOnTestnetsBottomSheet.selectors.js => Modals/FiatOnTestnetsModal.selectors.js} (57%) rename e2e/selectors/{Network/NetworkAddedBottomSheet.selectors.js => Modals/NetworkAddedModal.selectors.js} (67%) rename e2e/selectors/{Network/NetworkApprovalBottomSheet.selectors.js => Modals/NetworkApprovalModal.selectors.js} (85%) rename e2e/selectors/{Network => Modals}/NetworkEducationModal.selectors.js (100%) rename e2e/selectors/{Network => Modals}/NetworkListModal.selectors.js (100%) create mode 100644 e2e/selectors/Modals/RequestPaymentModal.selectors.js rename e2e/selectors/{Browser/SigningBottomSheet.selectors.js => Modals/SigningModal.selectors.js} (80%) rename e2e/selectors/{Browser => Modals}/SpamFilterModal.selectors.js (100%) rename e2e/selectors/{Settings/SecurityAndPrivacy => Modals}/SrpQuizModal.selectors.js (97%) rename e2e/selectors/{Transactions => Modals}/TransactionDetailsModal.selectors.js (87%) rename e2e/selectors/{Transactions => Modals}/TransactionProtectionModal.selectors.js (100%) delete mode 100644 e2e/selectors/Receive/RequestPaymentModal.selectors.js rename e2e/selectors/{Receive => }/RequestPaymentView.selectors.js (84%) rename e2e/selectors/{Receive => }/SendLinkView.selectors.js (100%) create mode 100644 e2e/selectors/Settings/SecurityAndPrivacy/ClearCookiesSection.selectors.js delete mode 100644 e2e/selectors/TokenOverview.selectors.js delete mode 100644 e2e/selectors/TransactionReview.selectors.js rename e2e/specs/confirmations/{advanced-gas-fees.mock.spec.js => advanced-gas-fees.spec.js} (82%) delete mode 100644 e2e/specs/confirmations/suggestedGasApi.mock.spec.js delete mode 100644 e2e/specs/notifications/account-syncing/mockData.js delete mode 100644 e2e/specs/notifications/account-syncing/sync-after-adding-custom-name-account.spec.js delete mode 100644 e2e/specs/notifications/account-syncing/sync-after-onboarding.spec.js delete mode 100644 e2e/specs/notifications/utils/constants.js delete mode 100644 e2e/specs/notifications/utils/helpers.js delete mode 100644 e2e/specs/notifications/utils/mocks.js delete mode 100644 e2e/specs/notifications/utils/user-storage/userStorageMockttpController.js delete mode 100644 e2e/specs/notifications/utils/user-storage/userStorageMockttpController.test.js rename e2e/specs/{wallet/portfolio-connect-account.spec.js => quarantine/portfolio-connect-account.failing.js} (91%) rename e2e/specs/{onboarding/term-of-use.spec.js => quarantine/term-of-use.broken.js} (92%) delete mode 100644 e2e/specs/ramps/offramp.spec.js create mode 100644 e2e/specs/wallet/suggestedGasApi.mock.spec.js delete mode 100644 ios/GoogleServices/GoogleService-Info-example.plist delete mode 100644 ios/GoogleServices/GoogleService-Info.plist create mode 100644 patches/@metamask+approval-controller+7.0.2.patch create mode 100644 patches/@metamask+assets-controllers++@metamask+preferences-controller+13.0.3.patch delete mode 100644 patches/@metamask+assets-controllers++multiformats+13.3.0.patch create mode 100644 patches/@metamask+assets-controllers+32.0.0.patch delete mode 100644 patches/@metamask+assets-controllers+39.0.0.patch delete mode 100644 patches/@metamask+ethjs-contract+0.4.1.patch delete mode 100644 patches/@metamask+ethjs-query+0.7.1.patch rename patches/{@metamask+post-message-stream+8.1.1.patch => @metamask+post-message-stream+8.1.0.patch} (95%) create mode 100644 patches/@metamask+preferences-controller+11.0.0.patch delete mode 100644 patches/@metamask+preferences-controller+13.1.0.patch rename patches/{detox+20.27.5.patch => detox+20.23.1.patch} (100%) create mode 100644 patches/ethjs-contract+0.2.3.patch create mode 100644 patches/ethjs-query+0.3.8.patch create mode 100755 scripts/bump-version.sh delete mode 100755 scripts/create-release-draft.sh delete mode 100755 scripts/set-build-version.sh delete mode 100755 scripts/set-semvar-version.sh create mode 100644 wdio/screen-objects/testIDs/BrowserScreen/BrowserScreen.testIds.js create mode 100644 wdio/screen-objects/testIDs/BrowserScreen/MultiTab.testIds.js create mode 100644 wdio/screen-objects/testIDs/Components/AccountApprovalModal.testIds.js create mode 100644 wdio/screen-objects/testIDs/Components/AccountListComponent.testIds.js create mode 100644 wdio/screen-objects/testIDs/Components/ConnectedAccountsModal.testIds.js create mode 100644 wdio/screen-objects/testIDs/Screens/EnableAutomaticSecurityChecksScreen.testIds.js create mode 100644 wdio/screen-objects/testIDs/Screens/RequestToken.testIds.js create mode 100644 wdio/screen-objects/testIDs/Screens/TokenOverviewScreen.testIds.js diff --git a/.android.env.example b/.android.env.example index 5c769312cca5..93b4a8c334e2 100644 --- a/.android.env.example +++ b/.android.env.example @@ -9,7 +9,7 @@ export FCM_CONFIG_PROJECT_ID= export FCM_CONFIG_STORAGE_BUCKET= export FCM_CONFIG_MESSAGING_SENDER_ID= export FCM_CONFIG_APP_ID= -export GOOGLE_SERVICES_B64_ANDROID= +export GOOGLE_SERVICES_B64= #Notifications Feature Announcements export FEATURES_ANNOUNCEMENTS_ACCESS_TOKEN= export FEATURES_ANNOUNCEMENTS_SPACE_ID= diff --git a/.depcheckrc.yml b/.depcheckrc.yml index 36e2bc04bb1b..c90705901b45 100644 --- a/.depcheckrc.yml +++ b/.depcheckrc.yml @@ -49,17 +49,22 @@ ignores: - 'rn-nodeify' ## Unused devDependencies to investigate + - '@ethersproject/abi' - '@metamask/swappable-obj-proxy' + - '@react-native-picker/picker' + - '@rnhooks/keyboard' - '@segment/sovran-react-native' - '@tradle/react-native-http' - 'asyncstorage-down' - 'buffer' - 'd3-shape' + - 'dnode' - 'eciesjs' - 'eth-block-tracker' - 'eth-json-rpc-infura' - 'events' - 'https-browserify' + - 'obs-store' - 'path' - 'pbkdf2' - 'pify' @@ -68,9 +73,11 @@ ignores: - 'react-native-aes-crypto' - 'react-native-aes-crypto-forked' - 'react-native-crypto' + - 'react-native-flash-message' - 'react-native-level-fs' - 'react-native-os' - 'react-native-randombytes' + - 'react-native-redash' - 'react-native-swipe-gestures' - 'react-native-tcp' - 'socket.io-client' diff --git a/.detoxrc.js b/.detoxrc.js index 46f0b4441e10..b1a80212b463 100644 --- a/.detoxrc.js +++ b/.detoxrc.js @@ -1,7 +1,7 @@ /** @type {Detox.DetoxConfig} */ module.exports = { artifacts: { - rootDir: "./artifacts", + rootDir: "./artifacts/screenshots", plugins: { screenshot: { shouldTakeAutomaticSnapshots: true, @@ -9,15 +9,10 @@ module.exports = { takeWhen: { testStart: false, testDone: false, - }, - }, - video: { - enabled: true, // Enable video recording - keepOnlyFailedTestsArtifacts: true, // Keep only failed tests' videos + } }, }, }, - testRunner: { args: { $0: 'jest', diff --git a/.eslintrc.js b/.eslintrc.js index edbe2143bb07..fc724dd4a95d 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -51,12 +51,6 @@ module.exports = { rules: { // under discussion 'no-unused-vars': 'off', - 'react/no-unstable-nested-components': [ - 'warn', - { - allowAsProps: true, - }, - ], }, }, { diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 4931485e00b5..a483a7157ca7 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -10,9 +10,6 @@ app/component-library/ @MetaMask/design-system-engineers patches/ @MetaMask/mobile-platform app/core/Engine.ts @MetaMask/mobile-platform app/core/Engine.test.js @MetaMask/mobile-platform -app/core/Analytics/ @MetaMask/mobile-platform -app/util/metrics/ @MetaMask/mobile-platform -app/components/hooks/useMetrics/ @MetaMask/mobile-platform # Supply Chain Team bitrise.yml @MetaMask/supply-chain @MetaMask/mobile-platform diff --git a/.github/workflows/add-team-label.yml b/.github/workflows/add-team-label.yml index b5d9eaa18603..2046456ef426 100644 --- a/.github/workflows/add-team-label.yml +++ b/.github/workflows/add-team-label.yml @@ -7,6 +7,8 @@ on: jobs: add-team-label: - uses: metamask/github-tools/.github/workflows/add-team-label.yml@18af6e4b56a18230d1792480e249ebc50b324927 + uses: metamask/github-tools/.github/workflows/add-team-label.yml@058012b49ff2fbd9649c566ba43b29497f93b21d + permissions: + pull-requests: write secrets: - TEAM_LABEL_TOKEN: ${{ secrets.TEAM_LABEL_TOKEN }} + PERSONAL_ACCESS_TOKEN: ${{ secrets.RELEASE_LABEL_TOKEN }} diff --git a/.github/workflows/bump-version-name.yml b/.github/workflows/bump-version-name.yml new file mode 100644 index 000000000000..9b12c7e2793b --- /dev/null +++ b/.github/workflows/bump-version-name.yml @@ -0,0 +1,30 @@ +name: Bump version name +on: + pull_request: + branches: + - develop + - main + types: [opened] + merge_group: + types: [checks_requested] + +jobs: + bump-version-name: + runs-on: ubuntu-latest + if: "contains(github.head_ref, 'release/')" + permissions: + contents: write + steps: + - uses: actions/checkout@v3 + - name: Bump script + env: + HEAD_REF: ${{ github.head_ref }} + run: | + ./scripts/bump-version.sh "$HEAD_REF" + git diff + git config user.name metamaskbot + git config user.email metamaskbot@users.noreply.github.com + git add bitrise.yml + git add package.json + git commit -m "Bump version name" + git push origin HEAD:"$HEAD_REF" --force diff --git a/.github/workflows/create-release-draft.yml b/.github/workflows/create-release-draft.yml deleted file mode 100644 index 9069da82b4e2..000000000000 --- a/.github/workflows/create-release-draft.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: create-release-draft - -on: - push: - tags: - - 'v*' - -permissions: - contents: write - pull-requests: read - -jobs: - draft_release: - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v3 - with: - ref: ${{ github.ref }} # Explicitly specifies the tag ref - - - - name: Setup GitHub CLI - run: | - sudo apt update - sudo apt install gh - echo "${{ secrets.GITHUB_TOKEN }}" | gh auth login --with-token - - - name: Create Draft Release - run: ./scripts/create-release-draft.sh ${{ github.ref_name }} ${{ github.workspace }} \ No newline at end of file diff --git a/.github/workflows/create-release-pr.yml b/.github/workflows/create-release-pr.yml index ce37698ff0f2..58c8c4152d26 100644 --- a/.github/workflows/create-release-pr.yml +++ b/.github/workflows/create-release-pr.yml @@ -9,18 +9,15 @@ on: semver-version: description: 'A semantic version. eg: x.x.x' required: true + version-number: + description: 'A natural version number. eg: 862' + required: true previous-version-tag: description: 'Previous release version tag. eg: v7.7.0' required: true jobs: - generate-build-version: - uses: MetaMask/metamask-mobile-build-version/.github/workflows/metamask-mobile-build-version.yml@v0.2.0 - permissions: - id-token: write - create-release-pr: runs-on: ubuntu-latest - needs: generate-build-version permissions: contents: write pull-requests: write @@ -39,7 +36,6 @@ jobs: # The workaround is to use a personal access token (BUG_REPORT_TOKEN) instead of # the default GITHUB_TOKEN for the checkout action. token: ${{ secrets.BUG_REPORT_TOKEN }} - - name: Set up Node.js uses: actions/setup-node@v3 with: @@ -47,11 +43,14 @@ jobs: cache: yarn - name: Install dependencies run: yarn --immutable - - name: Create Release & Changelog PR - id: create-release-changelog-pr + - name: Set Versions + id: set-versions + shell: bash + run: SEMVER_VERSION=${{ github.event.inputs.semver-version }} VERSION_NUMBER=${{ github.event.inputs.version-number }} yarn set-version + - name: Create Release PR + id: create-release-pr shell: bash env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - BASE_BRANCH: ${{ github.event.inputs.base-branch }} run: | - ./scripts/create-release-pr.sh ${{ github.event.inputs.previous-version-tag }} ${{ github.event.inputs.semver-version }} ${{ needs.generate-build-version.outputs.build-version }} \ No newline at end of file + ./scripts/create-release-pr.sh ${{ github.event.inputs.previous-version-tag }} ${{ github.event.inputs.semver-version }} \ No newline at end of file diff --git a/.github/workflows/update-latest-build-version.yml b/.github/workflows/update-latest-build-version.yml deleted file mode 100644 index 4d43acd8881d..000000000000 --- a/.github/workflows/update-latest-build-version.yml +++ /dev/null @@ -1,51 +0,0 @@ -############################################################################################## -# -# This Workflow is responsible for updating the latest build version of the project. -# You can provide your own base branch, tag, or SHA for git operations and the pull request. -# and it will generate the latest build version & update the neccessary files for you. -# -############################################################################################## -name: Update Latest Build Version - - -on: - workflow_dispatch: - inputs: - base-branch: - description: 'The base branch, tag, or SHA for git operations and the pull request.' - required: true -jobs: - generate-build-version: - uses: MetaMask/metamask-mobile-build-version/.github/workflows/metamask-mobile-build-version.yml@v0.2.0 - permissions: - id-token: write - - bump-version: - runs-on: ubuntu-latest - needs: generate-build-version - permissions: - contents: write - id-token: write - steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - ref: ${{ inputs.base-branch }} - token: ${{ secrets.PR_TOKEN }} - - - name: Bump script - env: - HEAD_REF: ${{ inputs.base-branch }} - run: | - ./scripts/set-build-version.sh ${{ needs.generate-build-version.outputs.build-version }} - git diff - git config user.name metamaskbot - git config user.email metamaskbot@users.noreply.github.com - git add bitrise.yml - git add package.json - git add ios/MetaMask.xcodeproj/project.pbxproj - git add android/app/build.gradle - git commit -m "Bump version number to ${{ needs.generate-build-version.outputs.build-version }}" - git push origin HEAD:"$HEAD_REF" --force - - \ No newline at end of file diff --git a/.gitignore b/.gitignore index f25f95d5af67..18fa57f9d473 100644 --- a/.gitignore +++ b/.gitignore @@ -40,7 +40,6 @@ android/app/_build* # if we ever want to add google services android/app/google-services.json -ios/GoogleService-Info.plist # node.js node_modules/ @@ -125,9 +124,3 @@ app/util/termsOfUse/termsOfUseContent.ts docs/assets/termsOfUse.html /app/images/branding - -# build metadata -android/app/src/main/assets/modules.json - -# Google firebase base64 derived configs -**/GoogleService-Info.plist \ No newline at end of file diff --git a/.ios.env.example b/.ios.env.example index cc449b8b6e10..05aadc9b3597 100644 --- a/.ios.env.example +++ b/.ios.env.example @@ -8,7 +8,7 @@ FCM_CONFIG_PROJECT_ID= FCM_CONFIG_STORAGE_BUCKET= FCM_CONFIG_MESSAGING_SENDER_ID= FCM_CONFIG_APP_ID= -GOOGLE_SERVICES_B64_IOS= +GOOGLE_SERVICES_B64= #Notifications Feature Announcements FEATURES_ANNOUNCEMENTS_ACCESS_TOKEN= FEATURES_ANNOUNCEMENTS_SPACE_ID= diff --git a/.iyarc b/.iyarc index e69de29bb2d1..abbf0e189d26 100644 --- a/.iyarc +++ b/.iyarc @@ -0,0 +1,3 @@ +# ReDoS vulnerability, no impact to this application, and fix not backported yet to the versions we use + +GHSA-c2qf-rxjj-qqgw diff --git a/.js.env.example b/.js.env.example index 6c0d0e327b04..68e8316f034e 100644 --- a/.js.env.example +++ b/.js.env.example @@ -68,10 +68,10 @@ export SEGMENT_FLUSH_INTERVAL="1" export SEGMENT_FLUSH_EVENT_LIMIT="1" # URL of security alerts API used to validate dApp requests. -export SECURITY_ALERTS_API_URL="https://security-alerts.api.cx.metamask.io" +export SECURITY_ALERTS_API_URL="http://localhost:3000" # Temporary mechanism to enable security alerts API prior to release. -export MM_SECURITY_ALERTS_API_ENABLED="true" +export SECURITY_ALERTS_API_ENABLED="true" # Firebase export FCM_CONFIG_API_KEY="" export FCM_CONFIG_AUTH_DOMAIN="" @@ -79,8 +79,7 @@ export FCM_CONFIG_PROJECT_ID="" export FCM_CONFIG_STORAGE_BUCKET="" export FCM_CONFIG_MESSAGING_SENDER_ID="" export FCM_CONFIG_APP_ID="" -export GOOGLE_SERVICES_B64_ANDROID="" -export GOOGLE_SERVICES_B64_IOS="" +export GOOGLE_SERVICES_B64="" #Notifications Feature Announcements export FEATURES_ANNOUNCEMENTS_ACCESS_TOKEN= export FEATURES_ANNOUNCEMENTS_SPACE_ID= @@ -91,10 +90,7 @@ export MM_ENABLE_SETTINGS_PAGE_DEV_OPTIONS="true" # The endpoint used to submit errors and tracing data to Sentry for dev environment. # export MM_SENTRY_DSN_DEV= -# Per dapp selected network (Amon Hen) feature flag -export MM_PER_DAPP_SELECTED_NETWORK="" - -export MM_CHAIN_PERMISSIONS="" - +# Multichain Feature flag +export MULTICHAIN_V1="" #Multichain feature flag specific to UI changes export MM_MULTICHAIN_V1_ENABLED="" diff --git a/.storybook/storybook.requires.js b/.storybook/storybook.requires.js index c08c085d9a97..a1ca7774ac88 100644 --- a/.storybook/storybook.requires.js +++ b/.storybook/storybook.requires.js @@ -126,7 +126,7 @@ const getStories = () => { "./app/components/Views/confirmations/components/UI/InfoRow/InfoRow.stories.tsx": require("../app/components/Views/confirmations/components/UI/InfoRow/InfoRow.stories.tsx"), "./app/components/Views/confirmations/components/UI/ExpandableSection/ExpandableSection.stories.tsx": require("../app/components/Views/confirmations/components/UI/ExpandableSection/ExpandableSection.stories.tsx"), "./app/components/Views/confirmations/components/UI/Tooltip/Tooltip.stories.tsx": require("../app/components/Views/confirmations/components/UI/Tooltip/Tooltip.stories.tsx"), - "./app/component-library/components/Texts/SensitiveText/SensitiveText.stories.tsx": require("../app/component-library/components/Texts/SensitiveText/SensitiveText.stories.tsx"), + "./app/components/Views/confirmations/components/UI/CopyButton/CopyButton.stories.tsx": require("../app/components/Views/confirmations/components/UI/CopyButton/CopyButton.stories.tsx"), }; }; diff --git a/.vscode/settings.json b/.vscode/settings.json index c74344a36370..5eb140d7b1fd 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,7 +6,5 @@ "cucumberautocomplete.steps": ["wdio/step-definitions/**/*.js"], "cucumberautocomplete.syncfeatures": "wdio/to/features/*.feature", "cucumberautocomplete.strictGherkinCompletion": true, - "typescript.tsdk": "node_modules/typescript/lib", - "javascript.preferences.importModuleSpecifier": "relative", - "typescript.preferences.importModuleSpecifier": "relative" + "typescript.tsdk": "node_modules/typescript/lib" } diff --git a/CHANGELOG.md b/CHANGELOG.md index b04b084a18aa..642666e84043 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,24 +2,112 @@ ## Current Main Branch -## 7.33.2 - Nov 1, 2024 +## 7.34.1 - Nov 6, 2024 ### Fixed -- [#10952](https://github.com/MetaMask/metamask-mobile/pull/10952): refactor(ramp): update ramp copy (#10952) +- [#12205](https://github.com/MetaMask/metamask-mobile/pull/12205): fix: add contractBalances as dependency -## 7.33.2 - Oct 29, 2024 -### Fixed -- [#12073](https://github.com/MetaMask/metamask-mobile/pull/12073): feat: Simulation re-trigger (#12073) +## 7.34.0 - Oct 28, 2024 +### Added +- [#11578](https://github.com/MetaMask/metamask-mobile/pull/11578): feat: 1653 first feature flag poc (#11578) +- [#11705](https://github.com/MetaMask/metamask-mobile/pull/11705): feat: Transition from Multiple Networks with Same ChainID to Unique Networks with Distinct ChainIDs and Multiple RPC URLs (#11705) +- [#11685](https://github.com/MetaMask/metamask-mobile/pull/11685): feat: multi rpc modal (#11685) +- [#11651](https://github.com/MetaMask/metamask-mobile/pull/11651): feat: add utm field to app_open event (#11651) +- [#11579](https://github.com/MetaMask/metamask-mobile/pull/11579): feat: 1940 Add custom traces (#11579) +- [#11815](https://github.com/MetaMask/metamask-mobile/pull/11815): feat: Address value component for use in re-designed confirmation pages (#11815) +- [#11737](https://github.com/MetaMask/metamask-mobile/pull/11737): feat: Adding simulation section to personal sign page (#11737) +- [#11736](https://github.com/MetaMask/metamask-mobile/pull/11736): feat: add copy button component (#11736) +- [#11703](https://github.com/MetaMask/metamask-mobile/pull/11703): feat: Adding expandable message section to personal sign page (#11703) +- [#11698](https://github.com/MetaMask/metamask-mobile/pull/11698): feat: add account_network section to re-designed confirmation page (#11698) +- [#11453](https://github.com/MetaMask/metamask-mobile/pull/11453): feat: Add signature tracing (#11453) +- [#11456](https://github.com/MetaMask/metamask-mobile/pull/11456): feat: Add metric for insufficient funds for gas (#11456) +- [#11602](https://github.com/MetaMask/metamask-mobile/pull/11602): feat: adding a basic personal sign page re-designed (#11602) +- [#11572](https://github.com/MetaMask/metamask-mobile/pull/11572): feat: add tooltip component for re-designed confirmation pages (#11572) +- [#11567](https://github.com/MetaMask/metamask-mobile/pull/11567): feat: add url value component for use in re-designed confirmation pages (#11567) +- [#11528](https://github.com/MetaMask/metamask-mobile/pull/11528): feat: expandable section for use in confirmation pages (#11528) +- [#11605](https://github.com/MetaMask/metamask-mobile/pull/11605): feat: STAKE-824: [FE] build staking input confirmation screen (#11605) +- [#11607](https://github.com/MetaMask/metamask-mobile/pull/11607): feat: add unstake screen for mobile staking (#11607) +- [#11660](https://github.com/MetaMask/metamask-mobile/pull/11660): feat: added ReactNode support for KeyValueRow tooltip and label (#11660) +- [#11733](https://github.com/MetaMask/metamask-mobile/pull/11733): feat: add references and utils for delete storage key (#11733) +- [#11653](https://github.com/MetaMask/metamask-mobile/pull/11653): feat: Implement partially local Snaps execution environment (#11653) +- [#11127](https://github.com/MetaMask/metamask-mobile/pull/11127): feat(1702): enhanced onboarding settings config (#11127) + +### Changed +- [#11852](https://github.com/MetaMask/metamask-mobile/pull/11852): chore: readd date time picker (#11852) +- [#11831](https://github.com/MetaMask/metamask-mobile/pull/11831): chore: Add conditional for api specification test (#11831) +- [#11838](https://github.com/MetaMask/metamask-mobile/pull/11838): chore: revert tags commit (#11838) +- [#11839](https://github.com/MetaMask/metamask-mobile/pull/11839): chore: Revert custom span (#11839) +- [#11824](https://github.com/MetaMask/metamask-mobile/pull/11824): chore: enable Sentry performance reports on QA builds (#11824) +- [#11825](https://github.com/MetaMask/metamask-mobile/pull/11825): chore: fix create qa build pipeline (#11825) +- [#11805](https://github.com/MetaMask/metamask-mobile/pull/11805): chore: Update Sentry Performance Sampling utils.js (#11805) +- [#11710](https://github.com/MetaMask/metamask-mobile/pull/11710): ci: Enable Detox E2E in Release mode (#11710) +- [#11757](https://github.com/MetaMask/metamask-mobile/pull/11757): docs: update e2e best practices link in readme (#11757) +- [#11746](https://github.com/MetaMask/metamask-mobile/pull/11746): "chore: Revert ""chore(js-ts): Convert app/util/test/ganache-contract-address-registry.js to TypeScript"" (#11746)" +- [#11694](https://github.com/MetaMask/metamask-mobile/pull/11694): test: Refactor ImportAccountView.js and LoginView.js files (#11694) +- [#11136](https://github.com/MetaMask/metamask-mobile/pull/11136): chore(build): let adb server live between builds (#11136) +- [#11669](https://github.com/MetaMask/metamask-mobile/pull/11669): chore: Merge 7.32.0 back into main (#11669) +- [#11667](https://github.com/MetaMask/metamask-mobile/pull/11667): chore: add 9f9a11 to git blame ignore (#11667) +- [#11262](https://github.com/MetaMask/metamask-mobile/pull/11262): chore: Refactor event tracking method (#11262) +- [#11520](https://github.com/MetaMask/metamask-mobile/pull/11520): chore: Reorganize `PortfolioBalance` (#11520) +- [#11761](https://github.com/MetaMask/metamask-mobile/pull/11761): chore: Add support for custom network images (#11761) +- [#11687](https://github.com/MetaMask/metamask-mobile/pull/11687): chore: upgrade assets controllers v32.0.0 (#11687) +- [#11471](https://github.com/MetaMask/metamask-mobile/pull/11471): chore: Componetize `Tokens` screen (#11471) +- [#11751](https://github.com/MetaMask/metamask-mobile/pull/11751): chore(devDeps): remove unused react-native-cli (#11751) +- [#11623](https://github.com/MetaMask/metamask-mobile/pull/11623): chore: Add tags to custom traces (#11623) +- [#11788](https://github.com/MetaMask/metamask-mobile/pull/11788): chore(ramp): upgrade sdk to 1.28.5 (#11788) +- [#11421](https://github.com/MetaMask/metamask-mobile/pull/11421): refactor(ramp): use list item from the components library (#11421) +- [#11086](https://github.com/MetaMask/metamask-mobile/pull/11086): test: initial ramps E2E test to build quote (#11086) +- [#11745](https://github.com/MetaMask/metamask-mobile/pull/11745): ci: fix get-next-semver-version invocation in add-release-label (#11745) +- [#11756](https://github.com/MetaMask/metamask-mobile/pull/11756): chore: Remove obsolete CI step (#11756) +- [#11656](https://github.com/MetaMask/metamask-mobile/pull/11656): chore: rename `isprivateConnection` to `isPrivateConnection ` (#11656) +- [#11546](https://github.com/MetaMask/metamask-mobile/pull/11546): chore(js-ts): Convert app/components/Views/AndroidBackHandler/index.js to TypeScript (#11546) +- [#11629](https://github.com/MetaMask/metamask-mobile/pull/11629): chore(js-ts): Convert app/util/transaction-reducer-helpers.js to TypeScript (#11629) +- [#11661](https://github.com/MetaMask/metamask-mobile/pull/11661): chore(js-ts): Convert app/components/Base/HorizontalSelector/index.js to TypeScript (#11661) +- [#11650](https://github.com/MetaMask/metamask-mobile/pull/11650): chore(js-ts): Convert app/components/UI/Swaps/components/InfoModal.js to TypeScript (#11650) +- [#11406](https://github.com/MetaMask/metamask-mobile/pull/11406): chore(js-ts): Convert app/util/test/ganache-contract-address-registry.js to TypeScript (#11406) +- [#11556](https://github.com/MetaMask/metamask-mobile/pull/11556): chore(js-ts): Convert app/components/UI/Fox/index.js to TypeScript (#11556) +- [#11525](https://github.com/MetaMask/metamask-mobile/pull/11525): chore(js-ts): Convert app/components/UI/StyledButton/styledButtonStyles.js to TypeScript (#11525) +- [#11385](https://github.com/MetaMask/metamask-mobile/pull/11385): refactor(1702-5): incoming transactions and network details settings into reusable components (#11385) +- [#11381](https://github.com/MetaMask/metamask-mobile/pull/11381): refactor(1702-4): ipfs gateway settings and display nft media settings components (#11381) +- [#11614](https://github.com/MetaMask/metamask-mobile/pull/11614): chore: Update UX CodeOwners responsibilities (#11614) +- [#11709](https://github.com/MetaMask/metamask-mobile/pull/11709): chore: updating codeowners to remove mobile-devs from component library (#11709) +- [#11617](https://github.com/MetaMask/metamask-mobile/pull/11617): chore: chore/7.33.0-Changelog (#11617) -## 7.33.0 - Oct 3, 2024 +### Fixed +- [#11787](https://github.com/MetaMask/metamask-mobile/pull/11787): fix: non deterministic date in test (#11787) +- [#11762](https://github.com/MetaMask/metamask-mobile/pull/11762): fix: snapshot of test to enable ci (#11762) +- [#11632](https://github.com/MetaMask/metamask-mobile/pull/11632): fix: add custom and add popular network detox test (#11632) +- [#11794](https://github.com/MetaMask/metamask-mobile/pull/11794): fix(action): github action to apply release label is broken (#11794) +- [#11760](https://github.com/MetaMask/metamask-mobile/pull/11760): fix: Android: Splash screen always showing behind other screens (#11760) +- [#11741](https://github.com/MetaMask/metamask-mobile/pull/11741): fix: rollback originWhitelist (#11741) +- [#11722](https://github.com/MetaMask/metamask-mobile/pull/11722): fix: add safe space on the left of bell icon (#11722) +- [#11139](https://github.com/MetaMask/metamask-mobile/pull/11139): fix: Reuse mmkv instance once created (#11139) +- [#11532](https://github.com/MetaMask/metamask-mobile/pull/11532): fix: fix approve flow on swap (#11532) +- [#11718](https://github.com/MetaMask/metamask-mobile/pull/11718): fix: token list after switching networks (#11718) +- [#11495](https://github.com/MetaMask/metamask-mobile/pull/11495): fix: fix asset symbol for incoming tx (#11495) +- [#11664](https://github.com/MetaMask/metamask-mobile/pull/11664): fix: Duplicate key in Settings and Privacy (#11664) +- [#11412](https://github.com/MetaMask/metamask-mobile/pull/11412): fix: upgrade assets-controllers to v31 (#11412) +- [#11631](https://github.com/MetaMask/metamask-mobile/pull/11631): fix: hotfix/issue-11539 (#11631) +- [#11834](https://github.com/MetaMask/metamask-mobile/pull/11834): fix: invalid wallet connect detection (wrong hostname in connect modal) (#11834) +- [#11701](https://github.com/MetaMask/metamask-mobile/pull/11701): fix: connect request completed source validation (#11701) +- [#11603](https://github.com/MetaMask/metamask-mobile/pull/11603): fix: await for detect origin before logging analytics (#11603) +- [#11595](https://github.com/MetaMask/metamask-mobile/pull/11595): fix: fix signature requested analytics (#11595) +- [#11592](https://github.com/MetaMask/metamask-mobile/pull/11592): fix: fix walletconnect source validation (#11592) +- [#11802](https://github.com/MetaMask/metamask-mobile/pull/11802): fix: persist token and phishing list (#11802) +- [#11729](https://github.com/MetaMask/metamask-mobile/pull/11729): fix: support for batch of signature requests (#11729) +- [#11771](https://github.com/MetaMask/metamask-mobile/pull/11771): fix: Add `preferContractSymbol` to Name components (#11771) +- [#11730](https://github.com/MetaMask/metamask-mobile/pull/11730): fix: Use domain for origin pill component (#11730) +- [#11620](https://github.com/MetaMask/metamask-mobile/pull/11620): fix: Fix unwanted `IncompleteAssetDisplayed` events (#11620) +- [#11792](https://github.com/MetaMask/metamask-mobile/pull/11792): fix: use object styling in Title component (#11792) +- [#11633](https://github.com/MetaMask/metamask-mobile/pull/11633): fix(ramp): disable button while confirming off-ramp transaction (#11633) +- [#11431](https://github.com/MetaMask/metamask-mobile/pull/11431): fix: refactor notifications unit tests (#11431) + +## 7.33.0 - Oct 17, 2024 ### Added - [#11507](https://github.com/MetaMask/metamask-mobile/pull/11507): feat: 10550 Re-introduce test for measuring cold app start + JS bundle load time (#11507) -- [#11347](https://github.com/MetaMask/metamask-mobile/pull/11347): "chore: revert ""feat: react native fast crypto for notifications"" (#11347)" - [#11318](https://github.com/MetaMask/metamask-mobile/pull/11318): feat: app event manager and attribution id parameters (#11318) - [#11445](https://github.com/MetaMask/metamask-mobile/pull/11445): feat: add the abilty to hide the disconnect all button as well as showing and hiding the accounts row when necessary (#11445) - [#11386](https://github.com/MetaMask/metamask-mobile/pull/11386): feat(3299): add tracking to network switching and confirmation (#11386) -- [#11379](https://github.com/MetaMask/metamask-mobile/pull/11379): refactor: rename the feature flag since it had a typo (#11379) - [#11239](https://github.com/MetaMask/metamask-mobile/pull/11239): feat(2739): permission summary view gets the ability to disconnect all (#11239) -- [#11382](https://github.com/MetaMask/metamask-mobile/pull/11382): chore(runway): cherry-pick feat: app event manager and attribution id parameters (#11382) - [#11497](https://github.com/MetaMask/metamask-mobile/pull/11497): feat: simple key-> value component for text value type (#11497) - [#11478](https://github.com/MetaMask/metamask-mobile/pull/11478): feat: adding title to confirmation page (#11478) - [#11477](https://github.com/MetaMask/metamask-mobile/pull/11477): feat: adding footer section to confirmation page (#11477) @@ -31,7 +119,7 @@ - [#11399](https://github.com/MetaMask/metamask-mobile/pull/11399): feat: add learn more modal component for staking (#11399) - [#11261](https://github.com/MetaMask/metamask-mobile/pull/11261): feat: STAKE-822 build your balance component (#11261) - [#11294](https://github.com/MetaMask/metamask-mobile/pull/11294): feat: added KeyValueRow to component-library/components-temp (#11294) -- [#11185](https://github.com/MetaMask/metamask-mobile/pull/11185): "feat: display ""Snaps (Beta)"" decorator tag in accounts list (#11185)" +- [#11185](https://github.com/MetaMask/metamask-mobile/pull/11185): feat: display ""Snaps (Beta)"" decorator tag in accounts list (#11185) - [#10829](https://github.com/MetaMask/metamask-mobile/pull/10829): feat: Eth snap keyring (#10829) - [#11455](https://github.com/MetaMask/metamask-mobile/pull/11455): feat: bootstrap a reset notifications feat (#11455) - [#11466](https://github.com/MetaMask/metamask-mobile/pull/11466): feat: add support for external links (#11466) @@ -120,7 +208,6 @@ ## 7.32.0 - Oct 7, 2024 ### Added - - [#10294](https://github.com/MetaMask/metamask-mobile/pull/10294): feat: create redux slice for featureFlags (#10294) - [#11314](https://github.com/MetaMask/metamask-mobile/pull/11314): feat: reject connection properly (#11314) - [#11132](https://github.com/MetaMask/metamask-mobile/pull/11132): feat: Add performance tracing infrastructure (#11132) diff --git a/README.md b/README.md index 815748fcafd0..2c4a6de04453 100644 --- a/README.md +++ b/README.md @@ -41,31 +41,23 @@ cd metamask-mobile **Firebase Messaging Setup** -Before running the app, keep in mind that MetaMask uses FCM (Firebase Cloud Message) to empower communications. Based on this, as an external contributor you would preferably need to provide your own FREE Firebase project config file with a matching client for package name `io.metamask`, and update your `google-services.json` file in the `android/app` or `GoogleService-Info.plist` file in the `ios` directory. +Before running the app, keep in mind that MetaMask uses FCM (Firebase Cloud Message) to empower communications. Based on this, as an external contributor you would preferably need to provide your own FREE Firebase project config file with a matching client for package name `io.metamask`, and update your `google-services.json` file in the `android/app` directory as well your `.env` files (`.ios.env`, `.js.env`, `.android.env`), adding `GOOGLE_SERVICES_B64` variable depending on the environment you are running the app (ios/android). -**External Contributors** -In case you don't have FCM account, you can use `./android/app/google-services-example.json` for Android or `./ios/GoogleServices/GoogleService-Info-example.plist` for iOS and follow the steps below to populate the correct environment variables in the `.env` files (`.ios.env`, `.js.env`, `.android.env`), adding `GOOGLE_SERVICES_B64_ANDROID` or `GOOGLE_SERVICES_B64_IOS` variable depending on the environment you are running the app (ios/android). +The value you should provide to `GOOGLE_SERVICES_B64` is the base64 encoded version of your Firebase project config file, which can be generated as follows: -**Internal Contributors** - -We should access the Firebase project config file from 1Password. - -The value you should provide to `GOOGLE_SERVICES_B64_ANDROID` or `GOOGLE_SERVICES_B64_IOS` is the base64 encoded version of your Firebase project config file, which can be generated as follows: - -**For Android** ```bash -export GOOGLE_SERVICES_B64_ANDROID="$(base64 -w0 -i ./android/app/google-services-example.json)" && echo "export GOOGLE_SERVICES_B64_ANDROID=\"$GOOGLE_SERVICES_B64_ANDROID\"" | tee -a .js.env .ios.env +base64 -i ./android/app/google-services-example.json ``` -**For iOS** -```bash -export GOOGLE_SERVICES_B64_IOS="$(base64 -w0 -i ./ios/GoogleServices/GoogleService-Info-example.plist)" && echo "export GOOGLE_SERVICES_B64_IOS=\"$GOOGLE_SERVICES_B64_IOS\"" | tee -a .js.env .ios.env -``` +Copy the result to your clipboard and paste it in the `GOOGLE_SERVICES_B64` variable in the `.env` file you are running the app. + +> [!CAUTION] +> In case you don't provide your own Firebase project config file, you will face the error `No matching client found for package name 'io.metamask'`. -[!CAUTION] -> In case you don't provide your own Firebase project config file or run the steps above, you will face the error `No matching client found for package name 'io.metamask'`. +You can make usage of a mock file at `android/app/google-services-example.json`, following the same steps above from the root of the project. In case of any doubt, please follow the instructions in the link below to get your Firebase project config file. + [Firebase Project Quickstart](https://firebaseopensource.com/projects/firebase/quickstart-js/messaging/readme/#getting_started) **Install dependencies** diff --git a/android/app/build.gradle b/android/app/build.gradle index 7644a77b8114..15f6a7ef5308 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -173,8 +173,8 @@ android { applicationId "io.metamask" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionName "7.33.2" - versionCode 1474 + versionCode 1480 + versionName "7.34.1" testBuildType System.getProperty('testBuildType', 'debug') missingDimensionStrategy 'react-native-camera', 'general' testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/android/app/google-services-example.json b/android/app/google-services-example.json index 02ea42cea0e9..f7765f0ad2ac 100644 --- a/android/app/google-services-example.json +++ b/android/app/google-services-example.json @@ -7,7 +7,11 @@ }, "client": [ { - "api_key": [{ "current_key": "" }], + "api_key": [ + { + "current_key": "" + } + ], "client_info": { "mobilesdk_app_id": "1:123456789000:android:f1bf012572b04063", "client_id": "android:io.metamask", @@ -17,31 +21,7 @@ "certificate_hash": [] } } - }, - { - "api_key": [{ "current_key": "" }], - "client_info": { - "mobilesdk_app_id": "1:123456789000:android:f1bf012572b04063", - "client_id": "android:io.metamask.qa", - "client_type": 1, - "android_client_info": { - "package_name": "io.metamask.qa", - "certificate_hash": [] - } - } - }, - { - "api_key": [{ "current_key": "" }], - "client_info": { - "mobilesdk_app_id": "1:123456789000:android:f1bf012572b04063", - "client_id": "android:io.metamask.flask", - "client_type": 1, - "android_client_info": { - "package_name": "io.metamask.flask", - "certificate_hash": [] - } - } } ], "configuration_version": "1" -} +} \ No newline at end of file diff --git a/app/actions/notification/helpers/index.test.tsx b/app/actions/notification/helpers/index.test.tsx deleted file mode 100644 index 8fd7a7ea805c..000000000000 --- a/app/actions/notification/helpers/index.test.tsx +++ /dev/null @@ -1,63 +0,0 @@ -// Import necessary libraries and modules -import { signIn, signOut, enableNotificationServices, disableNotificationServices } from '.'; -import Engine from '../../../core/Engine'; - -jest.mock('../../../core/Engine', () => ({ - resetState: jest.fn(), - context: { - AuthenticationController: { - performSignIn: jest.fn(), - performSignOut: jest.fn(), - getSessionProfile: jest.fn(), - }, - NotificationServicesController: { - enableMetamaskNotifications:jest.fn(), - disableNotificationServices:jest.fn(), - checkAccountsPresence: jest.fn(), - } - }, -})); - -describe('Notification Helpers', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - - it('signs in successfully and obtain profile', async () => { - (Engine.context.AuthenticationController.performSignIn as jest.Mock).mockResolvedValue('valid-access-token'); - (Engine.context.AuthenticationController.getSessionProfile as jest.Mock).mockResolvedValue('valid-profile'); - - const result = await signIn(); - - expect(Engine.context.AuthenticationController.performSignIn).toHaveBeenCalled(); - expect(Engine.context.AuthenticationController.getSessionProfile).toHaveBeenCalled(); - expect(result).toBeUndefined(); - }); - - it('signs out successfully', async () => { - (Engine.context.AuthenticationController.performSignOut as jest.Mock).mockResolvedValue(undefined); - - const result = await signOut(); - - expect(Engine.context.AuthenticationController.performSignOut).toHaveBeenCalled(); - expect(result).toBeUndefined(); - }); - - it('enables notification services successfully', async () => { - (Engine.context.NotificationServicesController.enableMetamaskNotifications as jest.Mock).mockResolvedValue(undefined); - - const result = await enableNotificationServices(); - - expect(Engine.context.NotificationServicesController.enableMetamaskNotifications).toHaveBeenCalled(); - expect(result).toBeUndefined(); - }); - - it('disables notification services successfully', async () => { - (Engine.context.NotificationServicesController.disableNotificationServices as jest.Mock).mockResolvedValue(undefined); - - const result = await disableNotificationServices(); - - expect(Engine.context.NotificationServicesController.disableNotificationServices).toHaveBeenCalled(); - expect(result).toBeUndefined(); - }); -}); diff --git a/app/actions/notification/helpers/index.ts b/app/actions/notification/helpers/index.ts index a52e524009ad..9f47da07f88e 100644 --- a/app/actions/notification/helpers/index.ts +++ b/app/actions/notification/helpers/index.ts @@ -2,8 +2,7 @@ import { getErrorMessage } from '@metamask/utils'; import { notificationsErrors } from '../constants'; import Engine from '../../../core/Engine'; -import { Notification, mmStorage, getAllUUIDs } from '../../../util/notifications'; -import { UserStorage } from '@metamask/notification-services-controller/dist/NotificationServicesController/types/user-storage/index.cjs'; +import { Notification } from '../../../util/notifications'; export type MarkAsReadNotificationsParam = Pick< Notification, @@ -84,7 +83,7 @@ export const checkAccountsPresence = async (accounts: string[]) => { export const deleteOnChainTriggersByAccount = async (accounts: string[]) => { try { - const userStorage = + const { userStorage } = await Engine.context.NotificationServicesController.deleteOnChainTriggersByAccount( accounts, ); @@ -93,7 +92,6 @@ export const deleteOnChainTriggersByAccount = async (accounts: string[]) => { notificationsErrors.DELETE_ON_CHAIN_TRIGGERS_BY_ACCOUNT, ); } - mmStorage.saveLocal('pnUserStorage', userStorage); } catch (error) { return getErrorMessage(error); } @@ -101,7 +99,7 @@ export const deleteOnChainTriggersByAccount = async (accounts: string[]) => { export const updateOnChainTriggersByAccount = async (accounts: string[]) => { try { - const userStorage = + const { userStorage } = await Engine.context.NotificationServicesController.updateOnChainTriggersByAccount( accounts, ); @@ -110,7 +108,6 @@ export const updateOnChainTriggersByAccount = async (accounts: string[]) => { notificationsErrors.UPDATE_ON_CHAIN_TRIGGERS_BY_ACCOUNT, ); } - mmStorage.saveLocal('pnUserStorage', userStorage); } catch (error) { return getErrorMessage(error); } @@ -120,7 +117,7 @@ export const createOnChainTriggersByAccount = async ( resetNotifications: boolean, ) => { try { - const userStorage = + const { userStorage } = await Engine.context.NotificationServicesController.createOnChainTriggers( { resetNotifications, @@ -132,7 +129,6 @@ export const createOnChainTriggersByAccount = async ( notificationsErrors.CREATE_ON_CHAIN_TRIGGERS_BY_ACCOUNT, ); } - mmStorage.saveLocal('pnUserStorage', userStorage); } catch (error) { return getErrorMessage(error); } @@ -175,15 +171,6 @@ export const markMetamaskNotificationsAsRead = async ( return getErrorMessage(error); } }; - -export const syncInternalAccountsWithUserStorage = async () => { - try { - await Engine.context.UserStorageController.syncInternalAccountsWithUserStorage(); - } catch (error) { - return getErrorMessage(error); - } -}; - /** * Perform the deletion of the notifications storage key and the creation of on chain triggers to reset the notifications. * @@ -191,45 +178,12 @@ export const syncInternalAccountsWithUserStorage = async () => { */ export const performDeleteStorage = async (): Promise => { try { - await Engine.context.UserStorageController.performDeleteStorage( - 'notifications.notification_settings', - ); - await Engine.context.NotificationServicesController.createOnChainTriggers({ + await Engine.context.UserStorageController.performDeleteStorage('notifications.notification_settings'); + await Engine.context.NotificationServicesController.createOnChainTriggers( + { resetNotifications: true, - }); - } catch (error) { - return getErrorMessage(error); - } -}; -export const enablePushNotifications = async (userStorage: UserStorage, fcmToken?: string) => { - try { - const uuids = getAllUUIDs(userStorage); - await Engine.context.NotificationServicesPushController.enablePushNotifications( - uuids, - fcmToken, - ); - } catch (error) { - return getErrorMessage(error); - } -}; - -export const disablePushNotifications = async (userStorage: UserStorage) => { - try { - const uuids = getAllUUIDs(userStorage); - await Engine.context.NotificationServicesPushController.disablePushNotifications( - uuids, - ); - } catch (error) { - return getErrorMessage(error); - } -}; - -export const updateTriggerPushNotifications = async (userStorage: UserStorage) => { - try { - const uuids = getAllUUIDs(userStorage); - await Engine.context.NotificationServicesPushController.updateTriggerPushNotifications( - uuids, - ); + }, + ); } catch (error) { return getErrorMessage(error); } diff --git a/app/actions/onboarding/index.ts b/app/actions/onboarding/index.ts index 641bf5568bd2..9866cf8d17b5 100644 --- a/app/actions/onboarding/index.ts +++ b/app/actions/onboarding/index.ts @@ -14,9 +14,7 @@ interface ClearEventsAction { export type OnboardingActionTypes = SaveEventAction | ClearEventsAction; -export function saveOnboardingEvent( - eventArgs: [IMetaMetricsEvent], -): SaveEventAction { +export function saveOnboardingEvent(eventArgs: [IMetaMetricsEvent]): SaveEventAction { return { type: SAVE_EVENT, event: eventArgs, @@ -27,4 +25,4 @@ export function clearOnboardingEvents(): ClearEventsAction { return { type: CLEAR_EVENTS, }; -} +} \ No newline at end of file diff --git a/app/actions/settings/index.js b/app/actions/settings/index.js index 0686f3e06aa0..787a70f6d387 100644 --- a/app/actions/settings/index.js +++ b/app/actions/settings/index.js @@ -67,10 +67,3 @@ export function toggleDeviceNotification(deviceNotificationEnabled) { deviceNotificationEnabled, }; } - -export function setTokenSortConfig(tokenSortConfig) { - return { - type: 'SET_TOKEN_SORT_CONFIG', - tokenSortConfig, - }; -} diff --git a/app/component-library/components-temp/CellSelectWithMenu/CellSelectWithMenu.stories.tsx b/app/component-library/components-temp/CellSelectWithMenu/CellSelectWithMenu.stories.tsx index 990704840a9f..46e8a658e40f 100644 --- a/app/component-library/components-temp/CellSelectWithMenu/CellSelectWithMenu.stories.tsx +++ b/app/component-library/components-temp/CellSelectWithMenu/CellSelectWithMenu.stories.tsx @@ -30,20 +30,8 @@ const CellSelectWithMenuMeta = { control: { type: 'boolean' }, defaultValue: SAMPLE_CELLSELECT_WITH_BUTTON_PROPS.isDisabled, }, - withAvatar: { - control: { type: 'boolean' }, - defaultValue: true, - }, - showSecondaryTextIcon: { - control: { type: 'boolean' }, - defaultValue: true, - }, - onTextClick: { - action: 'clicked', - }, }, }; - export default CellSelectWithMenuMeta; export const CellMultiSelectWithMenu = { diff --git a/app/component-library/components-temp/CellSelectWithMenu/CellSelectWithMenu.styles.ts b/app/component-library/components-temp/CellSelectWithMenu/CellSelectWithMenu.styles.ts index 97a8c23a18d6..99dfa994910a 100644 --- a/app/component-library/components-temp/CellSelectWithMenu/CellSelectWithMenu.styles.ts +++ b/app/component-library/components-temp/CellSelectWithMenu/CellSelectWithMenu.styles.ts @@ -55,9 +55,6 @@ const styleSheet = (params: { tagLabel: { marginTop: 4, }, - selectedTag: { - backgroundColor: colors.primary.muted, - }, containerRow: { flexDirection: 'row', alignItems: 'flex-start', diff --git a/app/component-library/components-temp/CellSelectWithMenu/CellSelectWithMenu.tsx b/app/component-library/components-temp/CellSelectWithMenu/CellSelectWithMenu.tsx index 144f2408e20c..e18ed0465956 100644 --- a/app/component-library/components-temp/CellSelectWithMenu/CellSelectWithMenu.tsx +++ b/app/component-library/components-temp/CellSelectWithMenu/CellSelectWithMenu.tsx @@ -6,7 +6,6 @@ import { TouchableOpacity, TouchableWithoutFeedback, View } from 'react-native'; // External dependencies. import { useStyles } from '../../hooks'; -import Tag from '../../../component-library/components/Tags/Tag'; // Internal dependencies. import styleSheet from './CellSelectWithMenu.styles'; @@ -35,7 +34,6 @@ const CellSelectWithMenu = ({ isSelected = false, children, withAvatar = true, - showSecondaryTextIcon = true, ...props }: CellSelectWithMenuProps) => { const { styles } = useStyles(styleSheet, { style }); @@ -79,27 +77,14 @@ const CellSelectWithMenu = ({ > {secondaryText} - {showSecondaryTextIcon && ( - - )} + )} - {!!tagLabel && ( - - )} {children && {children}} diff --git a/app/component-library/components-temp/CellSelectWithMenu/__snapshots__/CellSelectWithMenu.test.tsx.snap b/app/component-library/components-temp/CellSelectWithMenu/__snapshots__/CellSelectWithMenu.test.tsx.snap index f0bc6875e36d..315ea9c6914c 100644 --- a/app/component-library/components-temp/CellSelectWithMenu/__snapshots__/CellSelectWithMenu.test.tsx.snap +++ b/app/component-library/components-temp/CellSelectWithMenu/__snapshots__/CellSelectWithMenu.test.tsx.snap @@ -280,37 +280,6 @@ exports[`CellSelectWithMenu should render with default settings correctly 1`] = width={10} /> - - - Imported - - @@ -319,7 +288,7 @@ exports[`CellSelectWithMenu should render with default settings correctly 1`] = diff --git a/app/component-library/components-temp/Contracts/ContractBoxBase/ContractBoxBase.tsx b/app/component-library/components-temp/Contracts/ContractBoxBase/ContractBoxBase.tsx index 5ba78777e381..d92a8bbb5d7c 100644 --- a/app/component-library/components-temp/Contracts/ContractBoxBase/ContractBoxBase.tsx +++ b/app/component-library/components-temp/Contracts/ContractBoxBase/ContractBoxBase.tsx @@ -39,7 +39,7 @@ const ContractBoxBase = ({ theme: { colors }, } = useStyles(styleSheet, {}); - const renderIconView = ({ onPress, name, size, testID }: IconViewProps) => ( + const IconView = ({ onPress, name, size, testID }: IconViewProps) => ( @@ -78,19 +78,20 @@ const ContractBoxBase = ({ )} - {renderIconView({ - onPress: onCopyAddress, - name: IconName.Copy, - size: IconSize.Lg, - testID: COPY_ICON_TEST_ID, - })} - {hasBlockExplorer && - renderIconView({ - onPress: onExportAddress, - name: IconName.Export, - size: IconSize.Md, - testID: EXPORT_ICON_TEST_ID, - })} + + {hasBlockExplorer && ( + + )} ); diff --git a/app/component-library/components-temp/Contracts/ContractBoxBase/__snapshots__/ContractBoxBase.test.tsx.snap b/app/component-library/components-temp/Contracts/ContractBoxBase/__snapshots__/ContractBoxBase.test.tsx.snap index 56c4c78ddc2d..01c380bb58a3 100644 --- a/app/component-library/components-temp/Contracts/ContractBoxBase/__snapshots__/ContractBoxBase.test.tsx.snap +++ b/app/component-library/components-temp/Contracts/ContractBoxBase/__snapshots__/ContractBoxBase.test.tsx.snap @@ -65,21 +65,12 @@ exports[`Component ContractBoxBase should render correctly 1`] = ` } } > - - - + /> `; diff --git a/app/component-library/components-temp/ListItemMultiSelectButton/ListItemMultiSelectButton.stories.tsx b/app/component-library/components-temp/ListItemMultiSelectButton/ListItemMultiSelectButton.stories.tsx index 2abe8bf0b1fe..f1db9cbef129 100644 --- a/app/component-library/components-temp/ListItemMultiSelectButton/ListItemMultiSelectButton.stories.tsx +++ b/app/component-library/components-temp/ListItemMultiSelectButton/ListItemMultiSelectButton.stories.tsx @@ -14,11 +14,7 @@ import Text, { // Internal dependencies. import { default as ListItemSelectWithButtonComponent } from './ListItemMultiSelectButton'; -import { - BUTTON_TEST_ID, - DEFAULT_LISTITEMMULTISELECT_GAP, - SAMPLE_LISTITEMMULTISELECT_PROPS, -} from './ListItemMultiSelectButton.constants'; +import { SAMPLE_LISTITEMMULTISELECT_PROPS } from './ListItemMultiSelectButton.constants'; import { ListItemMultiSelectButtonProps } from './ListItemMultiSelectButton.types'; const ListItemSelectWithButtonMeta = { @@ -33,27 +29,6 @@ const ListItemSelectWithButtonMeta = { control: { type: 'boolean' }, defaultValue: SAMPLE_LISTITEMMULTISELECT_PROPS.isDisabled, }, - showButtonIcon: { - control: { type: 'boolean' }, - defaultValue: true, - }, - buttonIcon: { - control: { type: 'select' }, - options: Object.values(IconName), - defaultValue: IconName.MoreVertical, - }, - gap: { - control: { type: 'number' }, - defaultValue: DEFAULT_LISTITEMMULTISELECT_GAP, - }, - buttonProps: { - control: 'object', - defaultValue: { - textButton: '', - onButtonClick: () => null, - buttonTestId: BUTTON_TEST_ID, - }, - }, }, }; export default ListItemSelectWithButtonMeta; diff --git a/app/component-library/components-temp/ListItemMultiSelectButton/ListItemMultiSelectButton.styles.ts b/app/component-library/components-temp/ListItemMultiSelectButton/ListItemMultiSelectButton.styles.ts index 9f00528c58d9..4af6d6f86a92 100644 --- a/app/component-library/components-temp/ListItemMultiSelectButton/ListItemMultiSelectButton.styles.ts +++ b/app/component-library/components-temp/ListItemMultiSelectButton/ListItemMultiSelectButton.styles.ts @@ -85,7 +85,7 @@ const styleSheet = (params: { paddingTop: 32, }, buttonIcon: { - paddingRight: 20, + paddingHorizontal: 20, }, }); }; diff --git a/app/component-library/components-temp/ListItemMultiSelectButton/ListItemMultiSelectButton.tsx b/app/component-library/components-temp/ListItemMultiSelectButton/ListItemMultiSelectButton.tsx index 7f258b175dfd..a3cb0d079ffc 100644 --- a/app/component-library/components-temp/ListItemMultiSelectButton/ListItemMultiSelectButton.tsx +++ b/app/component-library/components-temp/ListItemMultiSelectButton/ListItemMultiSelectButton.tsx @@ -68,7 +68,7 @@ const ListItemMultiSelectButton: React.FC = ({ diff --git a/app/component-library/components-temp/ListItemMultiSelectButton/ListItemMultiSelectButton.types.ts b/app/component-library/components-temp/ListItemMultiSelectButton/ListItemMultiSelectButton.types.ts index 4f7ad98ca842..f92853d98758 100644 --- a/app/component-library/components-temp/ListItemMultiSelectButton/ListItemMultiSelectButton.types.ts +++ b/app/component-library/components-temp/ListItemMultiSelectButton/ListItemMultiSelectButton.types.ts @@ -41,9 +41,6 @@ export interface ListItemMultiSelectButtonProps */ showButtonIcon?: boolean; - /** - * Optional button props - */ buttonProps?: { /** * Optional button onClick function @@ -53,16 +50,6 @@ export interface ListItemMultiSelectButtonProps * Optional property to show text button */ textButton?: string | null; - - /** - * Optional property to show button icon - */ - showButtonIcon?: boolean; - - /** - * Optional property for button test ID - */ - buttonTestId?: string; }; } diff --git a/app/component-library/components-temp/ListItemMultiSelectButton/__snapshots__/ListItemMultiSelectButton.test.tsx.snap b/app/component-library/components-temp/ListItemMultiSelectButton/__snapshots__/ListItemMultiSelectButton.test.tsx.snap index 6afd161f5dbc..0d1b7d3f4f59 100644 --- a/app/component-library/components-temp/ListItemMultiSelectButton/__snapshots__/ListItemMultiSelectButton.test.tsx.snap +++ b/app/component-library/components-temp/ListItemMultiSelectButton/__snapshots__/ListItemMultiSelectButton.test.tsx.snap @@ -53,7 +53,7 @@ exports[`ListItemMultiSelectButton should render correctly with default props 1` diff --git a/app/component-library/components-temp/Price/AggregatedPercentage/AggregatedPercentage.constants.ts b/app/component-library/components-temp/Price/AggregatedPercentage/AggregatedPercentage.constants.ts deleted file mode 100644 index 52b0b69960a3..000000000000 --- a/app/component-library/components-temp/Price/AggregatedPercentage/AggregatedPercentage.constants.ts +++ /dev/null @@ -1,2 +0,0 @@ -export const FORMATTED_VALUE_PRICE_TEST_ID = 'formatted-value-price-test-id'; -export const FORMATTED_PERCENTAGE_TEST_ID = 'formatted-percentage-test-id'; diff --git a/app/component-library/components-temp/Price/AggregatedPercentage/AggregatedPercentage.test.tsx b/app/component-library/components-temp/Price/AggregatedPercentage/AggregatedPercentage.test.tsx index ac0bdb30a2ee..affec3613215 100644 --- a/app/component-library/components-temp/Price/AggregatedPercentage/AggregatedPercentage.test.tsx +++ b/app/component-library/components-temp/Price/AggregatedPercentage/AggregatedPercentage.test.tsx @@ -4,10 +4,6 @@ import AggregatedPercentage from './AggregatedPercentage'; import { mockTheme } from '../../../../util/theme'; import { useSelector } from 'react-redux'; import { selectCurrentCurrency } from '../../../../selectors/currencyRateController'; -import { - FORMATTED_VALUE_PRICE_TEST_ID, - FORMATTED_PERCENTAGE_TEST_ID, -} from './AggregatedPercentage.constants'; jest.mock('react-redux', () => ({ ...jest.requireActual('react-redux'), @@ -69,22 +65,4 @@ describe('AggregatedPercentage', () => { color: mockTheme.colors.error.default, }); }); - - it('renders correctly with privacy mode on', () => { - const { getByTestId } = render( - , - ); - - const formattedPercentage = getByTestId(FORMATTED_PERCENTAGE_TEST_ID); - const formattedValuePrice = getByTestId(FORMATTED_VALUE_PRICE_TEST_ID); - - expect(formattedPercentage.props.children).toBe('••••••••••'); - expect(formattedValuePrice.props.children).toBe('••••••••••'); - }); }); diff --git a/app/component-library/components-temp/Price/AggregatedPercentage/AggregatedPercentage.tsx b/app/component-library/components-temp/Price/AggregatedPercentage/AggregatedPercentage.tsx index 715587f6ddc7..c2a94c1bc1ab 100644 --- a/app/component-library/components-temp/Price/AggregatedPercentage/AggregatedPercentage.tsx +++ b/app/component-library/components-temp/Price/AggregatedPercentage/AggregatedPercentage.tsx @@ -1,19 +1,14 @@ import React from 'react'; -import { +import Text, { TextColor, TextVariant, } from '../../../../component-library/components/Texts/Text'; -import SensitiveText from '../../../../component-library/components/Texts/SensitiveText'; import { View } from 'react-native'; import { renderFiat } from '../../../../util/number'; import { useSelector } from 'react-redux'; import { selectCurrentCurrency } from '../../../../selectors/currencyRateController'; import styleSheet from './AggregatedPercentage.styles'; import { useStyles } from '../../../hooks'; -import { - FORMATTED_VALUE_PRICE_TEST_ID, - FORMATTED_PERCENTAGE_TEST_ID, -} from './AggregatedPercentage.constants'; export interface AggregatedPercentageProps { ethFiat: number; @@ -30,13 +25,11 @@ const AggregatedPercentage = ({ tokenFiat, tokenFiat1dAgo, ethFiat1dAgo, - privacyMode = false, }: { ethFiat: number; tokenFiat: number; tokenFiat1dAgo: number; ethFiat1dAgo: number; - privacyMode?: boolean; }) => { const { styles } = useStyles(styleSheet, {}); @@ -53,16 +46,12 @@ const AggregatedPercentage = ({ let percentageTextColor = TextColor.Default; - if (!privacyMode) { - if (percentageChange === 0) { - percentageTextColor = TextColor.Default; - } else if (percentageChange > 0) { - percentageTextColor = TextColor.Success; - } else { - percentageTextColor = TextColor.Error; - } + if (percentageChange === 0) { + percentageTextColor = TextColor.Default; + } else if (percentageChange > 0) { + percentageTextColor = TextColor.Success; } else { - percentageTextColor = TextColor.Alternative; + percentageTextColor = TextColor.Error; } const formattedPercentage = isValidAmount(percentageChange) @@ -81,24 +70,12 @@ const AggregatedPercentage = ({ return ( - + {formattedValuePrice} - - + + {formattedPercentage} - + ); }; diff --git a/app/component-library/components-temp/Price/AggregatedPercentage/__snapshots__/AggregatedPercentage.test.tsx.snap b/app/component-library/components-temp/Price/AggregatedPercentage/__snapshots__/AggregatedPercentage.test.tsx.snap index 1066d19a41b3..16b825b0e5de 100644 --- a/app/component-library/components-temp/Price/AggregatedPercentage/__snapshots__/AggregatedPercentage.test.tsx.snap +++ b/app/component-library/components-temp/Price/AggregatedPercentage/__snapshots__/AggregatedPercentage.test.tsx.snap @@ -21,7 +21,6 @@ exports[`AggregatedPercentage should render correctly 1`] = ` "lineHeight": 22, } } - testID="formatted-value-price-test-id" > +20 USD @@ -37,7 +36,6 @@ exports[`AggregatedPercentage should render correctly 1`] = ` "lineHeight": 22, } } - testID="formatted-percentage-test-id" > (+11.11%) diff --git a/app/component-library/components/Avatars/Avatar/variants/AvatarIcon/AvatarIcon.test.tsx b/app/component-library/components/Avatars/Avatar/variants/AvatarIcon/AvatarIcon.test.tsx index f6ab447037e6..f6366e5ff333 100644 --- a/app/component-library/components/Avatars/Avatar/variants/AvatarIcon/AvatarIcon.test.tsx +++ b/app/component-library/components/Avatars/Avatar/variants/AvatarIcon/AvatarIcon.test.tsx @@ -1,6 +1,6 @@ // Third party dependencies. import React from 'react'; -import { render } from '@testing-library/react-native'; +import { shallow } from 'enzyme'; // External dependencies. import AvatarIcon from './AvatarIcon'; @@ -10,7 +10,7 @@ import { SAMPLE_AVATARICON_PROPS } from './AvatarIcon.constants'; describe('AvatarIcon', () => { it('should render correctly', () => { - const { toJSON } = render(); - expect(toJSON()).toMatchSnapshot(); + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); }); }); diff --git a/app/component-library/components/Avatars/Avatar/variants/AvatarIcon/__snapshots__/AvatarIcon.test.tsx.snap b/app/component-library/components/Avatars/Avatar/variants/AvatarIcon/__snapshots__/AvatarIcon.test.tsx.snap index 1d343e9fea09..6c4f0afa3102 100644 --- a/app/component-library/components/Avatars/Avatar/variants/AvatarIcon/__snapshots__/AvatarIcon.test.tsx.snap +++ b/app/component-library/components/Avatars/Avatar/variants/AvatarIcon/__snapshots__/AvatarIcon.test.tsx.snap @@ -1,30 +1,20 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`AvatarIcon should render correctly 1`] = ` - - - + `; diff --git a/app/component-library/components/Buttons/Button/variants/ButtonLink/ButtonLink.test.tsx b/app/component-library/components/Buttons/Button/variants/ButtonLink/ButtonLink.test.tsx index f472c0f90d3b..e8d3d91de541 100644 --- a/app/component-library/components/Buttons/Button/variants/ButtonLink/ButtonLink.test.tsx +++ b/app/component-library/components/Buttons/Button/variants/ButtonLink/ButtonLink.test.tsx @@ -1,13 +1,15 @@ // Third party dependencies. import React from 'react'; -import { render, screen } from '@testing-library/react-native'; +import { shallow } from 'enzyme'; // Internal dependencies. import ButtonLink from './ButtonLink'; -describe('ButtonLink', () => { +describe('Link', () => { it('should render correctly', () => { - render(); - expect(screen.toJSON()).toMatchSnapshot(); + const wrapper = shallow( + , + ); + expect(wrapper).toMatchSnapshot(); }); }); diff --git a/app/component-library/components/Buttons/Button/variants/ButtonLink/__snapshots__/ButtonLink.test.tsx.snap b/app/component-library/components/Buttons/Button/variants/ButtonLink/__snapshots__/ButtonLink.test.tsx.snap index 1c09de8a64ea..ff32c2ade80c 100644 --- a/app/component-library/components/Buttons/Button/variants/ButtonLink/__snapshots__/ButtonLink.test.tsx.snap +++ b/app/component-library/components/Buttons/Button/variants/ButtonLink/__snapshots__/ButtonLink.test.tsx.snap @@ -1,39 +1,27 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`ButtonLink should render correctly 1`] = ` - +exports[`Link should render correctly 1`] = ` + - I'm a Link! + + I'm a Link! + - + `; diff --git a/app/component-library/components/Cells/Cell/foundation/CellBase/CellBase.types.ts b/app/component-library/components/Cells/Cell/foundation/CellBase/CellBase.types.ts index 172cb99124db..88b9c4852d6f 100644 --- a/app/component-library/components/Cells/Cell/foundation/CellBase/CellBase.types.ts +++ b/app/component-library/components/Cells/Cell/foundation/CellBase/CellBase.types.ts @@ -37,11 +37,6 @@ export interface CellBaseProps { * Optional prop to control the style of the CellBase. */ style?: StyleProp | undefined; - - /** - * Optional prop to control the visibility of the secondary text icon. - */ - showSecondaryTextIcon?: boolean; } /** diff --git a/app/component-library/components/Form/TextField/foundation/Input/Input.tsx b/app/component-library/components/Form/TextField/foundation/Input/Input.tsx index 0a9054e2a117..facc8e6e6fd0 100644 --- a/app/component-library/components/Form/TextField/foundation/Input/Input.tsx +++ b/app/component-library/components/Form/TextField/foundation/Input/Input.tsx @@ -21,7 +21,7 @@ const Input: React.FC = ({ isReadonly = false, onBlur, onFocus, - autoFocus = true, + autoFocus = false, ...props }) => { const [isFocused, setIsFocused] = useState(autoFocus); @@ -64,7 +64,7 @@ const Input: React.FC = ({ {...props} style={styles.base} editable={!isDisabled && !isReadonly} - autoFocus={autoFocus} + autoFocus onBlur={onBlurHandler} onFocus={onFocusHandler} /> diff --git a/app/component-library/components/Form/TextField/foundation/Input/__snapshots__/Input.test.tsx.snap b/app/component-library/components/Form/TextField/foundation/Input/__snapshots__/Input.test.tsx.snap index fd6fedfeaa49..99a88ffc241b 100644 --- a/app/component-library/components/Form/TextField/foundation/Input/__snapshots__/Input.test.tsx.snap +++ b/app/component-library/components/Form/TextField/foundation/Input/__snapshots__/Input.test.tsx.snap @@ -9,7 +9,7 @@ exports[`Input should render correctly 1`] = ` style={ { "backgroundColor": "#ffffff", - "borderColor": "#0376c9", + "borderColor": "transparent", "borderWidth": 1, "color": "#141618", "fontFamily": "Euclid Circular B", diff --git a/app/component-library/components/Pickers/PickerBase/PickerBase.stories.tsx b/app/component-library/components/Pickers/PickerBase/PickerBase.stories.tsx deleted file mode 100644 index e5a705d98ddd..000000000000 --- a/app/component-library/components/Pickers/PickerBase/PickerBase.stories.tsx +++ /dev/null @@ -1,57 +0,0 @@ -/* eslint-disable react/display-name */ -/* eslint-disable react-native/no-inline-styles */ -// External dependencies. -import React from 'react'; -import { View, Text } from 'react-native'; - -// Internal dependencies. -import PickerBase from './PickerBase'; -import { IconSize } from '../../Icons/Icon'; - -const PickerBaseMeta = { - title: 'Component Library / Pickers', - component: PickerBase, - argTypes: { - children: { - control: { type: 'text' }, - defaultValue: 'Select an option', - }, - iconSize: { - options: Object.values(IconSize), - control: { type: 'select' }, - defaultValue: IconSize.Md, - }, - }, -}; - -export default PickerBaseMeta; - -export const Default = { - render: ({ - children, - iconSize, - }: { - children: string; - iconSize: IconSize; - }) => ( - - null} iconSize={iconSize}> - {children} - - - ), -}; - -export const WithCustomStyles = { - render: () => ( - - null} - style={{ width: 200 }} - dropdownIconStyle={{ marginLeft: 20 }} - > - Custom Styled Picker - - - ), -}; diff --git a/app/component-library/components/Pickers/PickerBase/PickerBase.styles.ts b/app/component-library/components/Pickers/PickerBase/PickerBase.styles.ts index cad2a763c443..475e466e6b13 100644 --- a/app/component-library/components/Pickers/PickerBase/PickerBase.styles.ts +++ b/app/component-library/components/Pickers/PickerBase/PickerBase.styles.ts @@ -21,8 +21,7 @@ const styleSheet = (params: { }) => { const { vars, theme } = params; const { colors } = theme; - const { style, dropdownIconStyle } = vars; - + const { style } = vars; return StyleSheet.create({ base: Object.assign( { @@ -36,12 +35,9 @@ const styleSheet = (params: { } as ViewStyle, style, ) as ViewStyle, - dropdownIcon: Object.assign( - { - marginLeft: 16, - } as ViewStyle, - dropdownIconStyle, - ), + dropdownIcon: { + marginLeft: 16, + }, }); }; diff --git a/app/component-library/components/Pickers/PickerBase/PickerBase.test.tsx b/app/component-library/components/Pickers/PickerBase/PickerBase.test.tsx index 94ec1e73255f..662319adb469 100644 --- a/app/component-library/components/Pickers/PickerBase/PickerBase.test.tsx +++ b/app/component-library/components/Pickers/PickerBase/PickerBase.test.tsx @@ -1,78 +1,18 @@ // Third party dependencies. import React from 'react'; -import { Text } from 'react-native'; -import { render, fireEvent } from '@testing-library/react-native'; +import { View } from 'react-native'; +import { render } from '@testing-library/react-native'; // Internal dependencies. import PickerBase from './PickerBase'; -import { IconName, IconSize } from '../../Icons/Icon'; describe('PickerBase', () => { it('should render correctly', () => { const { toJSON } = render( - - Test Content + + , ); expect(toJSON()).toMatchSnapshot(); }); - - it('should call onPress when pressed', () => { - const onPressMock = jest.fn(); - const { getByText } = render( - - Test Content - , - ); - - fireEvent.press(getByText('Test Content')); - expect(onPressMock).toHaveBeenCalledTimes(1); - }); - - it('should render children correctly', () => { - const { getByText } = render( - - Child Component - , - ); - - expect(getByText('Child Component')).toBeTruthy(); - }); - - it('should render dropdown icon', () => { - const { UNSAFE_getByProps } = render( - - Test Content - , - ); - - const icon = UNSAFE_getByProps({ name: IconName.ArrowDown }); - expect(icon).toBeTruthy(); - }); - - it('should apply custom icon size', () => { - const { UNSAFE_getByProps } = render( - - Test Content - , - ); - - const icon = UNSAFE_getByProps({ - name: IconName.ArrowDown, - size: IconSize.Lg, - }); - expect(icon).toBeTruthy(); - }); - - it('should apply custom dropdown icon style', () => { - const customStyle = { marginLeft: 20 }; - const { UNSAFE_getByProps } = render( - - Test Content - , - ); - - const icon = UNSAFE_getByProps({ name: IconName.ArrowDown }); - expect(icon.props.style).toEqual(expect.objectContaining(customStyle)); - }); }); diff --git a/app/component-library/components/Pickers/PickerBase/PickerBase.tsx b/app/component-library/components/Pickers/PickerBase/PickerBase.tsx index 10d39f7be7e0..5488138d687a 100644 --- a/app/component-library/components/Pickers/PickerBase/PickerBase.tsx +++ b/app/component-library/components/Pickers/PickerBase/PickerBase.tsx @@ -15,18 +15,15 @@ import styleSheet from './PickerBase.styles'; const PickerBase: React.ForwardRefRenderFunction< TouchableOpacity, PickerBaseProps -> = ( - { iconSize = IconSize.Md, style, dropdownIconStyle, children, ...props }, - ref, -) => { - const { styles, theme } = useStyles(styleSheet, { style, dropdownIconStyle }); +> = ({ style, children, ...props }, ref) => { + const { styles, theme } = useStyles(styleSheet, { style }); const { colors } = theme; return ( {children} ; +export type PickerBaseStyleSheetVars = Pick; diff --git a/app/component-library/components/Pickers/PickerBase/README.md b/app/component-library/components/Pickers/PickerBase/README.md index ea5b298becda..74ec00f6ba7a 100644 --- a/app/component-library/components/Pickers/PickerBase/README.md +++ b/app/component-library/components/Pickers/PickerBase/README.md @@ -1,10 +1,10 @@ # PickerBase -PickerBase is a **wrapper** component used for providing a dropdown icon next to wrapped content. It's designed to be a flexible base for various picker-style components. +PickerBase is a **wrapper** component used for providing a dropdown icon next to wrapped content. ## Props -This component extends `TouchableOpacityProps` from React Native's [TouchableOpacity](https://reactnative.dev/docs/touchableopacity). +This component extends `TouchableOpacityProps` from React Native's [TouchableOpacityProps](https://reactnative.dev/docs/touchableOpacity) opacity. ### `onPress` @@ -22,55 +22,11 @@ Content to wrap in PickerBase. | :-------------------------------------------------- | :------------------------------------------------------ | | ReactNode | Yes | -### `iconSize` - -Size of the dropdown icon. - -| TYPE | REQUIRED | DEFAULT | -| :-------------------------------------------------- | :------------------------------------------------------ | :----------------------------------------------------- | -| IconSize | No | IconSize.Md | - -### `dropdownIconStyle` - -Custom styles for the dropdown icon. - -| TYPE | REQUIRED | -| :-------------------------------------------------- | :------------------------------------------------------ | -| ViewStyle | No | - -### `style` - -Custom styles for the main container. - -| TYPE | REQUIRED | -| :-------------------------------------------------- | :------------------------------------------------------ | -| ViewStyle | No | - -## Usage - ```javascript -import React from 'react'; -import { Text } from 'react-native'; +// Replace import with relative path. import PickerBase from 'app/component-library/components/Pickers/PickerBase'; -import { IconSize } from 'app/component-library/components/Icons/Icon'; - -const ExampleComponent = () => ( - console.log('Picker pressed')} - iconSize={IconSize.Lg} - dropdownIconStyle={{ marginLeft: 20 }} - style={{ backgroundColor: 'lightgray' }} - > - Select an option - -); -export default ExampleComponent; + + +; ``` - -## Notes - -- The component uses a `TouchableOpacity` as its base, providing press feedback. -- It automatically includes a dropdown icon (ArrowDown) to the right of the content. -- The component is designed to be flexible and can be customized using the `style` and `dropdownIconStyle` props. -- The dropdown icon color is determined by the theme's `colors.icon.default`. \ No newline at end of file diff --git a/app/component-library/components/Pickers/PickerBase/__snapshots__/PickerBase.test.tsx.snap b/app/component-library/components/Pickers/PickerBase/__snapshots__/PickerBase.test.tsx.snap index 21db5a5774ab..f93ccf2a438a 100644 --- a/app/component-library/components/Pickers/PickerBase/__snapshots__/PickerBase.test.tsx.snap +++ b/app/component-library/components/Pickers/PickerBase/__snapshots__/PickerBase.test.tsx.snap @@ -2,7 +2,7 @@ exports[`PickerBase should render correctly 1`] = ` - - Test Content - + ) => ( + // TODO: Replace "any" with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any + render: (args: any) => ( { expect(queryByTestId(PICKERNETWORK_ARROW_TESTID)).toBeNull(); }); - - it('hides network name and shows icon when hideNetworkName is true', () => { - const { queryByTestId } = render( - , - ); - - expect( - queryByTestId(WalletViewSelectorsIDs.NAVBAR_NETWORK_TEXT), - ).toBeNull(); - }); - - it('calls onPress when pressed', () => { - const onPress = jest.fn(); - const { getByTestId } = render( - , - ); - - fireEvent.press(getByTestId(PICKERNETWORK_ARROW_TESTID)); - - expect(onPress).toHaveBeenCalled(); - }); }); diff --git a/app/component-library/components/Pickers/PickerNetwork/PickerNetwork.tsx b/app/component-library/components/Pickers/PickerNetwork/PickerNetwork.tsx index 1b4642ba9676..9c4dd1f150a4 100644 --- a/app/component-library/components/Pickers/PickerNetwork/PickerNetwork.tsx +++ b/app/component-library/components/Pickers/PickerNetwork/PickerNetwork.tsx @@ -2,7 +2,7 @@ // Third party dependencies. import React from 'react'; -import { TouchableOpacity, View } from 'react-native'; +import { TouchableOpacity } from 'react-native'; // External dependencies. import Avatar, { AvatarSize, AvatarVariant } from '../../Avatars/Avatar'; @@ -21,31 +21,26 @@ const PickerNetwork = ({ style, label, imageSource, - hideNetworkName, ...props }: PickerNetworkProps) => { const { styles } = useStyles(stylesheet, { style }); return ( - - - - {hideNetworkName ? null : ( - - {label} - - )} + + + {label} + {onPress && ( void; - /** - * Whether to hide the network name. - */ - hideNetworkName?: boolean; } export type PickerNetworkStyleSheetVars = Pick; diff --git a/app/component-library/components/Pickers/PickerNetwork/README.md b/app/component-library/components/Pickers/PickerNetwork/README.md index 63cafd3a3384..f7e1dccc1f62 100644 --- a/app/component-library/components/Pickers/PickerNetwork/README.md +++ b/app/component-library/components/Pickers/PickerNetwork/README.md @@ -6,13 +6,13 @@ PickerNetwork is a component that renders an avatar based on the user selected n This component extends `TouchableOpacityProps` from React Native's [TouchableOpacity](https://reactnative.dev/docs/touchableopacity) component. -### `onPress` +### `imageSource` -Callback to trigger when pressed. +Optional network image from either a local or remote source. -| TYPE | REQUIRED | -| :-------------------------------------------------- | :------------------------------------------------------ | -| function | No | +| TYPE | REQUIRED | +| :-------------------------------------------------------------------- | :------------------------------------------------------ | +| [ImageSourcePropType](https://reactnative.dev/docs/image#imagesource) | Yes | ### `label` @@ -22,37 +22,21 @@ Network label to display. | :-------------------------------------------------- | :------------------------------------------------------ | | string | Yes | -### `imageSource` - -The source for the network avatar image. - -| TYPE | REQUIRED | -| :-------------------------------------------------- | :------------------------------------------------------ | -| ImageSourcePropType | No | - -### `hideNetworkName` +### `onPress` -Whether to hide the network name text. +Callback to trigger when picker is pressed. | TYPE | REQUIRED | | :-------------------------------------------------- | :------------------------------------------------------ | -| boolean | No | - -## Usage +| function | Yes | ```javascript +// Replace import with relative path. import PickerNetwork from 'app/component-library/components/Pickers/PickerNetwork'; console.log('Network picker pressed')} - label="Ethereum" - imageSource={require('./ethereum-logo.png')} + onPress={ONPRESS_CALLBACK} + label={NETWORK_LABEL} + image={{ uri: NETWORK_IMAGE_URL }} />; ``` - -## Notes - -- The component uses an `Avatar` component to display the network icon. -- If `onPress` is provided, a dropdown arrow icon will be displayed. -- The network name can be hidden using the `hideNetworkName` prop. -- The component uses custom styles defined in `PickerNetwork.styles.ts`. \ No newline at end of file diff --git a/app/component-library/components/Pickers/PickerNetwork/__snapshots__/PickerNetwork.test.tsx.snap b/app/component-library/components/Pickers/PickerNetwork/__snapshots__/PickerNetwork.test.tsx.snap index f59fab749339..c9c4f7fe7972 100644 --- a/app/component-library/components/Pickers/PickerNetwork/__snapshots__/PickerNetwork.test.tsx.snap +++ b/app/component-library/components/Pickers/PickerNetwork/__snapshots__/PickerNetwork.test.tsx.snap @@ -16,38 +16,34 @@ exports[`PickerNetwork renders correctly 1`] = ` } > - - - + testID="network-avatar-image" + /> @@ -599,7 +583,6 @@ exports[`AccountSelectorList renders all accounts with balances 1`] = ` style={ { "alignItems": "flex-end", - "flexDirection": "column", } } testID="account-balance-by-address-0xd018538C87232FF95acbCe4870629b75640a78E7" @@ -619,22 +602,7 @@ exports[`AccountSelectorList renders all accounts with balances 1`] = ` } > $6400.00 - - - 2 ETH +2 ETH @@ -1485,7 +1453,6 @@ exports[`AccountSelectorList renders correctly 1`] = ` style={ { "alignItems": "flex-end", - "flexDirection": "column", } } testID="account-balance-by-address-0xC4955C0d639D99699Bfd7Ec54d9FaFEe40e4D272" @@ -1505,22 +1472,7 @@ exports[`AccountSelectorList renders correctly 1`] = ` } > $3200.00 - - - 1 ETH +1 ETH @@ -1794,7 +1746,6 @@ exports[`AccountSelectorList renders correctly 1`] = ` style={ { "alignItems": "flex-end", - "flexDirection": "column", } } testID="account-balance-by-address-0xd018538C87232FF95acbCe4870629b75640a78E7" @@ -1814,22 +1765,7 @@ exports[`AccountSelectorList renders correctly 1`] = ` } > $6400.00 - - - 2 ETH +2 ETH @@ -2013,7 +1949,6 @@ exports[`AccountSelectorList should render all accounts but only the balance for style={ { "alignItems": "flex-end", - "flexDirection": "column", } } testID="account-balance-by-address-0xC4955C0d639D99699Bfd7Ec54d9FaFEe40e4D272" @@ -2033,22 +1968,7 @@ exports[`AccountSelectorList should render all accounts but only the balance for } > $3200.00 - - - 1 ETH +1 ETH diff --git a/app/components/UI/AnimatedTransactionModal/__snapshots__/index.test.tsx.snap b/app/components/UI/AnimatedTransactionModal/__snapshots__/index.test.tsx.snap index edb1bdd219f1..e99df64bf599 100644 --- a/app/components/UI/AnimatedTransactionModal/__snapshots__/index.test.tsx.snap +++ b/app/components/UI/AnimatedTransactionModal/__snapshots__/index.test.tsx.snap @@ -1,23 +1,28 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`AnimatedTransactionModal should render correctly 1`] = ` - `; diff --git a/app/components/UI/AnimatedTransactionModal/index.test.tsx b/app/components/UI/AnimatedTransactionModal/index.test.tsx index 4a22108e3df2..9d8108ca3ef0 100644 --- a/app/components/UI/AnimatedTransactionModal/index.test.tsx +++ b/app/components/UI/AnimatedTransactionModal/index.test.tsx @@ -1,23 +1,15 @@ import React from 'react'; -import { render, screen } from '@testing-library/react-native'; +import { shallow } from 'enzyme'; import AnimatedTransactionModal from './'; import { View } from 'react-native'; -import { ThemeContext } from '../../../util/theme'; - -const mockTheme = { - colors: { background: { default: 'white' } }, - themeAppearance: 'light', -}; describe('AnimatedTransactionModal', () => { it('should render correctly', () => { - render( - - - - - , + const wrapper = shallow( + + + , ); - expect(screen.toJSON()).toMatchSnapshot(); + expect(wrapper).toMatchSnapshot(); }); }); diff --git a/app/components/UI/AssetElement/index.constants.ts b/app/components/UI/AssetElement/index.constants.ts deleted file mode 100644 index 1b14c68f51c6..000000000000 --- a/app/components/UI/AssetElement/index.constants.ts +++ /dev/null @@ -1,2 +0,0 @@ -export const FIAT_BALANCE_TEST_ID = 'fiat-balance-test-id'; -export const MAIN_BALANCE_TEST_ID = 'main-balance-test-id'; diff --git a/app/components/UI/AssetElement/index.test.tsx b/app/components/UI/AssetElement/index.test.tsx index e664027b309b..1d178a7f4c3b 100644 --- a/app/components/UI/AssetElement/index.test.tsx +++ b/app/components/UI/AssetElement/index.test.tsx @@ -3,7 +3,6 @@ import { shallow } from 'enzyme'; import { render, fireEvent } from '@testing-library/react-native'; import AssetElement from './'; import { getAssetTestId } from '../../../../wdio/screen-objects/testIDs/Screens/WalletView.testIds'; -import { FIAT_BALANCE_TEST_ID, MAIN_BALANCE_TEST_ID } from './index.constants'; describe('AssetElement', () => { const onPressMock = jest.fn(); @@ -55,34 +54,4 @@ describe('AssetElement', () => { expect(onLongPressMock).toHaveBeenCalledWith(erc20Token); }); - - it('renders the fiat and token balance', () => { - const { getByTestId } = render( - , - ); - - expect(getByTestId(FIAT_BALANCE_TEST_ID)).toBeDefined(); - expect(getByTestId(MAIN_BALANCE_TEST_ID)).toBeDefined(); - }); - - it('renders the fiat balance with privacy mode', () => { - const { getByTestId } = render( - , - ); - - const fiatBalance = getByTestId(FIAT_BALANCE_TEST_ID); - const mainBalance = getByTestId(MAIN_BALANCE_TEST_ID); - - expect(fiatBalance.props.children).toBe('•••••••••'); - expect(mainBalance.props.children).toBe('••••••'); - }); }); diff --git a/app/components/UI/AssetElement/index.tsx b/app/components/UI/AssetElement/index.tsx index ff39a4eac1ac..a2810c48db00 100644 --- a/app/components/UI/AssetElement/index.tsx +++ b/app/components/UI/AssetElement/index.tsx @@ -1,7 +1,9 @@ /* eslint-disable react/prop-types */ import React from 'react'; import { TouchableOpacity, StyleSheet, Platform, View } from 'react-native'; -import { TextVariant } from '../../../component-library/components/Texts/Text'; +import Text, { + TextVariant, +} from '../../../component-library/components/Texts/Text'; import SkeletonText from '../Ramp/components/SkeletonText'; import { TokenI } from '../Tokens/types'; import generateTestId from '../../../../wdio/utils/generateTestId'; @@ -13,10 +15,6 @@ import { import { Colors } from '../../../util/theme/models'; import { fontStyles } from '../../../styles/common'; import { useTheme } from '../../../util/theme'; -import SensitiveText, { - SensitiveTextLength, -} from '../../../component-library/components/Texts/SensitiveText'; -import { FIAT_BALANCE_TEST_ID, MAIN_BALANCE_TEST_ID } from './index.constants'; interface AssetElementProps { children?: React.ReactNode; @@ -25,7 +23,6 @@ interface AssetElementProps { onLongPress?: ((asset: TokenI) => void) | null; balance?: string; mainBalance?: string | null; - privacyMode?: boolean; } const createStyles = (colors: Colors) => @@ -66,7 +63,6 @@ const AssetElement: React.FC = ({ mainBalance = null, onPress, onLongPress, - privacyMode = false, }) => { const { colors } = useTheme(); const styles = createStyles(colors); @@ -79,8 +75,6 @@ const AssetElement: React.FC = ({ onLongPress?.(asset); }; - // TODO: Use the SensitiveText component when it's available - // when privacyMode is true, we should hide the balance and the fiat return ( = ({ {balance && ( - {balance === TOKEN_BALANCE_LOADING ? ( ) : ( balance )} - + )} {mainBalance ? ( - + {mainBalance === TOKEN_BALANCE_LOADING ? ( ) : ( mainBalance )} - + ) : null} diff --git a/app/components/UI/AssetList/index.test.tsx b/app/components/UI/AssetList/index.test.tsx index b3a7e119ad10..cde9e86a8763 100644 --- a/app/components/UI/AssetList/index.test.tsx +++ b/app/components/UI/AssetList/index.test.tsx @@ -1,10 +1,10 @@ import React from 'react'; -import { render } from '@testing-library/react-native'; +import { shallow } from 'enzyme'; import AssetList from './'; describe('AssetList', () => { it('should render correctly', () => { - const { toJSON } = render( + const wrapper = shallow( { selectedAsset={{ address: '0xABC', symbol: 'ABC', decimals: 0 }} />, ); - expect(toJSON()).toMatchSnapshot(); + expect(wrapper).toMatchSnapshot(); }); }); diff --git a/app/components/UI/AssetOverview/AssetOverview.tsx b/app/components/UI/AssetOverview/AssetOverview.tsx index 995d61584c03..d6266bfbd575 100644 --- a/app/components/UI/AssetOverview/AssetOverview.tsx +++ b/app/components/UI/AssetOverview/AssetOverview.tsx @@ -1,9 +1,10 @@ import { zeroAddress } from 'ethereumjs-util'; import React, { useCallback, useEffect } from 'react'; -import { TouchableOpacity, View } from 'react-native'; +import { Platform, TouchableOpacity, View } from 'react-native'; import { useDispatch, useSelector } from 'react-redux'; import { strings } from '../../../../locales/i18n'; -import { TokenOverviewSelectorsIDs } from '../../../../e2e/selectors/TokenOverview.selectors'; +import { TOKEN_ASSET_OVERVIEW } from '../../../../wdio/screen-objects/testIDs/Screens/TokenOverviewScreen.testIds'; +import generateTestId from '../../../../wdio/utils/generateTestId'; import { newAssetTransaction } from '../../../actions/transaction'; import AppConstants from '../../../core/AppConstants'; import Engine from '../../../core/Engine'; @@ -258,7 +259,10 @@ const AssetOverview: React.FC = ({ } return ( - + {asset.hasBalanceError ? ( renderWarning() ) : ( diff --git a/app/components/UI/AssetOverview/Balance/Balance.tsx b/app/components/UI/AssetOverview/Balance/Balance.tsx index fed53bd539a9..02c890710519 100644 --- a/app/components/UI/AssetOverview/Balance/Balance.tsx +++ b/app/components/UI/AssetOverview/Balance/Balance.tsx @@ -34,7 +34,7 @@ interface BalanceProps { secondaryBalance?: string; } -export const NetworkBadgeSource = (chainId: string, ticker: string) => { +const NetworkBadgeSource = (chainId: string, ticker: string) => { const isMainnet = isMainnetByChainId(chainId); const isLineaMainnet = isLineaMainnetByChainId(chainId); @@ -88,9 +88,7 @@ const Balance = ({ asset, mainBalance, secondaryBalance }: BalanceProps) => { {asset.name || asset.symbol} - {isPooledStakingFeatureEnabled() && asset?.isETH && ( - - )} + {isPooledStakingFeatureEnabled() && asset?.isETH && } ); }; diff --git a/app/components/UI/AssetOverview/Balance/__snapshots__/index.test.tsx.snap b/app/components/UI/AssetOverview/Balance/__snapshots__/index.test.tsx.snap index 0a66cea0de29..d233e8e44fdf 100644 --- a/app/components/UI/AssetOverview/Balance/__snapshots__/index.test.tsx.snap +++ b/app/components/UI/AssetOverview/Balance/__snapshots__/index.test.tsx.snap @@ -203,7 +203,6 @@ exports[`Balance should render correctly with a fiat balance 1`] = ` "lineHeight": 24, } } - testID="fiat-balance-test-id" > 456 @@ -221,7 +220,6 @@ exports[`Balance should render correctly with a fiat balance 1`] = ` "textTransform": "uppercase", } } - testID="main-balance-test-id" > 123 @@ -435,7 +433,6 @@ exports[`Balance should render correctly without a fiat balance 1`] = ` "textTransform": "uppercase", } } - testID="main-balance-test-id" > 123 diff --git a/app/components/UI/AssetOverview/Price/Price.tsx b/app/components/UI/AssetOverview/Price/Price.tsx index 9d95b9e17b5a..f297a40115f9 100644 --- a/app/components/UI/AssetOverview/Price/Price.tsx +++ b/app/components/UI/AssetOverview/Price/Price.tsx @@ -17,7 +17,7 @@ import Text, { import PriceChart from '../PriceChart/PriceChart'; import { distributeDataPoints } from '../PriceChart/utils'; import styleSheet from './Price.styles'; -import { TokenOverviewSelectorsIDs } from '../../../../../e2e/selectors/TokenOverview.selectors'; +import { TOKEN_PRICE } from '../../../../../wdio/screen-objects/testIDs/Screens/TokenOverviewScreen.testIds'; import { TokenI } from '../../Tokens/types'; interface PriceProps { @@ -90,7 +90,7 @@ const Price = ({ {asset.symbol} )} {!isNaN(price) && ( - + {isLoading ? ( diff --git a/app/components/UI/AssetOverview/PriceChart/PriceChart.tsx b/app/components/UI/AssetOverview/PriceChart/PriceChart.tsx index 12dce2ffa9ea..2af05649ef6b 100644 --- a/app/components/UI/AssetOverview/PriceChart/PriceChart.tsx +++ b/app/components/UI/AssetOverview/PriceChart/PriceChart.tsx @@ -1,4 +1,3 @@ -/* eslint-disable react/no-unstable-nested-components */ import { TokenPrice } from 'app/components/hooks/useTokenHistoricalPrices'; import React, { useContext, useEffect, useRef, useState } from 'react'; import { diff --git a/app/components/UI/Stake/components/StakingEarnings/StakingEarnings.styles.tsx b/app/components/UI/AssetOverview/StakingEarnings/StakingEarnings.styles.tsx similarity index 92% rename from app/components/UI/Stake/components/StakingEarnings/StakingEarnings.styles.tsx rename to app/components/UI/AssetOverview/StakingEarnings/StakingEarnings.styles.tsx index 8d80278c2c80..e5961497522c 100644 --- a/app/components/UI/Stake/components/StakingEarnings/StakingEarnings.styles.tsx +++ b/app/components/UI/AssetOverview/StakingEarnings/StakingEarnings.styles.tsx @@ -1,5 +1,5 @@ +import { Theme } from '../../../../util/theme/models'; import { StyleSheet, TextStyle } from 'react-native'; -import type { Theme } from '../../../../../util/theme/models'; const styleSheet = (params: { theme: Theme }) => { const { theme } = params; diff --git a/app/components/UI/AssetOverview/StakingEarnings/StakingEarnings.test.tsx b/app/components/UI/AssetOverview/StakingEarnings/StakingEarnings.test.tsx new file mode 100644 index 000000000000..f9a8c51b5a56 --- /dev/null +++ b/app/components/UI/AssetOverview/StakingEarnings/StakingEarnings.test.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import StakingEarnings from './'; +import renderWithProvider from '../../../../util/test/renderWithProvider'; +import { strings } from '../../../../../locales/i18n'; + +jest.mock('../../Stake/constants', () => ({ + isPooledStakingFeatureEnabled: jest.fn().mockReturnValue(true), +})); + +const mockNavigate = jest.fn(); + +jest.mock('@react-navigation/native', () => { + const actualReactNavigation = jest.requireActual('@react-navigation/native'); + return { + ...actualReactNavigation, + useNavigation: () => ({ + navigate: mockNavigate, + }), + }; +}); + +describe('Staking Earnings', () => { + it('should render correctly', () => { + const { toJSON, getByText } = renderWithProvider(); + + expect(getByText(strings('stake.your_earnings'))).toBeDefined(); + expect(getByText(strings('stake.annual_rate'))).toBeDefined(); + expect(getByText(strings('stake.lifetime_rewards'))).toBeDefined(); + expect(getByText(strings('stake.estimated_annual_earnings'))).toBeDefined(); + expect(toJSON()).toMatchSnapshot(); + }); +}); diff --git a/app/components/UI/Stake/components/StakingEarnings/__snapshots__/StakingEarnings.test.tsx.snap b/app/components/UI/AssetOverview/StakingEarnings/__snapshots__/StakingEarnings.test.tsx.snap similarity index 98% rename from app/components/UI/Stake/components/StakingEarnings/__snapshots__/StakingEarnings.test.tsx.snap rename to app/components/UI/AssetOverview/StakingEarnings/__snapshots__/StakingEarnings.test.tsx.snap index 17f64f7622bb..3f9bd60d6774 100644 --- a/app/components/UI/Stake/components/StakingEarnings/__snapshots__/StakingEarnings.test.tsx.snap +++ b/app/components/UI/AssetOverview/StakingEarnings/__snapshots__/StakingEarnings.test.tsx.snap @@ -159,7 +159,7 @@ exports[`Staking Earnings should render correctly 1`] = ` } } > - $5000 + $2 - 2.5 ETH + 0.02151 ETH @@ -231,7 +231,7 @@ exports[`Staking Earnings should render correctly 1`] = ` } } > - $5000 + $15.93 - 2.5 ETH + 0.0131 ETH diff --git a/app/components/UI/AssetOverview/StakingEarnings/index.tsx b/app/components/UI/AssetOverview/StakingEarnings/index.tsx new file mode 100644 index 000000000000..d9538aaa50a8 --- /dev/null +++ b/app/components/UI/AssetOverview/StakingEarnings/index.tsx @@ -0,0 +1,123 @@ +import React from 'react'; +import { View } from 'react-native'; +import Text, { + TextColor, + TextVariant, +} from '../../../../component-library/components/Texts/Text'; +import { useStyles } from '../../../../component-library/hooks'; +import styleSheet from './StakingEarnings.styles'; +import { + IconColor, + IconName, +} from '../../../../component-library/components/Icons/Icon'; +import ButtonIcon, { + ButtonIconSizes, +} from '../../../../component-library/components/Buttons/ButtonIcon'; +import useTooltipModal from '../../../../components/hooks/useTooltipModal'; +import { strings } from '../../../../../locales/i18n'; +import { isPooledStakingFeatureEnabled } from '../../Stake/constants'; + +// TODO: Remove mock data when connecting component to backend. +const MOCK_DATA = { + ANNUAL_EARNING_RATE: '2.6%', + LIFETIME_REWARDS: { + FIAT: '$2', + ETH: '0.02151 ETH', + }, + EST_ANNUAL_EARNINGS: { + FIAT: '$15.93', + ETH: '0.0131 ETH', + }, +}; + +const StakingEarnings = () => { + // TODO: Remove mock data when connecting component to backend. + const { ANNUAL_EARNING_RATE, LIFETIME_REWARDS, EST_ANNUAL_EARNINGS } = + MOCK_DATA; + + const { styles } = useStyles(styleSheet, {}); + + const { openTooltipModal } = useTooltipModal(); + + const onNavigateToTooltipModal = () => + openTooltipModal( + strings('stake.annual_rate'), + strings('tooltip_modal.reward_rate.tooltip'), + ); + + if (!isPooledStakingFeatureEnabled()) return <>; + + return ( + + + {strings('stake.your_earnings')} + + + {/* Annual Rate */} + + + + {strings('stake.annual_rate')} + + + + + {ANNUAL_EARNING_RATE} + + + + + + {strings('stake.lifetime_rewards')} + + + + {LIFETIME_REWARDS.FIAT} + + {LIFETIME_REWARDS.ETH} + + + + + + + {strings('stake.estimated_annual_earnings')} + + + + {EST_ANNUAL_EARNINGS.FIAT} + + {EST_ANNUAL_EARNINGS.ETH} + + + + + + ); +}; + +export default StakingEarnings; diff --git a/app/components/UI/AssetOverview/TokenDetails/TokenDetails.tsx b/app/components/UI/AssetOverview/TokenDetails/TokenDetails.tsx index 368e2352d23b..8864c78c35ca 100644 --- a/app/components/UI/AssetOverview/TokenDetails/TokenDetails.tsx +++ b/app/components/UI/AssetOverview/TokenDetails/TokenDetails.tsx @@ -1,11 +1,11 @@ import { zeroAddress } from 'ethereumjs-util'; -import React from 'react'; +import React, { useState } from 'react'; import { View } from 'react-native'; import { useSelector } from 'react-redux'; import i18n from '../../../../../locales/i18n'; import { useStyles } from '../../../../component-library/hooks'; import styleSheet from './TokenDetails.styles'; -import { safeToChecksumAddress } from '../../../../util/address'; +import { formatAddress, safeToChecksumAddress } from '../../../../util/address'; import { selectTokenList } from '../../../../selectors/tokenListController'; import { selectContractExchangeRates } from '../../../../selectors/tokenRatesController'; import { @@ -21,8 +21,8 @@ import Logger from '../../../../util/Logger'; import TokenDetailsList from './TokenDetailsList'; import MarketDetailsList from './MarketDetailsList'; import { TokenI } from '../../Tokens/types'; +import StakingEarnings from '../StakingEarnings'; import { isPooledStakingFeatureEnabled } from '../../Stake/constants'; -import StakingEarnings from '../../Stake/components/StakingEarnings'; export interface TokenDetails { contractAddress: string | null; @@ -52,6 +52,9 @@ const TokenDetails: React.FC = ({ asset }) => { const currentCurrency = useSelector(selectCurrentCurrency); const tokenContractAddress = safeToChecksumAddress(asset.address); + // TEMP: Remove once component has been implemented. + const [hasStakingPositions] = useState(true); + let tokenMetadata; let marketData; @@ -72,12 +75,13 @@ const TokenDetails: React.FC = ({ asset }) => { const tokenDetails: TokenDetails = asset.isETH ? { - contractAddress: zeroAddress(), + contractAddress: formatAddress(zeroAddress(), 'short'), tokenDecimal: 18, tokenList: '', } : { - contractAddress: tokenContractAddress || null, + contractAddress: + formatAddress(tokenContractAddress as string, 'short') || null, tokenDecimal: tokenMetadata?.decimals || null, tokenList: tokenMetadata?.aggregators.join(', ') || null, }; @@ -123,7 +127,9 @@ const TokenDetails: React.FC = ({ asset }) => { return ( - {asset.isETH && isPooledStakingFeatureEnabled() && } + {asset.isETH && + hasStakingPositions && + isPooledStakingFeatureEnabled() && } {(asset.isETH || tokenMetadata) && ( )} diff --git a/app/components/UI/AssetOverview/TokenDetails/TokenDetailsList/TokenDetailsList.tsx b/app/components/UI/AssetOverview/TokenDetails/TokenDetailsList/TokenDetailsList.tsx index 7697440bfbdf..b218361c5ff9 100644 --- a/app/components/UI/AssetOverview/TokenDetails/TokenDetailsList/TokenDetailsList.tsx +++ b/app/components/UI/AssetOverview/TokenDetails/TokenDetailsList/TokenDetailsList.tsx @@ -17,7 +17,6 @@ import Icon, { import ClipboardManager from '../../../../../core/ClipboardManager'; import { TokenDetails } from '../TokenDetails'; import TokenDetailsListItem from '../TokenDetailsListItem'; -import { formatAddress } from '../../../../../util/address'; interface TokenDetailsListProps { tokenDetails: TokenDetails; @@ -63,7 +62,7 @@ const TokenDetailsList: React.FC = ({ onPress={copyAccountToClipboard} > - {formatAddress(tokenDetails.contractAddress, 'short')} + {tokenDetails.contractAddress} @@ -496,27 +485,16 @@ exports[`AssetOverview should render correctly 1`] = ` } > @@ -602,27 +580,16 @@ exports[`AssetOverview should render correctly 1`] = ` } > @@ -708,27 +675,16 @@ exports[`AssetOverview should render correctly 1`] = ` } > @@ -814,27 +770,16 @@ exports[`AssetOverview should render correctly 1`] = ` } > @@ -1115,7 +1060,6 @@ exports[`AssetOverview should render correctly 1`] = ` "textTransform": "uppercase", } } - testID="main-balance-test-id" > 0 ETH diff --git a/app/components/UI/BlockingActionModal/__snapshots__/index.test.tsx.snap b/app/components/UI/BlockingActionModal/__snapshots__/index.test.tsx.snap index 80fd1c281a96..757058bdf97f 100644 --- a/app/components/UI/BlockingActionModal/__snapshots__/index.test.tsx.snap +++ b/app/components/UI/BlockingActionModal/__snapshots__/index.test.tsx.snap @@ -1,23 +1,42 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`BlockingActionModal should render correctly 1`] = ` - - - + Please wait + + - - Please wait - - - + /> - + `; diff --git a/app/components/UI/BlockingActionModal/index.test.tsx b/app/components/UI/BlockingActionModal/index.test.tsx index c48dfcb4cc8e..bb386a795545 100644 --- a/app/components/UI/BlockingActionModal/index.test.tsx +++ b/app/components/UI/BlockingActionModal/index.test.tsx @@ -1,15 +1,15 @@ import React from 'react'; import { Text } from 'react-native'; -import { render, screen } from '@testing-library/react-native'; +import { shallow } from 'enzyme'; import BlockingActionModal from './'; describe('BlockingActionModal', () => { it('should render correctly', () => { - render( + const wrapper = shallow( {'Please wait'} , ); - expect(screen.toJSON()).toMatchSnapshot(); + expect(wrapper).toMatchSnapshot(); }); }); diff --git a/app/components/UI/BrowserBottomBar/index.js b/app/components/UI/BrowserBottomBar/index.js index 875bf6f93ac3..b005dfe0c150 100644 --- a/app/components/UI/BrowserBottomBar/index.js +++ b/app/components/UI/BrowserBottomBar/index.js @@ -11,7 +11,15 @@ import { MetaMetricsEvents } from '../../../core/Analytics'; import Device from '../../../util/device'; import { ThemeContext, mockTheme } from '../../../util/theme'; -import { BrowserViewSelectorsIDs } from '../../../../e2e/selectors/Browser/BrowserView.selectors'; +import generateTestId from '../../../../wdio/utils/generateTestId'; +import { + HOME_BUTTON, + TABS_BUTTON, + FORWARD_BUTTON, + BACK_BUTTON, + OPTIONS_BUTTON, + SEARCH_BUTTON, +} from '../../../../wdio/screen-objects/testIDs/BrowserScreen/BrowserScreen.testIds'; import { withMetricsAwareness } from '../../../components/hooks/useMetrics'; // NOTE: not needed anymore. The use of BottomTabBar already accomodates the home indicator height @@ -152,7 +160,7 @@ class BrowserBottomBar extends PureComponent { @@ -184,14 +192,14 @@ class BrowserBottomBar extends PureComponent { @@ -199,7 +207,7 @@ class BrowserBottomBar extends PureComponent { diff --git a/app/components/UI/CollectibleContracts/index.test.tsx b/app/components/UI/CollectibleContracts/index.test.tsx index 8ed9f29a8302..33b8adfd8361 100644 --- a/app/components/UI/CollectibleContracts/index.test.tsx +++ b/app/components/UI/CollectibleContracts/index.test.tsx @@ -99,7 +99,7 @@ describe('CollectibleContracts', () => { AccountsController: MOCK_ACCOUNTS_CONTROLLER_STATE, NftController: { allNfts: { - [MOCK_ADDRESS.toLowerCase()]: { + [MOCK_ADDRESS]: { '0x1': [ { address: '0x72b1FDb6443338A158DeC2FbF411B71aeB157A42', @@ -131,7 +131,7 @@ describe('CollectibleContracts', () => { }, }, allNftContracts: { - [MOCK_ADDRESS.toLowerCase()]: { + [MOCK_ADDRESS]: { '0x1': [ { address: '0x72b1FDb6443338A158DeC2FbF411B71aeB157A42', diff --git a/app/components/UI/DeleteWalletModal/index.tsx b/app/components/UI/DeleteWalletModal/index.tsx index 843fad7db961..fb518e737c15 100644 --- a/app/components/UI/DeleteWalletModal/index.tsx +++ b/app/components/UI/DeleteWalletModal/index.tsx @@ -21,7 +21,7 @@ import { tlc } from '../../../util/general'; import { useTheme } from '../../../util/theme'; import Device from '../../../util/device'; import Routes from '../../../constants/navigation/Routes'; -import { DeleteWalletModalSelectorsIDs } from '../../../../e2e/selectors/Settings/SecurityAndPrivacy/DeleteWalletModal.selectors'; +import { DeleteWalletModalSelectorsIDs } from '../../../../e2e/selectors/Modals/DeleteWalletModal.selectors'; import generateTestId from '../../../../wdio/utils/generateTestId'; import { MetaMetricsEvents } from '../../../core/Analytics'; import { useMetrics } from '../../../components/hooks/useMetrics'; diff --git a/app/components/UI/EditGasFee1559/__snapshots__/index.test.tsx.snap b/app/components/UI/EditGasFee1559/__snapshots__/index.test.tsx.snap index 9e57dc2ffc7b..23e9d694ce4f 100644 --- a/app/components/UI/EditGasFee1559/__snapshots__/index.test.tsx.snap +++ b/app/components/UI/EditGasFee1559/__snapshots__/index.test.tsx.snap @@ -47,7 +47,7 @@ exports[`EditGasFee1559 should render correctly 1`] = ` black={true} bold={true} > - + Edit priority - - { + const getAnalyticsParams = useCallback(() => { try { return { ...analyticsParams, @@ -214,9 +215,9 @@ const EditGasFee1559 = ({ } catch (error) { return {}; } - }; + }, [analyticsParams, chainId, selectedOption, view]); - const toggleAdvancedOptions = () => { + const toggleAdvancedOptions = useCallback(() => { if (!showAdvancedOptions) { trackEvent( MetaMetricsEvents.GAS_ADVANCED_OPTIONS_CLICKED, @@ -224,138 +225,158 @@ const EditGasFee1559 = ({ ); } setShowAdvancedOptions((showAdvancedOptions) => !showAdvancedOptions); - }; + }, [getAnalyticsParams, showAdvancedOptions, trackEvent]); - const toggleLearnMoreModal = () => { + const toggleLearnMoreModal = useCallback(() => { setShowLearnMoreModal((showLearnMoreModal) => !showLearnMoreModal); - }; + }, []); - const save = () => { + const save = useCallback(() => { trackEvent(MetaMetricsEvents.GAS_FEE_CHANGED, getAnalyticsParams()); onSave(selectedOption); - }; - - const changeGas = (gas, selectedOption) => { - setSelectedOption(selectedOption); - onChange(gas, selectedOption); - }; - - const changedMaxPriorityFee = (value) => { - const lowerValue = new BigNumber( - gasOptions?.[warningMinimumEstimateOption]?.suggestedMaxPriorityFeePerGas, - ); - const higherValue = new BigNumber( - gasOptions?.high?.suggestedMaxPriorityFeePerGas, - ).multipliedBy(new BigNumber(1.5)); - const updateFloor = new BigNumber(updateOption?.maxPriortyFeeThreshold); - - const valueBN = new BigNumber(value); - - if (updateFloor && !updateFloor.isNaN() && valueBN.lt(updateFloor)) { - setMaxPriorityFeeError( - updateOption?.isCancel - ? strings('edit_gas_fee_eip1559.max_priority_fee_cancel_low', { - cancel_value: updateFloor, - }) - : strings('edit_gas_fee_eip1559.max_priority_fee_speed_up_low', { - speed_up_floor_value: updateFloor, - }), - ); - } else if (!lowerValue.isNaN() && valueBN.lt(lowerValue)) { - setMaxPriorityFeeError( - strings('edit_gas_fee_eip1559.max_priority_fee_low'), - ); - } else if (!higherValue.isNaN() && valueBN.gt(higherValue)) { - setMaxPriorityFeeError( - strings('edit_gas_fee_eip1559.max_priority_fee_high'), + }, [getAnalyticsParams, onSave, selectedOption, trackEvent]); + + const changeGas = useCallback( + (gas, selectedOption) => { + setSelectedOption(selectedOption); + onChange(gas, selectedOption); + }, + [onChange], + ); + + const changedMaxPriorityFee = useCallback( + (value) => { + const lowerValue = new BigNumber( + gasOptions?.[ + warningMinimumEstimateOption + ]?.suggestedMaxPriorityFeePerGas, ); - } else { - setMaxPriorityFeeError(''); - } + const higherValue = new BigNumber( + gasOptions?.high?.suggestedMaxPriorityFeePerGas, + ).multipliedBy(new BigNumber(1.5)); + const updateFloor = new BigNumber(updateOption?.maxPriortyFeeThreshold); + + const valueBN = new BigNumber(value); + + if (updateFloor && !updateFloor.isNaN() && valueBN.lt(updateFloor)) { + setMaxPriorityFeeError( + updateOption?.isCancel + ? strings('edit_gas_fee_eip1559.max_priority_fee_cancel_low', { + cancel_value: updateFloor, + }) + : strings('edit_gas_fee_eip1559.max_priority_fee_speed_up_low', { + speed_up_floor_value: updateFloor, + }), + ); + } else if (!lowerValue.isNaN() && valueBN.lt(lowerValue)) { + setMaxPriorityFeeError( + strings('edit_gas_fee_eip1559.max_priority_fee_low'), + ); + } else if (!higherValue.isNaN() && valueBN.gt(higherValue)) { + setMaxPriorityFeeError( + strings('edit_gas_fee_eip1559.max_priority_fee_high'), + ); + } else { + setMaxPriorityFeeError(''); + } + + const newGas = { ...gasFee, suggestedMaxPriorityFeePerGas: value }; + + changeGas(newGas, null); + }, + [changeGas, gasFee, gasOptions, updateOption, warningMinimumEstimateOption], + ); - const newGas = { ...gasFee, suggestedMaxPriorityFeePerGas: value }; - - changeGas(newGas, null); - }; - - const changedMaxFeePerGas = (value) => { - const lowerValue = new BigNumber( - gasOptions?.[warningMinimumEstimateOption]?.suggestedMaxFeePerGas, - ); - const higherValue = new BigNumber( - gasOptions?.high?.suggestedMaxFeePerGas, - ).multipliedBy(new BigNumber(1.5)); - const updateFloor = new BigNumber(updateOption?.maxFeeThreshold); - - const valueBN = new BigNumber(value); - - if (updateFloor && !updateFloor.isNaN() && valueBN.lt(updateFloor)) { - setMaxFeeError( - updateOption?.isCancel - ? strings('edit_gas_fee_eip1559.max_fee_cancel_low', { - cancel_value: updateFloor, - }) - : strings('edit_gas_fee_eip1559.max_fee_speed_up_low', { - speed_up_floor_value: updateFloor, - }), + const changedMaxFeePerGas = useCallback( + (value) => { + const lowerValue = new BigNumber( + gasOptions?.[warningMinimumEstimateOption]?.suggestedMaxFeePerGas, ); - } else if (!lowerValue.isNaN() && valueBN.lt(lowerValue)) { - setMaxFeeError(strings('edit_gas_fee_eip1559.max_fee_low')); - } else if (!higherValue.isNaN() && valueBN.gt(higherValue)) { - setMaxFeeError(strings('edit_gas_fee_eip1559.max_fee_high')); - } else { + const higherValue = new BigNumber( + gasOptions?.high?.suggestedMaxFeePerGas, + ).multipliedBy(new BigNumber(1.5)); + const updateFloor = new BigNumber(updateOption?.maxFeeThreshold); + + const valueBN = new BigNumber(value); + + if (updateFloor && !updateFloor.isNaN() && valueBN.lt(updateFloor)) { + setMaxFeeError( + updateOption?.isCancel + ? strings('edit_gas_fee_eip1559.max_fee_cancel_low', { + cancel_value: updateFloor, + }) + : strings('edit_gas_fee_eip1559.max_fee_speed_up_low', { + speed_up_floor_value: updateFloor, + }), + ); + } else if (!lowerValue.isNaN() && valueBN.lt(lowerValue)) { + setMaxFeeError(strings('edit_gas_fee_eip1559.max_fee_low')); + } else if (!higherValue.isNaN() && valueBN.gt(higherValue)) { + setMaxFeeError(strings('edit_gas_fee_eip1559.max_fee_high')); + } else { + setMaxFeeError(''); + } + + const newGas = { ...gasFee, suggestedMaxFeePerGas: value }; + changeGas(newGas, null); + }, + [changeGas, gasFee, gasOptions, updateOption, warningMinimumEstimateOption], + ); + + const changedGasLimit = useCallback( + (value) => { + const newGas = { ...gasFee, suggestedGasLimit: value }; + changeGas(newGas, null); + }, + [changeGas, gasFee], + ); + + const selectOption = useCallback( + (option) => { + setSelectedOption(option); setMaxFeeError(''); - } + setMaxPriorityFeeError(''); + changeGas({ ...gasOptions[option] }, option); + }, + [changeGas, gasOptions], + ); - const newGas = { ...gasFee, suggestedMaxFeePerGas: value }; - changeGas(newGas, null); - }; - - const changedGasLimit = (value) => { - const newGas = { ...gasFee, suggestedGasLimit: value }; - changeGas(newGas, null); - }; - - const selectOption = (option) => { - setSelectedOption(option); - setMaxFeeError(''); - setMaxPriorityFeeError(''); - changeGas({ ...gasOptions[option] }, option); - }; - - const shouldIgnore = (option) => - ignoreOptions.find((item) => item === option); - - const renderLabel = (selected, disabled, label) => ( - - {label} - + const shouldIgnore = useCallback( + (option) => ignoreOptions.find((item) => item === option), + [ignoreOptions], ); - const renderOptions = () => - [ - { - name: AppConstants.GAS_OPTIONS.LOW, - label: strings('edit_gas_fee_eip1559.low'), - }, - { - name: AppConstants.GAS_OPTIONS.MEDIUM, - label: strings('edit_gas_fee_eip1559.market'), - }, - { - name: AppConstants.GAS_OPTIONS.HIGH, - label: strings('edit_gas_fee_eip1559.aggressive'), - }, - ] - .filter(({ name }) => !shouldIgnore(name)) - .map(({ name, label, ...option }) => ({ - name, - label: renderLabel(selectedOption === name, false, label), - topLabel: recommended?.name === name && recommended.render, - ...option, - ...extendOptions[name], - })); + const renderOptions = useMemo( + () => + [ + { + name: AppConstants.GAS_OPTIONS.LOW, + label: strings('edit_gas_fee_eip1559.low'), + }, + { + name: AppConstants.GAS_OPTIONS.MEDIUM, + label: strings('edit_gas_fee_eip1559.market'), + }, + { + name: AppConstants.GAS_OPTIONS.HIGH, + label: strings('edit_gas_fee_eip1559.aggressive'), + }, + ] + .filter(({ name }) => !shouldIgnore(name)) + .map(({ name, label, ...option }) => ({ + name, + label: (selected, disabled) => ( + + {label} + + ), + topLabel: recommended?.name === name && recommended.render, + ...option, + ...extendOptions[name], + })), + [recommended, extendOptions, shouldIgnore], + ); const isMainnet = isMainnetByChainId(chainId); const nativeCurrencySelected = primaryCurrency === 'ETH' || !isMainnet; @@ -558,7 +579,7 @@ const EditGasFee1559 = ({ ); - const renderWarning = () => { + const renderWarning = useMemo(() => { if (!warning) return null; if (typeof warning === 'string') return ( @@ -585,9 +606,9 @@ const EditGasFee1559 = ({ ); return warning; - }; + }, [warning, styles, colors]); - const renderError = () => { + const renderError = useMemo(() => { if (!error) return null; if (typeof error === 'string') return ( @@ -614,15 +635,15 @@ const EditGasFee1559 = ({ ); return error; - }; + }, [error, styles, colors]); - const renderDisplayTitle = () => { + const renderDisplayTitle = useMemo(() => { if (updateOption) return updateOption.isCancel ? strings('edit_gas_fee_eip1559.cancel_transaction') : strings('edit_gas_fee_eip1559.speed_up_transaction'); return strings('edit_gas_fee_eip1559.edit_priority'); - }; + }, [updateOption]); return ( diff --git a/app/components/UI/EditGasFeeLegacy/__snapshots__/index.test.tsx.snap b/app/components/UI/EditGasFeeLegacy/__snapshots__/index.test.tsx.snap index b64630444d75..2925ad35a5c8 100644 --- a/app/components/UI/EditGasFeeLegacy/__snapshots__/index.test.tsx.snap +++ b/app/components/UI/EditGasFeeLegacy/__snapshots__/index.test.tsx.snap @@ -57,8 +57,6 @@ exports[`EditGasFeeLegacy should render correctly 1`] = ` /> - - { + const getAnalyticsParams = useCallback(() => { try { return { ...analyticsParams, @@ -163,9 +163,9 @@ const EditGasFeeLegacy = ({ } catch (error) { return {}; } - }; + }, [analyticsParams, chainId, selectedOption, view]); - const toggleAdvancedOptions = () => { + const toggleAdvancedOptions = useCallback(() => { if (!showAdvancedOptions) { trackEvent( MetaMetricsEvents.GAS_ADVANCED_OPTIONS_CLICKED, @@ -173,92 +173,113 @@ const EditGasFeeLegacy = ({ ); } setShowAdvancedOptions((showAdvancedOptions) => !showAdvancedOptions); - }; + }, [getAnalyticsParams, showAdvancedOptions, trackEvent]); - const save = () => { + const save = useCallback(() => { trackEvent(MetaMetricsEvents.GAS_FEE_CHANGED, getAnalyticsParams()); onSave(selectedOption); - }; + }, [getAnalyticsParams, onSave, selectedOption, trackEvent]); - const changeGas = (gas, selectedOption) => { - setSelectedOption(selectedOption); - onChange(gas, selectedOption); - }; - - const changedGasPrice = (value) => { - const lowerValue = new BigNumber( - gasEstimateType === GAS_ESTIMATE_TYPES.LEGACY - ? gasOptions?.[warningMinimumEstimateOption] - : gasOptions?.gasPrice, - ); - const higherValue = new BigNumber( - gasEstimateType === GAS_ESTIMATE_TYPES.LEGACY - ? gasOptions?.high - : gasOptions?.gasPrice, - ).multipliedBy(new BigNumber(1.5)); + const changeGas = useCallback( + (gas, selectedOption) => { + setSelectedOption(selectedOption); + onChange(gas, selectedOption); + }, + [onChange], + ); - const valueBN = new BigNumber(value); + const changedGasPrice = useCallback( + (value) => { + const lowerValue = new BigNumber( + gasEstimateType === GAS_ESTIMATE_TYPES.LEGACY + ? gasOptions?.[warningMinimumEstimateOption] + : gasOptions?.gasPrice, + ); + const higherValue = new BigNumber( + gasEstimateType === GAS_ESTIMATE_TYPES.LEGACY + ? gasOptions?.high + : gasOptions?.gasPrice, + ).multipliedBy(new BigNumber(1.5)); - if (!lowerValue.isNaN() && valueBN.lt(lowerValue)) { - setGasPriceError(strings('edit_gas_fee_eip1559.gas_price_low')); - } else if (!higherValue.isNaN() && valueBN.gt(higherValue)) { - setGasPriceError(strings('edit_gas_fee_eip1559.gas_price_high')); - } else { - setGasPriceError(''); - } + const valueBN = new BigNumber(value); - const newGas = { ...gasFee, suggestedGasPrice: value }; + if (!lowerValue.isNaN() && valueBN.lt(lowerValue)) { + setGasPriceError(strings('edit_gas_fee_eip1559.gas_price_low')); + } else if (!higherValue.isNaN() && valueBN.gt(higherValue)) { + setGasPriceError(strings('edit_gas_fee_eip1559.gas_price_high')); + } else { + setGasPriceError(''); + } - changeGas(newGas, null); - }; + const newGas = { ...gasFee, suggestedGasPrice: value }; - const changedGasLimit = (value) => { - const newGas = { ...gasFee, suggestedGasLimit: value }; + changeGas(newGas, null); + }, + [ + changeGas, + gasEstimateType, + gasFee, + gasOptions, + warningMinimumEstimateOption, + ], + ); - changeGas(newGas, null); - }; + const changedGasLimit = useCallback( + (value) => { + const newGas = { ...gasFee, suggestedGasLimit: value }; - const selectOption = (option) => { - setGasPriceError(''); - setSelectedOption(option); - changeGas({ ...gasFee, suggestedGasPrice: gasOptions[option] }, option); - }; + changeGas(newGas, null); + }, + [changeGas, gasFee], + ); - const shouldIgnore = (option) => - ignoreOptions.find((item) => item === option); + const selectOption = useCallback( + (option) => { + setGasPriceError(''); + setSelectedOption(option); + changeGas({ ...gasFee, suggestedGasPrice: gasOptions[option] }, option); + }, + [changeGas, gasFee, gasOptions], + ); - const renderLabel = (selected, disabled, label) => ( - - {label} - + const shouldIgnore = useCallback( + (option) => ignoreOptions.find((item) => item === option), + [ignoreOptions], ); - const renderOptions = () => - [ - { - name: AppConstants.GAS_OPTIONS.LOW, - label: strings('edit_gas_fee_eip1559.low'), - }, - { - name: AppConstants.GAS_OPTIONS.MEDIUM, - label: strings('edit_gas_fee_eip1559.medium'), - }, - { - name: AppConstants.GAS_OPTIONS.HIGH, - label: strings('edit_gas_fee_eip1559.high'), - }, - ] - .filter(({ name }) => !shouldIgnore(name)) - .map(({ name, label, ...option }) => ({ - name, - label: renderLabel(selectedOption === name, false, label), - topLabel: recommended?.name === name && recommended.render, - ...option, - ...extendOptions[name], - })); + const renderOptions = useMemo( + () => + [ + { + name: AppConstants.GAS_OPTIONS.LOW, + label: strings('edit_gas_fee_eip1559.low'), + }, + { + name: AppConstants.GAS_OPTIONS.MEDIUM, + label: strings('edit_gas_fee_eip1559.medium'), + }, + { + name: AppConstants.GAS_OPTIONS.HIGH, + label: strings('edit_gas_fee_eip1559.high'), + }, + ] + .filter(({ name }) => !shouldIgnore(name)) + .map(({ name, label, ...option }) => ({ + name, + label: (selected, disabled) => ( + + {label} + + ), + topLabel: recommended?.name === name && recommended.render, + ...option, + ...extendOptions[name], + })), + [recommended, extendOptions, shouldIgnore], + ); - const renderWarning = () => { + const renderWarning = useMemo(() => { if (!warning) return null; if (typeof warning === 'string') return ( @@ -285,9 +306,9 @@ const EditGasFeeLegacy = ({ ); return warning; - }; + }, [warning, styles, colors]); - const renderError = () => { + const renderError = useMemo(() => { if (!error) return null; if (typeof error === 'string') return ( @@ -314,7 +335,7 @@ const EditGasFeeLegacy = ({ ); return error; - }; + }, [error, styles, colors]); const isMainnet = isMainnetByChainId(chainId); const nativeCurrencySelected = primaryCurrency === 'ETH' || !isMainnet; diff --git a/app/components/UI/EnableAutomaticSecurityChecksModal/EnableAutomaticSecurityChecksModal.tsx b/app/components/UI/EnableAutomaticSecurityChecksModal/EnableAutomaticSecurityChecksModal.tsx index e729f72f7e1c..8f88277cc406 100644 --- a/app/components/UI/EnableAutomaticSecurityChecksModal/EnableAutomaticSecurityChecksModal.tsx +++ b/app/components/UI/EnableAutomaticSecurityChecksModal/EnableAutomaticSecurityChecksModal.tsx @@ -1,5 +1,5 @@ import React, { useCallback, useEffect, useRef } from 'react'; -import { View, Image } from 'react-native'; +import { View, Image, Platform } from 'react-native'; import { createStyles } from './styles'; import { strings } from '../../../../locales/i18n'; import Text, { @@ -23,7 +23,12 @@ import { import { MetaMetricsEvents } from '../../../core/Analytics'; import { ScrollView } from 'react-native-gesture-handler'; -import { EnableAutomaticSecurityChecksIDs } from '../../../../e2e/selectors/Modals/EnableAutomaticSecurityChecks.selectors'; +import { + ENABLE_AUTOMATIC_SECURITY_CHECK_CONTAINER_ID, + ENABLE_AUTOMATIC_SECURITY_CHECK_NO_THANKS_BUTTON_ID, +} from '../../../../wdio/screen-objects/testIDs/Screens/EnableAutomaticSecurityChecksScreen.testIds'; + +import generateTestId from '../../../../wdio/utils/generateTestId'; import generateDeviceAnalyticsMetaData from '../../../util/metrics'; import { useMetrics } from '../../../components/hooks/useMetrics'; @@ -87,7 +92,10 @@ const EnableAutomaticSecurityChecksModal = () => { @@ -114,7 +122,10 @@ const EnableAutomaticSecurityChecksModal = () => { label={strings( 'enable_automatic_security_check_modal.secondary_action', )} - testID={EnableAutomaticSecurityChecksIDs.NO_THANKS_BUTTON} + {...generateTestId( + Platform, + ENABLE_AUTOMATIC_SECURITY_CHECK_NO_THANKS_BUTTON_ID, + )} size={ButtonSize.Md} onPress={triggerCloseAndDisableAutomaticSecurityChecks} /> diff --git a/app/components/UI/ManageNetworks/ManageNetworks.tsx b/app/components/UI/ManageNetworks/ManageNetworks.tsx index 56fed1d3a22c..e5ac44ab8ead 100644 --- a/app/components/UI/ManageNetworks/ManageNetworks.tsx +++ b/app/components/UI/ManageNetworks/ManageNetworks.tsx @@ -20,7 +20,7 @@ import Routes from '../../../constants/navigation/Routes'; import getDecimalChainId from '../../../util/networks/getDecimalChainId'; import { useMetrics } from '../../../components/hooks/useMetrics'; import { MetaMetricsEvents } from '../../../core/Analytics'; -import { ConnectedAccountsSelectorsIDs } from '../../../../e2e/selectors/Browser/ConnectedAccountModal.selectors'; +import { ConnectedAccountsSelectorsIDs } from '../../../../e2e/selectors/Modals/ConnectedAccountModal.selectors'; import AppConstants from '../../../core/AppConstants'; import styles from './ManageNetworks.styles'; diff --git a/app/components/UI/ManageNetworks/__snapshots__/ManageNetworks.test.js.snap b/app/components/UI/ManageNetworks/__snapshots__/ManageNetworks.test.js.snap index 4d89a9523493..d86999527a36 100644 --- a/app/components/UI/ManageNetworks/__snapshots__/ManageNetworks.test.js.snap +++ b/app/components/UI/ManageNetworks/__snapshots__/ManageNetworks.test.js.snap @@ -84,38 +84,34 @@ exports[`ManageNetworks should render correctly 1`] = ` testID="accounts-connected-network-picker" > - - - E - - + E + { MetaMetrics.getInstance().trackEvent(event, params); @@ -360,7 +361,7 @@ export function getPaymentRequestOptionsTitle( navigation.pop()} style={styles.backButton} - testID={CommonSelectorsIDs.BACK_ARROW_BUTTON} + testID={ImportTokenViewSelectorsIDs.BACK_BUTTON} > navigation.pop()} style={styles.backButton} - testID={CommonSelectorsIDs.BACK_ARROW_BUTTON} + testID={ImportTokenViewSelectorsIDs.BACK_BUTTON} > ( - - {title} - + {title} ), headerStyle: innerStyles.headerStyle, headerLeft: () => @@ -1872,9 +1868,7 @@ export function getStakingNavbar(title, navigation, themeColors, options) { onPress={navigationPop} style={innerStyles.headerLeft} /> - ) : ( - <> - ), + ) : null, headerRight: () => hasCancelButton ? ( - ) : ( - <> - ), + ) : null, }; } diff --git a/app/components/UI/NetworkInfo/index.tsx b/app/components/UI/NetworkInfo/index.tsx index bc1a39f8f785..c4a55151b232 100644 --- a/app/components/UI/NetworkInfo/index.tsx +++ b/app/components/UI/NetworkInfo/index.tsx @@ -19,7 +19,7 @@ import { selectUseTokenDetection } from '../../../selectors/preferencesControlle import Avatar, { AvatarVariant, } from '../../../component-library/components/Avatars/Avatar'; -import { NetworkEducationModalSelectorsIDs } from '../../../../e2e/selectors/Network/NetworkEducationModal.selectors'; +import { NetworkEducationModalSelectorsIDs } from '../../../../e2e/selectors/Modals/NetworkEducationModal.selectors'; const createStyles = (colors: { background: { default: string }; diff --git a/app/components/UI/NetworkModal/NetworkAdded/index.tsx b/app/components/UI/NetworkModal/NetworkAdded/index.tsx index 299781879c20..d4dc06b8dc68 100644 --- a/app/components/UI/NetworkModal/NetworkAdded/index.tsx +++ b/app/components/UI/NetworkModal/NetworkAdded/index.tsx @@ -4,7 +4,7 @@ import StyledButton from '../../StyledButton'; import { strings } from '../../../../../locales/i18n'; import Text from '../../../Base/Text'; import { useTheme } from '../../../../util/theme'; -import { NetworkAddedBottomSheetSelectorsIDs } from '../../../../../e2e/selectors/Network/NetworkAddedBottomSheet.selectors'; +import { NetworkAddedModalSelectorsIDs } from '../../../../../e2e/selectors/Modals/NetworkAddedModal.selectors'; // TODO: Replace "any" with type // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -57,7 +57,7 @@ const NetworkAdded = (props: NetworkAddedProps) => { @@ -66,7 +66,7 @@ const NetworkAdded = (props: NetworkAddedProps) => { {strings('networks.switch_network')} diff --git a/app/components/UI/NetworkModal/NetworkDetails/index.tsx b/app/components/UI/NetworkModal/NetworkDetails/index.tsx index cc9ab3c5e66c..9cbd21cb0535 100644 --- a/app/components/UI/NetworkModal/NetworkDetails/index.tsx +++ b/app/components/UI/NetworkModal/NetworkDetails/index.tsx @@ -60,7 +60,7 @@ const NetworkDetails = (props: NetworkDetailsProps) => { }, ]; - const renderDetailsView = () => ( + const DetailsView = () => ( <> {DisplayData.map((item, index) => ( @@ -79,7 +79,9 @@ const NetworkDetails = (props: NetworkDetailsProps) => { action={goBack} title={strings('networks.network_details')} /> - {renderDetailsView()} + + + ); }; diff --git a/app/components/UI/NetworkModal/__snapshots__/index.test.tsx.snap b/app/components/UI/NetworkModal/__snapshots__/index.test.tsx.snap index 8099909473bd..5352aa688998 100644 --- a/app/components/UI/NetworkModal/__snapshots__/index.test.tsx.snap +++ b/app/components/UI/NetworkModal/__snapshots__/index.test.tsx.snap @@ -230,38 +230,34 @@ exports[`NetworkDetails renders correctly 1`] = ` } > - - - T - - + T + { label: strings('accountApproval.cancel'), size: ButtonSize.Lg, onPress: showCheckNetworkModal, - testID: NetworkApprovalBottomSheetSelectorsIDs.CANCEL_BUTTON, + testID: NetworkApprovalModalSelectorsIDs.CANCEL_BUTTON, }; const confirmButtonProps: ButtonProps = { @@ -161,7 +161,7 @@ const NetworkModals = (props: NetworkProps) => { toggleUseSafeChainsListValidation(true); showCheckNetworkModal(); }, - testID: NetworkApprovalBottomSheetSelectorsIDs.CONFIRM_NETWORK_CHECK, + testID: NetworkApprovalModalSelectorsIDs.CONFIRM_NETWORK_CHECK, }; const useSafeChainsListValidation = useSelector( diff --git a/app/components/UI/NetworkSelectorList/NetworkSelectorList.styles.ts b/app/components/UI/NetworkSelectorList/NetworkSelectorList.styles.ts index e279b943357f..133a87f969d5 100644 --- a/app/components/UI/NetworkSelectorList/NetworkSelectorList.styles.ts +++ b/app/components/UI/NetworkSelectorList/NetworkSelectorList.styles.ts @@ -3,8 +3,9 @@ import { StyleSheet } from 'react-native'; const styleSheet = () => StyleSheet.create({ networkItemContainer: { - paddingHorizontal: 10, - paddingVertical: 14, + flexDirection: 'row', + alignItems: 'center', + padding: 10, }, networkAvatar: { marginHorizontal: 10, diff --git a/app/components/UI/NetworkSelectorList/NetworkSelectorList.tsx b/app/components/UI/NetworkSelectorList/NetworkSelectorList.tsx index 152348b85739..59fd85ddfefe 100644 --- a/app/components/UI/NetworkSelectorList/NetworkSelectorList.tsx +++ b/app/components/UI/NetworkSelectorList/NetworkSelectorList.tsx @@ -24,7 +24,7 @@ const NetworkSelectorList = ({ onSelectNetwork, networks = [], isLoading = false, - selectedChainIds, + selectedNetworkIds, isMultiSelect = true, renderRightAccessory, isSelectionDisabled, @@ -33,6 +33,7 @@ const NetworkSelectorList = ({ }: NetworkConnectMultiSelectorProps) => { const networksLengthRef = useRef(0); const { styles } = useStyles(styleSheet, {}); + /** * Ref for the FlatList component. * The type of the ref is not explicitly defined. @@ -50,8 +51,8 @@ const NetworkSelectorList = ({ ? CellVariant.MultiSelect : CellVariant.Select; let isSelectedNetwork = isSelected; - if (selectedChainIds) { - isSelectedNetwork = selectedChainIds.includes(id); + if (selectedNetworkIds) { + isSelectedNetwork = selectedNetworkIds.includes(id); } return ( @@ -75,7 +76,7 @@ const NetworkSelectorList = ({ }, [ isLoading, - selectedChainIds, + selectedNetworkIds, renderRightAccessory, isSelectionDisabled, onSelectNetwork, diff --git a/app/components/UI/NetworkSelectorList/NetworkSelectorList.types.ts b/app/components/UI/NetworkSelectorList/NetworkSelectorList.types.ts index 48b3bd6ab07a..ebc0e3b4d6c5 100644 --- a/app/components/UI/NetworkSelectorList/NetworkSelectorList.types.ts +++ b/app/components/UI/NetworkSelectorList/NetworkSelectorList.types.ts @@ -12,7 +12,7 @@ export interface NetworkConnectMultiSelectorProps { onSelectNetwork?: (id: string, isSelected: boolean) => void; networks?: Network[]; isLoading?: boolean; - selectedChainIds?: string[]; + selectedNetworkIds?: string[]; isMultiSelect?: boolean; renderRightAccessory?: (id: string, name: string) => React.ReactNode; isSelectionDisabled?: boolean; diff --git a/app/components/UI/NetworkVerificationInfo/NetworkVerificationInfo.tsx b/app/components/UI/NetworkVerificationInfo/NetworkVerificationInfo.tsx index 96761b376894..569f0c3fefcd 100644 --- a/app/components/UI/NetworkVerificationInfo/NetworkVerificationInfo.tsx +++ b/app/components/UI/NetworkVerificationInfo/NetworkVerificationInfo.tsx @@ -40,7 +40,7 @@ import { toggleUseSafeChainsListValidation, isMultichainVersion1Enabled, } from '../../../util/networks'; -import { NetworkApprovalBottomSheetSelectorsIDs } from '../../../../e2e/selectors/Network/NetworkApprovalBottomSheet.selectors'; +import { NetworkApprovalModalSelectorsIDs } from '../../../../e2e/selectors/Modals/NetworkApprovalModal.selectors'; import hideKeyFromUrl from '../../../util/hideKeyFromUrl'; import { convertHexToDecimal } from '@metamask/controller-utils'; @@ -100,20 +100,6 @@ const NetworkVerificationInfo = ({ [customNetworkInformation], ); - const dappOrigin = useMemo(() => { - // @ts-expect-error - The CustomNetworkInformation type is missing the pageMeta property - const customNetworkUrl = customNetworkInformation.pageMeta?.url; - const url = customNetworkUrl ? new URL(customNetworkUrl) : null; - if (url) { - try { - return url.hostname; - } catch (error) { - console.error('Invalid URL:', error); - } - } - return 'Undefined dapp origin'; - }, [customNetworkInformation]); - const renderCurrencySymbol = () => ( <> ) : ( - + {isCustomNetwork @@ -451,7 +437,9 @@ const NetworkVerificationInfo = ({ {strings( 'switch_custom_network.add_network_and_give_dapp_permission_warning', { - dapp_origin: dappOrigin, + // @ts-expect-error let's adjust the CustomNetworkInformation after multichain controllers have been updated by the api team + dapp_origin: new URL(customNetworkInformation.pageMeta.url) + ?.hostname, }, )} @@ -473,14 +461,14 @@ const NetworkVerificationInfo = ({ label: strings('confirmation_modal.cancel_cta'), variant: ButtonVariants.Secondary, size: ButtonSize.Lg, - testID: NetworkApprovalBottomSheetSelectorsIDs.CANCEL_BUTTON, + testID: NetworkApprovalModalSelectorsIDs.CANCEL_BUTTON, }, { onPress: onConfirm, label: strings('confirmation_modal.confirm_cta'), variant: ButtonVariants.Primary, size: ButtonSize.Lg, - testID: NetworkApprovalBottomSheetSelectorsIDs.APPROVE_BUTTON, + testID: NetworkApprovalModalSelectorsIDs.APPROVE_BUTTON, }, ]} buttonsAlignment={ButtonsAlignment.Horizontal} diff --git a/app/components/UI/NetworkVerificationInfo/__snapshots__/NetworkVerificationInfo.test.tsx.snap b/app/components/UI/NetworkVerificationInfo/__snapshots__/NetworkVerificationInfo.test.tsx.snap index bbcf6abbafdf..6126b24708fc 100644 --- a/app/components/UI/NetworkVerificationInfo/__snapshots__/NetworkVerificationInfo.test.tsx.snap +++ b/app/components/UI/NetworkVerificationInfo/__snapshots__/NetworkVerificationInfo.test.tsx.snap @@ -91,40 +91,36 @@ exports[`NetworkVerificationInfo renders correctly 1`] = ` } > - - - + testID="network-avatar-image" + /> - - - - - - -  - - - - - - - Testing Title - - - Testing description - - - - - - -`; - -exports[`BaseNotification gets icon correctly for each status 2`] = ` - - - - - - - -  - - - - - - - Testing Title - - - Testing description - - - - - - -`; - -exports[`BaseNotification gets icon correctly for each status 3`] = ` - - - - - - - -  - - - - - - - Testing Title - - - Testing description - - - - - - -`; - -exports[`BaseNotification gets icon correctly for each status 4`] = ` - - - - - -  - - - - - Testing Title - - - Testing description - - - - - - -`; - -exports[`BaseNotification gets icon correctly for each status 5`] = ` - - - - - -  - - - - - Testing Title - - - Testing description - - - - - - -`; - -exports[`BaseNotification gets icon correctly for each status 6`] = ` - - - - - -  - - - - - Testing Title - - - Testing description - - - - - - -`; - -exports[`BaseNotification gets icon correctly for each status 7`] = ` - - - - - -  - - - - - Testing Title - - - Testing description - - - - - - -`; - -exports[`BaseNotification gets icon correctly for each status 8`] = ` - - - - - -  - - - - - Testing Title - - - Testing description - - - - - - -`; - -exports[`BaseNotification gets icon correctly for each status 9`] = ` - - - - - -  - - - - - Testing Title - - - Testing description - - - - - - -`; - -exports[`BaseNotification gets icon correctly for each status 10`] = ` - - - - - -  - - - - - Testing Title - - - Testing description - - - - - - -`; diff --git a/app/components/UI/Notification/BaseNotification/index.js b/app/components/UI/Notification/BaseNotification/index.js index 79b1a7dfc2e1..96a11304d75c 100644 --- a/app/components/UI/Notification/BaseNotification/index.js +++ b/app/components/UI/Notification/BaseNotification/index.js @@ -72,7 +72,6 @@ export const getIcon = (status, colors, styles) => { case 'success': case 'received': case 'received_payment': - case 'eth_received': return ( { return strings('notifications.cancelled_title'); case 'error': return strings('notifications.error_title'); - case 'eth_received': - return strings('notifications.eth_received_title'); } }; -export const getDescription = (status, { amount = null, type = null }) => { - if (amount && typeof amount !== 'object') { - return strings(`notifications.${type}_${status}_message`, { amount }); +const getDescription = (status, { amount = null }) => { + if (amount) { + return strings(`notifications.${status}_message`, { amount }); } return strings(`notifications.${status}_message`); }; diff --git a/app/components/UI/Notification/BaseNotification/index.test.jsx b/app/components/UI/Notification/BaseNotification/index.test.jsx deleted file mode 100644 index 11cb5aa6a17c..000000000000 --- a/app/components/UI/Notification/BaseNotification/index.test.jsx +++ /dev/null @@ -1,47 +0,0 @@ -import React from 'react'; -import BaseNotification, { getDescription } from './'; -import renderWithProvider from '../../../../util/test/renderWithProvider'; -import { strings } from '../../../../../locales/i18n'; - -const defaultProps = [ - { status: 'pending', data: { description: 'Testing description', title: 'Testing Title' } }, - { status: 'pending_withdrawal', data: { description: 'Testing description', title: 'Testing Title' } }, - { status: 'pending_deposit', data: { description: 'Testing description', title: 'Testing Title' } }, - { status: 'success_deposit', data: { description: 'Testing description', title: 'Testing Title' } }, - { status: 'success_withdrawal', data: { description: 'Testing description', title: 'Testing Title' } }, - { status: 'received', data: { description: 'Testing description', title: 'Testing Title' } }, - { status: 'received_payment', data: { description: 'Testing description', title: 'Testing Title' } }, - { status: 'eth_received', data: { description: 'Testing description', title: 'Testing Title' } }, - { status: 'cancelled', data: { description: 'Testing description', title: 'Testing Title' } }, - { status: 'error', data: { description: 'Testing description', title: 'Testing Title' } }, - ]; - -describe('BaseNotification', () => { - it('gets icon correctly for each status', () => { - defaultProps.forEach(({ status, data}) => { - const { toJSON } = renderWithProvider(); - expect(toJSON()).toMatchSnapshot(); - }); - }); - - it('gets titles correctly for each status', () => { - defaultProps.forEach(({ status }) => { - const { getByText } = renderWithProvider(); - expect(getByText(strings(`notifications.${status}_title`))).toBeTruthy(); - }); - }); - - it('gets descriptions correctly for if they are provided', () => { - defaultProps.forEach(({ status, data }) => { - const { getByText } = renderWithProvider(); - expect(getByText(data.description)).toBeTruthy(); - }); - }); - - it('constructs the correct description using getDescription when no description is provided', () => { - defaultProps.forEach(({ status }) => { - const { getByText } = renderWithProvider(); - expect(getByText(getDescription(status, {}))).toBeTruthy(); - }); - }); -}); diff --git a/app/components/UI/Notification/List/__snapshots__/index.test.tsx.snap b/app/components/UI/Notification/List/__snapshots__/index.test.tsx.snap index 6109381f4d0f..3d46759d65b0 100644 --- a/app/components/UI/Notification/List/__snapshots__/index.test.tsx.snap +++ b/app/components/UI/Notification/List/__snapshots__/index.test.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`NotificationsList renders correctly 1`] = ` +exports[`NotificationsList should render correctly 1`] = ` `; - -exports[`NotificationsList renders empty state 1`] = ` - - - } - contentContainerStyle={ - { - "flexGrow": 1, - } - } - data={[]} - getItem={[Function]} - getItemCount={[Function]} - initialNumToRender={10} - keyExtractor={[Function]} - maxToRenderPerBatch={2} - onContentSizeChange={[Function]} - onEndReachedThreshold={0.5} - onLayout={[Function]} - onMomentumScrollBegin={[Function]} - onMomentumScrollEnd={[Function]} - onRefresh={[Function]} - onScroll={[Function]} - onScrollBeginDrag={[Function]} - onScrollEndDrag={[Function]} - refreshControl={ - - } - refreshing={false} - removeClippedSubviews={false} - renderItem={[Function]} - scrollEventThrottle={50} - stickyHeaderIndices={[]} - tabLabel="" - viewabilityConfigCallbackPairs={[]} - > - - - - - - Nothing to see here - - - This is where you can find notifications once there’s activity in your wallet. - - - - - -`; diff --git a/app/components/UI/Notification/List/index.test.tsx b/app/components/UI/Notification/List/index.test.tsx index 5908fb62a6eb..895f11207753 100644 --- a/app/components/UI/Notification/List/index.test.tsx +++ b/app/components/UI/Notification/List/index.test.tsx @@ -1,111 +1,18 @@ import React from 'react'; -import { renderHook, act } from '@testing-library/react-hooks'; -import { NotificationServicesController } from '@metamask/notification-services-controller'; -import { Provider } from 'react-redux'; -import createMockStore from 'redux-mock-store'; -import NotificationsList, { NotificationsListItem } from './'; -import NotificationsService from '../../../../util/notifications/services/NotificationService'; -import renderWithProvider, { DeepPartial } from '../../../../util/test/renderWithProvider'; +import NotificationsList from './'; +import renderWithProvider from '../../../../util/test/renderWithProvider'; import MOCK_NOTIFICATIONS from '../__mocks__/mock_notifications'; -import initialRootState, { backgroundState } from '../../../../util/test/initial-root-state'; -import { RootState } from '../../../../reducers'; -import { createNavigationProps } from '../../../../util/testUtils'; -import { hasNotificationModal, hasNotificationComponents, NotificationComponentState } from '../../../../util/notifications/notification-states'; -import { useMarkNotificationAsRead } from '../../../../util/notifications/hooks/useNotifications'; -import { Notification } from '../../../../util/notifications/types'; -// eslint-disable-next-line import/no-namespace -import * as Actions from '../../../../actions/notification/helpers'; -import { NotificationState } from '../../../../util/notifications/notification-states/types/NotificationState'; -import { TRIGGER_TYPES } from '../../../../util/notifications/constants'; -const mockNavigation = createNavigationProps({}); +import { NavigationProp, ParamListBase } from '@react-navigation/native'; -const mockTrackEvent = jest.fn(); - -jest.mock('../../../../util/notifications/services/NotificationService', () => ({ - ...jest.requireActual('../../../../util/notifications/services/NotificationService'), - getBadgeCount: jest.fn(), - decrementBadgeCount: jest.fn(), - setBadgeCount: jest.fn(), -})); - -jest.mock('../../../../util/notifications/notification-states', () => ({ - hasNotificationModal: jest.fn(), - hasNotificationComponents: jest.fn(), - NotificationComponentState: {}, -})); - -jest.mock('../../../hooks/useMetrics', () => ({ - useMetrics: () => ({ - trackEvent: mockTrackEvent, - }), - MetaMetricsEvents: { - NOTIFICATION_CLICKED: 'NOTIFICATION_CLICKED', - }, -})); - -const navigation = { +const navigationMock = { navigate: jest.fn(), -}; - -const mockInitialState: DeepPartial = { - engine: { - backgroundState: { - ...backgroundState, - NotificationServicesController: { - metamaskNotificationsList: [], - }, - }, - }, -}; - -jest.mock('../NotificationMenuItem', () => ({ - NotificationMenuItem: { - Root: ({ children }: { children: React.ReactNode }) =>
{children}
, - Icon: jest.fn(({ isRead }: { isRead: boolean }) =>
{isRead ? 'Read Icon' : 'Unread Icon'}
), - Content: jest.fn(() =>
Mocked Content
), - }, -})); - -jest.mock('react-redux', () => ({ - ...jest.requireActual('react-redux'), - useSelector: (fn: (state: DeepPartial) => unknown) => fn(mockInitialState), -})); - -function arrangeStore() { - const store = createMockStore()(initialRootState); +} as unknown as NavigationProp; - // Ensure dispatch mocks are handled correctly - store.dispatch = jest.fn().mockImplementation((action) => { - if (typeof action === 'function') { - return action(store.dispatch, store.getState); - } - return Promise.resolve(); - }); - - return store; -} - -function arrangeActions() { - const mockMarkNotificationAsRead = jest.spyOn(Actions, 'markMetamaskNotificationsAsRead').mockResolvedValue(undefined); - - return { - mockMarkNotificationAsRead, - }; -} - -function arrangeHook() { - const store = arrangeStore(); - const hook = renderHook(() => useMarkNotificationAsRead(), { - wrapper: ({ children }) => {children}, - }); - - return hook; -} describe('NotificationsList', () => { - it('renders correctly', () => { + it('should render correctly', () => { const { toJSON } = renderWithProvider( { ); expect(toJSON()).toMatchSnapshot(); }); - - it('renders empty state', () => { - const { toJSON } = renderWithProvider( - , - ); - expect(toJSON()).toMatchSnapshot(); - }); - - it('marks notification as read and not navigates if modal does not exist', async () => { - (hasNotificationModal as jest.Mock).mockReturnValue(false); - (NotificationsService.getBadgeCount as jest.Mock).mockResolvedValue(0); - const mockActions = arrangeActions(); - const { result } = arrangeHook(); - await act(async () => { - await result.current.markNotificationAsRead([ - { - id: MOCK_NOTIFICATIONS[2].id, - type: MOCK_NOTIFICATIONS[2].type, - isRead: MOCK_NOTIFICATIONS[2].isRead, - }, - ]); - }); - - expect(mockActions.mockMarkNotificationAsRead).toHaveBeenCalledWith([ - { - id: MOCK_NOTIFICATIONS[2].id, - type: MOCK_NOTIFICATIONS[2].type, - isRead: MOCK_NOTIFICATIONS[2].isRead, - }, - ]); - expect(navigation.navigate).not.toHaveBeenCalled(); - }); - - it('derives notificationState correctly based on notification type', () => { - (hasNotificationComponents as unknown as jest.Mock).mockReturnValue(true); - (NotificationComponentState as Record>)[MOCK_NOTIFICATIONS[2].type] = { - createMenuItem: jest.fn().mockReturnValue({ - title: MOCK_NOTIFICATIONS[2].type, - description: { - start: MOCK_NOTIFICATIONS[2].type, - }, - image: { - url: MOCK_NOTIFICATIONS[2].type, - variant: 'circle', - }, - badgeIcon: MOCK_NOTIFICATIONS[2].type, - createdAt: MOCK_NOTIFICATIONS[2].createdAt, - isRead: MOCK_NOTIFICATIONS[2].isRead, - }), - guardFn: (n): n is NotificationServicesController.Types.INotification => true, - }; - - renderWithProvider( - - ); - - expect((NotificationComponentState as Record>)[MOCK_NOTIFICATIONS[2].type].createMenuItem).toHaveBeenCalledWith(MOCK_NOTIFICATIONS[2]); - }); }); - diff --git a/app/components/UI/Notification/List/index.tsx b/app/components/UI/Notification/List/index.tsx index afa08f1bc583..fcfd61a8002f 100644 --- a/app/components/UI/Notification/List/index.tsx +++ b/app/components/UI/Notification/List/index.tsx @@ -16,7 +16,7 @@ import { } from '../../../../util/notifications/notification-states'; import Routes from '../../../../constants/navigation/Routes'; import { MetaMetricsEvents } from '../../../../core/Analytics'; -import { Notification } from '../../../../util/notifications'; +import { Notification, TRIGGER_TYPES } from '../../../../util/notifications'; import { useListNotifications, useMarkNotificationAsRead, @@ -56,7 +56,7 @@ function Loading() { ); } -export function NotificationsListItem(props: NotificationsListItemProps) { +function NotificationsListItem(props: NotificationsListItemProps) { const { styles } = useStyles(); const { markNotificationAsRead } = useMarkNotificationAsRead(); const { trackEvent } = useMetrics(); @@ -69,7 +69,7 @@ export function NotificationsListItem(props: NotificationsListItemProps) { isRead: item.isRead, }, ]); - if (hasNotificationModal(item?.type)) { + if (hasNotificationModal(item.type)) { props.navigation.navigate(Routes.NOTIFICATIONS.DETAILS, { notification: item, }); @@ -86,9 +86,9 @@ export function NotificationsListItem(props: NotificationsListItemProps) { trackEvent(MetaMetricsEvents.NOTIFICATION_CLICKED, { notification_id: item.id, notification_type: item.type, - ...('chain_id' in item && { - chain_id: item.chain_id, - }), + ...(item.type !== TRIGGER_TYPES.FEATURES_ANNOUNCEMENT + ? { chain_id: item?.chain_id } + : {}), previously_read: item.isRead, }); }, @@ -97,14 +97,11 @@ export function NotificationsListItem(props: NotificationsListItemProps) { const menuItemState = useMemo(() => { const notificationState = - props.notification?.type && hasNotificationComponents(props.notification.type) - ? NotificationComponentState[props.notification.type] - : undefined; - - return notificationState?.createMenuItem(props.notification); + NotificationComponentState[props.notification.type]; + return notificationState.createMenuItem(props.notification); }, [props.notification]); - if (!hasNotificationComponents(props.notification.type) || !menuItemState) { + if (!hasNotificationComponents(props.notification.type)) { return null; } @@ -132,7 +129,7 @@ function useNotificationListProps(props: { const getListProps = useCallback( (data: Notification[], tabLabel?: string) => { const listProps: FlatListProps = { - keyExtractor: (item: Notification) => item.id, + keyExtractor: (item) => item.id, data, ListEmptyComponent: ( ), contentContainerStyle: styles.list, - renderItem: ({ item }: { item: Notification }) => ( + renderItem: ({ item }) => ( ), diff --git a/app/components/UI/PaymentRequest/__snapshots__/index.test.tsx.snap b/app/components/UI/PaymentRequest/__snapshots__/index.test.tsx.snap index 9db1d0309f31..2f8efc7e4ba7 100644 --- a/app/components/UI/PaymentRequest/__snapshots__/index.test.tsx.snap +++ b/app/components/UI/PaymentRequest/__snapshots__/index.test.tsx.snap @@ -1,460 +1,32 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`PaymentRequest renders correctly 1`] = ` - - - - - - - Choose an asset to request - - - - -  - - - - - - Top picks - - - - - - - - - - - - - - - ETH - - - Ether - - - - - - - - - - - - - - - - - SAI - - - Sai Stablecoin v1.0 - - - - - - - - - - + + `; diff --git a/app/components/UI/PaymentRequest/index.js b/app/components/UI/PaymentRequest/index.js index bdbb3bb8f90c..ac632e49634c 100644 --- a/app/components/UI/PaymentRequest/index.js +++ b/app/components/UI/PaymentRequest/index.js @@ -60,7 +60,7 @@ import { selectTokens } from '../../../selectors/tokensController'; import { selectContractExchangeRates } from '../../../selectors/tokenRatesController'; import { selectSelectedInternalAccountChecksummedAddress } from '../../../selectors/accountsController'; -import { RequestPaymentViewSelectors } from '../../../../e2e/selectors/Receive/RequestPaymentView.selectors'; +import { RequestPaymentViewSelectors } from '../../../../e2e/selectors/RequestPaymentView.selectors'; const KEYBOARD_OFFSET = 120; const createStyles = (colors) => diff --git a/app/components/UI/PaymentRequest/index.test.tsx b/app/components/UI/PaymentRequest/index.test.tsx index 391fe7e3b89c..5915fdecd57d 100644 --- a/app/components/UI/PaymentRequest/index.test.tsx +++ b/app/components/UI/PaymentRequest/index.test.tsx @@ -1,198 +1,18 @@ import React from 'react'; -import { render, fireEvent, act } from '@testing-library/react-native'; -import PaymentRequest from './index'; +import { shallow } from 'enzyme'; +import PaymentRequest from './'; import { Provider } from 'react-redux'; import configureMockStore from 'redux-mock-store'; -import { ThemeContext, mockTheme } from '../../../util/theme'; -import { MOCK_ACCOUNTS_CONTROLLER_STATE } from '../../../util/test/accountsControllerTestUtils'; - -jest.mock('react', () => ({ - ...jest.requireActual('react'), - useState: jest.fn(), -})); const mockStore = configureMockStore(); - -const initialState = { - engine: { - backgroundState: { - CurrencyRateController: { - conversionRate: 1, - currentCurrency: 'USD', - }, - TokenRatesController: { - contractExchangeRates: {}, - marketData: { - '0x1': { - '0x0d8775f59023cbe76e541b6497bbed3cd21acbdc': { - price: 1, - }, - }, - }, - }, - TokensController: { - marketData: { - '0x1': { - '0x0d8775f59023cbe76e541b6497bbed3cd21acbdc': { - price: 1, - }, - }, - }, - tokens: [], - }, - NetworkController: { - provider: { - ticker: 'ETH', - chainId: '1', - }, - }, - AccountsController: { - ...MOCK_ACCOUNTS_CONTROLLER_STATE, - internalAccounts: { - ...MOCK_ACCOUNTS_CONTROLLER_STATE.internalAccounts, - selectedAccount: {}, - }, - }, - TokenListController: { - tokenList: { - '0x1': { - '0x0d8775f59023cbe76e541b6497bbed3cd21acbdc': { - address: '0x0d8775f59023cbe76e541b6497bbed3cd21acbdc', - symbol: 'BAT', - decimals: 18, - name: 'Basic Attention Token', - iconUrl: - 'https://assets.coingecko.com/coins/images/677/thumb/basic-attention-token.png?1547034427', - type: 'erc20', - }, - }, - }, - }, - PreferencesController: { - ipfsGateway: {}, - }, - }, - }, - settings: { - primaryCurrency: 'ETH', - }, -}; - -let mockSetShowError: jest.Mock; -let mockShowError = false; - -beforeEach(() => { - mockSetShowError = jest.fn((value) => { - mockShowError = value; - }); - (React.useState as jest.Mock).mockImplementation((state) => [ - state, - mockSetShowError, - ]); -}); - -const store = mockStore(initialState); - -const mockNavigation = { - setOptions: jest.fn(), - setParams: jest.fn(), - navigate: jest.fn(), - goBack: jest.fn(), -}; - -const mockRoute = { - params: { - dispatch: jest.fn(), - }, -}; - -const renderComponent = (props = {}) => - render( - - - - - , - ); - +const store = mockStore({}); describe('PaymentRequest', () => { - it('renders correctly', () => { - const { toJSON } = renderComponent(); - expect(toJSON()).toMatchSnapshot(); - }); - - it('displays the correct title for asset selection', () => { - const { getByText } = renderComponent(); - expect(getByText('Choose an asset to request')).toBeTruthy(); - }); - - it('allows searching for assets', () => { - const { getByPlaceholderText } = renderComponent(); - const searchInput = getByPlaceholderText('Search assets'); - fireEvent.changeText(searchInput, 'ETH'); - expect(searchInput.props.value).toBe('ETH'); - }); - - it('switches to amount input mode when an asset is selected', async () => { - const { getByText } = renderComponent({ navigation: mockNavigation }); - - await act(async () => { - fireEvent.press(getByText('ETH')); - }); - - expect(getByText('Enter amount')).toBeTruthy(); - expect(mockNavigation.setParams).toHaveBeenCalledWith({ - mode: 'amount', - dispatch: expect.any(Function), - }); - }); - - it('updates amount when input changes', async () => { - const { getByText, getByPlaceholderText } = renderComponent(); - - // First, select an asset - await act(async () => { - fireEvent.press(getByText('ETH')); - }); - - const amountInput = getByPlaceholderText('0.00'); - await act(async () => { - fireEvent.changeText(amountInput, '1.5'); - }); - - expect(amountInput.props.value).toBe('1.5'); - }); - - it('displays an error when an invalid amount is entered', async () => { - const { getByText, getByPlaceholderText, debug, queryByText } = - renderComponent(); - - (React.useState as jest.Mock).mockImplementation(() => [ - mockShowError, - mockSetShowError, - ]); - - mockSetShowError(true); - - await act(async () => { - fireEvent.press(getByText('ETH')); - }); - - const amountInput = getByPlaceholderText('0.00'); - const nextButton = getByText('Next'); - - await act(async () => { - fireEvent.changeText(amountInput, '0'); - fireEvent.press(nextButton); - }); - - debug(); - - expect(mockSetShowError).toHaveBeenCalledWith(true); - expect(queryByText('Invalid request, please try again')).toBeTruthy(); + it('should render correctly', () => { + const wrapper = shallow( + + + , + ); + expect(wrapper).toMatchSnapshot(); }); }); diff --git a/app/components/UI/PaymentRequestSuccess/index.js b/app/components/UI/PaymentRequestSuccess/index.js index 08a3925ab655..1310dd135d8c 100644 --- a/app/components/UI/PaymentRequestSuccess/index.js +++ b/app/components/UI/PaymentRequestSuccess/index.js @@ -30,7 +30,7 @@ import { protectWalletModalVisible } from '../../../actions/user'; import ClipboardManager from '../../../core/ClipboardManager'; import { ThemeContext, mockTheme } from '../../../util/theme'; import generateTestId from '../../../../wdio/utils/generateTestId'; -import { SendLinkViewSelectorsIDs } from '../../../../e2e/selectors/Receive/SendLinkView.selectors'; +import { SendLinkViewSelectorsIDs } from '../../../../e2e/selectors/SendLinkView.selectors'; const isIos = Device.isIos(); diff --git a/app/components/UI/PermissionsSummary/PermissionsSummary.test.tsx b/app/components/UI/PermissionsSummary/PermissionsSummary.test.tsx index 5ce8f2a4f7b3..ebc79900213e 100644 --- a/app/components/UI/PermissionsSummary/PermissionsSummary.test.tsx +++ b/app/components/UI/PermissionsSummary/PermissionsSummary.test.tsx @@ -29,24 +29,6 @@ const mockInitialState = { }; describe('PermissionsSummary', () => { - it('should render correctly for network switch', () => { - const { toJSON } = renderWithProvider( - , - { state: mockInitialState }, - ); - expect(toJSON()).toMatchSnapshot(); - }); it('should render correctly', () => { const { toJSON } = renderWithProvider( { const { colors } = useTheme(); const { styles } = useStyles(styleSheet, { isRenderedAsBottomSheet }); const { navigate } = useNavigation(); const selectedAccount = useSelectedAccount(); - - // if network switch, we get the chain name from the customNetworkInformation - let chainName = ''; - let chainImage: ImageSourcePropType; - if (isNetworkSwitch && customNetworkInformation?.chainId) { - chainName = customNetworkInformation?.chainName; - // @ts-expect-error getNetworkImageSource is not implemented in typescript - chainImage = getNetworkImageSource({ - chainId: customNetworkInformation?.chainId, - }); - } + const networkName = useSelector(selectNetworkName); const confirm = () => { onUserAction?.(USER_INTENT.Confirm); - onConfirm?.(); }; const cancel = () => { onUserAction?.(USER_INTENT.Cancel); - onCancel?.(); }; const handleEditAccountsButtonPress = () => { @@ -165,62 +144,6 @@ const PermissionsSummary = ({ }); }, [navigate, currentPageInformation?.url]); - const getAccountLabel = useCallback(() => { - if (isAlreadyConnected) { - if (accountAddresses.length === 0 && selectedAccount) { - return `${strings('permissions.connected_to')} ${selectedAccount.name}`; - } - if (accountAddresses.length === 1) { - const matchedConnectedAccount = accounts.find( - (account) => account.address === accountAddresses[0], - ); - return matchedConnectedAccount?.name; - } - - return `${accountAddresses.length} ${strings( - 'accounts.accounts_connected', - )}`; - } - - if (accountAddresses.length === 1 && accounts?.length >= 1) { - const matchedAccount = accounts.find( - (account) => account.address === accountAddresses[0], - ); - return `${strings('permissions.requesting_for')}${ - matchedAccount?.name ? matchedAccount.name : accountAddresses[0] - }`; - } - - if (accountAddresses.length === 0 && selectedAccount) { - return `${strings('permissions.requesting_for')}${selectedAccount?.name}`; - } - - return strings('permissions.requesting_for_accounts', { - numberOfAccounts: accountAddresses.length, - }); - }, [accountAddresses, isAlreadyConnected, selectedAccount, accounts]); - - const getNetworkLabel = useCallback(() => { - if (isAlreadyConnected) { - return networkAvatars.length === 1 - ? networkAvatars[0]?.name - : `${strings('permissions.n_networks_connect', { - numberOfNetworks: networkAvatars.length, - })}`; - } - - if (networkAvatars.length === 1) { - return ( - networkAvatars[0]?.name && - `${strings('permissions.requesting_for')}${networkAvatars[0]?.name}` - ); - } - - return strings('permissions.requesting_for_networks', { - numberOfNetworks: networkAvatars.length, - }); - }, [networkAvatars, isAlreadyConnected]); - function renderAccountPermissionsRequestInfoCard() { return ( @@ -235,35 +158,31 @@ const PermissionsSummary = ({ /> - {strings('permissions.see_your_accounts')} + {strings('permissions.wants_to_see_your_accounts')} - {getAccountLabel()} + {strings('permissions.requesting_for')} + + + {`${ + selectedAccount?.name ?? + strings('browser.undefined_account') + }`} - - {accountAddresses.length > 0 ? ( - ({ - variant: AvatarVariant.Account, - accountAddress: address, - size: AvatarSize.Xs, - }))} + {selectedAccount?.address && ( + + - ) : ( - selectedAccount?.address && ( - - ) - )} - + + )} {renderEndAccessory()} @@ -289,46 +208,21 @@ const PermissionsSummary = ({ {strings('permissions.use_enabled_networks')} - {isNetworkSwitch && ( - <> - - - - {strings('permissions.requesting_for')} - - - {chainName} - - - - - - )} - {!isNetworkSwitch && ( - <> - - - - {getNetworkLabel()} - - - - - ({ - ...avatar, - variant: AvatarVariant.Network, - }))} - /> - - - )} + + + + {strings('permissions.requesting_for')} + + + {networkName} + + + + + +
{!isNetworkSwitch && renderEndAccessory()} @@ -353,7 +247,6 @@ const PermissionsSummary = ({ })} - {/*TODO These should be conditional upon which permissions are being requested*/} {!isNetworkSwitch && renderAccountPermissionsRequestInfoCard()} {renderNetworkPermissionsRequestInfoCard()} @@ -392,7 +285,7 @@ const PermissionsSummary = ({ ]} testID={CommonSelectorsIDs.CONNECT_BUTTON} > - {strings('accounts.connect')} + {strings('confirmation_modal.confirm_cta')} )} diff --git a/app/components/UI/PermissionsSummary/PermissionsSummary.types.ts b/app/components/UI/PermissionsSummary/PermissionsSummary.types.ts index 3bf71acd2778..c80d27e198a9 100644 --- a/app/components/UI/PermissionsSummary/PermissionsSummary.types.ts +++ b/app/components/UI/PermissionsSummary/PermissionsSummary.types.ts @@ -1,5 +1,4 @@ import { USER_INTENT } from '../../../constants/permissions'; -import { Account } from '../../hooks/useAccounts'; export interface PermissionsSummaryProps { currentPageInformation: { @@ -10,19 +9,10 @@ export interface PermissionsSummaryProps { onEdit?: () => void; onEditNetworks?: () => void; onBack?: () => void; - onCancel?: () => void; - onConfirm?: () => void; onUserAction?: React.Dispatch>; showActionButtons?: boolean; isAlreadyConnected?: boolean; isRenderedAsBottomSheet?: boolean; isDisconnectAllShown?: boolean; isNetworkSwitch?: boolean; - customNetworkInformation?: { - chainName: string; - chainId: string; - }; - accounts?: Account[]; - accountAddresses?: string[]; - networkAvatars?: ({ name: string; imageSource: string } | null)[]; } diff --git a/app/components/UI/PermissionsSummary/__snapshots__/PermissionsSummary.test.tsx.snap b/app/components/UI/PermissionsSummary/__snapshots__/PermissionsSummary.test.tsx.snap index 5fb871e2b3df..07ce968d48ce 100644 --- a/app/components/UI/PermissionsSummary/__snapshots__/PermissionsSummary.test.tsx.snap +++ b/app/components/UI/PermissionsSummary/__snapshots__/PermissionsSummary.test.tsx.snap @@ -240,7 +240,22 @@ exports[`PermissionsSummary should render correctly 1`] = ` } } > - Connected to Account 2 + Requesting for +
+ + Account 2
@@ -520,7 +535,22 @@ exports[`PermissionsSummary should render correctly 1`] = ` } } > - 0 networks connected + Requesting for + + + Ethereum Main Network @@ -540,7 +570,297 @@ exports[`PermissionsSummary should render correctly 1`] = ` "flexDirection": "row", } } - /> + > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 + + @@ -752,501 +1072,7 @@ exports[`PermissionsSummary should render correctly 1`] = ` ] } > - Connect - - - - - - -`; - -exports[`PermissionsSummary should render correctly for network switch 1`] = ` - - - - - - - - - - a - - - - - - - - - app.uniswap.org wants to: - - - - - - - - - - Use your enabled networks - - - - - - Requesting for - - - Sepolia - - - - - - - - - - - - - - - - - Disconnect all - - - - - - - Cancel - - - - - Connect + Confirm diff --git a/app/components/UI/Ramp/Views/BuildQuote/__snapshots__/BuildQuote.test.tsx.snap b/app/components/UI/Ramp/Views/BuildQuote/__snapshots__/BuildQuote.test.tsx.snap index c8fc6d56cfe9..d8474b6cb32e 100644 --- a/app/components/UI/Ramp/Views/BuildQuote/__snapshots__/BuildQuote.test.tsx.snap +++ b/app/components/UI/Ramp/Views/BuildQuote/__snapshots__/BuildQuote.test.tsx.snap @@ -8717,7 +8717,7 @@ exports[`BuildQuote View renders correctly 1`] = ` onLoadEnd={[Function]} source={ { - "uri": "", + "uri": undefined, } } style={ @@ -11839,7 +11839,7 @@ exports[`BuildQuote View renders correctly 2`] = ` onLoadEnd={[Function]} source={ { - "uri": "", + "uri": undefined, } } style={ diff --git a/app/components/UI/Ramp/Views/NetworkSwitcher/__snapshots__/NetworkSwitcher.test.tsx.snap b/app/components/UI/Ramp/Views/NetworkSwitcher/__snapshots__/NetworkSwitcher.test.tsx.snap index bdf21b1ce926..da5eb51bb0e1 100644 --- a/app/components/UI/Ramp/Views/NetworkSwitcher/__snapshots__/NetworkSwitcher.test.tsx.snap +++ b/app/components/UI/Ramp/Views/NetworkSwitcher/__snapshots__/NetworkSwitcher.test.tsx.snap @@ -1062,38 +1062,34 @@ exports[`NetworkSwitcher View renders and dismisses network modal when pressing } > - - - C - - + C + diff --git a/app/components/UI/Ramp/Views/Settings/__snapshots__/ActivationKeyForm.test.tsx.snap b/app/components/UI/Ramp/Views/Settings/__snapshots__/ActivationKeyForm.test.tsx.snap index 0d6c3a48b2c2..bd9145f787a1 100644 --- a/app/components/UI/Ramp/Views/Settings/__snapshots__/ActivationKeyForm.test.tsx.snap +++ b/app/components/UI/Ramp/Views/Settings/__snapshots__/ActivationKeyForm.test.tsx.snap @@ -536,7 +536,7 @@ exports[`AddActivationKey renders correctly 1`] = ` { "alignItems": "center", "backgroundColor": "#ffffff", - "borderColor": "#0376c9", + "borderColor": "#bbc0c5", "borderRadius": 8, "borderWidth": 1, "flexDirection": "row", diff --git a/app/components/UI/ReceiveRequest/index.js b/app/components/UI/ReceiveRequest/index.js index 8cdbcb0f5cb4..adeb81bc78ca 100644 --- a/app/components/UI/ReceiveRequest/index.js +++ b/app/components/UI/ReceiveRequest/index.js @@ -28,7 +28,7 @@ import { isNetworkRampSupported } from '../Ramp/utils'; import { createBuyNavigationDetails } from '../Ramp/routes/utils'; import { selectSelectedInternalAccountChecksummedAddress } from '../../../selectors/accountsController'; import { getRampNetworks } from '../../../reducers/fiatOrders'; -import { RequestPaymentModalSelectorsIDs } from '../../../../e2e/selectors/Receive/RequestPaymentModal.selectors'; +import { RequestPaymentModalSelectorsIDs } from '../../../../e2e/selectors/Modals/RequestPaymentModal.selectors'; import { withMetricsAwareness } from '../../../components/hooks/useMetrics'; import { getDecimalChainId } from '../../../util/networks'; import QRAccountDisplay from '../../Views/QRAccountDisplay'; diff --git a/app/components/UI/ReusableModal/__snapshots__/index.test.tsx.snap b/app/components/UI/ReusableModal/__snapshots__/index.test.tsx.snap index b46a1d36dd29..840c56c6f509 100644 --- a/app/components/UI/ReusableModal/__snapshots__/index.test.tsx.snap +++ b/app/components/UI/ReusableModal/__snapshots__/index.test.tsx.snap @@ -2,74 +2,6 @@ exports[`ReusableModal should render correctly 1`] = ` - - - - - - + `; diff --git a/app/components/UI/ReusableModal/index.test.tsx b/app/components/UI/ReusableModal/index.test.tsx index f97cf05d2105..2c93fa2b4375 100644 --- a/app/components/UI/ReusableModal/index.test.tsx +++ b/app/components/UI/ReusableModal/index.test.tsx @@ -1,28 +1,15 @@ import React from 'react'; import { SafeAreaView } from 'react-native'; -import { render, screen } from '@testing-library/react-native'; +import { shallow } from 'enzyme'; import ReusableModal from './'; -import { useNavigation } from '@react-navigation/native'; - -jest.mock('@react-navigation/native', () => ({ - ...jest.requireActual('@react-navigation/native'), - useNavigation: jest.fn(), -})); describe('ReusableModal', () => { - beforeEach(() => { - (useNavigation as jest.Mock).mockReturnValue({ - navigate: jest.fn(), - goBack: jest.fn(), - }); - }); - it('should render correctly', () => { - render( + const wrapper = shallow( {null} , ); - expect(screen.toJSON()).toMatchSnapshot(); + expect(wrapper).toMatchSnapshot(); }); }); diff --git a/app/components/UI/Screen/index.test.tsx b/app/components/UI/Screen/index.test.tsx index a32016dc0d90..2707be551491 100644 --- a/app/components/UI/Screen/index.test.tsx +++ b/app/components/UI/Screen/index.test.tsx @@ -1,15 +1,15 @@ import React from 'react'; -import { render } from '@testing-library/react-native'; +import { shallow } from 'enzyme'; import { View } from 'react-native'; import Screen from './'; describe('Screen', () => { it('should render correctly', () => { - const { toJSON } = render( + const wrapper = shallow( Foobar , ); - expect(toJSON()).toMatchSnapshot(); + expect(wrapper).toMatchSnapshot(); }); }); diff --git a/app/components/UI/SimulationDetails/AssetPill/AssetPill.tsx b/app/components/UI/SimulationDetails/AssetPill/AssetPill.tsx index 8830e10e79b2..534c0d58c507 100644 --- a/app/components/UI/SimulationDetails/AssetPill/AssetPill.tsx +++ b/app/components/UI/SimulationDetails/AssetPill/AssetPill.tsx @@ -66,7 +66,7 @@ const AssetPill: React.FC = ({ asset }) => { preferContractSymbol testID="simulation-details-asset-pill-name" type={NameType.EthereumAddress} - value={asset.address as Hex} + value={asset.address as Hex} /> )} diff --git a/app/components/UI/SliderButton/__snapshots__/index.test.tsx.snap b/app/components/UI/SliderButton/__snapshots__/index.test.tsx.snap index ce6e987c71f1..f1d879adf066 100644 --- a/app/components/UI/SliderButton/__snapshots__/index.test.tsx.snap +++ b/app/components/UI/SliderButton/__snapshots__/index.test.tsx.snap @@ -54,8 +54,7 @@ exports[`SliderButton should render correctly 1`] = ` ] } /> - - Incomplete Text - + - - - + diff --git a/app/components/UI/SliderButton/index.test.tsx b/app/components/UI/SliderButton/index.test.tsx index 4a41f222ba49..609b86151928 100644 --- a/app/components/UI/SliderButton/index.test.tsx +++ b/app/components/UI/SliderButton/index.test.tsx @@ -1,15 +1,15 @@ import React from 'react'; -import { render, screen } from '@testing-library/react-native'; +import { shallow } from 'enzyme'; import SliderButton from './index'; describe('SliderButton', () => { it('should render correctly', () => { - render( + const wrapper = shallow( , ); - expect(screen.toJSON()).toMatchSnapshot(); + expect(wrapper).toMatchSnapshot(); }); }); diff --git a/app/components/UI/SlippageSlider/__snapshots__/index.test.tsx.snap b/app/components/UI/SlippageSlider/__snapshots__/index.test.tsx.snap index 14cdaa1c8f11..1ab792850fdf 100644 --- a/app/components/UI/SlippageSlider/__snapshots__/index.test.tsx.snap +++ b/app/components/UI/SlippageSlider/__snapshots__/index.test.tsx.snap @@ -44,6 +44,7 @@ exports[`SlippageSlider should render correctly 1`] = ` } > - - - + - - - - - + + undefined% - - + diff --git a/app/components/UI/SlippageSlider/index.test.tsx b/app/components/UI/SlippageSlider/index.test.tsx index 9aea690ccce3..75f7754b500b 100644 --- a/app/components/UI/SlippageSlider/index.test.tsx +++ b/app/components/UI/SlippageSlider/index.test.tsx @@ -1,10 +1,10 @@ import React from 'react'; -import { render, screen } from '@testing-library/react-native'; +import { shallow } from 'enzyme'; import SlippageSlider from './index'; describe('SlippageSlider', () => { it('should render correctly', () => { - render( + const wrapper = shallow( { formatTooltipText={(text) => `${text}%`} />, ); - expect(screen.toJSON()).toMatchSnapshot(); + expect(wrapper).toMatchSnapshot(); }); }); diff --git a/app/components/UI/Stake/Views/StakeConfirmationView/StakeConfirmationView.test.tsx b/app/components/UI/Stake/Views/StakeConfirmationView/StakeConfirmationView.test.tsx index 90bdb658e9a4..109fe3e7fac4 100644 --- a/app/components/UI/Stake/Views/StakeConfirmationView/StakeConfirmationView.test.tsx +++ b/app/components/UI/Stake/Views/StakeConfirmationView/StakeConfirmationView.test.tsx @@ -7,7 +7,6 @@ import { backgroundState } from '../../../../../util/test/initial-root-state'; import configureMockStore from 'redux-mock-store'; import { Provider } from 'react-redux'; import { StakeConfirmationViewProps } from './StakeConfirmationView.types'; -import { MOCK_POOL_STAKING_SDK } from '../../__mocks__/mockData'; jest.mock('../../../../hooks/useIpfsGateway', () => jest.fn()); @@ -54,37 +53,12 @@ jest.mock('@react-navigation/native', () => { }; }); -jest.mock('../../hooks/usePoolStakedDeposit', () => ({ - __esModule: true, - default: () => ({ - attemptDepositTransaction: jest.fn(), - }), -})); - -jest.mock('../../hooks/useStakeContext', () => ({ - __esModule: true, - useStakeContext: jest.fn(() => MOCK_POOL_STAKING_SDK), -})); - -jest.mock('../../hooks/usePooledStakes', () => ({ - __esModule: true, - default: () => ({ - refreshPooledStakes: jest.fn(), - }), -})); - describe('StakeConfirmationView', () => { it('render matches snapshot', () => { const props: StakeConfirmationViewProps = { route: { key: '1', - params: { - amountWei: '3210000000000000', - amountFiat: '7.46', - annualRewardRate: '2.5%', - annualRewardsETH: '2.5 ETH', - annualRewardsFiat: '$5000', - }, + params: { amountWei: '3210000000000000', amountFiat: '7.46' }, name: 'params', }, }; diff --git a/app/components/UI/Stake/Views/StakeConfirmationView/StakeConfirmationView.tsx b/app/components/UI/Stake/Views/StakeConfirmationView/StakeConfirmationView.tsx index d0341d0b4447..2f1a4890286d 100644 --- a/app/components/UI/Stake/Views/StakeConfirmationView/StakeConfirmationView.tsx +++ b/app/components/UI/Stake/Views/StakeConfirmationView/StakeConfirmationView.tsx @@ -5,13 +5,19 @@ import { useStyles } from '../../../../hooks/useStyles'; import { getStakingNavbar } from '../../../Navbar'; import styleSheet from './StakeConfirmationView.styles'; import TokenValueStack from '../../components/StakingConfirmation/TokenValueStack/TokenValueStack'; -import AccountCard from '../../components/StakingConfirmation/AccountCard/AccountCard'; +import AccountHeaderCard from '../../components/StakingConfirmation/AccountHeaderCard/AccountHeaderCard'; import RewardsCard from '../../components/StakingConfirmation/RewardsCard/RewardsCard'; import ConfirmationFooter from '../../components/StakingConfirmation/ConfirmationFooter/ConfirmationFooter'; import { StakeConfirmationViewProps } from './StakeConfirmationView.types'; +import { MOCK_GET_VAULT_RESPONSE } from '../../components/StakingBalance/mockData'; import { strings } from '../../../../../../locales/i18n'; -import { FooterButtonGroupActions } from '../../components/StakingConfirmation/ConfirmationFooter/FooterButtonGroup/FooterButtonGroup.types'; -import UnstakingTimeCard from '../../components/StakingConfirmation/UnstakeTimeCard/UnstakeTimeCard'; + +const MOCK_REWARD_DATA = { + REWARDS: { + ETH: '0.13 ETH', + FIAT: '$334.93', + }, +}; const MOCK_STAKING_CONTRACT_NAME = 'MM Pooled Staking'; @@ -38,23 +44,15 @@ const StakeConfirmationView = ({ route }: StakeConfirmationViewProps) => { tokenSymbol="ETH" /> - + - - + ); }; diff --git a/app/components/UI/Stake/Views/StakeConfirmationView/StakeConfirmationView.types.ts b/app/components/UI/Stake/Views/StakeConfirmationView/StakeConfirmationView.types.ts index 20214a0fc52a..8c723135f4ff 100644 --- a/app/components/UI/Stake/Views/StakeConfirmationView/StakeConfirmationView.types.ts +++ b/app/components/UI/Stake/Views/StakeConfirmationView/StakeConfirmationView.types.ts @@ -3,9 +3,6 @@ import { RouteProp } from '@react-navigation/native'; interface StakeConfirmationViewRouteParams { amountWei: string; amountFiat: string; - annualRewardsETH: string; - annualRewardsFiat: string; - annualRewardRate: string; } export interface StakeConfirmationViewProps { diff --git a/app/components/UI/Stake/Views/StakeConfirmationView/__snapshots__/StakeConfirmationView.test.tsx.snap b/app/components/UI/Stake/Views/StakeConfirmationView/__snapshots__/StakeConfirmationView.test.tsx.snap index 755eda70c024..9d14c100f637 100644 --- a/app/components/UI/Stake/Views/StakeConfirmationView/__snapshots__/StakeConfirmationView.test.tsx.snap +++ b/app/components/UI/Stake/Views/StakeConfirmationView/__snapshots__/StakeConfirmationView.test.tsx.snap @@ -45,7 +45,7 @@ exports[`StakeConfirmationView render matches snapshot 1`] = ` onLoadEnd={[Function]} source={ { - "uri": "", + "uri": undefined, } } style={ @@ -638,146 +638,18 @@ exports[`StakeConfirmationView render matches snapshot 1`] = ` } } > - - - - - - - - - - - + width={16} + /> - 2.5% + 2.8% @@ -1228,7 +1100,7 @@ exports[`StakeConfirmationView render matches snapshot 1`] = ` } } > - $5000 + $334.93 - 2.5 ETH + 0.13 ETH @@ -1388,157 +1260,6 @@ exports[`StakeConfirmationView render matches snapshot 1`] = ` - - - - - - - Unstaking time - - - - - - - - - - - - 1 to 11 days - - - - - - - Continue + Confirm diff --git a/app/components/UI/Stake/Views/StakeInputView/StakeInputView.test.tsx b/app/components/UI/Stake/Views/StakeInputView/StakeInputView.test.tsx index c7c3005ad89a..10ac002beb1d 100644 --- a/app/components/UI/Stake/Views/StakeInputView/StakeInputView.test.tsx +++ b/app/components/UI/Stake/Views/StakeInputView/StakeInputView.test.tsx @@ -4,11 +4,7 @@ import StakeInputView from './StakeInputView'; import { renderScreen } from '../../../../../util/test/renderWithProvider'; import Routes from '../../../../../constants/navigation/Routes'; import { backgroundState } from '../../../../../util/test/initial-root-state'; -import { Stake } from '../../sdk/stakeSdkProvider'; -import { ChainId, PooledStakingContract } from '@metamask/stake-sdk'; -import { Contract } from 'ethers'; -import { MOCK_GET_VAULT_RESPONSE } from '../../__mocks__/mockData'; -import { toWei } from '../../../../../util/number'; +import { BN } from 'ethereumjs-util'; function render(Component: React.ComponentType) { return renderScreen( @@ -54,80 +50,16 @@ jest.mock('../../../../../selectors/currencyRateController.ts', () => ({ selectCurrentCurrency: jest.fn(() => 'USD'), })); -const mockBalanceBN = toWei('1.5'); // 1.5 ETH - -const mockPooledStakingContractService: PooledStakingContract = { - chainId: ChainId.ETHEREUM, - connectSignerOrProvider: jest.fn(), - contract: new Contract('0x0000000000000000000000000000000000000000', []), - convertToShares: jest.fn(), - encodeClaimExitedAssetsTransactionData: jest.fn(), - encodeDepositTransactionData: jest.fn(), - encodeEnterExitQueueTransactionData: jest.fn(), - encodeMulticallTransactionData: jest.fn(), - estimateClaimExitedAssetsGas: jest.fn(), - estimateDepositGas: jest.fn(), - estimateEnterExitQueueGas: jest.fn(), - estimateMulticallGas: jest.fn(), -}; - -jest.mock('../../hooks/useStakeContext.ts', () => ({ - useStakeContext: jest.fn(() => { - const stakeContext: Stake = { - setSdkType: jest.fn(), - stakingContract: mockPooledStakingContractService, - }; - return stakeContext; - }), -})); - +const mockBalanceBN = new BN('1500000000000000000'); jest.mock('../../hooks/useBalance', () => ({ __esModule: true, default: () => ({ - balanceETH: '1.5', + balance: '1.5', balanceWei: mockBalanceBN, balanceFiatNumber: '3000', }), })); -const mockGasFee = toWei('0.0001'); - -jest.mock('../../hooks/useStakingGasFee', () => ({ - __esModule: true, - default: () => ({ - estimatedGasFeeWei: mockGasFee, - gasLimit: 70122, - isLoadingStakingGasFee: false, - isStakingGasFeeError: false, - refreshGasValues: jest.fn(), - }), -})); - -const mockVaultData = MOCK_GET_VAULT_RESPONSE; -// Mock hooks - -jest.mock('../../hooks/useStakingEligibility', () => ({ - __esModule: true, - default: () => ({ - isEligible: true, - loading: false, - error: null, - refreshPooledStakingEligibility: jest.fn(), - }), -})); - -jest.mock('../../hooks/useVaultData', () => ({ - __esModule: true, - default: () => ({ - vaultData: mockVaultData, - loading: false, - error: null, - refreshVaultData: jest.fn(), - annualRewardRate: '2.5%', - annualRewardRateDecimal: 0.025, - }), -})); - describe('StakeInputView', () => { it('render matches snapshot', () => { render(StakeInputView); @@ -161,7 +93,7 @@ describe('StakeInputView', () => { fireEvent.press(screen.getByText('2')); - expect(screen.getByText('0.05 ETH')).toBeTruthy(); + expect(screen.getByText('0.052 ETH')).toBeTruthy(); }); }); diff --git a/app/components/UI/Stake/Views/StakeInputView/StakeInputView.tsx b/app/components/UI/Stake/Views/StakeInputView/StakeInputView.tsx index dd45e4002868..0431e67a77f5 100644 --- a/app/components/UI/Stake/Views/StakeInputView/StakeInputView.tsx +++ b/app/components/UI/Stake/Views/StakeInputView/StakeInputView.tsx @@ -17,14 +17,14 @@ import EstimatedAnnualRewardsCard from '../../components/EstimatedAnnualRewardsC import Routes from '../../../../../constants/navigation/Routes'; import styleSheet from './StakeInputView.styles'; import useStakingInputHandlers from '../../hooks/useStakingInput'; +import useBalance from '../../hooks/useBalance'; import InputDisplay from '../../components/InputDisplay'; -import { MetaMetricsEvents, useMetrics } from '../../../../hooks/useMetrics'; const StakeInputView = () => { const title = strings('stake.stake_eth'); const navigation = useNavigation(); const { styles, theme } = useStyles(styleSheet, {}); - const { trackEvent, createEventBuilder } = useMetrics(); + const { balance, balanceFiatNumber, balanceWei } = useBalance(); const { isEth, @@ -41,27 +41,12 @@ const StakeInputView = () => { handleKeypadChange, calculateEstimatedAnnualRewards, estimatedAnnualRewards, - annualRewardsETH, - annualRewardsFiat, - annualRewardRate, - isLoadingVaultData, - handleMax, - balanceValue, - } = useStakingInputHandlers(); + } = useStakingInputHandlers(balanceWei); const navigateToLearnMoreModal = () => { navigation.navigate('StakeModals', { screen: Routes.STAKING.MODALS.LEARN_MORE, }); - trackEvent( - createEventBuilder(MetaMetricsEvents.STAKE_LEARN_MORE_CLICKED) - .addProperties({ - selected_provider: 'consensys', - text: 'Tooltip Question Mark Trigger', - location: 'Stake Input View' - }) - .build() - ); }; const handleStakePress = useCallback(() => { @@ -70,40 +55,9 @@ const StakeInputView = () => { params: { amountWei: amountWei.toString(), amountFiat: fiatAmount, - annualRewardsETH, - annualRewardsFiat, - annualRewardRate, - }, - }); - trackEvent( - createEventBuilder(MetaMetricsEvents.REVIEW_STAKE_BUTTON_CLICKED) - .addProperties({ - selected_provider: 'consensys', - tokens_to_stake_native_value: amountEth, - tokens_to_stake_usd_value: fiatAmount, - }) - .build(), - ); - }, [ - amountEth, - navigation, - amountWei, - fiatAmount, - annualRewardsETH, - annualRewardsFiat, - annualRewardRate, - trackEvent, - createEventBuilder - ]); - - const handleMaxButtonPress = () => { - navigation.navigate('StakeModals', { - screen: Routes.STAKING.MODALS.MAX_INPUT, - params: { - handleMaxPress: handleMax, }, }); - }; + }, [amountWei, fiatAmount, navigation]); const balanceText = strings('stake.balance'); @@ -113,6 +67,10 @@ const StakeInputView = () => { ? strings('stake.not_enough_eth') : strings('stake.review'); + const balanceValue = isEth + ? `${balance} ETH` + : `${balanceFiatNumber?.toString()} ${currentCurrency.toUpperCase()}`; + useEffect(() => { navigation.setOptions( getStakingNavbar(title, navigation, theme.colors, { @@ -143,13 +101,11 @@ const StakeInputView = () => { - - - - Stake ETH - - + Stake ETH + @@ -600,7 +577,7 @@ exports[`StakeInputView render matches snapshot 1`] = ` } } > - 2.5% + 2.6% { - const { theme } = params; - const { colors } = theme; - - return StyleSheet.create({ - mainContainer: { - paddingTop: 8, - paddingHorizontal: 16, - backgroundColor: colors.background.alternative, - height: '100%', - justifyContent: 'space-between', - }, - cardsContainer: { - paddingTop: 8, - gap: 8, - }, - }); -}; - -export default styleSheet; diff --git a/app/components/UI/Stake/Views/UnstakeConfirmationView/UnstakeConfirmationView.test.tsx b/app/components/UI/Stake/Views/UnstakeConfirmationView/UnstakeConfirmationView.test.tsx deleted file mode 100644 index 735c23b5be75..000000000000 --- a/app/components/UI/Stake/Views/UnstakeConfirmationView/UnstakeConfirmationView.test.tsx +++ /dev/null @@ -1,87 +0,0 @@ -import React from 'react'; -import UnstakeConfirmationView from './UnstakeConfirmationView'; -import renderWithProvider from '../../../../../util/test/renderWithProvider'; -import { Image } from 'react-native'; -import { createMockAccountsControllerState } from '../../../../../util/test/accountsControllerTestUtils'; -import { backgroundState } from '../../../../../util/test/initial-root-state'; -import { UnstakeConfirmationViewProps } from './UnstakeConfirmationView.types'; -import { MOCK_POOL_STAKING_SDK } from '../../__mocks__/mockData'; - -const MOCK_ADDRESS_1 = '0x0'; -const MOCK_ADDRESS_2 = '0x1'; - -const MOCK_ACCOUNTS_CONTROLLER_STATE = createMockAccountsControllerState([ - MOCK_ADDRESS_1, - MOCK_ADDRESS_2, -]); - -const mockInitialState = { - settings: {}, - engine: { - backgroundState: { - ...backgroundState, - AccountsController: MOCK_ACCOUNTS_CONTROLLER_STATE, - }, - }, -}; - -jest.mock('../../../../hooks/useIpfsGateway', () => jest.fn()); - -Image.getSize = jest.fn((_uri, success) => { - success(100, 100); // Mock successful response for ETH native Icon Image -}); - -const mockNavigate = jest.fn(); -const mockSetOptions = jest.fn(); - -jest.mock('@react-navigation/native', () => { - const actualReactNavigation = jest.requireActual('@react-navigation/native'); - return { - ...actualReactNavigation, - useNavigation: () => ({ - navigate: mockNavigate, - setOptions: mockSetOptions, - }), - }; -}); - -jest.mock('../../hooks/usePoolStakedDeposit', () => ({ - __esModule: true, - default: () => ({ - attemptDepositTransaction: jest.fn(), - }), -})); - -jest.mock('../../hooks/usePooledStakes', () => ({ - __esModule: true, - default: () => ({ - refreshPooledStakes: jest.fn(), - }), -})); - -jest.mock('../../hooks/useStakeContext', () => ({ - __esModule: true, - useStakeContext: jest.fn(() => MOCK_POOL_STAKING_SDK), -})); - -describe('UnstakeConfirmationView', () => { - it('render matches snapshot', () => { - const props: UnstakeConfirmationViewProps = { - route: { - key: '1', - name: 'params', - params: { - amountWei: '4999820000000000000', - amountFiat: '12894.52', - }, - }, - }; - - const { toJSON } = renderWithProvider( - , - { state: mockInitialState }, - ); - - expect(toJSON()).toMatchSnapshot(); - }); -}); diff --git a/app/components/UI/Stake/Views/UnstakeConfirmationView/UnstakeConfirmationView.tsx b/app/components/UI/Stake/Views/UnstakeConfirmationView/UnstakeConfirmationView.tsx deleted file mode 100644 index 1a78eab35e51..000000000000 --- a/app/components/UI/Stake/Views/UnstakeConfirmationView/UnstakeConfirmationView.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { View } from 'react-native'; -import React, { useEffect } from 'react'; -import { useNavigation } from '@react-navigation/native'; -import styleSheet from './UnstakeConfirmationView.styles'; -import { useStyles } from '../../../../hooks/useStyles'; -import { getStakingNavbar } from '../../../Navbar'; -import { strings } from '../../../../../../locales/i18n'; -import UnstakingTimeCard from '../../components/StakingConfirmation/UnstakeTimeCard/UnstakeTimeCard'; -import { UnstakeConfirmationViewProps } from './UnstakeConfirmationView.types'; -import TokenValueStack from '../../components/StakingConfirmation/TokenValueStack/TokenValueStack'; -import AccountCard from '../../components/StakingConfirmation/AccountCard/AccountCard'; -import ConfirmationFooter from '../../components/StakingConfirmation/ConfirmationFooter/ConfirmationFooter'; -import { FooterButtonGroupActions } from '../../components/StakingConfirmation/ConfirmationFooter/FooterButtonGroup/FooterButtonGroup.types'; - -const MOCK_STAKING_CONTRACT_NAME = 'MM Pooled Staking'; - -const UnstakeConfirmationView = ({ route }: UnstakeConfirmationViewProps) => { - const { styles, theme } = useStyles(styleSheet, {}); - - const navigation = useNavigation(); - - useEffect(() => { - navigation.setOptions( - getStakingNavbar(strings('stake.unstake'), navigation, theme.colors, { - backgroundColor: theme.colors.background.alternative, - hasCancelButton: false, - }), - ); - }, [navigation, theme.colors]); - - return ( - - - - - - - - - - - ); -}; - -export default UnstakeConfirmationView; diff --git a/app/components/UI/Stake/Views/UnstakeConfirmationView/UnstakeConfirmationView.types.ts b/app/components/UI/Stake/Views/UnstakeConfirmationView/UnstakeConfirmationView.types.ts deleted file mode 100644 index 3b8a1bf4c130..000000000000 --- a/app/components/UI/Stake/Views/UnstakeConfirmationView/UnstakeConfirmationView.types.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { RouteProp } from '@react-navigation/native'; - -interface UnstakeConfirmationViewRouteParams { - amountWei: string; - amountFiat: string; -} - -export interface UnstakeConfirmationViewProps { - route: RouteProp<{ params: UnstakeConfirmationViewRouteParams }, 'params'>; -} diff --git a/app/components/UI/Stake/Views/UnstakeConfirmationView/__snapshots__/UnstakeConfirmationView.test.tsx.snap b/app/components/UI/Stake/Views/UnstakeConfirmationView/__snapshots__/UnstakeConfirmationView.test.tsx.snap deleted file mode 100644 index b883796d5064..000000000000 --- a/app/components/UI/Stake/Views/UnstakeConfirmationView/__snapshots__/UnstakeConfirmationView.test.tsx.snap +++ /dev/null @@ -1,1291 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`UnstakeConfirmationView render matches snapshot 1`] = ` - - - - - - - - - - - - - - - - - - - - - - - 4.99982 - - ETH - - - $12894.52 - - - - - - - - - - - Unstaking time - - - - - - - - - - - - 1 to 11 days - - - - - - - - - - - - - - Unstaking to - - - - - - - - - - - - - - - - - - - - - - - Account 1 - - - - - - - - - - - - - Interacting with - - - - - - - - - - - - - - - - - - - - - - - MM Pooled Staking - - - - - - - - - - - - - - - Network - - - - - - - - - - - - - Ethereum Main Network - - - - - - - - - - - - - - - Terms of service - - - - - Risk disclosure - - - - - - - Cancel - - - - - Continue - - - - - -`; diff --git a/app/components/UI/Stake/Views/UnstakeInputView/UnstakeInputView.test.tsx b/app/components/UI/Stake/Views/UnstakeInputView/UnstakeInputView.test.tsx index 02c92e513390..e46d645f671c 100644 --- a/app/components/UI/Stake/Views/UnstakeInputView/UnstakeInputView.test.tsx +++ b/app/components/UI/Stake/Views/UnstakeInputView/UnstakeInputView.test.tsx @@ -4,11 +4,6 @@ import UnstakeInputView from './UnstakeInputView'; import { renderScreen } from '../../../../../util/test/renderWithProvider'; import Routes from '../../../../../constants/navigation/Routes'; import { backgroundState } from '../../../../../util/test/initial-root-state'; -import { - MOCK_GET_POOLED_STAKES_API_RESPONSE, - MOCK_GET_VAULT_RESPONSE, - MOCK_STAKED_ETH_ASSET, -} from '../../__mocks__/mockData'; function render(Component: React.ComponentType) { return renderScreen( @@ -53,39 +48,6 @@ jest.mock('../../../../../selectors/currencyRateController.ts', () => ({ selectCurrentCurrency: jest.fn(() => 'USD'), })); -const mockVaultData = MOCK_GET_VAULT_RESPONSE; -const mockPooledStakeData = MOCK_GET_POOLED_STAKES_API_RESPONSE.accounts[0]; - -jest.mock('../../hooks/useStakingEligibility', () => ({ - __esModule: true, - default: () => ({ - isEligible: true, - loading: false, - error: null, - refreshPooledStakingEligibility: jest.fn(), - }), -})); - -jest.mock('../../hooks/useVaultData', () => ({ - __esModule: true, - default: () => ({ - vaultData: mockVaultData, - loading: false, - error: null, - annualRewardRate: '2.5%', - annualRewardRateDecimal: 0.025, - }), -})); - -jest.mock('../../hooks/useBalance', () => ({ - __esModule: true, - default: () => ({ - stakedBalanceWei: mockPooledStakeData.assets, - stakedBalanceFiat: MOCK_STAKED_ETH_ASSET.balanceFiat, - formattedStakedBalanceETH: '5.79133 ETH', - }), -})); - describe('UnstakeInputView', () => { it('render matches snapshot', () => { render(UnstakeInputView); @@ -119,7 +81,7 @@ describe('UnstakeInputView', () => { fireEvent.press(screen.getByText('25%')); - expect(screen.getByText('1.44783')).toBeTruthy(); + expect(screen.getByText('1.14999')).toBeTruthy(); }); }); @@ -134,14 +96,13 @@ describe('UnstakeInputView', () => { render(UnstakeInputView); fireEvent.press(screen.getByText('1')); - expect(screen.getByText('Review')).toBeTruthy(); }); it('displays `Not enough ETH` when input exceeds balance', () => { render(UnstakeInputView); - fireEvent.press(screen.getByText('8')); + fireEvent.press(screen.getByText('6')); expect(screen.queryAllByText('Not enough ETH')).toHaveLength(2); }); }); diff --git a/app/components/UI/Stake/Views/UnstakeInputView/UnstakeInputView.tsx b/app/components/UI/Stake/Views/UnstakeInputView/UnstakeInputView.tsx index c9f6149b8fa0..c109940d3a54 100644 --- a/app/components/UI/Stake/Views/UnstakeInputView/UnstakeInputView.tsx +++ b/app/components/UI/Stake/Views/UnstakeInputView/UnstakeInputView.tsx @@ -1,5 +1,6 @@ import { useNavigation } from '@react-navigation/native'; import React, { useCallback, useEffect } from 'react'; +import { BN } from 'ethereumjs-util'; import UnstakeInputViewBanner from './UnstakeBanner'; import { strings } from '../../../../../../locales/i18n'; import Button, { @@ -8,30 +9,29 @@ import Button, { ButtonWidthTypes, } from '../../../../../component-library/components/Buttons/Button'; import { TextVariant } from '../../../../../component-library/components/Texts/Text'; +import { renderFromWei, weiToFiatNumber } from '../../../../../util/number'; import Keypad from '../../../../Base/Keypad'; import { useStyles } from '../../../../hooks/useStyles'; import { getStakingNavbar } from '../../../Navbar'; import ScreenLayout from '../../../Ramp/components/ScreenLayout'; import QuickAmounts from '../../components/QuickAmounts'; import { View } from 'react-native'; +import useStakingInputHandlers from '../../hooks/useStakingInput'; import styleSheet from './UnstakeInputView.styles'; import InputDisplay from '../../components/InputDisplay'; -import Routes from '../../../../../constants/navigation/Routes'; -import { MetaMetricsEvents, useMetrics } from '../../../../hooks/useMetrics'; -import useUnstakingInputHandlers from '../../hooks/useUnstakingInput'; const UnstakeInputView = () => { const title = strings('stake.unstake_eth'); const navigation = useNavigation(); const { styles, theme } = useStyles(styleSheet, {}); - const { trackEvent, createEventBuilder } = useMetrics(); + + const stakeBalance = '4599964000000000000'; //TODO: Replace with actual balance - STAKE-806 const { isEth, currentCurrency, isNonZeroAmount, amountEth, - amountWei, fiatAmount, isOverMaximum, handleCurrencySwitch, @@ -39,10 +39,16 @@ const UnstakeInputView = () => { percentageOptions, handleAmountPress, handleKeypadChange, - stakedBalanceValue, - } = useUnstakingInputHandlers(); + conversionRate, + } = useStakingInputHandlers(new BN(stakeBalance)); + + const stakeBalanceInEth = renderFromWei(stakeBalance, 5); + const stakeBalanceFiatNumber = weiToFiatNumber(stakeBalance, conversionRate); const stakedBalanceText = strings('stake.staked_balance'); + const stakedBalanceValue = isEth + ? `${stakeBalanceInEth} ETH` + : `${stakeBalanceFiatNumber?.toString()} ${currentCurrency.toUpperCase()}`; const buttonLabel = !isNonZeroAmount ? strings('stake.enter_amount') @@ -59,23 +65,8 @@ const UnstakeInputView = () => { }, [navigation, theme.colors, title]); const handleUnstakePress = useCallback(() => { - navigation.navigate('StakeScreens', { - screen: Routes.STAKING.UNSTAKE_CONFIRMATION, - params: { - amountWei: amountWei.toString(), - amountFiat: fiatAmount, - }, - }); - trackEvent( - createEventBuilder(MetaMetricsEvents.REVIEW_UNSTAKE_BUTTON_CLICKED) - .addProperties({ - selected_provider: 'consensys', - tokens_to_stake_native_value: amountEth, - tokens_to_stake_usd_value: fiatAmount, - }) - .build(), - ); - }, [amountEth, amountWei, createEventBuilder, fiatAmount, navigation, trackEvent]); + // TODO: Display the Review bottom sheet: STAKE-841 + }, []); return ( diff --git a/app/components/UI/Stake/Views/UnstakeInputView/UnstakeInputView.types.ts b/app/components/UI/Stake/Views/UnstakeInputView/UnstakeInputView.types.ts deleted file mode 100644 index e58d20f58afd..000000000000 --- a/app/components/UI/Stake/Views/UnstakeInputView/UnstakeInputView.types.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { RouteProp } from '@react-navigation/native'; - -interface UnstakeInputViewRouteParams { - stakedBalanceWei: string; -} - -export interface UnstakeInputViewProps { - route: RouteProp<{ params: UnstakeInputViewRouteParams }, 'params'>; -} diff --git a/app/components/UI/Stake/Views/UnstakeInputView/__snapshots__/UnstakeInputView.test.tsx.snap b/app/components/UI/Stake/Views/UnstakeInputView/__snapshots__/UnstakeInputView.test.tsx.snap index 263d1be6b4e1..5e7927b0b5c4 100644 --- a/app/components/UI/Stake/Views/UnstakeInputView/__snapshots__/UnstakeInputView.test.tsx.snap +++ b/app/components/UI/Stake/Views/UnstakeInputView/__snapshots__/UnstakeInputView.test.tsx.snap @@ -102,49 +102,26 @@ exports[`UnstakeInputView render matches snapshot 1`] = ` pointerEvents="box-none" style={ { - "alignItems": "flex-start", - "bottom": 0, - "justifyContent": "center", - "left": 0, - "opacity": 1, - "position": "absolute", - "top": 0, - } - } - /> - - - - Unstake ETH - - + Unstake ETH + Staked balance : - 5.79133 ETH + 4.59996 ETH = { - fetchFromApi: jest.fn(), - getPooledStakes: jest.fn(), - getVaultData: jest.fn(), - getPooledStakingEligibility: jest.fn(), - baseUrl: 'https://staking.api.com', -}; - -const MOCK_POOLED_STAKING_CONTRACT_SERVICE = { - chainId: ChainId.ETHEREUM, - connectSignerOrProvider: jest.fn(), - contract: new Contract('0x0000000000000000000000000000000000000000', []), - convertToShares: jest.fn(), - encodeClaimExitedAssetsTransactionData: jest.fn(), - encodeDepositTransactionData: jest.fn(), - encodeEnterExitQueueTransactionData: jest.fn(), - encodeMulticallTransactionData: jest.fn(), - estimateClaimExitedAssetsGas: jest.fn(), - estimateDepositGas: jest.fn(), - estimateEnterExitQueueGas: jest.fn(), - estimateMulticallGas: jest.fn(), -}; - -export const MOCK_POOL_STAKING_SDK: Stake = { - stakingContract: MOCK_POOLED_STAKING_CONTRACT_SERVICE, - stakingApiService: MOCK_STAKING_API_SERVICE as StakingApiService, - sdkType: StakingType.POOLED, - setSdkType: jest.fn(), -}; diff --git a/app/components/UI/Stake/components/EstimatedAnnualRewardsCard.tsx b/app/components/UI/Stake/components/EstimatedAnnualRewardsCard.tsx index 7c2b306cef39..5cecf7b494ae 100644 --- a/app/components/UI/Stake/components/EstimatedAnnualRewardsCard.tsx +++ b/app/components/UI/Stake/components/EstimatedAnnualRewardsCard.tsx @@ -4,7 +4,6 @@ import { strings } from '../../../../../locales/i18n'; import Icon, { IconColor, IconName, - IconSize, } from '../../../../component-library/components/Icons/Icon'; import Text, { TextColor, @@ -12,7 +11,6 @@ import Text, { } from '../../../../component-library/components/Texts/Text'; import { useTheme } from '../../../../util/theme'; import type { Colors } from '../../../../util/theme/models'; -import SkeletonPlaceholder from 'react-native-skeleton-placeholder'; const createStyles = (colors: Colors) => StyleSheet.create({ @@ -44,14 +42,12 @@ const createStyles = (colors: Colors) => interface EstimatedAnnualRewardsCardProps { estimatedAnnualRewards: string; - isLoading?: boolean; onIconPress: () => void; } const EstimatedAnnualRewardsCard = ({ estimatedAnnualRewards, onIconPress, - isLoading = false, }: EstimatedAnnualRewardsCardProps) => { const { colors } = useTheme(); const styles = createStyles(colors); @@ -67,27 +63,13 @@ const EstimatedAnnualRewardsCard = ({ onPress={onIconPress} accessibilityLabel="Learn More" > - + - {isLoading ? ( - - - - ) : ( - - {estimatedAnnualRewards} - - )} + + {estimatedAnnualRewards} + - Unstake anytime. Typically takes less than 3 days, but can take up to 11 days to process. + Unstake anytime. Typically takes up to 11 days to process. { const sheetRef = useRef(null); const navigation = useNavigation(); - const { trackEvent, createEventBuilder } = useMetrics(); const handleClose = () => { sheetRef.current?.onCloseBottomSheet(); @@ -93,15 +91,6 @@ const LearnMoreModal = () => { url: POOLED_STAKING_FAQ_URL, }, }); - trackEvent( - createEventBuilder(MetaMetricsEvents.STAKE_LEARN_MORE_CLICKED) - .addProperties({ - selected_provider: 'consensys', - text: 'Learn More', - location: 'Learn More Modal' - }) - .build() - ); }} // Take to the faq page label={strings('stake.learn_more')} variant={ButtonVariants.Secondary} diff --git a/app/components/UI/Stake/components/MaxInputModal/MaxInputModal.styles.ts b/app/components/UI/Stake/components/MaxInputModal/MaxInputModal.styles.ts deleted file mode 100644 index ae5cd275a1e3..000000000000 --- a/app/components/UI/Stake/components/MaxInputModal/MaxInputModal.styles.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { StyleSheet } from 'react-native'; - -const createMaxInputModalStyles = () => - StyleSheet.create({ - container: { - paddingHorizontal: 16, - }, - textContainer: { - paddingBottom: 16, - paddingRight: 16, - }, - buttonContainer: { - flexDirection: 'row', - gap: 16, - paddingHorizontal: 16, - paddingBottom: 16, - }, - button: { - flex: 1, - }, - }); - -export default createMaxInputModalStyles; diff --git a/app/components/UI/Stake/components/MaxInputModal/MaxInputModal.test.tsx b/app/components/UI/Stake/components/MaxInputModal/MaxInputModal.test.tsx deleted file mode 100644 index 8092f9d9fc5d..000000000000 --- a/app/components/UI/Stake/components/MaxInputModal/MaxInputModal.test.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import { renderScreen } from '../../../../../util/test/renderWithProvider'; -import MaxInputModal from '.'; -import { fireEvent } from '@testing-library/react-native'; -import Routes from '../../../../../constants/navigation/Routes'; - -const mockNavigate = jest.fn(); -const mockGoBack = jest.fn(); -const mockHandleMaxPress = jest.fn(); - -jest.mock('@react-navigation/native', () => { - const actualReactNavigation = jest.requireActual('@react-navigation/native'); - return { - ...actualReactNavigation, - useRoute: () => ({ - params: { - handleMaxPress: mockHandleMaxPress, - }, - }), - useNavigation: () => ({ - navigate: mockNavigate, - goBack: mockGoBack, - }), - }; -}); - -const renderMaxInputModal = () => - renderScreen(MaxInputModal, { name: Routes.STAKING.MODALS.MAX_INPUT }); - -describe('MaxInputModal', () => { - it('render matches snapshot', () => { - const { toJSON } = renderMaxInputModal(); - expect(toJSON()).toMatchSnapshot(); - }); - - it('calls handleMaxPress when "Use max" button is pressed', () => { - const { getByText } = renderMaxInputModal(); - - // Press the "Use Max" button - const useMaxButton = getByText('Use max'); - fireEvent.press(useMaxButton); - - // Check if handleMaxPress was called - expect(mockHandleMaxPress).toHaveBeenCalledTimes(1); - }); - - it('closes the BottomSheet when "Cancel" button is pressed', () => { - const { getByText } = renderMaxInputModal(); - - // Press the "Cancel" button - const cancelButton = getByText('Cancel'); - fireEvent.press(cancelButton); - - // Check if the BottomSheet's close function was called - expect(mockGoBack).toHaveBeenCalled(); - }); - - it('closes the BottomSheet when "Use Max" button is pressed', () => { - const { getByText } = renderMaxInputModal(); - - // Press the "Use Max" button - const useMaxButton = getByText('Use max'); - fireEvent.press(useMaxButton); - - // Check if the BottomSheet's close function was called - expect(mockGoBack).toHaveBeenCalled(); - }); -}); diff --git a/app/components/UI/Stake/components/MaxInputModal/__snapshots__/MaxInputModal.test.tsx.snap b/app/components/UI/Stake/components/MaxInputModal/__snapshots__/MaxInputModal.test.tsx.snap deleted file mode 100644 index c3aa8b2abf50..000000000000 --- a/app/components/UI/Stake/components/MaxInputModal/__snapshots__/MaxInputModal.test.tsx.snap +++ /dev/null @@ -1,656 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`MaxInputModal render matches snapshot 1`] = ` - - - - - - - - - - - - - MaxInput - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Max - - - - - - - - - - - - - Max is the total amount of ETH you have, minus the gas fee required to stake. It’s a good idea to keep some extra ETH in your wallet for future transactions. - - - - - - - - Cancel - - - - - - - Use max - - - - - - - - - - - - - - - - - -`; diff --git a/app/components/UI/Stake/components/MaxInputModal/index.tsx b/app/components/UI/Stake/components/MaxInputModal/index.tsx deleted file mode 100644 index a7534a2214c6..000000000000 --- a/app/components/UI/Stake/components/MaxInputModal/index.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import React, { useRef } from 'react'; -import { View } from 'react-native'; -import BottomSheet, { - type BottomSheetRef, -} from '../../../../../component-library/components/BottomSheets/BottomSheet'; -import Text, { - TextVariant, -} from '../../../../../component-library/components/Texts/Text'; -import Button, { - ButtonSize, - ButtonVariants, - ButtonWidthTypes, -} from '../../../../../component-library/components/Buttons/Button'; -import { strings } from '../../../../../../locales/i18n'; -import BottomSheetHeader from '../../../../../component-library/components/BottomSheets/BottomSheetHeader'; -import createMaxInputModalStyles from './MaxInputModal.styles'; -import { useRoute, RouteProp } from '@react-navigation/native'; - -const styles = createMaxInputModalStyles(); - -interface MaxInputModalRouteParams { - handleMaxPress: () => void; -} - -const MaxInputModal = () => { - const route = - useRoute>(); - const sheetRef = useRef(null); - - const { handleMaxPress } = route.params; - - const handleCancel = () => { - sheetRef.current?.onCloseBottomSheet(); - }; - - const handleConfirm = () => { - sheetRef.current?.onCloseBottomSheet(); - handleMaxPress(); - }; - - return ( - - - - - {strings('stake.max_modal.title')} - - - - - {strings('stake.max_modal.description')} - - - - - - diff --git a/app/components/Views/NFTAutoDetectionModal/NFTAutoDetectionModal.tsx b/app/components/Views/NFTAutoDetectionModal/NFTAutoDetectionModal.tsx index df3930970af8..bf787491664b 100644 --- a/app/components/Views/NFTAutoDetectionModal/NFTAutoDetectionModal.tsx +++ b/app/components/Views/NFTAutoDetectionModal/NFTAutoDetectionModal.tsx @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-require-imports */ /* eslint-disable import/no-commonjs */ /* eslint-disable @typescript-eslint/no-var-requires */ -import React, { useRef } from 'react'; +import React, { useRef, useCallback } from 'react'; import BottomSheet, { BottomSheetRef, } from '../../../component-library/components/BottomSheets/BottomSheet'; @@ -35,29 +35,31 @@ const NFTAutoDetectionModal = () => { const chainId = useSelector(selectChainId); const displayNftMedia = useSelector(selectDisplayNftMedia); const { trackEvent } = useMetrics(); - - const enableNftDetectionAndDismissModal = (value: boolean) => { - if (value) { - const { PreferencesController } = Engine.context; - if (!displayNftMedia) { - PreferencesController.setDisplayNftMedia(true); + const enableNftDetectionAndDismissModal = useCallback( + (value: boolean) => { + if (value) { + const { PreferencesController } = Engine.context; + if (!displayNftMedia) { + PreferencesController.setDisplayNftMedia(true); + } + PreferencesController.setUseNftDetection(true); + trackEvent(MetaMetricsEvents.NFT_AUTO_DETECTION_MODAL_ENABLE, { + chainId, + }); + } else { + trackEvent(MetaMetricsEvents.NFT_AUTO_DETECTION_MODAL_DISABLE, { + chainId, + }); } - PreferencesController.setUseNftDetection(true); - trackEvent(MetaMetricsEvents.NFT_AUTO_DETECTION_MODAL_ENABLE, { - chainId, - }); - } else { - trackEvent(MetaMetricsEvents.NFT_AUTO_DETECTION_MODAL_DISABLE, { - chainId, - }); - } - if (sheetRef?.current) { - sheetRef.current.onCloseBottomSheet(); - } else { - navigation.goBack(); - } - }; + if (sheetRef?.current) { + sheetRef.current.onCloseBottomSheet(); + } else { + navigation.goBack(); + } + }, + [displayNftMedia, trackEvent, chainId, navigation], + ); return ( diff --git a/app/components/Views/NavigationUnitTest/__snapshots__/TestScreen2.test.js.snap b/app/components/Views/NavigationUnitTest/__snapshots__/TestScreen2.test.js.snap index bae18b32fea6..ae5908847fd5 100644 --- a/app/components/Views/NavigationUnitTest/__snapshots__/TestScreen2.test.js.snap +++ b/app/components/Views/NavigationUnitTest/__snapshots__/TestScreen2.test.js.snap @@ -414,7 +414,7 @@ exports[`NavigationUnitTest should render correctly 1`] = ` } } > - TestSubStack + TestScreen2 @@ -592,309 +592,10 @@ exports[`NavigationUnitTest should render correctly 1`] = ` } } > - - - - - - - - - - - - TestScreen3 - - - - - - - - - - - - - - - - - - TestScreen3 - THIS SHOULD NOT HAVE CHANGED, take a deeper look - - - - - - - - - - + + TestScreen2 + THIS SHOULD NOT HAVE CHANGED, take a deeper look + diff --git a/app/components/Views/NavigationUnitTest/index.js b/app/components/Views/NavigationUnitTest/index.js index 0e314b9b3bd3..f142272337ca 100644 --- a/app/components/Views/NavigationUnitTest/index.js +++ b/app/components/Views/NavigationUnitTest/index.js @@ -4,7 +4,6 @@ */ /* eslint-disable react/prop-types */ -/* eslint-disable react/no-unstable-nested-components */ import React from 'react'; import { createStackNavigator } from '@react-navigation/stack'; import { @@ -16,55 +15,54 @@ import { Text } from 'react-native'; const Stack = createStackNavigator(); -const TestScreen = ({ route }) => { - const routes = useNavigationState((state) => state.routes); +const NavigationUnitTestFactory = ({ firstRoute, secondRoute }) => { + const TestScreen = ({ route }) => { + const routes = useNavigationState((state) => state.routes); - const name = findRouteNameFromNavigatorState(routes); + const name = findRouteNameFromNavigatorState(routes); - if (name !== route.params.screenName) - throw new Error( - 'Error, react navigation api changed: https://reactnavigation.org/docs/navigation-prop/#dangerouslygetstate', - ); + if (name !== route.params.screenName) + throw new Error( + 'Error, react navigation api changed: https://reactnavigation.org/docs/navigation-prop/#dangerouslygetstate', + ); - return {name} THIS SHOULD NOT HAVE CHANGED, take a deeper look; -}; - -const TestSubStack = () => ( - - - -); + return {name} THIS SHOULD NOT HAVE CHANGED, take a deeper look; + }; -const TestStack = ({ secondRoute }) => ( - - - - -); + const TestSubStack = () => ( + + + + ); -const NavigationUnitTest = ({ firstRoute, secondRoute }) => ( - - - + const TestStack = () => ( + + - -); + ); -const NavigationUnitTestFactory = ({ firstRoute, secondRoute }) => ( - -); + const NavigationUnitTest = () => ( + + + + + + + ); + return ; +}; export default NavigationUnitTestFactory; diff --git a/app/components/Views/NetworkConnect/NetworkConnectMultiSelector/NetworkConnectMultiSelector.tsx b/app/components/Views/NetworkConnect/NetworkConnectMultiSelector/NetworkConnectMultiSelector.tsx index d44f7b3bea50..181b86d44d77 100644 --- a/app/components/Views/NetworkConnect/NetworkConnectMultiSelector/NetworkConnectMultiSelector.tsx +++ b/app/components/Views/NetworkConnect/NetworkConnectMultiSelector/NetworkConnectMultiSelector.tsx @@ -1,10 +1,6 @@ // Third party dependencies. -import React, { useCallback, useState, useEffect } from 'react'; +import React, { useCallback, useState } from 'react'; import { Platform, SafeAreaView, View } from 'react-native'; -import { useSelector } from 'react-redux'; -import { useNavigation } from '@react-navigation/native'; -import { NetworkConfiguration } from '@metamask/network-controller'; -import { isEqual } from 'lodash'; // External dependencies. import { strings } from '../../../../../locales/i18n'; @@ -14,12 +10,14 @@ import Button, { ButtonVariants, } from '../../../../component-library/components/Buttons/Button'; import SheetHeader from '../../../../component-library/components/Sheet/SheetHeader'; +import { useNavigation } from '@react-navigation/native'; import { useStyles } from '../../../../component-library/hooks'; import { USER_INTENT } from '../../../../constants/permissions'; import HelpText, { HelpTextSeverity, } from '../../../../component-library/components/Form/HelpText'; +import { Network } from '../../../../components/UI/NetworkSelectorList/NetworkSelectorList.types'; // Internal dependencies. import ConnectNetworkModalSelectorsIDs from '../../../../../e2e/selectors/Modals/ConnectNetworkModal.selectors'; @@ -28,11 +26,7 @@ import { NetworkConnectMultiSelectorProps } from './NetworkConnectMultiSelector. import Routes from '../../../../constants/navigation/Routes'; import Checkbox from '../../../../component-library/components/Checkbox'; import NetworkSelectorList from '../../../UI/NetworkSelectorList/NetworkSelectorList'; -import { selectNetworkConfigurations } from '../../../../selectors/networkController'; -import Engine from '../../../../core/Engine'; -import { PermissionKeys } from '../../../../core/Permissions/specifications'; -import { CaveatTypes } from '../../../../core/Permissions/constants'; -import { getNetworkImageSource } from '../../../../util/networks'; +import { PopularList } from '../../../../util/networks/customNetworks'; const NetworkConnectMultiSelector = ({ isLoading, @@ -41,122 +35,34 @@ const NetworkConnectMultiSelector = ({ hostname, onBack, isRenderedAsBottomSheet = true, - onNetworksSelected, - initialChainId, - selectedChainIds: propSelectedChainIds, - isInitializedWithPermittedChains = true, }: NetworkConnectMultiSelectorProps) => { const { styles } = useStyles(styleSheet, { isRenderedAsBottomSheet }); const { navigate } = useNavigation(); - const [selectedChainIds, setSelectedChainIds] = useState([]); - const [originalChainIds, setOriginalChainIds] = useState([]); - const networkConfigurations = useSelector(selectNetworkConfigurations); - - useEffect(() => { - if (propSelectedChainIds && !isInitializedWithPermittedChains) { - setSelectedChainIds(propSelectedChainIds); - setOriginalChainIds(propSelectedChainIds); - } - }, [propSelectedChainIds, isInitializedWithPermittedChains]); - - useEffect(() => { - if (!isInitializedWithPermittedChains) return; - - let currentlyPermittedChains: string[] = []; - try { - const caveat = Engine.context.PermissionController.getCaveat( - hostname, - PermissionKeys.permittedChains, - CaveatTypes.restrictNetworkSwitching, - ); - if (Array.isArray(caveat?.value)) { - currentlyPermittedChains = caveat.value.filter( - (item): item is string => typeof item === 'string', - ); - } - } catch (e) { - // noop - } - - if (currentlyPermittedChains.length === 0 && initialChainId) { - currentlyPermittedChains = [initialChainId]; - } + const [selectedNetworkIds, setSelectedNetworkIds] = useState([]); - setSelectedChainIds(currentlyPermittedChains); - setOriginalChainIds(currentlyPermittedChains); - }, [hostname, isInitializedWithPermittedChains, initialChainId]); - - const handleUpdateNetworkPermissions = useCallback(async () => { - if (onNetworksSelected) { - onNetworksSelected(selectedChainIds); - } else { - let hasPermittedChains = false; - try { - hasPermittedChains = Engine.context.PermissionController.hasCaveat( - hostname, - PermissionKeys.permittedChains, - CaveatTypes.restrictNetworkSwitching, - ); - } catch { - // noop - } - - if (hasPermittedChains) { - Engine.context.PermissionController.updateCaveat( - hostname, - PermissionKeys.permittedChains, - CaveatTypes.restrictNetworkSwitching, - selectedChainIds, - ); - } else { - Engine.context.PermissionController.grantPermissionsIncremental({ - subject: { - origin: hostname, - }, - approvedPermissions: { - [PermissionKeys.permittedChains]: { - caveats: [ - { - type: CaveatTypes.restrictNetworkSwitching, - value: selectedChainIds, - }, - ], - }, - }, - }); - } - onUserAction(USER_INTENT.Confirm); - } - }, [selectedChainIds, hostname, onUserAction, onNetworksSelected]); - - const networks = Object.entries(networkConfigurations).map( - ([key, network]: [string, NetworkConfiguration]) => ({ - id: key, - name: network.name, - rpcUrl: network.rpcEndpoints[network.defaultRpcEndpointIndex].url, - isSelected: false, - //@ts-expect-error - The utils/network file is still JS and this function expects a networkType, and should be optional - imageSource: getNetworkImageSource({ - chainId: network?.chainId, - }), - }), - ); + const mockNetworks: Network[] = PopularList.map((network) => ({ + id: network.chainId, + name: network.nickname, + rpcUrl: network.rpcUrl, + isSelected: false, + imageSource: network.rpcPrefs.imageSource, + })); const onSelectNetwork = useCallback( - (clickedChainId) => { - const selectedAddressIndex = selectedChainIds.indexOf(clickedChainId); + (clickedNetworkId) => { + const selectedAddressIndex = selectedNetworkIds.indexOf(clickedNetworkId); // Reconstruct selected network ids. - const newNetworkList = networks.reduce((acc, { id }) => { - if (clickedChainId === id) { + const newNetworkList = mockNetworks.reduce((acc, { id }) => { + if (clickedNetworkId === id) { selectedAddressIndex === -1 && acc.push(id); - } else if (selectedChainIds.includes(id)) { + } else if (selectedNetworkIds.includes(id)) { acc.push(id); } return acc; }, [] as string[]); - setSelectedChainIds(newNetworkList); + setSelectedNetworkIds(newNetworkList); }, - [networks, selectedChainIds], + [mockNetworks, selectedNetworkIds], ); const toggleRevokeAllNetworkPermissionsModal = useCallback(() => { @@ -171,12 +77,13 @@ const NetworkConnectMultiSelector = ({ }, }); }, [navigate, urlWithProtocol]); - const areAllNetworksSelected = networks + + const areAllNetworksSelected = mockNetworks .map(({ id }) => id) - .every((id) => selectedChainIds?.includes(id)); + .every((id) => selectedNetworkIds.includes(id)); - const areAnyNetworksSelected = selectedChainIds?.length !== 0; - const areNoNetworksSelected = selectedChainIds?.length === 0; + const areAnyNetworksSelected = selectedNetworkIds?.length !== 0; + const areNoNetworksSelected = selectedNetworkIds?.length === 0; const renderSelectAllCheckbox = useCallback((): React.JSX.Element | null => { const areSomeNetworksSelectedButNotAll = @@ -184,13 +91,13 @@ const NetworkConnectMultiSelector = ({ const selectAll = () => { if (isLoading) return; - const allSelectedChainIds = networks.map(({ id }) => id); - setSelectedChainIds(allSelectedChainIds); + const allSelectedNetworkIds = mockNetworks.map(({ id }) => id); + setSelectedNetworkIds(allSelectedNetworkIds); }; const unselectAll = () => { if (isLoading) return; - setSelectedChainIds([]); + setSelectedNetworkIds([]); }; const onPress = () => { @@ -211,32 +118,29 @@ const NetworkConnectMultiSelector = ({ }, [ areAllNetworksSelected, areAnyNetworksSelected, - networks, + mockNetworks, isLoading, - setSelectedChainIds, + setSelectedNetworkIds, styles.selectAllContainer, ]); - const isUpdateDisabled = - selectedChainIds.length === 0 || - isLoading || - isEqual(selectedChainIds, originalChainIds); + const renderCtaButtons = useCallback(() => { + const isConnectDisabled = Boolean(!selectedNetworkIds.length) || isLoading; - const renderCtaButtons = useCallback( - () => ( + return ( {areAnyNetworksSelected && ( ); - const renderSecondaryButton = () => ( + const SecondaryButton = () => (