From bff1e2160746363085f1f5a9bb92eb5e0e958554 Mon Sep 17 00:00:00 2001 From: Howard Braham Date: Mon, 7 Oct 2024 20:48:14 -0700 Subject: [PATCH 1/6] refactor: routes constants (#27078) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This is one small step in the larger task to refactor routing, in order to speed up load time (MetaMask/MetaMask-planning#2898) The changes are mostly to increase DRY, and to make a closer coupling between connected routes and their analytics tracking names. I wanted to get this in separately in order to reduce complexity and merge conflicts later. [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/27078?quickstart=1) ## **Related issues** Progresses: MetaMask/MetaMask-planning#2898 ## **Manual testing steps** ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [x] 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 - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.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: legobeat <109787230+legobeat@users.noreply.github.com> --- ui/helpers/constants/routes.ts | 583 ++++++++++++++++----------------- 1 file changed, 284 insertions(+), 299 deletions(-) diff --git a/ui/helpers/constants/routes.ts b/ui/helpers/constants/routes.ts index c755c9914f25..eec9075a64d8 100644 --- a/ui/helpers/constants/routes.ts +++ b/ui/helpers/constants/routes.ts @@ -1,307 +1,292 @@ -const DEFAULT_ROUTE = '/'; -const UNLOCK_ROUTE = '/unlock'; -const LOCK_ROUTE = '/lock'; -const ASSET_ROUTE = '/asset'; -const SETTINGS_ROUTE = '/settings'; -const GENERAL_ROUTE = '/settings/general'; -const ADVANCED_ROUTE = '/settings/advanced'; - -const DEVELOPER_OPTIONS_ROUTE = '/settings/developer-options'; -const EXPERIMENTAL_ROUTE = '/settings/experimental'; -const SECURITY_ROUTE = '/settings/security'; -const ABOUT_US_ROUTE = '/settings/about-us'; -const ALERTS_ROUTE = '/settings/alerts'; -const NETWORKS_ROUTE = '/settings/networks'; -const NETWORKS_FORM_ROUTE = '/settings/networks/form'; -const ADD_NETWORK_ROUTE = '/settings/networks/add-network'; -const ADD_POPULAR_CUSTOM_NETWORK = +// PATH_NAME_MAP is used to pull a convenient name for analytics tracking events. The key must +// be react-router ready path, and can include params such as :id for popup windows +export const PATH_NAME_MAP: { [key: string]: string } = {}; + +export const DEFAULT_ROUTE = '/'; +PATH_NAME_MAP[DEFAULT_ROUTE] = 'Home'; + +export const UNLOCK_ROUTE = '/unlock'; +PATH_NAME_MAP[UNLOCK_ROUTE] = 'Unlock Page'; + +export const LOCK_ROUTE = '/lock'; +PATH_NAME_MAP[LOCK_ROUTE] = 'Lock Page'; + +export const ASSET_ROUTE = '/asset'; +PATH_NAME_MAP[`${ASSET_ROUTE}/:asset/:id`] = `Asset Page`; +PATH_NAME_MAP[`${ASSET_ROUTE}/image/:asset/:id`] = `Nft Image Page`; + +export const SETTINGS_ROUTE = '/settings'; +PATH_NAME_MAP[SETTINGS_ROUTE] = 'Settings Page'; + +export const GENERAL_ROUTE = '/settings/general'; +PATH_NAME_MAP[GENERAL_ROUTE] = 'General Settings Page'; + +export const ADVANCED_ROUTE = '/settings/advanced'; +PATH_NAME_MAP[ADVANCED_ROUTE] = 'Advanced Settings Page'; + +export const DEVELOPER_OPTIONS_ROUTE = '/settings/developer-options'; +// DEVELOPER_OPTIONS_ROUTE not in PATH_NAME_MAP because we're not tracking analytics for this page + +export const EXPERIMENTAL_ROUTE = '/settings/experimental'; +PATH_NAME_MAP[EXPERIMENTAL_ROUTE] = 'Experimental Settings Page'; + +export const SECURITY_ROUTE = '/settings/security'; +PATH_NAME_MAP[SECURITY_ROUTE] = 'Security Settings Page'; + +export const ABOUT_US_ROUTE = '/settings/about-us'; +PATH_NAME_MAP[ABOUT_US_ROUTE] = 'About Us Page'; + +export const ALERTS_ROUTE = '/settings/alerts'; +PATH_NAME_MAP[ALERTS_ROUTE] = 'Alerts Settings Page'; + +export const NETWORKS_ROUTE = '/settings/networks'; +PATH_NAME_MAP[NETWORKS_ROUTE] = 'Network Settings Page'; + +export const NETWORKS_FORM_ROUTE = '/settings/networks/form'; +PATH_NAME_MAP[NETWORKS_FORM_ROUTE] = 'Network Settings Page Form'; + +export const ADD_NETWORK_ROUTE = '/settings/networks/add-network'; +PATH_NAME_MAP[ADD_NETWORK_ROUTE] = 'Add Network From Settings Page Form'; + +export const ADD_POPULAR_CUSTOM_NETWORK = '/settings/networks/add-popular-custom-network'; -const CONTACT_LIST_ROUTE = '/settings/contact-list'; -const CONTACT_EDIT_ROUTE = '/settings/contact-list/edit-contact'; -const CONTACT_ADD_ROUTE = '/settings/contact-list/add-contact'; -const CONTACT_VIEW_ROUTE = '/settings/contact-list/view-contact'; -const REVEAL_SEED_ROUTE = '/seed'; -const RESTORE_VAULT_ROUTE = '/restore-vault'; -const IMPORT_TOKEN_ROUTE = '/import-token'; -const IMPORT_TOKENS_ROUTE = '/import-tokens'; -const CONFIRM_IMPORT_TOKEN_ROUTE = '/confirm-import-token'; -const CONFIRM_ADD_SUGGESTED_TOKEN_ROUTE = '/confirm-add-suggested-token'; -const NEW_ACCOUNT_ROUTE = '/new-account'; -const CONFIRM_ADD_SUGGESTED_NFT_ROUTE = '/confirm-add-suggested-nft'; -const CONNECT_HARDWARE_ROUTE = '/new-account/connect'; +PATH_NAME_MAP[ADD_POPULAR_CUSTOM_NETWORK] = + 'Add Network From A List Of Popular Custom Networks'; + +export const CONTACT_LIST_ROUTE = '/settings/contact-list'; +PATH_NAME_MAP[CONTACT_LIST_ROUTE] = 'Contact List Settings Page'; + +export const CONTACT_EDIT_ROUTE = '/settings/contact-list/edit-contact'; +PATH_NAME_MAP[`${CONTACT_EDIT_ROUTE}/:address`] = 'Edit Contact Settings Page'; + +export const CONTACT_ADD_ROUTE = '/settings/contact-list/add-contact'; +PATH_NAME_MAP[CONTACT_ADD_ROUTE] = 'Add Contact Settings Page'; + +export const CONTACT_VIEW_ROUTE = '/settings/contact-list/view-contact'; +PATH_NAME_MAP[`${CONTACT_VIEW_ROUTE}/:address`] = 'View Contact Settings Page'; + +export const REVEAL_SEED_ROUTE = '/seed'; +PATH_NAME_MAP[REVEAL_SEED_ROUTE] = 'Reveal Secret Recovery Phrase Page'; + +export const RESTORE_VAULT_ROUTE = '/restore-vault'; +PATH_NAME_MAP[RESTORE_VAULT_ROUTE] = 'Restore Vault Page'; + +export const IMPORT_TOKEN_ROUTE = '/import-token'; +PATH_NAME_MAP[IMPORT_TOKEN_ROUTE] = 'Import Token Page'; + +export const IMPORT_TOKENS_ROUTE = '/import-tokens'; +PATH_NAME_MAP[IMPORT_TOKENS_ROUTE] = 'Import Tokens Page'; + +export const CONFIRM_IMPORT_TOKEN_ROUTE = '/confirm-import-token'; +PATH_NAME_MAP[CONFIRM_IMPORT_TOKEN_ROUTE] = 'Confirm Import Token Page'; + +export const CONFIRM_ADD_SUGGESTED_TOKEN_ROUTE = '/confirm-add-suggested-token'; +PATH_NAME_MAP[CONFIRM_ADD_SUGGESTED_TOKEN_ROUTE] = + 'Confirm Add Suggested Token Page'; + +export const NEW_ACCOUNT_ROUTE = '/new-account'; +PATH_NAME_MAP[NEW_ACCOUNT_ROUTE] = 'New Account Page'; + +export const CONFIRM_ADD_SUGGESTED_NFT_ROUTE = '/confirm-add-suggested-nft'; +PATH_NAME_MAP[CONFIRM_ADD_SUGGESTED_NFT_ROUTE] = + 'Confirm Add Suggested NFT Page'; + +export const CONNECT_HARDWARE_ROUTE = '/new-account/connect'; +PATH_NAME_MAP[CONNECT_HARDWARE_ROUTE] = 'Connect Hardware Wallet Page'; + ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) -const CUSTODY_ACCOUNT_ROUTE = '/new-account/custody'; -const INSTITUTIONAL_FEATURES_DONE_ROUTE = '/institutional-features/done'; -const CUSTODY_ACCOUNT_DONE_ROUTE = '/new-account/custody/done'; -const CONFIRM_ADD_CUSTODIAN_TOKEN = '/confirm-add-custodian-token'; -const INTERACTIVE_REPLACEMENT_TOKEN_PAGE = +export const CUSTODY_ACCOUNT_ROUTE = '/new-account/custody'; +PATH_NAME_MAP[CUSTODY_ACCOUNT_ROUTE] = 'Connect Custody'; + +export const INSTITUTIONAL_FEATURES_DONE_ROUTE = '/institutional-features/done'; +PATH_NAME_MAP[INSTITUTIONAL_FEATURES_DONE_ROUTE] = + 'Institutional Features Done Page'; + +export const CUSTODY_ACCOUNT_DONE_ROUTE = '/new-account/custody/done'; +PATH_NAME_MAP[CUSTODY_ACCOUNT_DONE_ROUTE] = 'Connect Custody Account done'; + +export const CONFIRM_ADD_CUSTODIAN_TOKEN = '/confirm-add-custodian-token'; +PATH_NAME_MAP[CONFIRM_ADD_CUSTODIAN_TOKEN] = 'Confirm Add Custodian Token'; + +export const INTERACTIVE_REPLACEMENT_TOKEN_PAGE = '/interactive-replacement-token-page'; -const SRP_REMINDER = '/onboarding/remind-srp'; +PATH_NAME_MAP[INTERACTIVE_REPLACEMENT_TOKEN_PAGE] = + 'Interactive replacement token page'; + +export const SRP_REMINDER = '/onboarding/remind-srp'; +PATH_NAME_MAP[SRP_REMINDER] = 'Secret Recovery Phrase Reminder'; ///: END:ONLY_INCLUDE_IF -const SEND_ROUTE = '/send'; -const CONNECTIONS = '/connections'; -const REVIEW_PERMISSIONS = '/review-permissions'; -const PERMISSIONS = '/permissions'; -const TOKEN_DETAILS = '/token-details'; -const CONNECT_ROUTE = '/connect'; -const CONNECT_CONFIRM_PERMISSIONS_ROUTE = '/confirm-permissions'; -const CONNECT_SNAPS_CONNECT_ROUTE = '/snaps-connect'; -const CONNECT_SNAP_INSTALL_ROUTE = '/snap-install'; -const CONNECT_SNAP_UPDATE_ROUTE = '/snap-update'; -const CONNECT_SNAP_RESULT_ROUTE = '/snap-install-result'; -const SNAPS_ROUTE = '/snaps'; -const SNAPS_VIEW_ROUTE = '/snaps/view'; -const NOTIFICATIONS_ROUTE = '/notifications'; -const NOTIFICATIONS_SETTINGS_ROUTE = '/notifications/settings'; -const CONNECTED_ROUTE = '/connected'; -const CONNECTED_ACCOUNTS_ROUTE = '/connected/accounts'; -const CROSS_CHAIN_SWAP_ROUTE = '/cross-chain'; -const SWAPS_ROUTE = '/swaps'; -const PREPARE_SWAP_ROUTE = '/swaps/prepare-swap-page'; -const SWAPS_NOTIFICATION_ROUTE = '/swaps/notification-page'; -const BUILD_QUOTE_ROUTE = '/swaps/build-quote'; -const VIEW_QUOTE_ROUTE = '/swaps/view-quote'; -const LOADING_QUOTES_ROUTE = '/swaps/loading-quotes'; -const AWAITING_SIGNATURES_ROUTE = '/swaps/awaiting-signatures'; -const SMART_TRANSACTION_STATUS_ROUTE = '/swaps/smart-transaction-status'; -const AWAITING_SWAP_ROUTE = '/swaps/awaiting-swap'; -const SWAPS_ERROR_ROUTE = '/swaps/swaps-error'; -const SWAPS_MAINTENANCE_ROUTE = '/swaps/maintenance'; - -const ONBOARDING_ROUTE = '/onboarding'; -const ONBOARDING_REVIEW_SRP_ROUTE = '/onboarding/review-recovery-phrase'; -const ONBOARDING_CONFIRM_SRP_ROUTE = '/onboarding/confirm-recovery-phrase'; -const ONBOARDING_CREATE_PASSWORD_ROUTE = '/onboarding/create-password'; -const ONBOARDING_COMPLETION_ROUTE = '/onboarding/completion'; -const MMI_ONBOARDING_COMPLETION_ROUTE = '/onboarding/account-completion'; -const ONBOARDING_UNLOCK_ROUTE = '/onboarding/unlock'; -const ONBOARDING_HELP_US_IMPROVE_ROUTE = '/onboarding/help-us-improve'; -const ONBOARDING_IMPORT_WITH_SRP_ROUTE = + +export const SEND_ROUTE = '/send'; +PATH_NAME_MAP[SEND_ROUTE] = 'Send Page'; + +export const CONNECTIONS = '/connections'; +PATH_NAME_MAP[CONNECTIONS] = 'Connections'; + +export const PERMISSIONS = '/permissions'; +PATH_NAME_MAP[PERMISSIONS] = 'Permissions'; + +export const REVIEW_PERMISSIONS = '/review-permissions'; + +export const TOKEN_DETAILS = '/token-details'; +PATH_NAME_MAP[`${TOKEN_DETAILS}/:address`] = 'Token Details Page'; + +export const CONNECT_ROUTE = '/connect'; +PATH_NAME_MAP[`${CONNECT_ROUTE}/:id`] = 'Connect To Site Confirmation Page'; + +export const CONNECT_CONFIRM_PERMISSIONS_ROUTE = '/confirm-permissions'; +PATH_NAME_MAP[`${CONNECT_ROUTE}/:id${CONNECT_CONFIRM_PERMISSIONS_ROUTE}`] = + 'Grant Connected Site Permissions Confirmation Page'; + +export const CONNECT_SNAPS_CONNECT_ROUTE = '/snaps-connect'; +PATH_NAME_MAP[`${CONNECT_ROUTE}/:id${CONNECT_SNAPS_CONNECT_ROUTE}`] = + 'Snaps Connect Page'; + +export const CONNECT_SNAP_INSTALL_ROUTE = '/snap-install'; +PATH_NAME_MAP[`${CONNECT_ROUTE}/:id${CONNECT_SNAP_INSTALL_ROUTE}`] = + 'Snap Install Page'; + +export const CONNECT_SNAP_UPDATE_ROUTE = '/snap-update'; +PATH_NAME_MAP[`${CONNECT_ROUTE}/:id${CONNECT_SNAP_UPDATE_ROUTE}`] = + 'Snap Update Page'; + +export const CONNECT_SNAP_RESULT_ROUTE = '/snap-install-result'; +PATH_NAME_MAP[`${CONNECT_ROUTE}/:id${CONNECT_SNAP_RESULT_ROUTE}`] = + 'Snap Install Result Page'; + +export const SNAPS_ROUTE = '/snaps'; +PATH_NAME_MAP[SNAPS_ROUTE] = 'Snaps List Page'; + +export const SNAPS_VIEW_ROUTE = '/snaps/view'; +PATH_NAME_MAP[`${SNAPS_VIEW_ROUTE}/:snapId`] = 'Snap View Page'; + +export const NOTIFICATIONS_ROUTE = '/notifications'; +PATH_NAME_MAP[NOTIFICATIONS_ROUTE] = 'Notifications Page'; +PATH_NAME_MAP[`${NOTIFICATIONS_ROUTE}/:uuid`] = 'Notification Detail Page'; + +export const NOTIFICATIONS_SETTINGS_ROUTE = '/notifications/settings'; +PATH_NAME_MAP[NOTIFICATIONS_SETTINGS_ROUTE] = 'Notifications Settings Page'; + +export const CONNECTED_ROUTE = '/connected'; +PATH_NAME_MAP[CONNECTED_ROUTE] = 'Sites Connected To This Account Page'; + +export const CONNECTED_ACCOUNTS_ROUTE = '/connected/accounts'; +PATH_NAME_MAP[CONNECTED_ACCOUNTS_ROUTE] = + 'Accounts Connected To This Site Page'; + +export const CONFIRM_TRANSACTION_ROUTE = '/confirm-transaction'; +PATH_NAME_MAP[CONFIRM_TRANSACTION_ROUTE] = 'Confirmation Root Page'; +PATH_NAME_MAP[`${CONFIRM_TRANSACTION_ROUTE}/:id`] = 'Confirmation Root Page'; + +export const CONFIRMATION_V_NEXT_ROUTE = '/confirmation'; +PATH_NAME_MAP[CONFIRMATION_V_NEXT_ROUTE] = 'New Confirmation Page'; +PATH_NAME_MAP[`${CONFIRMATION_V_NEXT_ROUTE}/:id`] = 'New Confirmation Page'; + +export const CONFIRM_SEND_ETHER_PATH = '/send-ether'; +PATH_NAME_MAP[`${CONFIRM_TRANSACTION_ROUTE}/:id${CONFIRM_SEND_ETHER_PATH}`] = + 'Confirm Send Ether Transaction Page'; + +export const CONFIRM_SEND_TOKEN_PATH = '/send-token'; +PATH_NAME_MAP[`${CONFIRM_TRANSACTION_ROUTE}/:id${CONFIRM_SEND_TOKEN_PATH}`] = + 'Confirm Send Token Transaction Page'; + +export const CONFIRM_DEPLOY_CONTRACT_PATH = '/deploy-contract'; +PATH_NAME_MAP[ + `${CONFIRM_TRANSACTION_ROUTE}/:id${CONFIRM_DEPLOY_CONTRACT_PATH}` +] = 'Confirm Deploy Contract Transaction Page'; + +export const CONFIRM_APPROVE_PATH = '/approve'; +PATH_NAME_MAP[`${CONFIRM_TRANSACTION_ROUTE}/:id${CONFIRM_APPROVE_PATH}`] = + 'Confirm Approve Transaction Page'; + +export const CONFIRM_SET_APPROVAL_FOR_ALL_PATH = '/set-approval-for-all'; +PATH_NAME_MAP[ + `${CONFIRM_TRANSACTION_ROUTE}/:id${CONFIRM_SET_APPROVAL_FOR_ALL_PATH}` +] = 'Confirm Set Approval For All Transaction Page'; + +export const CONFIRM_TRANSFER_FROM_PATH = '/transfer-from'; +PATH_NAME_MAP[`${CONFIRM_TRANSACTION_ROUTE}/:id${CONFIRM_TRANSFER_FROM_PATH}`] = + 'Confirm Transfer From Transaction Page'; + +export const CONFIRM_SAFE_TRANSFER_FROM_PATH = '/safe-transfer-from'; +PATH_NAME_MAP[ + `${CONFIRM_TRANSACTION_ROUTE}/:id${CONFIRM_SAFE_TRANSFER_FROM_PATH}` +] = 'Confirm Safe Transfer From Transaction Page'; + +export const CONFIRM_TOKEN_METHOD_PATH = '/token-method'; +PATH_NAME_MAP[`${CONFIRM_TRANSACTION_ROUTE}/:id${CONFIRM_TOKEN_METHOD_PATH}`] = + 'Confirm Token Method Transaction Page'; + +export const CONFIRM_INCREASE_ALLOWANCE_PATH = '/increase-allowance'; +PATH_NAME_MAP[ + `${CONFIRM_TRANSACTION_ROUTE}/:id${CONFIRM_INCREASE_ALLOWANCE_PATH}` +] = 'Confirm Increase Allowance Transaction Page'; + +export const SIGNATURE_REQUEST_PATH = '/signature-request'; +PATH_NAME_MAP[`${CONFIRM_TRANSACTION_ROUTE}/:id${SIGNATURE_REQUEST_PATH}`] = + 'Signature Request Page'; + +export const DECRYPT_MESSAGE_REQUEST_PATH = '/decrypt-message-request'; +PATH_NAME_MAP[ + `${CONFIRM_TRANSACTION_ROUTE}/:id${DECRYPT_MESSAGE_REQUEST_PATH}` +] = 'Decrypt Message Request Page'; + +export const ENCRYPTION_PUBLIC_KEY_REQUEST_PATH = + '/encryption-public-key-request'; +PATH_NAME_MAP[ + `${CONFIRM_TRANSACTION_ROUTE}/:id${ENCRYPTION_PUBLIC_KEY_REQUEST_PATH}` +] = 'Encryption Public Key Request Page'; + +export const CROSS_CHAIN_SWAP_ROUTE = '/cross-chain'; + +export const SWAPS_ROUTE = '/swaps'; + +export const PREPARE_SWAP_ROUTE = '/swaps/prepare-swap-page'; +PATH_NAME_MAP[PREPARE_SWAP_ROUTE] = 'Prepare Swap Page'; + +export const SWAPS_NOTIFICATION_ROUTE = '/swaps/notification-page'; +PATH_NAME_MAP[SWAPS_NOTIFICATION_ROUTE] = 'Swaps Notification Page'; + +export const BUILD_QUOTE_ROUTE = '/swaps/build-quote'; +PATH_NAME_MAP[BUILD_QUOTE_ROUTE] = 'Swaps Build Quote Page'; + +export const VIEW_QUOTE_ROUTE = '/swaps/view-quote'; +PATH_NAME_MAP[VIEW_QUOTE_ROUTE] = 'Swaps View Quotes Page'; + +export const LOADING_QUOTES_ROUTE = '/swaps/loading-quotes'; +PATH_NAME_MAP[LOADING_QUOTES_ROUTE] = 'Swaps Loading Quotes Page'; + +export const AWAITING_SIGNATURES_ROUTE = '/swaps/awaiting-signatures'; + +export const SMART_TRANSACTION_STATUS_ROUTE = '/swaps/smart-transaction-status'; + +export const AWAITING_SWAP_ROUTE = '/swaps/awaiting-swap'; +PATH_NAME_MAP[AWAITING_SWAP_ROUTE] = 'Swaps Awaiting Swaps Page'; + +export const SWAPS_ERROR_ROUTE = '/swaps/swaps-error'; +PATH_NAME_MAP[SWAPS_ERROR_ROUTE] = 'Swaps Error Page'; + +export const SWAPS_MAINTENANCE_ROUTE = '/swaps/maintenance'; + +export const ONBOARDING_ROUTE = '/onboarding'; +export const ONBOARDING_REVIEW_SRP_ROUTE = '/onboarding/review-recovery-phrase'; +export const ONBOARDING_CONFIRM_SRP_ROUTE = + '/onboarding/confirm-recovery-phrase'; +export const ONBOARDING_CREATE_PASSWORD_ROUTE = '/onboarding/create-password'; +export const ONBOARDING_COMPLETION_ROUTE = '/onboarding/completion'; +export const MMI_ONBOARDING_COMPLETION_ROUTE = '/onboarding/account-completion'; +export const ONBOARDING_UNLOCK_ROUTE = '/onboarding/unlock'; +export const ONBOARDING_HELP_US_IMPROVE_ROUTE = '/onboarding/help-us-improve'; +export const ONBOARDING_IMPORT_WITH_SRP_ROUTE = '/onboarding/import-with-recovery-phrase'; -const ONBOARDING_SECURE_YOUR_WALLET_ROUTE = '/onboarding/secure-your-wallet'; -const ONBOARDING_PRIVACY_SETTINGS_ROUTE = '/onboarding/privacy-settings'; -const ONBOARDING_PIN_EXTENSION_ROUTE = '/onboarding/pin-extension'; -const ONBOARDING_WELCOME_ROUTE = '/onboarding/welcome'; -const ONBOARDING_METAMETRICS = '/onboarding/metametrics'; +export const ONBOARDING_SECURE_YOUR_WALLET_ROUTE = + '/onboarding/secure-your-wallet'; +export const ONBOARDING_PRIVACY_SETTINGS_ROUTE = '/onboarding/privacy-settings'; +export const ONBOARDING_PIN_EXTENSION_ROUTE = '/onboarding/pin-extension'; +export const ONBOARDING_WELCOME_ROUTE = '/onboarding/welcome'; +export const ONBOARDING_METAMETRICS = '/onboarding/metametrics'; ///: BEGIN:ONLY_INCLUDE_IF(build-flask) -const INITIALIZE_EXPERIMENTAL_AREA = '/initialize/experimental-area'; -const ONBOARDING_EXPERIMENTAL_AREA = '/onboarding/experimental-area'; +export const INITIALIZE_EXPERIMENTAL_AREA = '/initialize/experimental-area'; +export const ONBOARDING_EXPERIMENTAL_AREA = '/onboarding/experimental-area'; ///: END:ONLY_INCLUDE_IF - -const CONFIRM_TRANSACTION_ROUTE = '/confirm-transaction'; -const CONFIRM_SEND_ETHER_PATH = '/send-ether'; -const CONFIRM_SEND_TOKEN_PATH = '/send-token'; -const CONFIRM_DEPLOY_CONTRACT_PATH = '/deploy-contract'; -const CONFIRM_APPROVE_PATH = '/approve'; -const CONFIRM_SET_APPROVAL_FOR_ALL_PATH = '/set-approval-for-all'; -const CONFIRM_TRANSFER_FROM_PATH = '/transfer-from'; -const CONFIRM_SAFE_TRANSFER_FROM_PATH = '/safe-transfer-from'; -const CONFIRM_TOKEN_METHOD_PATH = '/token-method'; -const CONFIRM_INCREASE_ALLOWANCE_PATH = '/increase-allowance'; -const SIGNATURE_REQUEST_PATH = '/signature-request'; -const DECRYPT_MESSAGE_REQUEST_PATH = '/decrypt-message-request'; -const ENCRYPTION_PUBLIC_KEY_REQUEST_PATH = '/encryption-public-key-request'; -const CONFIRMATION_V_NEXT_ROUTE = '/confirmation'; - -// Used to pull a convenient name for analytics tracking events. The key must -// be react-router ready path, and can include params such as :id for popup windows -const PATH_NAME_MAP = { - [DEFAULT_ROUTE]: 'Home', - [UNLOCK_ROUTE]: 'Unlock Page', - [LOCK_ROUTE]: 'Lock Page', - [`${ASSET_ROUTE}/:asset/:id`]: `Asset Page`, - [`${ASSET_ROUTE}/image/:asset/:id`]: `Nft Image Page`, - [SETTINGS_ROUTE]: 'Settings Page', - [GENERAL_ROUTE]: 'General Settings Page', - [ADVANCED_ROUTE]: 'Advanced Settings Page', - // DEVELOPER_OPTIONS_ROUTE not included because we're not tracking analytics for this page - // [DEVELOPER_OPTIONS_ROUTE]: 'Experimental Settings Page', - [EXPERIMENTAL_ROUTE]: 'Experimental Settings Page', - [SECURITY_ROUTE]: 'Security Settings Page', - [ABOUT_US_ROUTE]: 'About Us Page', - [ALERTS_ROUTE]: 'Alerts Settings Page', - [NETWORKS_ROUTE]: 'Network Settings Page', - [NETWORKS_FORM_ROUTE]: 'Network Settings Page Form', - [ADD_NETWORK_ROUTE]: 'Add Network From Settings Page Form', - [ADD_POPULAR_CUSTOM_NETWORK]: - 'Add Network From A List Of Popular Custom Networks', - [CONTACT_LIST_ROUTE]: 'Contact List Settings Page', - [`${CONTACT_EDIT_ROUTE}/:address`]: 'Edit Contact Settings Page', - [CONTACT_ADD_ROUTE]: 'Add Contact Settings Page', - [`${CONTACT_VIEW_ROUTE}/:address`]: 'View Contact Settings Page', - [REVEAL_SEED_ROUTE]: 'Reveal Secret Recovery Phrase Page', - [RESTORE_VAULT_ROUTE]: 'Restore Vault Page', - [IMPORT_TOKEN_ROUTE]: 'Import Token Page', - [CONFIRM_IMPORT_TOKEN_ROUTE]: 'Confirm Import Token Page', - [CONFIRM_ADD_SUGGESTED_TOKEN_ROUTE]: 'Confirm Add Suggested Token Page', - [IMPORT_TOKENS_ROUTE]: 'Import Tokens Page', - [NEW_ACCOUNT_ROUTE]: 'New Account Page', - [CONFIRM_ADD_SUGGESTED_NFT_ROUTE]: 'Confirm Add Suggested NFT Page', - [CONNECT_HARDWARE_ROUTE]: 'Connect Hardware Wallet Page', - [NOTIFICATIONS_ROUTE]: 'Notifications Page', - [NOTIFICATIONS_SETTINGS_ROUTE]: 'Notifications Settings Page', - [`${NOTIFICATIONS_ROUTE}/:uuid`]: 'Notification Detail Page', - [`${CONNECT_ROUTE}/:id${CONNECT_SNAPS_CONNECT_ROUTE}`]: 'Snaps Connect Page', - [`${CONNECT_ROUTE}/:id${CONNECT_SNAP_INSTALL_ROUTE}`]: 'Snap Install Page', - [`${CONNECT_ROUTE}/:id${CONNECT_SNAP_UPDATE_ROUTE}`]: 'Snap Update Page', - [`${CONNECT_ROUTE}/:id${CONNECT_SNAP_RESULT_ROUTE}`]: - 'Snap Install Result Page', - [SNAPS_ROUTE]: 'Snaps List Page', - [`${SNAPS_VIEW_ROUTE}/:snapId`]: 'Snap View Page', - ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) - [INSTITUTIONAL_FEATURES_DONE_ROUTE]: 'Institutional Features Done Page', - [CUSTODY_ACCOUNT_ROUTE]: 'Connect Custody', - [CUSTODY_ACCOUNT_DONE_ROUTE]: 'Connect Custody Account done', - [CONFIRM_ADD_CUSTODIAN_TOKEN]: 'Confirm Add Custodian Token', - [INTERACTIVE_REPLACEMENT_TOKEN_PAGE]: 'Interactive replacement token page', - [SRP_REMINDER]: 'Secret Recovery Phrase Reminder', - ///: END:ONLY_INCLUDE_IF - [SEND_ROUTE]: 'Send Page', - [CONNECTIONS]: 'Connections', - [PERMISSIONS]: 'Permissions', - [`${TOKEN_DETAILS}/:address`]: 'Token Details Page', - [`${CONNECT_ROUTE}/:id`]: 'Connect To Site Confirmation Page', - [`${CONNECT_ROUTE}/:id${CONNECT_CONFIRM_PERMISSIONS_ROUTE}`]: - 'Grant Connected Site Permissions Confirmation Page', - [CONNECTED_ROUTE]: 'Sites Connected To This Account Page', - [CONNECTED_ACCOUNTS_ROUTE]: 'Accounts Connected To This Site Page', - [`${CONFIRM_TRANSACTION_ROUTE}/:id`]: 'Confirmation Root Page', - [CONFIRM_TRANSACTION_ROUTE]: 'Confirmation Root Page', - // TODO: rename when this is the only confirmation page - [CONFIRMATION_V_NEXT_ROUTE]: 'New Confirmation Page', - [`${CONFIRMATION_V_NEXT_ROUTE}/:id`]: 'New Confirmation Page', - [`${CONFIRM_TRANSACTION_ROUTE}/:id${CONFIRM_TOKEN_METHOD_PATH}`]: - 'Confirm Token Method Transaction Page', - [`${CONFIRM_TRANSACTION_ROUTE}/:id${CONFIRM_SEND_ETHER_PATH}`]: - 'Confirm Send Ether Transaction Page', - [`${CONFIRM_TRANSACTION_ROUTE}/:id${CONFIRM_SEND_TOKEN_PATH}`]: - 'Confirm Send Token Transaction Page', - [`${CONFIRM_TRANSACTION_ROUTE}/:id${CONFIRM_DEPLOY_CONTRACT_PATH}`]: - 'Confirm Deploy Contract Transaction Page', - [`${CONFIRM_TRANSACTION_ROUTE}/:id${CONFIRM_APPROVE_PATH}`]: - 'Confirm Approve Transaction Page', - [`${CONFIRM_TRANSACTION_ROUTE}/:id${CONFIRM_SET_APPROVAL_FOR_ALL_PATH}`]: - 'Confirm Set Approval For All Transaction Page', - [`${CONFIRM_TRANSACTION_ROUTE}/:id${CONFIRM_INCREASE_ALLOWANCE_PATH}`]: - 'Confirm Increase Allowance Transaction Page', - [`${CONFIRM_TRANSACTION_ROUTE}/:id${CONFIRM_TRANSFER_FROM_PATH}`]: - 'Confirm Transfer From Transaction Page', - [`${CONFIRM_TRANSACTION_ROUTE}/:id${CONFIRM_SAFE_TRANSFER_FROM_PATH}`]: - 'Confirm Safe Transfer From Transaction Page', - [`${CONFIRM_TRANSACTION_ROUTE}/:id${SIGNATURE_REQUEST_PATH}`]: - 'Signature Request Page', - [`${CONFIRM_TRANSACTION_ROUTE}/:id${DECRYPT_MESSAGE_REQUEST_PATH}`]: - 'Decrypt Message Request Page', - [`${CONFIRM_TRANSACTION_ROUTE}/:id${ENCRYPTION_PUBLIC_KEY_REQUEST_PATH}`]: - 'Encryption Public Key Request Page', - [BUILD_QUOTE_ROUTE]: 'Swaps Build Quote Page', - [PREPARE_SWAP_ROUTE]: 'Prepare Swap Page', - [SWAPS_NOTIFICATION_ROUTE]: 'Swaps Notification Page', - [VIEW_QUOTE_ROUTE]: 'Swaps View Quotes Page', - [LOADING_QUOTES_ROUTE]: 'Swaps Loading Quotes Page', - [AWAITING_SWAP_ROUTE]: 'Swaps Awaiting Swaps Page', - [SWAPS_ERROR_ROUTE]: 'Swaps Error Page', -}; - -export { - DEFAULT_ROUTE, - ALERTS_ROUTE, - ASSET_ROUTE, - UNLOCK_ROUTE, - LOCK_ROUTE, - SETTINGS_ROUTE, - REVEAL_SEED_ROUTE, - RESTORE_VAULT_ROUTE, - IMPORT_TOKEN_ROUTE, - CONFIRM_IMPORT_TOKEN_ROUTE, - CONFIRM_ADD_SUGGESTED_TOKEN_ROUTE, - IMPORT_TOKENS_ROUTE, - NEW_ACCOUNT_ROUTE, - CONFIRM_ADD_SUGGESTED_NFT_ROUTE, - CONNECT_HARDWARE_ROUTE, - SEND_ROUTE, - CONNECTIONS, - PERMISSIONS, - REVIEW_PERMISSIONS, - TOKEN_DETAILS, - CONFIRM_TRANSACTION_ROUTE, - CONFIRM_SEND_ETHER_PATH, - CONFIRM_SEND_TOKEN_PATH, - CONFIRM_DEPLOY_CONTRACT_PATH, - CONFIRM_APPROVE_PATH, - CONFIRM_SET_APPROVAL_FOR_ALL_PATH, - CONFIRM_TRANSFER_FROM_PATH, - CONFIRM_SAFE_TRANSFER_FROM_PATH, - CONFIRM_TOKEN_METHOD_PATH, - CONFIRM_INCREASE_ALLOWANCE_PATH, - SIGNATURE_REQUEST_PATH, - DECRYPT_MESSAGE_REQUEST_PATH, - ENCRYPTION_PUBLIC_KEY_REQUEST_PATH, - CONFIRMATION_V_NEXT_ROUTE, - ADVANCED_ROUTE, - DEVELOPER_OPTIONS_ROUTE, - EXPERIMENTAL_ROUTE, - SECURITY_ROUTE, - GENERAL_ROUTE, - ABOUT_US_ROUTE, - CONTACT_LIST_ROUTE, - CONTACT_EDIT_ROUTE, - CONTACT_ADD_ROUTE, - CONTACT_VIEW_ROUTE, - ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) - CUSTODY_ACCOUNT_DONE_ROUTE, - CUSTODY_ACCOUNT_ROUTE, - INSTITUTIONAL_FEATURES_DONE_ROUTE, - CONFIRM_ADD_CUSTODIAN_TOKEN, - INTERACTIVE_REPLACEMENT_TOKEN_PAGE, - SRP_REMINDER, - ///: END:ONLY_INCLUDE_IF - NETWORKS_ROUTE, - NETWORKS_FORM_ROUTE, - ADD_NETWORK_ROUTE, - ADD_POPULAR_CUSTOM_NETWORK, - CONNECT_ROUTE, - CONNECT_CONFIRM_PERMISSIONS_ROUTE, - CONNECT_SNAPS_CONNECT_ROUTE, - CONNECT_SNAP_INSTALL_ROUTE, - CONNECT_SNAP_UPDATE_ROUTE, - CONNECT_SNAP_RESULT_ROUTE, - NOTIFICATIONS_ROUTE, - NOTIFICATIONS_SETTINGS_ROUTE, - SNAPS_ROUTE, - SNAPS_VIEW_ROUTE, - CROSS_CHAIN_SWAP_ROUTE, - CONNECTED_ROUTE, - CONNECTED_ACCOUNTS_ROUTE, - PATH_NAME_MAP, - SWAPS_ROUTE, - PREPARE_SWAP_ROUTE, - SWAPS_NOTIFICATION_ROUTE, - BUILD_QUOTE_ROUTE, - VIEW_QUOTE_ROUTE, - LOADING_QUOTES_ROUTE, - AWAITING_SWAP_ROUTE, - AWAITING_SIGNATURES_ROUTE, - SWAPS_ERROR_ROUTE, - SWAPS_MAINTENANCE_ROUTE, - SMART_TRANSACTION_STATUS_ROUTE, - ONBOARDING_ROUTE, - ONBOARDING_HELP_US_IMPROVE_ROUTE, - ONBOARDING_CREATE_PASSWORD_ROUTE, - ONBOARDING_IMPORT_WITH_SRP_ROUTE, - ONBOARDING_SECURE_YOUR_WALLET_ROUTE, - ONBOARDING_REVIEW_SRP_ROUTE, - ONBOARDING_CONFIRM_SRP_ROUTE, - ONBOARDING_PRIVACY_SETTINGS_ROUTE, - ONBOARDING_COMPLETION_ROUTE, - MMI_ONBOARDING_COMPLETION_ROUTE, - ONBOARDING_UNLOCK_ROUTE, - ONBOARDING_PIN_EXTENSION_ROUTE, - ONBOARDING_WELCOME_ROUTE, - ONBOARDING_METAMETRICS, - ///: BEGIN:ONLY_INCLUDE_IF(build-flask) - INITIALIZE_EXPERIMENTAL_AREA, - ONBOARDING_EXPERIMENTAL_AREA, - ///: END:ONLY_INCLUDE_IF -}; From 44aa02715fd9ea8665440ac286e7ee3f40880823 Mon Sep 17 00:00:00 2001 From: Vinicius Stevam <45455812+vinistevam@users.noreply.github.com> Date: Tue, 8 Oct 2024 08:19:37 +0100 Subject: [PATCH 2/6] fix: banner alert to render multiple general alerts (#27339) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR aims to fix the banner alert to support rendering multiple alerts. Previously we only rendered one alert and if there were more alerts we rendered the banner with a default copy informing the user there are multiple alerts. - Fixed padding on the alerts modal based on [figma](https://www.figma.com/design/gcwF9smHsgvFWQK83lT5UU/Confirmation-redesign-V4?node-id=3355-12480&node-type=frame&t=3Vbe0qFcmcfN5uCG-0) - Fixed bug Contract Interaction and Alerts - 'Cannot read properties of undefined (reading 'key')` [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/27339?quickstart=1) ## **Related issues** Fixes: https://github.com/MetaMask/MetaMask-planning/issues/2873 https://github.com/MetaMask/metamask-extension/issues/27238 ## **Manual testing steps** 1. Create a transaction with high nonce 2. Go to test dapp 3. Trigger a malicious transaction from PPOM session ## **Screenshots/Recordings** ### **Before** ### **After** ![Screenshot from 2024-09-23 13-38-10](https://github.com/user-attachments/assets/f4cbe8ee-7217-4718-998a-2016c9c60b88) ![Screenshot from 2024-09-23 14-09-42](https://github.com/user-attachments/assets/abb8c0c0-8cb8-4230-9469-d0b8b9f2a9a1) ![Screenshot from 2024-09-23 14-21-53](https://github.com/user-attachments/assets/0747e0d0-d50f-4f59-9a9e-0baefb4d9b5e) [bug.webm](https://github.com/user-attachments/assets/eb447959-78f0-4ccc-a554-cca272e59b19) ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.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: Ariella Vu <20778143+digiwand@users.noreply.github.com> --- app/_locales/de/messages.json | 6 -- app/_locales/el/messages.json | 6 -- app/_locales/en/messages.json | 6 -- app/_locales/en_GB/messages.json | 6 -- app/_locales/es/messages.json | 6 -- app/_locales/fr/messages.json | 6 -- app/_locales/hi/messages.json | 6 -- app/_locales/id/messages.json | 6 -- app/_locales/ja/messages.json | 6 -- app/_locales/ko/messages.json | 6 -- app/_locales/pt/messages.json | 6 -- app/_locales/ru/messages.json | 6 -- app/_locales/tl/messages.json | 6 -- app/_locales/tr/messages.json | 6 -- app/_locales/vi/messages.json | 6 -- app/_locales/zh_CN/messages.json | 6 -- .../alert-system/alert-modal/alert-modal.tsx | 9 +- .../app/alert-system/alert-modal/index.scss | 2 - .../confirm-alert-modal.tsx | 9 +- .../general-alert/general-alert.tsx | 2 +- .../multiple-alert-modal.test.tsx | 68 ++++++++++++- .../multiple-alert-modal.tsx | 6 +- ui/hooks/useAlerts.test.ts | 97 +++++++++++++------ ui/hooks/useAlerts.ts | 4 +- .../components/confirm/title/title.test.tsx | 14 ++- .../components/confirm/title/title.tsx | 39 +++----- 26 files changed, 170 insertions(+), 176 deletions(-) diff --git a/app/_locales/de/messages.json b/app/_locales/de/messages.json index 92cc0f25f1a7..bda0d4d894e7 100644 --- a/app/_locales/de/messages.json +++ b/app/_locales/de/messages.json @@ -381,12 +381,6 @@ "alertActionUpdateGasFeeLevel": { "message": "Gas-Optionen aktualisieren" }, - "alertBannerMultipleAlertsDescription": { - "message": "Wenn Sie diese Anfrage genehmigen, könnten Dritte, die für Betrügereien bekannt sind, alle Ihre Assets an sich reißen." - }, - "alertBannerMultipleAlertsTitle": { - "message": "Mehrere Benachrichtigungen!" - }, "alertDisableTooltip": { "message": "Dies kann in „Einstellungen > Benachrichtigungen“ geändert werden." }, diff --git a/app/_locales/el/messages.json b/app/_locales/el/messages.json index c7f7137665a4..6010f1939602 100644 --- a/app/_locales/el/messages.json +++ b/app/_locales/el/messages.json @@ -381,12 +381,6 @@ "alertActionUpdateGasFeeLevel": { "message": "Ενημέρωση επιλογών των τελών συναλλαγών" }, - "alertBannerMultipleAlertsDescription": { - "message": "Εάν εγκρίνετε αυτό το αίτημα, ένας τρίτος που είναι γνωστός για απάτες μπορεί να αποκτήσει όλα τα περιουσιακά σας στοιχεία." - }, - "alertBannerMultipleAlertsTitle": { - "message": "Πολλαπλές ειδοποιήσεις!" - }, "alertDisableTooltip": { "message": "Αυτό μπορεί να αλλάξει στις \"Ρυθμίσεις > Ειδοποιήσεις\"" }, diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index de17cf4ea877..30c913d1de74 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -428,12 +428,6 @@ "alertActionUpdateGasFeeLevel": { "message": "Update gas options" }, - "alertBannerMultipleAlertsDescription": { - "message": "If you approve this request, a third party known for scams might take all your assets." - }, - "alertBannerMultipleAlertsTitle": { - "message": "Multiple alerts!" - }, "alertDisableTooltip": { "message": "This can be changed in \"Settings > Alerts\"" }, diff --git a/app/_locales/en_GB/messages.json b/app/_locales/en_GB/messages.json index d02d9b8c1af5..3c8962e7f7c9 100644 --- a/app/_locales/en_GB/messages.json +++ b/app/_locales/en_GB/messages.json @@ -400,12 +400,6 @@ "alertActionUpdateGasFeeLevel": { "message": "Update gas options" }, - "alertBannerMultipleAlertsDescription": { - "message": "If you approve this request, a third party known for scams might take all your assets." - }, - "alertBannerMultipleAlertsTitle": { - "message": "Multiple alerts!" - }, "alertDisableTooltip": { "message": "This can be changed in \"Settings > Alerts\"" }, diff --git a/app/_locales/es/messages.json b/app/_locales/es/messages.json index 3430b44cad96..772471fdfd65 100644 --- a/app/_locales/es/messages.json +++ b/app/_locales/es/messages.json @@ -381,12 +381,6 @@ "alertActionUpdateGasFeeLevel": { "message": "Actualizar opciones de gas" }, - "alertBannerMultipleAlertsDescription": { - "message": "Si aprueba esta solicitud, un tercero conocido por estafas podría quedarse con todos sus activos." - }, - "alertBannerMultipleAlertsTitle": { - "message": "¡Alertas múltiples!" - }, "alertDisableTooltip": { "message": "Esto se puede modificar en \"Configuración > Alertas\"" }, diff --git a/app/_locales/fr/messages.json b/app/_locales/fr/messages.json index b2429962bad3..4a537a554315 100644 --- a/app/_locales/fr/messages.json +++ b/app/_locales/fr/messages.json @@ -381,12 +381,6 @@ "alertActionUpdateGasFeeLevel": { "message": "Mettre à jour les options de gaz" }, - "alertBannerMultipleAlertsDescription": { - "message": "Si vous approuvez cette demande, un tiers connu pour ses activités frauduleuses pourrait s’emparer de tous vos actifs." - }, - "alertBannerMultipleAlertsTitle": { - "message": "Plusieurs alertes !" - }, "alertDisableTooltip": { "message": "Vous pouvez modifier ceci dans « Paramètres > Alertes »" }, diff --git a/app/_locales/hi/messages.json b/app/_locales/hi/messages.json index 91bcfebef973..7fb1a04cb137 100644 --- a/app/_locales/hi/messages.json +++ b/app/_locales/hi/messages.json @@ -381,12 +381,6 @@ "alertActionUpdateGasFeeLevel": { "message": "गैस के विकल्प को अपडेट करें" }, - "alertBannerMultipleAlertsDescription": { - "message": "यदि आप इस रिक्वेस्ट को एप्रूव करते हैं, तो स्कैम के लिए मशहूर कोई थर्ड पार्टी आपके सारे एसेट चुरा सकती है।" - }, - "alertBannerMultipleAlertsTitle": { - "message": "एकाधिक एलर्ट!" - }, "alertDisableTooltip": { "message": "इसे \"सेटिंग > अलर्ट\" में बदला जा सकता है" }, diff --git a/app/_locales/id/messages.json b/app/_locales/id/messages.json index 82ab45bdfa99..be3ef95ad448 100644 --- a/app/_locales/id/messages.json +++ b/app/_locales/id/messages.json @@ -381,12 +381,6 @@ "alertActionUpdateGasFeeLevel": { "message": "Perbarui opsi gas" }, - "alertBannerMultipleAlertsDescription": { - "message": "Jika Anda menyetujui permintaan ini, pihak ketiga yang terdeteksi melakukan penipuan dapat mengambil semua aset Anda." - }, - "alertBannerMultipleAlertsTitle": { - "message": "Beberapa peringatan!" - }, "alertDisableTooltip": { "message": "Ini dapat diubah dalam \"Pengaturan > Peringatan\"" }, diff --git a/app/_locales/ja/messages.json b/app/_locales/ja/messages.json index 280889881f57..1ffbc9f1e4eb 100644 --- a/app/_locales/ja/messages.json +++ b/app/_locales/ja/messages.json @@ -381,12 +381,6 @@ "alertActionUpdateGasFeeLevel": { "message": "ガスオプションを更新" }, - "alertBannerMultipleAlertsDescription": { - "message": "このリクエストを承認すると、詐欺が判明しているサードパーティに資産をすべて奪われる可能性があります。" - }, - "alertBannerMultipleAlertsTitle": { - "message": "複数アラート!" - }, "alertDisableTooltip": { "message": "これは「設定」>「アラート」で変更できます" }, diff --git a/app/_locales/ko/messages.json b/app/_locales/ko/messages.json index c1591b2fc28e..a1c79024f651 100644 --- a/app/_locales/ko/messages.json +++ b/app/_locales/ko/messages.json @@ -381,12 +381,6 @@ "alertActionUpdateGasFeeLevel": { "message": "가스 옵션 업데이트" }, - "alertBannerMultipleAlertsDescription": { - "message": "이 요청을 승인하면 스캠을 목적으로 하는 제3자가 회원님의 자산을 모두 가져갈 수 있습니다." - }, - "alertBannerMultipleAlertsTitle": { - "message": "여러 경고!" - }, "alertDisableTooltip": { "message": "\"설정 > 경고\"에서 변경할 수 있습니다" }, diff --git a/app/_locales/pt/messages.json b/app/_locales/pt/messages.json index 95637cb057f9..52eb392f9d94 100644 --- a/app/_locales/pt/messages.json +++ b/app/_locales/pt/messages.json @@ -381,12 +381,6 @@ "alertActionUpdateGasFeeLevel": { "message": "Atualizar opções de gás" }, - "alertBannerMultipleAlertsDescription": { - "message": "Se você aprovar esta solicitação, um terceiro conhecido por aplicar golpes poderá se apropriar de todos os seus ativos." - }, - "alertBannerMultipleAlertsTitle": { - "message": "Vários alertas!" - }, "alertDisableTooltip": { "message": "Isso pode ser alterado em \"Configurações > Alertas\"" }, diff --git a/app/_locales/ru/messages.json b/app/_locales/ru/messages.json index 6ce19f83b4ed..9f4f15461bab 100644 --- a/app/_locales/ru/messages.json +++ b/app/_locales/ru/messages.json @@ -381,12 +381,6 @@ "alertActionUpdateGasFeeLevel": { "message": "Обновить параметры газа" }, - "alertBannerMultipleAlertsDescription": { - "message": "Если вы одобрите этот запрос, третья сторона, которая, как известно, совершала мошеннические действия, может похитить все ваши активы." - }, - "alertBannerMultipleAlertsTitle": { - "message": "Множественные оповещения!" - }, "alertDisableTooltip": { "message": "Это можно изменить в разделе «Настройки» > «Оповещения»" }, diff --git a/app/_locales/tl/messages.json b/app/_locales/tl/messages.json index 1246c2a085a1..c2ffc42763d0 100644 --- a/app/_locales/tl/messages.json +++ b/app/_locales/tl/messages.json @@ -381,12 +381,6 @@ "alertActionUpdateGasFeeLevel": { "message": "I-update ang mga opsyon sa gas" }, - "alertBannerMultipleAlertsDescription": { - "message": "Kung aaprubahan mo ang kahilingang ito, maaaring kunin ng third party na kilala sa mga panloloko ang lahat asset mo." - }, - "alertBannerMultipleAlertsTitle": { - "message": "Iba't ibang alerto!" - }, "alertDisableTooltip": { "message": "Puwede itong baguhin sa \"Mga Setting > Mga Alerto\"" }, diff --git a/app/_locales/tr/messages.json b/app/_locales/tr/messages.json index eedc60659269..676896deaaae 100644 --- a/app/_locales/tr/messages.json +++ b/app/_locales/tr/messages.json @@ -381,12 +381,6 @@ "alertActionUpdateGasFeeLevel": { "message": "Gaz seçeneklerini güncelle" }, - "alertBannerMultipleAlertsDescription": { - "message": "Bu talebi onaylarsanız dolandırıcılıkla bilinen üçüncü bir taraf tüm varlıklarınızı çalabilir." - }, - "alertBannerMultipleAlertsTitle": { - "message": "Çoklu uyarı!" - }, "alertDisableTooltip": { "message": "\"Ayarlar > Uyarılar\" kısmında değiştirilebilir" }, diff --git a/app/_locales/vi/messages.json b/app/_locales/vi/messages.json index 955c302f19a8..442478665c00 100644 --- a/app/_locales/vi/messages.json +++ b/app/_locales/vi/messages.json @@ -381,12 +381,6 @@ "alertActionUpdateGasFeeLevel": { "message": "Cập nhật tùy chọn phí gas" }, - "alertBannerMultipleAlertsDescription": { - "message": "Nếu bạn chấp thuận yêu cầu này, một bên thứ ba nổi tiếng là lừa đảo có thể lấy hết tài sản của bạn." - }, - "alertBannerMultipleAlertsTitle": { - "message": "Có nhiều cảnh báo!" - }, "alertDisableTooltip": { "message": "Bạn có thể thay đổi trong phần \"Cài đặt > Cảnh báo\"" }, diff --git a/app/_locales/zh_CN/messages.json b/app/_locales/zh_CN/messages.json index 14395afca8b8..9f33ef4a6b35 100644 --- a/app/_locales/zh_CN/messages.json +++ b/app/_locales/zh_CN/messages.json @@ -381,12 +381,6 @@ "alertActionUpdateGasFeeLevel": { "message": "更新燃料选项" }, - "alertBannerMultipleAlertsDescription": { - "message": "如果您批准此请求,以欺诈闻名的第三方可能会拿走您的所有资产。" - }, - "alertBannerMultipleAlertsTitle": { - "message": "多个提醒!" - }, "alertDisableTooltip": { "message": "这可以在“设置 > 提醒”中进行更改" }, diff --git a/ui/components/app/alert-system/alert-modal/alert-modal.tsx b/ui/components/app/alert-system/alert-modal/alert-modal.tsx index 46fbe1f8b8e3..10f5d90c3e77 100644 --- a/ui/components/app/alert-system/alert-modal/alert-modal.tsx +++ b/ui/components/app/alert-system/alert-modal/alert-modal.tsx @@ -157,10 +157,9 @@ function AlertDetails({ {customDetails ?? ( @@ -209,12 +208,11 @@ export function AcknowledgeCheckboxBase({ return ( {customAcknowledgeButton ?? ( diff --git a/ui/components/app/alert-system/alert-modal/index.scss b/ui/components/app/alert-system/alert-modal/index.scss index 722dbf763446..c9100ae95345 100644 --- a/ui/components/app/alert-system/alert-modal/index.scss +++ b/ui/components/app/alert-system/alert-modal/index.scss @@ -8,7 +8,5 @@ &__acknowledge-checkbox { @include design-system.H6; - - padding-top: 2px; } } diff --git a/ui/components/app/alert-system/confirm-alert-modal/confirm-alert-modal.tsx b/ui/components/app/alert-system/confirm-alert-modal/confirm-alert-modal.tsx index 96bcebab9953..f84c8113ae1e 100644 --- a/ui/components/app/alert-system/confirm-alert-modal/confirm-alert-modal.tsx +++ b/ui/components/app/alert-system/confirm-alert-modal/confirm-alert-modal.tsx @@ -90,8 +90,7 @@ function ConfirmDetails({ {t('confirmationAlertModalDetails')} - + {t('alertModalReviewAllAlerts')} diff --git a/ui/components/app/alert-system/general-alert/general-alert.tsx b/ui/components/app/alert-system/general-alert/general-alert.tsx index 3ba74445acef..5ac2b2a335fb 100644 --- a/ui/components/app/alert-system/general-alert/general-alert.tsx +++ b/ui/components/app/alert-system/general-alert/general-alert.tsx @@ -27,7 +27,7 @@ export type GeneralAlertProps = { provider?: SecurityProvider; reportUrl?: string; severity: AlertSeverity; - title: string; + title?: string; }; function ReportLink({ diff --git a/ui/components/app/alert-system/multiple-alert-modal/multiple-alert-modal.test.tsx b/ui/components/app/alert-system/multiple-alert-modal/multiple-alert-modal.test.tsx index c4b79fb28b7c..3d176e57ccd0 100644 --- a/ui/components/app/alert-system/multiple-alert-modal/multiple-alert-modal.test.tsx +++ b/ui/components/app/alert-system/multiple-alert-modal/multiple-alert-modal.test.tsx @@ -4,6 +4,7 @@ import { fireEvent } from '@testing-library/react'; import { Severity } from '../../../../helpers/constants/design-system'; import { renderWithProvider } from '../../../../../test/lib/render-helpers'; import mockState from '../../../../../test/data/mock-state.json'; +import * as useAlertsModule from '../../../../hooks/useAlerts'; import { MultipleAlertModal, MultipleAlertModalProps, @@ -84,6 +85,56 @@ describe('MultipleAlertModal', () => { }, }); + it('defaults to the first alert if the selected alert is not found', async () => { + const setAlertConfirmedMock = jest.fn(); + const useAlertsSpy = jest.spyOn(useAlertsModule, 'default'); + const dangerAlertMock = alertsMock.find( + (alert) => alert.key === DATA_ALERT_KEY_MOCK, + ); + (useAlertsSpy as jest.Mock).mockReturnValue({ + setAlertConfirmed: setAlertConfirmedMock, + alerts: alertsMock, + generalAlerts: [], + fieldAlerts: alertsMock, + getFieldAlerts: () => alertsMock, + isAlertConfirmed: () => false, + }); + + const { getByText, queryByText, rerender } = renderWithProvider( + , + mockStore, + ); + + // shows the contract alert + expect(getByText(alertsMock[2].message)).toBeInTheDocument(); + + // Update the mock to return only the data alert + (useAlertsSpy as jest.Mock).mockReturnValue({ + setAlertConfirmed: setAlertConfirmedMock, + alerts: [dangerAlertMock], + generalAlerts: [], + fieldAlerts: [dangerAlertMock], + getFieldAlerts: () => [dangerAlertMock], + isAlertConfirmed: () => false, + }); + + // Rerender the component to apply the updated mock + rerender( + , + ); + + // verifies the data alert is shown + expect(queryByText(alertsMock[0].message)).not.toBeInTheDocument(); + expect(getByText(alertsMock[1].message)).toBeInTheDocument(); + useAlertsSpy.mockRestore(); + }); + it('renders the multiple alert modal', () => { const { getByTestId } = renderWithProvider( , @@ -107,7 +158,7 @@ describe('MultipleAlertModal', () => { expect(onAcknowledgeClickMock).toHaveBeenCalledTimes(1); }); - it('render the next alert when the "Got it" button is clicked', () => { + it('renders the next alert when the "Got it" button is clicked', () => { const { getByTestId, getByText } = renderWithProvider( , mockStoreAcknowledgeAlerts, @@ -134,6 +185,20 @@ describe('MultipleAlertModal', () => { expect(onAcknowledgeClickMock).toHaveBeenCalledTimes(1); }); + it('resets to the first alert if there are unconfirmed alerts and the final alert is acknowledged', () => { + const { getByTestId, getByText } = renderWithProvider( + , + mockStore, + ); + + fireEvent.click(getByTestId('alert-modal-button')); + + expect(getByText(alertsMock[0].message)).toBeInTheDocument(); + }); + describe('Navigation', () => { it('calls next alert when the next button is clicked', () => { const { getByTestId, getByText } = renderWithProvider( @@ -144,6 +209,7 @@ describe('MultipleAlertModal', () => { fireEvent.click(getByTestId('alert-modal-next-button')); expect(getByText(alertsMock[2].message)).toBeInTheDocument(); + expect(getByText(alertsMock[2].message)).toBeInTheDocument(); }); it('calls previous alert when the previous button is clicked', () => { diff --git a/ui/components/app/alert-system/multiple-alert-modal/multiple-alert-modal.tsx b/ui/components/app/alert-system/multiple-alert-modal/multiple-alert-modal.tsx index d3b289343d00..62875bffcfe0 100644 --- a/ui/components/app/alert-system/multiple-alert-modal/multiple-alert-modal.tsx +++ b/ui/components/app/alert-system/multiple-alert-modal/multiple-alert-modal.tsx @@ -162,7 +162,9 @@ export function MultipleAlertModal({ initialAlertIndex === -1 ? 0 : initialAlertIndex, ); - const selectedAlert = alerts[selectedIndex]; + // If the selected alert is not found, default to the first alert + const selectedAlert = alerts[selectedIndex] ?? alerts[0]; + const hasUnconfirmedAlerts = alerts.some( (alert: Alert) => !isAlertConfirmed(alert.key) && alert.severity === Severity.Danger, @@ -207,7 +209,7 @@ export function MultipleAlertModal({ { ); }; - const { result } = renderHookUseAlert(); + const renderAndReturnResult = ( + ownerId?: string, + state?: { confirmAlerts: ConfirmAlertsState }, + ) => { + return renderHookUseAlert(ownerId, state).result; + }; describe('alerts', () => { it('returns all alerts', () => { + const result = renderAndReturnResult(); expect(result.current.alerts).toEqual(alertsMock); expect(result.current.hasAlerts).toEqual(true); expect(result.current.hasDangerAlerts).toEqual(true); @@ -67,6 +73,7 @@ describe('useAlerts', () => { }); it('returns alerts ordered by severity', () => { + const result = renderAndReturnResult(); const orderedAlerts = result.current.alerts; expect(orderedAlerts[0].severity).toEqual(Severity.Danger); }); @@ -74,7 +81,7 @@ describe('useAlerts', () => { describe('unconfirmedDangerAlerts', () => { it('returns all unconfirmed danger alerts', () => { - const { result: result1 } = renderHookUseAlert(undefined, { + const result = renderAndReturnResult(undefined, { confirmAlerts: { alerts: { [ownerIdMock]: alertsMock, @@ -83,15 +90,15 @@ describe('useAlerts', () => { confirmed: {}, }, }); - expect(result1.current.hasAlerts).toEqual(true); - expect(result1.current.hasUnconfirmedDangerAlerts).toEqual(true); - expect(result1.current.unconfirmedDangerAlerts).toHaveLength(1); + expect(result.current.hasAlerts).toEqual(true); + expect(result.current.hasUnconfirmedDangerAlerts).toEqual(true); + expect(result.current.unconfirmedDangerAlerts).toHaveLength(1); }); }); describe('unconfirmedFieldDangerAlerts', () => { it('returns all unconfirmed field danger alerts', () => { - const { result: result1 } = renderHookUseAlert(undefined, { + const result = renderAndReturnResult(undefined, { confirmAlerts: { alerts: { [ownerIdMock]: alertsMock, @@ -112,7 +119,7 @@ describe('useAlerts', () => { alert.field === fromAlertKeyMock && alert.severity === Severity.Danger, ); - expect(result1.current.unconfirmedFieldDangerAlerts).toEqual([ + expect(result.current.unconfirmedFieldDangerAlerts).toEqual([ expectedFieldDangerAlert, ]); }); @@ -120,7 +127,7 @@ describe('useAlerts', () => { describe('hasUnconfirmedFieldDangerAlerts', () => { it('returns true if there are unconfirmed field danger alerts', () => { - const { result: result1 } = renderHookUseAlert(undefined, { + const result = renderAndReturnResult(undefined, { confirmAlerts: { alerts: { [ownerIdMock]: alertsMock, @@ -136,11 +143,11 @@ describe('useAlerts', () => { }, }, }); - expect(result1.current.hasUnconfirmedFieldDangerAlerts).toEqual(true); + expect(result.current.hasUnconfirmedFieldDangerAlerts).toEqual(true); }); it('returns false if there are no unconfirmed field danger alerts', () => { - const { result: result1 } = renderHookUseAlert(undefined, { + const result = renderAndReturnResult(undefined, { confirmAlerts: { alerts: { [ownerIdMock]: alertsMock, @@ -156,16 +163,43 @@ describe('useAlerts', () => { }, }, }); - expect(result1.current.hasUnconfirmedFieldDangerAlerts).toEqual(false); + expect(result.current.hasUnconfirmedFieldDangerAlerts).toEqual(false); }); }); describe('generalAlerts', () => { - it('returns general alerts', () => { - const expectedGeneralAlerts = alertsMock.find( - (alert) => alert.key === dataAlertKeyMock, - ); - expect(result.current.generalAlerts).toEqual([expectedGeneralAlerts]); + it('returns general alerts sorted by severity', () => { + const warningGeneralAlert = { + key: dataAlertKeyMock, + severity: Severity.Warning as AlertSeverity, + message: 'Alert 2', + }; + const expectedGeneralAlerts = [ + { + ...warningGeneralAlert, + severity: Severity.Info as AlertSeverity, + message: 'Alert 3', + key: fromAlertKeyMock, + }, + { + ...warningGeneralAlert, + severity: Severity.Danger as AlertSeverity, + message: 'Alert 1', + key: toAlertKeyMock, + }, + warningGeneralAlert, + ]; + + const result = renderAndReturnResult(undefined, { + confirmAlerts: { + alerts: { + [ownerIdMock]: expectedGeneralAlerts, + }, + confirmed: {}, + }, + }); + + expect(result.current.generalAlerts).toEqual(expectedGeneralAlerts); }); }); @@ -174,22 +208,26 @@ describe('useAlerts', () => { (alert) => alert.field === fromAlertKeyMock, ); it('returns all alert filtered by field property', () => { + const result = renderAndReturnResult(); expect(result.current.getFieldAlerts(fromAlertKeyMock)).toEqual([ expectedFieldAlerts, ]); }); it('returns empty array if field is not provided', () => { + const result = renderAndReturnResult(); expect(result.current.getFieldAlerts()).toEqual([]); }); it('returns empty array, when no alert for specified field', () => { + const result = renderAndReturnResult(); expect(result.current.getFieldAlerts('mockedField')).toEqual([]); }); }); describe('fieldAlerts', () => { it('returns all alerts with field property', () => { + const result = renderAndReturnResult(); expect(result.current.fieldAlerts).toEqual([ alertsMock[0], alertsMock[2], @@ -197,38 +235,33 @@ describe('useAlerts', () => { }); it('returns empty array if no alerts with field property', () => { - const { result: resultAlerts } = renderHookUseAlert('mockedOwnerId'); - expect(resultAlerts.current.fieldAlerts).toEqual([]); + const result = renderAndReturnResult('mockedOwnerId'); + expect(result.current.fieldAlerts).toEqual([]); }); }); describe('isAlertConfirmed', () => { it('returns an if an alert is confirmed', () => { + const result = renderAndReturnResult(); expect(result.current.isAlertConfirmed(fromAlertKeyMock)).toBe(true); }); it('returns an if an alert is not confirmed', () => { - const { result: resultAlerts } = renderHookUseAlert(ownerId2Mock); - expect(resultAlerts.current.isAlertConfirmed(fromAlertKeyMock)).toBe( - false, - ); + const result = renderAndReturnResult(ownerId2Mock); + expect(result.current.isAlertConfirmed(fromAlertKeyMock)).toBe(false); }); }); describe('setAlertConfirmed', () => { it('dismisses alert confirmation', () => { - const { result: resultAlerts } = renderHookUseAlert(); - resultAlerts.current.setAlertConfirmed(fromAlertKeyMock, false); - expect(resultAlerts.current.isAlertConfirmed(fromAlertKeyMock)).toBe( - false, - ); + const result = renderAndReturnResult(); + result.current.setAlertConfirmed(fromAlertKeyMock, false); + expect(result.current.isAlertConfirmed(fromAlertKeyMock)).toBe(false); }); it('confirms an alert', () => { - const { result: resultAlerts } = renderHookUseAlert(ownerId2Mock); - resultAlerts.current.setAlertConfirmed(fromAlertKeyMock, true); - expect(resultAlerts.current.isAlertConfirmed(fromAlertKeyMock)).toBe( - true, - ); + const result = renderAndReturnResult(ownerId2Mock); + result.current.setAlertConfirmed(fromAlertKeyMock, true); + expect(result.current.isAlertConfirmed(fromAlertKeyMock)).toBe(true); }); }); }); diff --git a/ui/hooks/useAlerts.ts b/ui/hooks/useAlerts.ts index 06d79800f634..4b8e74a46d42 100644 --- a/ui/hooks/useAlerts.ts +++ b/ui/hooks/useAlerts.ts @@ -24,8 +24,8 @@ const useAlerts = (ownerId: string) => { selectConfirmedAlertKeys(state as AlertsState, ownerId), ); - const generalAlerts = useSelector((state) => - selectGeneralAlerts(state as AlertsState, ownerId), + const generalAlerts = sortAlertsBySeverity( + useSelector((state) => selectGeneralAlerts(state as AlertsState, ownerId)), ); const fieldAlerts = sortAlertsBySeverity( diff --git a/ui/pages/confirmations/components/confirm/title/title.test.tsx b/ui/pages/confirmations/components/confirm/title/title.test.tsx index eeaab80fd46b..3c03343c2afb 100644 --- a/ui/pages/confirmations/components/confirm/title/title.test.tsx +++ b/ui/pages/confirmations/components/confirm/title/title.test.tsx @@ -162,16 +162,23 @@ describe('ConfirmTitle', () => { reason: 'mock reason', key: 'mock key', }; + + const alertMock2 = { + ...alertMock, + key: 'mock key 2', + reason: 'mock reason 2', + }; const mockAlertState = (state: Partial = {}) => getMockPersonalSignConfirmStateForRequest(unapprovedPersonalSignMsg, { metamask: {}, confirmAlerts: { alerts: { - [unapprovedPersonalSignMsg.id]: [alertMock, alertMock, alertMock], + [unapprovedPersonalSignMsg.id]: [alertMock, alertMock2], }, confirmed: { [unapprovedPersonalSignMsg.id]: { [alertMock.key]: false, + [alertMock2.key]: false, }, }, ...state, @@ -194,7 +201,7 @@ describe('ConfirmTitle', () => { expect(queryByText(alertMock.message)).toBeInTheDocument(); }); - it('renders alert banner when there are multiple alerts', () => { + it('renders multiple alert banner when there are multiple alerts', () => { const mockStore = configureMockStore([])(mockAlertState()); const { getByText } = renderWithConfirmContextProvider( @@ -202,7 +209,8 @@ describe('ConfirmTitle', () => { mockStore, ); - expect(getByText('Multiple alerts!')).toBeInTheDocument(); + expect(getByText(alertMock.reason)).toBeInTheDocument(); + expect(getByText(alertMock2.reason)).toBeInTheDocument(); }); }); }); diff --git a/ui/pages/confirmations/components/confirm/title/title.tsx b/ui/pages/confirmations/components/confirm/title/title.tsx index 702c496b4e25..2645feed8a41 100644 --- a/ui/pages/confirmations/components/confirm/title/title.tsx +++ b/ui/pages/confirmations/components/confirm/title/title.tsx @@ -4,7 +4,6 @@ import { } from '@metamask/transaction-controller'; import React, { memo, useMemo } from 'react'; import GeneralAlert from '../../../../../components/app/alert-system/general-alert/general-alert'; -import { getHighestSeverity } from '../../../../../components/app/alert-system/utils'; import { Box, Text } from '../../../../../components/component-library'; import { TextAlign, @@ -25,37 +24,27 @@ import { getIsRevokeSetApprovalForAll } from '../info/utils'; import { useCurrentSpendingCap } from './hooks/useCurrentSpendingCap'; function ConfirmBannerAlert({ ownerId }: { ownerId: string }) { - const t = useI18nContext(); const { generalAlerts } = useAlerts(ownerId); if (generalAlerts.length === 0) { return null; } - const hasMultipleAlerts = generalAlerts.length > 1; - const singleAlert = generalAlerts[0]; - const highestSeverity = hasMultipleAlerts - ? getHighestSeverity(generalAlerts) - : singleAlert.severity; return ( - - + + {generalAlerts.map((alert) => ( + + + + ))} ); } From 782d03783b9ef3a8e47bb7e1a25e5f8ec808c5e9 Mon Sep 17 00:00:00 2001 From: Norbert Elter <72046715+itsyoboieltr@users.noreply.github.com> Date: Tue, 8 Oct 2024 14:23:41 +0200 Subject: [PATCH 3/6] fix: test coverage quality gate (#27691) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/27691?quickstart=1) Fixes an issue with test coverage quality gates. ## **Related issues** Fixes: https://github.com/MetaMask/MetaMask-planning/issues/3328 ## **Manual testing steps** 1. Test coverage should be correctly reported/validated ## **Screenshots/Recordings** Not applicable ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.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. --- .github/workflows/update-coverage.yml | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/.github/workflows/update-coverage.yml b/.github/workflows/update-coverage.yml index f246bde7eb32..fd1b0d5134e3 100644 --- a/.github/workflows/update-coverage.yml +++ b/.github/workflows/update-coverage.yml @@ -6,10 +6,6 @@ on: - cron: 0 0 * * * workflow_dispatch: -permissions: - contents: write - pull-requests: write - jobs: run-tests: name: Run tests @@ -27,6 +23,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v4 + with: + token: ${{ secrets.LAVAMOAT_UPDATE_TOKEN }} - name: Update coverage run: | @@ -34,8 +32,8 @@ jobs: - name: Checkout/create branch, commit, and force push run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" + git config user.name "MetaMask Bot" + git config user.email "metamaskbot@users.noreply.github.com" git checkout -b metamaskbot/update-coverage git add coverage.json git commit -m "chore: Update coverage.json" @@ -43,6 +41,6 @@ jobs: - name: Create/update pull request env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.LAVAMOAT_UPDATE_TOKEN }} run: | gh pr create --title "chore: Update coverage.json" --body "This PR is automatically opened to update the coverage.json file when test coverage increases. Coverage increased from $STORED_COVERAGE% to $CURRENT_COVERAGE%." --base develop --head metamaskbot/update-coverage || gh pr edit --body "This PR is automatically opened to update the coverage.json file when test coverage increases. Coverage increased from $STORED_COVERAGE% to $CURRENT_COVERAGE%." From 1f741ff5aab1e94b8289dba5acedee621f6fa21f Mon Sep 17 00:00:00 2001 From: MetaMask Bot <37885440+metamaskbot@users.noreply.github.com> Date: Tue, 8 Oct 2024 10:44:51 -0230 Subject: [PATCH 4/6] chore: Update coverage.json (#27696) This PR is automatically opened to update the coverage.json file when test coverage increases. Coverage increased from 0% to 71%. Co-authored-by: MetaMask Bot --- coverage.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coverage.json b/coverage.json index f65ea343e9b3..9887e06e2db6 100644 --- a/coverage.json +++ b/coverage.json @@ -1 +1 @@ -{ "coverage": 0 } +{ "coverage": 71 } From 261e6bfa734cb00daa6a21ef34298e927b090785 Mon Sep 17 00:00:00 2001 From: Charly Chevalier Date: Tue, 8 Oct 2024 15:37:02 +0200 Subject: [PATCH 5/6] fix(btc): fix address validation (#27690) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** The `isBtcTestnetAddress` was fragile and was mainly relying on `isBtcMainnetAddress` and `isEthAddress` to work. However if both of those functions were falsy, then `isBtcTestnetAddress` would become truthy (which is not always correct). It was spotted with some testing with a "wrong" eth addresss that we use in some tests: `0x0` ```ts const addr = '0x0'; isEthAddress(addr); // false <- yes, this is false based on this: https://github.com/MetaMask/utils/blob/v9.2.1/src/hex.ts#L15-L22 isBtcMainnetAddress(addr); // false isBtcTestnetAddress(addr); // true <- THIS IS WRONG ``` We now rely on a third party library that will test against multiple BTC format addresses (legacy, segwit, etc...) [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/27690?quickstart=1) ## **Related issues** N/A ## **Manual testing steps** N/A ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.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. --- package.json | 1 + shared/lib/multichain.test.ts | 17 +++++++++++------ shared/lib/multichain.ts | 11 +++-------- yarn.lock | 26 ++++++++++++++++++++++++++ 4 files changed, 41 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index cc317effc2ae..512b44b1b6ab 100644 --- a/package.json +++ b/package.json @@ -378,6 +378,7 @@ "base32-encode": "^1.2.0", "base64-js": "^1.5.1", "bignumber.js": "^4.1.0", + "bitcoin-address-validation": "^2.2.3", "blo": "1.2.0", "bn.js": "^5.2.1", "bowser": "^2.11.0", diff --git a/shared/lib/multichain.test.ts b/shared/lib/multichain.test.ts index 6c59f506e721..3b982ff8aff3 100644 --- a/shared/lib/multichain.test.ts +++ b/shared/lib/multichain.test.ts @@ -1,22 +1,27 @@ import { isBtcMainnetAddress, isBtcTestnetAddress } from './multichain'; -const MAINNET_ADDRESSES = [ +const BTC_MAINNET_ADDRESSES = [ // P2WPKH 'bc1qwl8399fz829uqvqly9tcatgrgtwp3udnhxfq4k', // P2PKH '1P5ZEDWTKTFGxQjZphgWPQUpe554WKDfHQ', ]; -const TESTNET_ADDRESSES = [ +const BTC_TESTNET_ADDRESSES = [ // P2WPKH 'tb1q6rmsq3vlfdhjdhtkxlqtuhhlr6pmj09y6w43g8', ]; const ETH_ADDRESSES = ['0x6431726EEE67570BF6f0Cf892aE0a3988F03903F']; +const SOL_ADDRESSES = [ + '7EcDhSYGxXyscszYEp35KHN8vvw3svAuLKTzXwCFLtV', + 'DpNXPNWvWoHaZ9P3WtfGCb2ZdLihW8VW1w1Ph4KDH9iG', +]; + describe('multichain', () => { // @ts-expect-error This is missing from the Mocha type definitions - it.each(MAINNET_ADDRESSES)( + it.each(BTC_MAINNET_ADDRESSES)( 'returns true if address is compatible with BTC mainnet: %s', (address: string) => { expect(isBtcMainnetAddress(address)).toBe(true); @@ -24,7 +29,7 @@ describe('multichain', () => { ); // @ts-expect-error This is missing from the Mocha type definitions - it.each([...TESTNET_ADDRESSES, ...ETH_ADDRESSES])( + it.each([...BTC_TESTNET_ADDRESSES, ...ETH_ADDRESSES, ...SOL_ADDRESSES])( 'returns false if address is not compatible with BTC mainnet: %s', (address: string) => { expect(isBtcMainnetAddress(address)).toBe(false); @@ -32,7 +37,7 @@ describe('multichain', () => { ); // @ts-expect-error This is missing from the Mocha type definitions - it.each(TESTNET_ADDRESSES)( + it.each(BTC_TESTNET_ADDRESSES)( 'returns true if address is compatible with BTC testnet: %s', (address: string) => { expect(isBtcTestnetAddress(address)).toBe(true); @@ -40,7 +45,7 @@ describe('multichain', () => { ); // @ts-expect-error This is missing from the Mocha type definitions - it.each([...MAINNET_ADDRESSES, ...ETH_ADDRESSES])( + it.each([...BTC_MAINNET_ADDRESSES, ...ETH_ADDRESSES, ...SOL_ADDRESSES])( 'returns false if address is compatible with BTC testnet: %s', (address: string) => { expect(isBtcTestnetAddress(address)).toBe(false); diff --git a/shared/lib/multichain.ts b/shared/lib/multichain.ts index fec52295eada..8ef03509541b 100644 --- a/shared/lib/multichain.ts +++ b/shared/lib/multichain.ts @@ -1,6 +1,4 @@ -// TODO: Remove restricted import -// eslint-disable-next-line import/no-restricted-paths -import { isEthAddress } from '../../app/scripts/lib/multichain/address'; +import { validate, Network } from 'bitcoin-address-validation'; /** * Returns whether an address is on the Bitcoin mainnet. @@ -14,10 +12,7 @@ import { isEthAddress } from '../../app/scripts/lib/multichain/address'; * @returns `true` if the address is on the Bitcoin mainnet, `false` otherwise. */ export function isBtcMainnetAddress(address: string): boolean { - return ( - !isEthAddress(address) && - (address.startsWith('bc1') || address.startsWith('1')) - ); + return validate(address, Network.mainnet); } /** @@ -29,5 +24,5 @@ export function isBtcMainnetAddress(address: string): boolean { * @returns `true` if the address is on the Bitcoin testnet, `false` otherwise. */ export function isBtcTestnetAddress(address: string): boolean { - return !isEthAddress(address) && !isBtcMainnetAddress(address); + return validate(address, Network.testnet); } diff --git a/yarn.lock b/yarn.lock index 4cae5223a04c..f94e1d68786a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13263,6 +13263,13 @@ __metadata: languageName: node linkType: hard +"base58-js@npm:^1.0.0": + version: 1.0.5 + resolution: "base58-js@npm:1.0.5" + checksum: 10/46c1b39d3a70bca0a47d56069c74a25d547680afd0f28609c90f280f5d614f5de36db5df993fa334db24008a68ab784a72fcdaa13eb40078e03c8999915a1100 + languageName: node + linkType: hard + "base64-arraybuffer-es6@npm:^0.7.0": version: 0.7.0 resolution: "base64-arraybuffer-es6@npm:0.7.0" @@ -13447,6 +13454,17 @@ __metadata: languageName: node linkType: hard +"bitcoin-address-validation@npm:^2.2.3": + version: 2.2.3 + resolution: "bitcoin-address-validation@npm:2.2.3" + dependencies: + base58-js: "npm:^1.0.0" + bech32: "npm:^2.0.0" + sha256-uint8array: "npm:^0.10.3" + checksum: 10/01603b5edf610ecf0843ae546534313f1cffabc8e7435a3678bc9788f18a54e51302218a539794aafd49beb5be70b5d1d507eb7442cb33970fcd665592a71305 + languageName: node + linkType: hard + "bitcoin-ops@npm:^1.3.0, bitcoin-ops@npm:^1.4.1": version: 1.4.1 resolution: "bitcoin-ops@npm:1.4.1" @@ -26204,6 +26222,7 @@ __metadata: base64-js: "npm:^1.5.1" bify-module-groups: "npm:^2.0.0" bignumber.js: "npm:^4.1.0" + bitcoin-address-validation: "npm:^2.2.3" blo: "npm:1.2.0" bn.js: "npm:^5.2.1" bowser: "npm:^2.11.0" @@ -32839,6 +32858,13 @@ __metadata: languageName: node linkType: hard +"sha256-uint8array@npm:^0.10.3": + version: 0.10.7 + resolution: "sha256-uint8array@npm:0.10.7" + checksum: 10/e427f9d2f9c521dea552f033d3f0c3bd641ab214d214dd41bde3c805edde393519cf982b3eee7d683b32e5f28fa23b2278d25935940e13fbe831b216a37832be + languageName: node + linkType: hard + "shallow-clone@npm:^0.1.2": version: 0.1.2 resolution: "shallow-clone@npm:0.1.2" From 83455b8a871187e29000e35d2fef76dd7039d750 Mon Sep 17 00:00:00 2001 From: seaona <54408225+seaona@users.noreply.github.com> Date: Tue, 8 Oct 2024 15:43:17 +0200 Subject: [PATCH 6/6] test: removing race condition for asserting inner values (PR-#2) (#27664) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR fixes an anti-pattern in our e2e tests, where we assert that an element value is equal to a desired value. This opens the door to a race condition where the element is already present, but it does not have the value we want yet, making the assertion to fail. We should find the element by its value, instead of asserting its inner value. [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/27664?quickstart=1) ## **Related issues** Fixes: https://github.com/MetaMask/metamask-extension/issues/19870 Note: this is the second PR for this work. The first PR was merged [here](https://github.com/MetaMask/metamask-extension/pull/27606) ## **Manual testing steps** 1. Check ci ## **Screenshots/Recordings** n/a ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.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. --- test/e2e/flask/btc/create-btc-account.spec.ts | 9 ++--- .../signatures/malicious-signatures.spec.ts | 3 +- .../signatures/personal-sign.spec.ts | 3 +- .../signatures/sign-typed-data-v3.spec.ts | 23 +++++------- .../signatures/sign-typed-data-v4.spec.ts | 4 +- .../signatures/sign-typed-data.spec.ts | 3 +- .../signatures/signature-helpers.ts | 9 ++--- .../confirmations/signatures/siwe.spec.ts | 19 +++++----- .../dapp-interactions/dapp-tx-edit.spec.js | 37 ++++--------------- .../dapp-interactions/encrypt-decrypt.spec.js | 28 +++++++------- .../failing-contract.spec.js | 12 ++++-- 11 files changed, 59 insertions(+), 91 deletions(-) diff --git a/test/e2e/flask/btc/create-btc-account.spec.ts b/test/e2e/flask/btc/create-btc-account.spec.ts index a6031a956a37..a4ac650f8f78 100644 --- a/test/e2e/flask/btc/create-btc-account.spec.ts +++ b/test/e2e/flask/btc/create-btc-account.spec.ts @@ -135,11 +135,10 @@ describe('Create BTC Account', function (this: Suite) { await driver.clickElement( '[data-testid="account-options-menu-button"]', ); - const lockButton = await driver.findClickableElement( - '[data-testid="global-menu-lock"]', - ); - assert.equal(await lockButton.getText(), 'Lock MetaMask'); - await lockButton.click(); + await driver.clickElement({ + css: '[data-testid="global-menu-lock"]', + text: 'Lock MetaMask', + }); await driver.clickElement({ text: 'Forgot password?', diff --git a/test/e2e/tests/confirmations/signatures/malicious-signatures.spec.ts b/test/e2e/tests/confirmations/signatures/malicious-signatures.spec.ts index 053c9f40f8b7..fc8a6d0ab240 100644 --- a/test/e2e/tests/confirmations/signatures/malicious-signatures.spec.ts +++ b/test/e2e/tests/confirmations/signatures/malicious-signatures.spec.ts @@ -50,11 +50,10 @@ describe('Malicious Confirmation Signature - Bad Domain @no-mmi', function (this }: TestSuiteArguments) => { await openDappAndTriggerSignature(driver, SignatureType.SIWE_BadDomain); - await driver.clickElement( + await driver.clickElementAndWaitForWindowToClose( '[data-testid="confirm-footer-cancel-button"]', ); - await driver.waitUntilXWindowHandles(2); await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); const rejectionResult = await driver.waitForSelector({ diff --git a/test/e2e/tests/confirmations/signatures/personal-sign.spec.ts b/test/e2e/tests/confirmations/signatures/personal-sign.spec.ts index dca5e6ba27d5..418cc4ab513d 100644 --- a/test/e2e/tests/confirmations/signatures/personal-sign.spec.ts +++ b/test/e2e/tests/confirmations/signatures/personal-sign.spec.ts @@ -74,11 +74,10 @@ describe('Confirmation Signature - Personal Sign @no-mmi', function (this: Suite }: TestSuiteArguments) => { await openDappAndTriggerSignature(driver, SignatureType.PersonalSign); - await driver.clickElement( + await driver.clickElementAndWaitForWindowToClose( '[data-testid="confirm-footer-cancel-button"]', ); - await driver.waitUntilXWindowHandles(2); await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); const rejectionResult = await driver.waitForSelector({ diff --git a/test/e2e/tests/confirmations/signatures/sign-typed-data-v3.spec.ts b/test/e2e/tests/confirmations/signatures/sign-typed-data-v3.spec.ts index f2c62e617899..6961f0a5eaf2 100644 --- a/test/e2e/tests/confirmations/signatures/sign-typed-data-v3.spec.ts +++ b/test/e2e/tests/confirmations/signatures/sign-typed-data-v3.spec.ts @@ -56,7 +56,6 @@ describe('Confirmation Signature - Sign Typed Data V3 @no-mmi', function (this: await assertInfoValues(driver); await scrollAndConfirmAndAssertConfirm(driver); - await driver.delay(1000); await assertSignatureConfirmedMetrics({ driver, mockedEndpoints: mockedEndpoints as MockedEndpoint[], @@ -81,10 +80,9 @@ describe('Confirmation Signature - Sign Typed Data V3 @no-mmi', function (this: SignatureType.SignTypedDataV3, ); - await driver.clickElement( + await driver.clickElementAndWaitForWindowToClose( '[data-testid="confirm-footer-cancel-button"]', ); - await driver.delay(1000); await assertSignatureRejectedMetrics({ driver, @@ -141,16 +139,13 @@ async function assertVerifiedResults(driver: Driver, publicAddress: string) { await driver.waitUntilXWindowHandles(2); await driver.switchToWindowWithTitle('E2E Test Dapp'); await driver.clickElement('#signTypedDataV3Verify'); - await driver.delay(500); - - const verifyResult = await driver.findElement('#signTypedDataV3Result'); - const verifyRecoverAddress = await driver.findElement( - '#signTypedDataV3VerifyResult', - ); + await driver.waitForSelector({ + css: '#signTypedDataV3Result', + text: '0x0a22f7796a2a70c8dc918e7e6eb8452c8f2999d1a1eb5ad714473d36270a40d6724472e5609948c778a07216bd082b60b6f6853d6354c731fd8ccdd3a2f4af261b', + }); - assert.equal( - await verifyResult.getText(), - '0x0a22f7796a2a70c8dc918e7e6eb8452c8f2999d1a1eb5ad714473d36270a40d6724472e5609948c778a07216bd082b60b6f6853d6354c731fd8ccdd3a2f4af261b', - ); - assert.equal(await verifyRecoverAddress.getText(), publicAddress); + await driver.waitForSelector({ + css: '#signTypedDataV3VerifyResult', + text: publicAddress, + }); } diff --git a/test/e2e/tests/confirmations/signatures/sign-typed-data-v4.spec.ts b/test/e2e/tests/confirmations/signatures/sign-typed-data-v4.spec.ts index ca0dbb8f9bb6..33b94be6b332 100644 --- a/test/e2e/tests/confirmations/signatures/sign-typed-data-v4.spec.ts +++ b/test/e2e/tests/confirmations/signatures/sign-typed-data-v4.spec.ts @@ -50,7 +50,6 @@ describe('Confirmation Signature - Sign Typed Data V4 @no-mmi', function (this: await assertInfoValues(driver); await scrollAndConfirmAndAssertConfirm(driver); - await driver.delay(1000); await assertAccountDetailsMetrics( driver, @@ -87,10 +86,9 @@ describe('Confirmation Signature - Sign Typed Data V4 @no-mmi', function (this: SignatureType.SignTypedDataV4, ); - await driver.clickElement( + await driver.clickElementAndWaitForWindowToClose( '[data-testid="confirm-footer-cancel-button"]', ); - await driver.delay(1000); await assertSignatureRejectedMetrics({ driver, diff --git a/test/e2e/tests/confirmations/signatures/sign-typed-data.spec.ts b/test/e2e/tests/confirmations/signatures/sign-typed-data.spec.ts index a9a9dfd52ae9..1017d44a00dc 100644 --- a/test/e2e/tests/confirmations/signatures/sign-typed-data.spec.ts +++ b/test/e2e/tests/confirmations/signatures/sign-typed-data.spec.ts @@ -76,10 +76,9 @@ describe('Confirmation Signature - Sign Typed Data @no-mmi', function (this: Sui }: TestSuiteArguments) => { await openDappAndTriggerSignature(driver, SignatureType.SignTypedData); - await driver.clickElement( + await driver.clickElementAndWaitForWindowToClose( '[data-testid="confirm-footer-cancel-button"]', ); - await driver.delay(1000); await assertSignatureRejectedMetrics({ driver, diff --git a/test/e2e/tests/confirmations/signatures/signature-helpers.ts b/test/e2e/tests/confirmations/signatures/signature-helpers.ts index d69a2f6a69ac..9b87e5b4e9cc 100644 --- a/test/e2e/tests/confirmations/signatures/signature-helpers.ts +++ b/test/e2e/tests/confirmations/signatures/signature-helpers.ts @@ -218,11 +218,10 @@ export async function clickHeaderInfoBtn(driver: Driver) { } export async function assertHeaderInfoBalance(driver: Driver) { - const headerBalanceEl = await driver.findElement( - '[data-testid="confirmation-account-details-modal__account-balance"]', - ); - await driver.waitForNonEmptyElement(headerBalanceEl); - assert.equal(await headerBalanceEl.getText(), `${WALLET_ETH_BALANCE}\nETH`); + await driver.waitForSelector({ + css: '[data-testid="confirmation-account-details-modal__account-balance"]', + text: `${WALLET_ETH_BALANCE} ETH`, + }); } export async function copyAddressAndPasteWalletAddress(driver: Driver) { diff --git a/test/e2e/tests/confirmations/signatures/siwe.spec.ts b/test/e2e/tests/confirmations/signatures/siwe.spec.ts index edc3a2020862..1dd545034731 100644 --- a/test/e2e/tests/confirmations/signatures/siwe.spec.ts +++ b/test/e2e/tests/confirmations/signatures/siwe.spec.ts @@ -47,7 +47,6 @@ describe('Confirmation Signature - SIWE @no-mmi', function (this: Suite) { await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); await assertInfoValues(driver); await scrollAndConfirmAndAssertConfirm(driver); - await driver.delay(1000); await assertVerifiedSiweMessage( driver, @@ -77,18 +76,16 @@ describe('Confirmation Signature - SIWE @no-mmi', function (this: Suite) { }: TestSuiteArguments) => { await openDappAndTriggerSignature(driver, SignatureType.SIWE); - await driver.clickElement( + await driver.clickElementAndWaitForWindowToClose( '[data-testid="confirm-footer-cancel-button"]', ); - await driver.waitUntilXWindowHandles(2); await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); - const rejectionResult = await driver.findElement('#siweResult'); - assert.equal( - await rejectionResult.getText(), - 'Error: User rejected the request.', - ); + await driver.waitForSelector({ + css: '#siweResult', + text: 'Error: User rejected the request.', + }); await assertSignatureRejectedMetrics({ driver, mockedEndpoints: mockedEndpoints as MockedEndpoint[], @@ -119,6 +116,8 @@ async function assertVerifiedSiweMessage(driver: Driver, message: string) { await driver.waitUntilXWindowHandles(2); await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); - const verifySigUtil = await driver.findElement('#siweResult'); - assert.equal(await verifySigUtil.getText(), message); + await driver.waitForSelector({ + css: '#siweResult', + text: message, + }); } diff --git a/test/e2e/tests/dapp-interactions/dapp-tx-edit.spec.js b/test/e2e/tests/dapp-interactions/dapp-tx-edit.spec.js index df98799a462d..131ebdf4ee73 100644 --- a/test/e2e/tests/dapp-interactions/dapp-tx-edit.spec.js +++ b/test/e2e/tests/dapp-interactions/dapp-tx-edit.spec.js @@ -1,10 +1,9 @@ -const { strict: assert } = require('assert'); const { defaultGanacheOptions, - withFixtures, + logInWithBalanceValidation, openDapp, - unlockWallet, WINDOW_TITLES, + withFixtures, } = require('../../helpers'); const { SMART_CONTRACTS } = require('../../seeder/smart-contracts'); const FixtureBuilder = require('../../fixture-builder'); @@ -26,32 +25,22 @@ describe('Editing confirmations of dapp initiated contract interactions', functi const contractAddress = await contractRegistry.getContractAddress( smartContract, ); - await unlockWallet(driver); + await logInWithBalanceValidation(driver); // deploy contract await openDapp(driver, contractAddress); // wait for deployed contract, calls and confirms a contract method where ETH is sent await driver.findClickableElement('#deployButton'); await driver.clickElement('#depositButton'); - await driver.waitUntilXWindowHandles(3); - const windowHandles = await driver.getAllWindowHandles(); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); await driver.waitForSelector({ css: '.confirm-page-container-summary__action__name', text: 'Deposit', }); - const editTransactionButton = await driver.isElementPresentAndVisible( + await driver.assertElementNotPresent( '[data-testid="confirm-page-back-edit-button"]', ); - assert.equal( - editTransactionButton, - false, - `Edit transaction button should not be visible on a contract interaction created by a dapp`, - ); }, ); }); @@ -68,29 +57,19 @@ describe('Editing confirmations of dapp initiated contract interactions', functi title: this.test.fullTitle(), }, async ({ driver }) => { - await unlockWallet(driver); + await logInWithBalanceValidation(driver); await openDapp(driver); await driver.clickElement('#sendButton'); - await driver.waitUntilXWindowHandles(3); - const windowHandles = await driver.getAllWindowHandles(); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); await driver.waitForSelector({ css: '.confirm-page-container-summary__action__name', text: 'Sending ETH', }); - const editTransactionButton = await driver.isElementPresentAndVisible( + await driver.assertElementNotPresent( '[data-testid="confirm-page-back-edit-button"]', ); - assert.equal( - editTransactionButton, - false, - `Edit transaction button should not be visible on a simple send transaction created by a dapp`, - ); }, ); }); diff --git a/test/e2e/tests/dapp-interactions/encrypt-decrypt.spec.js b/test/e2e/tests/dapp-interactions/encrypt-decrypt.spec.js index fbf11b16cd40..296e36fe4bbe 100644 --- a/test/e2e/tests/dapp-interactions/encrypt-decrypt.spec.js +++ b/test/e2e/tests/dapp-interactions/encrypt-decrypt.spec.js @@ -1,4 +1,3 @@ -const { strict: assert } = require('assert'); const { defaultGanacheOptions, withFixtures, @@ -46,11 +45,10 @@ async function decryptMessage(driver) { async function verifyDecryptedMessageMM(driver, message) { await driver.clickElement({ text: 'Decrypt message', tag: 'div' }); - const notificationMessage = await driver.isElementPresent({ + await driver.waitForSelector({ text: message, tag: 'div', }); - assert.equal(notificationMessage, true); await driver.clickElement({ text: 'Decrypt', tag: 'button' }); } @@ -91,10 +89,10 @@ describe('Encrypt Decrypt', function () { await decryptMessage(driver); // Account balance is converted properly - const decryptAccountBalanceLabel = await driver.findElement( - '.request-decrypt-message__balance-value', - ); - assert.equal(await decryptAccountBalanceLabel.getText(), '25 ETH'); + await driver.waitForSelector({ + css: '.request-decrypt-message__balance-value', + text: '25 ETH', + }); // Verify message in MetaMask Notification await verifyDecryptedMessageMM(driver, message); @@ -187,10 +185,10 @@ describe('Encrypt Decrypt', function () { text: 'Request encryption public key', }); // Account balance is converted properly - const accountBalanceLabel = await driver.findElement( - '.request-encryption-public-key__balance-value', - ); - assert.equal(await accountBalanceLabel.getText(), '25 ETH'); + await driver.waitForSelector({ + css: '.request-encryption-public-key__balance-value', + text: '25 ETH', + }); }, ); }); @@ -230,10 +228,10 @@ describe('Encrypt Decrypt', function () { }); // Account balance is converted properly - const accountBalanceLabel = await driver.findElement( - '.request-encryption-public-key__balance-value', - ); - assert.equal(await accountBalanceLabel.getText(), '25 ETH'); + await driver.waitForSelector({ + css: '.request-encryption-public-key__balance-value', + text: '25 ETH', + }); }, ); }); diff --git a/test/e2e/tests/dapp-interactions/failing-contract.spec.js b/test/e2e/tests/dapp-interactions/failing-contract.spec.js index f27768fb7e4c..5770adb1a3b9 100644 --- a/test/e2e/tests/dapp-interactions/failing-contract.spec.js +++ b/test/e2e/tests/dapp-interactions/failing-contract.spec.js @@ -46,11 +46,13 @@ describe('Failing contract interaction ', function () { // display warning when transaction is expected to fail const warningText = 'We were not able to estimate gas. There might be an error in the contract and this transaction may fail.'; - const warning = await driver.findElement('.mm-banner-alert .mm-text'); + await driver.waitForSelector({ + css: '.mm-banner-alert .mm-text', + text: warningText, + }); const confirmButton = await driver.findElement( '[data-testid="page-container-footer-next"]', ); - assert.equal(await warning.getText(), warningText); assert.equal(await confirmButton.isEnabled(), false); // dismiss warning and confirm the transaction @@ -113,11 +115,13 @@ describe('Failing contract interaction on non-EIP1559 network', function () { // display warning when transaction is expected to fail const warningText = 'We were not able to estimate gas. There might be an error in the contract and this transaction may fail.'; - const warning = await driver.findElement('.mm-banner-alert .mm-text'); + await driver.waitForSelector({ + css: '.mm-banner-alert .mm-text', + text: warningText, + }); const confirmButton = await driver.findElement( '[data-testid="page-container-footer-next"]', ); - assert.equal(await warning.getText(), warningText); assert.equal(await confirmButton.isEnabled(), false); // dismiss warning and confirm the transaction