From dba315a64b9c32fbb2cef9a4223388666320517f Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Mon, 2 Dec 2024 15:00:49 -0500 Subject: [PATCH 01/90] Add migration and tests for enabling STX by default, update preferences-controller with `smartTransactionsOptInStatus` in `controllerMetadata` --- .../controllers/preferences-controller.ts | 4 + app/scripts/migrations/135.test.ts | 131 ++++++++++++++++++ app/scripts/migrations/135.ts | 91 ++++++++++++ app/scripts/migrations/index.js | 1 + 4 files changed, 227 insertions(+) create mode 100644 app/scripts/migrations/135.test.ts create mode 100644 app/scripts/migrations/135.ts diff --git a/app/scripts/controllers/preferences-controller.ts b/app/scripts/controllers/preferences-controller.ts index d705be4c3180..5c47bebb5243 100644 --- a/app/scripts/controllers/preferences-controller.ts +++ b/app/scripts/controllers/preferences-controller.ts @@ -457,6 +457,10 @@ const controllerMetadata = { }, isMultiAccountBalancesEnabled: { persist: true, anonymous: true }, showIncomingTransactions: { persist: true, anonymous: true }, + smartTransactionsOptInStatus: { + persist: true, + anonymous: true, + }, }; export class PreferencesController extends BaseController< diff --git a/app/scripts/migrations/135.test.ts b/app/scripts/migrations/135.test.ts new file mode 100644 index 000000000000..04ae0a72ff8e --- /dev/null +++ b/app/scripts/migrations/135.test.ts @@ -0,0 +1,131 @@ +import { SmartTransaction } from '@metamask/smart-transactions-controller/dist/types'; +import { migrate, VersionedData } from './135'; + +const prevVersion = 134; + +describe('migration #135', () => { + const mockSmartTransaction: SmartTransaction = { + uuid: 'test-uuid', + }; + + it('should update the version metadata', async () => { + const oldStorage: VersionedData = { + meta: { version: prevVersion }, + data: {}, + }; + + const newStorage = await migrate(oldStorage); + expect(newStorage.meta).toStrictEqual({ version: 135 }); + }); + + it('should set stx opt-in to true when stx opt-in status is null', async () => { + const oldStorage: VersionedData = { + meta: { version: prevVersion }, + data: { + PreferencesController: { + smartTransactionsOptInStatus: null, + }, + }, + }; + + const newStorage = await migrate(oldStorage); + expect( + newStorage.data.PreferencesController?.smartTransactionsOptInStatus, + ).toBe(true); + }); + + it('should set stx opt-in to true when stx opt-in status is undefined', async () => { + const oldStorage: VersionedData = { + meta: { version: prevVersion }, + data: { + PreferencesController: {}, + }, + }; + + const newStorage = await migrate(oldStorage); + expect( + newStorage.data.PreferencesController?.smartTransactionsOptInStatus, + ).toBe(true); + }); + + it('should set stx opt-in to true when stx opt-in is false and no existing smart transactions', async () => { + const oldStorage: VersionedData = { + meta: { version: prevVersion }, + data: { + PreferencesController: { + smartTransactionsOptInStatus: false, + }, + SmartTransactionsController: { + smartTransactionsState: { + smartTransactions: {}, + }, + }, + }, + }; + + const newStorage = await migrate(oldStorage); + expect( + newStorage.data.PreferencesController?.smartTransactionsOptInStatus, + ).toBe(true); + }); + + it('should not change stx opt-in when stx opt-in is false but has existing smart transactions', async () => { + const oldStorage: VersionedData = { + meta: { version: prevVersion }, + data: { + PreferencesController: { + smartTransactionsOptInStatus: false, + }, + SmartTransactionsController: { + smartTransactionsState: { + smartTransactions: { + '0x1': [mockSmartTransaction], + }, + }, + }, + }, + }; + + const newStorage = await migrate(oldStorage); + expect( + newStorage.data.PreferencesController?.smartTransactionsOptInStatus, + ).toBe(false); + }); + + it('should not change stx opt-in when stx opt-in is already true', async () => { + const oldStorage: VersionedData = { + meta: { version: prevVersion }, + data: { + PreferencesController: { + smartTransactionsOptInStatus: true, + }, + }, + }; + + const newStorage = await migrate(oldStorage); + expect( + newStorage.data.PreferencesController?.smartTransactionsOptInStatus, + ).toBe(true); + }); + + it('should capture exception if PreferencesController state is invalid', async () => { + const sentryCaptureExceptionMock = jest.fn(); + global.sentry = { + captureException: sentryCaptureExceptionMock, + }; + + const oldStorage = { + meta: { version: prevVersion }, + data: { + PreferencesController: 'invalid', + }, + } as unknown as VersionedData; + + const newStorage = await migrate(oldStorage); + + expect(sentryCaptureExceptionMock).toHaveBeenCalledTimes(1); + expect(sentryCaptureExceptionMock).toHaveBeenCalledWith( + new Error('Invalid PreferencesController state: string'), + ); + }); +}); diff --git a/app/scripts/migrations/135.ts b/app/scripts/migrations/135.ts new file mode 100644 index 000000000000..85b0f0b2899a --- /dev/null +++ b/app/scripts/migrations/135.ts @@ -0,0 +1,91 @@ +import { hasProperty, isObject } from '@metamask/utils'; +import { cloneDeep } from 'lodash'; +import type { SmartTransaction } from '@metamask/smart-transactions-controller/dist/types'; + +export type VersionedData = { + meta: { + version: number; + }; + data: { + PreferencesController?: { + smartTransactionsOptInStatus?: boolean | null; + }; + SmartTransactionsController?: { + smartTransactionsState: { + smartTransactions: Record; + }; + }; + }; +}; + +export const version = 135; + +function transformState(state: VersionedData['data']) { + console.log('Migration 135 state:', JSON.stringify(state, null, 2)); + console.log('Transform state input:', state); + if ( + !hasProperty(state, 'PreferencesController') || + !isObject(state.PreferencesController) + ) { + global.sentry?.captureException?.( + new Error( + `Invalid PreferencesController state: ${typeof state.PreferencesController}`, + ), + ); + console.log('Invalid PreferencesController state'); + return state; + } + + const { PreferencesController } = state; + const currentOptInStatus = + PreferencesController?.smartTransactionsOptInStatus; + console.log('Current STX opt-in status:', currentOptInStatus); + + if (currentOptInStatus === undefined || currentOptInStatus === null) { + console.log('Setting null/undefined status to true'); + PreferencesController.smartTransactionsOptInStatus = true; + } else if ( + currentOptInStatus === false && + !hasExistingSmartTransactions(state) + ) { + console.log('Setting false status to true (no existing transactions)'); + PreferencesController.smartTransactionsOptInStatus = true; + } + + return state; +} + +function hasExistingSmartTransactions(state: VersionedData['data']): boolean { + if ( + !hasProperty(state, 'SmartTransactionsController') || + !isObject( + state.SmartTransactionsController?.smartTransactionsState + ?.smartTransactions, + ) + ) { + return false; + } + + const { smartTransactions } = + state.SmartTransactionsController.smartTransactionsState; + + return Object.values(smartTransactions).some( + (chainSmartTransactions: SmartTransaction[]) => + chainSmartTransactions.length > 0, + ); +} + +export async function migrate( + originalVersionedData: VersionedData, +): Promise { + console.log('=== MIGRATION 135 START ==='); + console.log('Original version:', originalVersionedData.meta.version); + console.log('Original data:', JSON.stringify(originalVersionedData.data, null, 2)); + const versionedData = cloneDeep(originalVersionedData); + console.log('STX status before:', versionedData.data?.PreferencesController?.smartTransactionsOptInStatus); + versionedData.meta.version = version; + transformState(versionedData.data); + console.log('STX status after:', versionedData.data?.PreferencesController?.smartTransactionsOptInStatus); + console.log('=== MIGRATION 135 END ==='); + return versionedData; +} diff --git a/app/scripts/migrations/index.js b/app/scripts/migrations/index.js index 887732ad9dbc..459578ba3eda 100644 --- a/app/scripts/migrations/index.js +++ b/app/scripts/migrations/index.js @@ -155,6 +155,7 @@ const migrations = [ require('./132'), require('./133'), require('./134'), + require('./135'), ]; export default migrations; From 59b94a5a812049bd0f7f47bc65396ed032a47793 Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Mon, 2 Dec 2024 16:17:26 -0500 Subject: [PATCH 02/90] add logging to trace state and metadata change in preferences controller and migration's state transformation. --- app/scripts/controllers/preferences-controller.ts | 6 ++++++ app/scripts/migrations/135.ts | 12 ++++++------ .../settings/advanced-tab/advanced-tab.container.js | 5 +++++ 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/app/scripts/controllers/preferences-controller.ts b/app/scripts/controllers/preferences-controller.ts index 5c47bebb5243..df644d1c5c74 100644 --- a/app/scripts/controllers/preferences-controller.ts +++ b/app/scripts/controllers/preferences-controller.ts @@ -406,6 +406,12 @@ const controllerMetadata = { preferences: { persist: true, anonymous: true, + properties: { + smartTransactionsOptInStatus: { + persist: true, + anonymous: true, + }, + }, }, ipfsGateway: { persist: true, diff --git a/app/scripts/migrations/135.ts b/app/scripts/migrations/135.ts index 85b0f0b2899a..a650c1c66292 100644 --- a/app/scripts/migrations/135.ts +++ b/app/scripts/migrations/135.ts @@ -22,7 +22,7 @@ export const version = 135; function transformState(state: VersionedData['data']) { console.log('Migration 135 state:', JSON.stringify(state, null, 2)); - console.log('Transform state input:', state); + console.log('Migration 135, Transform state input:', state); if ( !hasProperty(state, 'PreferencesController') || !isObject(state.PreferencesController) @@ -32,26 +32,26 @@ function transformState(state: VersionedData['data']) { `Invalid PreferencesController state: ${typeof state.PreferencesController}`, ), ); - console.log('Invalid PreferencesController state'); + console.log('Migration 135 - Invalid PreferencesController'); return state; } const { PreferencesController } = state; const currentOptInStatus = PreferencesController?.smartTransactionsOptInStatus; - console.log('Current STX opt-in status:', currentOptInStatus); + console.log('Migration 135 - Current STX Status:', currentOptInStatus); if (currentOptInStatus === undefined || currentOptInStatus === null) { - console.log('Setting null/undefined status to true'); + console.log('Migration 135 - Setting null/undefined status to true'); PreferencesController.smartTransactionsOptInStatus = true; } else if ( currentOptInStatus === false && !hasExistingSmartTransactions(state) ) { - console.log('Setting false status to true (no existing transactions)'); + console.log('Migration 135 - Setting false status to true (no existing transactions)'); PreferencesController.smartTransactionsOptInStatus = true; } - + console.log('Migration 135 - Final State:', JSON.stringify(state, null, 2)); return state; } diff --git a/ui/pages/settings/advanced-tab/advanced-tab.container.js b/ui/pages/settings/advanced-tab/advanced-tab.container.js index 0be61499c1af..f86366d804e9 100644 --- a/ui/pages/settings/advanced-tab/advanced-tab.container.js +++ b/ui/pages/settings/advanced-tab/advanced-tab.container.js @@ -24,6 +24,11 @@ import { import AdvancedTab from './advanced-tab.component'; export const mapStateToProps = (state) => { + console.log('STX LOGGING IN: Advanced Tab State:', { + preferences: getPreferences(state), + stxEnabled: getSmartTransactionsPreferenceEnabled(state), + metamask: state.metamask, + }); const { appState: { errorInSettings }, metamask, From 606f29355fe1f4ea18203344ea823077ee2aa5e7 Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Mon, 2 Dec 2024 16:59:12 -0500 Subject: [PATCH 03/90] add logging in setPreference in preferences controller and actions.ts --- app/scripts/controllers/preferences-controller.ts | 3 +++ ui/store/actions.ts | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/app/scripts/controllers/preferences-controller.ts b/app/scripts/controllers/preferences-controller.ts index df644d1c5c74..389e308fdb2b 100644 --- a/app/scripts/controllers/preferences-controller.ts +++ b/app/scripts/controllers/preferences-controller.ts @@ -935,11 +935,14 @@ export class PreferencesController extends BaseController< preference: keyof Preferences, value: Preferences[typeof preference], ): Preferences { + console.log('Setting preference:', { preference, value }); const currentPreferences = this.getPreferences(); + console.log('Current preferences:', currentPreferences); const updatedPreferences = { ...currentPreferences, [preference]: value, }; + console.log('Updated preferences:', updatedPreferences); this.update((state) => { state.preferences = updatedPreferences; diff --git a/ui/store/actions.ts b/ui/store/actions.ts index 01b8b9e458d9..507295a23c2c 100644 --- a/ui/store/actions.ts +++ b/ui/store/actions.ts @@ -3039,12 +3039,14 @@ export function setPreference( AnyAction > { return (dispatch: MetaMaskReduxDispatch) => { + console.log('setPreference called:', { preference, value }); showLoading && dispatch(showLoadingIndication()); return new Promise((resolve, reject) => { callBackgroundMethod( 'setPreference', [preference, value], (err, updatedPreferences) => { + console.log('setPreference result:', { err, updatedPreferences }); showLoading && dispatch(hideLoadingIndication()); if (err) { dispatch(displayWarning(err)); @@ -3131,8 +3133,10 @@ export function setSmartTransactionsPreferenceEnabled( value: boolean, ): ThunkAction { return async (dispatch, getState) => { + console.log('Setting STX preference:', value); const smartTransactionsOptInStatus = getSmartTransactionsOptInStatusInternal(getState()); + console.log('Current STX status:', smartTransactionsOptInStatus); trackMetaMetricsEvent({ category: MetaMetricsEventCategory.Settings, event: MetaMetricsEventName.SettingsUpdated, @@ -3143,6 +3147,7 @@ export function setSmartTransactionsPreferenceEnabled( }); await dispatch(setPreference('smartTransactionsOptInStatus', value)); await forceUpdateMetamaskState(dispatch); + console.log('After dispatch:', getSmartTransactionsOptInStatusInternal(getState())); }; } From 629b2a270b8915ff6d68040d64fe8d6fcb1f4c7f Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Mon, 2 Dec 2024 17:06:48 -0500 Subject: [PATCH 04/90] update `VersionedData` in the migration to have preferences: --- app/scripts/migrations/135.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/scripts/migrations/135.ts b/app/scripts/migrations/135.ts index a650c1c66292..9f0cc9ee6d13 100644 --- a/app/scripts/migrations/135.ts +++ b/app/scripts/migrations/135.ts @@ -8,6 +8,9 @@ export type VersionedData = { }; data: { PreferencesController?: { + preferences?: { + smartTransactionsOptInStatus?: boolean | null; + }; smartTransactionsOptInStatus?: boolean | null; }; SmartTransactionsController?: { @@ -52,6 +55,13 @@ function transformState(state: VersionedData['data']) { PreferencesController.smartTransactionsOptInStatus = true; } console.log('Migration 135 - Final State:', JSON.stringify(state, null, 2)); + if (!state.PreferencesController.preferences) { + state.PreferencesController.preferences = {}; + } + + const { preferences } = state.PreferencesController; + preferences.smartTransactionsOptInStatus = true; + return state; } From 3010831e84f188685824e0aec0194bca7b4805f9 Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Wed, 4 Dec 2024 01:17:21 -0500 Subject: [PATCH 05/90] Add UI for legacy transaction flow, creation of STX Banner Alert for transaction flows that occur when experimental/Improved transaction requests is not toggled on. --- app/_locales/en/messages.json | 6 ++ shared/constants/alerts.ts | 2 + ui/ducks/alerts/index.js | 1 + ui/ducks/alerts/stx-migration.js | 34 +++++++++ ui/helpers/constants/zendesk-url.js | 2 + .../components/stx-banner-alert/index.js | 1 + .../stx-banner-alert/stx-banner-alert.js | 45 ++++++++++++ .../stx-banner-alert/stx-banner-alert.test.js | 70 +++++++++++++++++++ .../transaction-alerts/transaction-alerts.js | 2 + .../transaction-alerts.test.js | 46 ++++++++++++ 10 files changed, 209 insertions(+) create mode 100644 ui/ducks/alerts/stx-migration.js create mode 100644 ui/pages/confirmations/components/stx-banner-alert/index.js create mode 100644 ui/pages/confirmations/components/stx-banner-alert/stx-banner-alert.js create mode 100644 ui/pages/confirmations/components/stx-banner-alert/stx-banner-alert.test.js diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index f125126e878c..cf6878628296 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -6815,5 +6815,11 @@ }, "zeroGasPriceOnSpeedUpError": { "message": "Zero gas price on speed up" + }, + "smartTransactionsEnabledMessage": { + "message": "You're now protected with MetaMask Smart Transactions" + }, + "smartTransactionsLearnMore": { + "message": "Learn more" } } diff --git a/shared/constants/alerts.ts b/shared/constants/alerts.ts index bbf6318f448e..bf3159495fef 100644 --- a/shared/constants/alerts.ts +++ b/shared/constants/alerts.ts @@ -2,6 +2,7 @@ export enum AlertTypes { unconnectedAccount = 'unconnectedAccount', web3ShimUsage = 'web3ShimUsage', invalidCustomNetwork = 'invalidCustomNetwork', + stxMigration = 'stxMigration', } /** @@ -10,6 +11,7 @@ export enum AlertTypes { export const TOGGLEABLE_ALERT_TYPES = [ AlertTypes.unconnectedAccount, AlertTypes.web3ShimUsage, + AlertTypes.stxMigration, ]; export enum Web3ShimUsageAlertStates { diff --git a/ui/ducks/alerts/index.js b/ui/ducks/alerts/index.js index 28dd8c8976d0..3599f3e6b5e2 100644 --- a/ui/ducks/alerts/index.js +++ b/ui/ducks/alerts/index.js @@ -1,4 +1,5 @@ export { default as unconnectedAccount } from './unconnected-account'; export { default as invalidCustomNetwork } from './invalid-custom-network'; +export { default as stxMigration } from './stx-migration'; export { ALERT_STATE } from './enums'; diff --git a/ui/ducks/alerts/stx-migration.js b/ui/ducks/alerts/stx-migration.js new file mode 100644 index 000000000000..8fb80f594206 --- /dev/null +++ b/ui/ducks/alerts/stx-migration.js @@ -0,0 +1,34 @@ +import { createSlice } from '@reduxjs/toolkit'; +import { AlertTypes } from '../../../shared/constants/alerts'; +import { ALERT_STATE } from './enums'; + +const name = AlertTypes.stxMigration; + +const initialState = { + state: ALERT_STATE.CLOSED, +}; + +const slice = createSlice({ + name, + initialState, + reducers: { + showSTXMigrationAlert: (state) => { + state.state = ALERT_STATE.OPEN; + }, + dismissSTXMigrationAlert: (state) => { + state.state = ALERT_STATE.CLOSED; + }, + }, +}); + +const { actions, reducer } = slice; + +// Selectors +export const getSTXAlertState = (state) => state.metamask.alerts?.[name]?.state; +export const stxAlertIsOpen = (state) => + state.metamask.alerts?.[name]?.state === ALERT_STATE.OPEN; + +// Actions +export const { showSTXMigrationAlert, dismissSTXMigrationAlert } = actions; + +export default reducer; diff --git a/ui/helpers/constants/zendesk-url.js b/ui/helpers/constants/zendesk-url.js index 3986df5b41ef..5c4b9211411d 100644 --- a/ui/helpers/constants/zendesk-url.js +++ b/ui/helpers/constants/zendesk-url.js @@ -49,6 +49,8 @@ const ZENDESK_URLS = { 'https://support.metamask.io/networks-and-sidechains/managing-networks/verifying-custom-network-information/', NETWORK_DEPRECATED: 'https://support.metamask.io/networks-and-sidechains/eth-on-testnets/', + SMART_TRANSACTIONS_LEARN_MORE: + 'https://support.metamask.io/transactions-and-gas/transactions/smart-transactions/', }; export default ZENDESK_URLS; diff --git a/ui/pages/confirmations/components/stx-banner-alert/index.js b/ui/pages/confirmations/components/stx-banner-alert/index.js new file mode 100644 index 000000000000..d0f36a4e188d --- /dev/null +++ b/ui/pages/confirmations/components/stx-banner-alert/index.js @@ -0,0 +1 @@ +export { default as STXBannerAlert } from './stx-banner-alert'; diff --git a/ui/pages/confirmations/components/stx-banner-alert/stx-banner-alert.js b/ui/pages/confirmations/components/stx-banner-alert/stx-banner-alert.js new file mode 100644 index 000000000000..09f6d0c2479f --- /dev/null +++ b/ui/pages/confirmations/components/stx-banner-alert/stx-banner-alert.js @@ -0,0 +1,45 @@ +import React from 'react'; +import { useSelector, useDispatch } from 'react-redux'; +import { useI18nContext } from '../../../../hooks/useI18nContext'; +import { + BannerAlert, + ButtonLink, + Text, + BannerAlertSeverity, +} from '../../../../components/component-library'; +import { + stxAlertIsOpen, + dismissSTXMigrationAlert, +} from '../../../../ducks/alerts/stx-migration'; +import ZENDESK_URLS from '../../../../helpers/constants/zendesk-url'; + +const STXBannerAlert = () => { + const dispatch = useDispatch(); + const shouldShow = useSelector(stxAlertIsOpen); + const t = useI18nContext(); + + if (!shouldShow) { + return null; + } + + return ( + dispatch(dismissSTXMigrationAlert())} + data-testid="stx-banner-alert" + > + + {t('smartTransactionsEnabledMessage')} + dispatch(dismissSTXMigrationAlert())} + externalLink + > + {t('smartTransactionsLearnMore')} + + + + ); +}; + +export default STXBannerAlert; diff --git a/ui/pages/confirmations/components/stx-banner-alert/stx-banner-alert.test.js b/ui/pages/confirmations/components/stx-banner-alert/stx-banner-alert.test.js new file mode 100644 index 000000000000..c538f0f48f0c --- /dev/null +++ b/ui/pages/confirmations/components/stx-banner-alert/stx-banner-alert.test.js @@ -0,0 +1,70 @@ +import React from 'react'; +import { screen } from '@testing-library/react'; +import { renderWithProvider } from '../../../../../test/jest/rendering'; +import configureStore from '../../../../store/store'; +import { AlertTypes } from '../../../../../shared/constants/alerts'; +import { ALERT_STATE } from '../../../../ducks/alerts/enums'; +import { STXBannerAlert } from './stx-banner-alert'; + +describe('STXBannerAlert', () => { + const mockState = { + metamask: { + alerts: { + [AlertTypes.stxMigration]: { + state: ALERT_STATE.OPEN, + }, + }, + }, + }; + + it('renders banner when alert is open', () => { + const store = configureStore(mockState); + renderWithProvider(, store); + + expect(screen.getByTestId('stx-banner-alert')).toBeInTheDocument(); + expect( + screen.getByText('smartTransactionsEnabledMessage'), + ).toBeInTheDocument(); + expect(screen.getByText('smartTransactionsLearnMore')).toBeInTheDocument(); + }); + + it('does not render when alert is closed', () => { + const closedState = { + metamask: { + alerts: { + [AlertTypes.stxMigration]: { + state: ALERT_STATE.CLOSED, + }, + }, + }, + }; + const store = configureStore(closedState); + renderWithProvider(, store); + + expect(screen.queryByTestId('stx-banner-alert')).not.toBeInTheDocument(); + }); + + it('dispatches dismissal action when close button clicked', () => { + const store = configureStore(mockState); + renderWithProvider(, store); + + screen.getByRole('button', { name: /close/iu }).click(); + + const state = store.getState(); + expect(state.metamask.alerts[AlertTypes.stxMigration].state).toBe( + ALERT_STATE.CLOSED, + ); + }); + + it('dispatches dismissal action when learn more link clicked', () => { + const store = configureStore(mockState); + renderWithProvider(, store); + + screen.getByText('smartTransactionsLearnMore').click(); + + const state = store.getState(); + expect(state.metamask.alerts[AlertTypes.stxMigration].state).toBe( + ALERT_STATE.CLOSED, + ); + }); +}); diff --git a/ui/pages/confirmations/components/transaction-alerts/transaction-alerts.js b/ui/pages/confirmations/components/transaction-alerts/transaction-alerts.js index 5127003a81e8..df24479ba6d0 100644 --- a/ui/pages/confirmations/components/transaction-alerts/transaction-alerts.js +++ b/ui/pages/confirmations/components/transaction-alerts/transaction-alerts.js @@ -5,6 +5,7 @@ import { TransactionType } from '@metamask/transaction-controller'; import { PriorityLevels } from '../../../../../shared/constants/gas'; import { useGasFeeContext } from '../../../../contexts/gasFee'; import { useI18nContext } from '../../../../hooks/useI18nContext'; +import { STXBannerAlert } from '../stx-banner-alert'; import { BannerAlert, ///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask) @@ -81,6 +82,7 @@ const TransactionAlerts = ({ return (
+ {isSuspiciousResponse(txData?.securityProviderResponse) && ( { @@ -33,6 +35,11 @@ const STATE_MOCK = { ...mockNetworkState({ chainId: CHAIN_ID_MOCK, }), + alerts: { + stxMigration: { + state: ALERT_STATE.OPEN, + }, + }, }, }; @@ -558,3 +565,42 @@ describe('TransactionAlerts', () => { }); }); }); + +describe('STX Migration Alert', () => { + it('should show STX banner when stxAlertIsOpen is true', () => { + const { getByTestId } = render({ + componentProps: { + txData: { + chainId: CHAIN_ID_MOCK, + txParams: { value: '0x1' }, + }, + }, + }); + expect(getByTestId('stx-banner-alert')).toBeInTheDocument(); + }); + + it('should not show STX banner when stxAlertIsOpen is false', () => { + const closedState = { + ...STATE_MOCK, + metamask: { + ...STATE_MOCK.metamask, + alerts: { + [AlertTypes.stxMigration]: { + state: ALERT_STATE.CLOSED, + }, + }, + }, + }; + const store = configureStore(closedState); + const { queryByTestId } = renderWithProvider( + , + store, + ); + expect(queryByTestId('stx-banner-alert')).not.toBeInTheDocument(); + }); +}); From f89ab5129ba7ca5d8e238b5d8c673814f070b34d Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Wed, 4 Dec 2024 15:21:49 -0500 Subject: [PATCH 06/90] update `stx-migration.js` to include `extraReducers`, added test and passing, update console.logs to debug in migration code for testing manually --- app/scripts/migrations/135.ts | 26 +++++----- ui/ducks/alerts/stx-migration.js | 8 +++ ui/ducks/alerts/stx-migration.test.js | 75 +++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 13 deletions(-) create mode 100644 ui/ducks/alerts/stx-migration.test.js diff --git a/app/scripts/migrations/135.ts b/app/scripts/migrations/135.ts index 9f0cc9ee6d13..f45d101ae8c5 100644 --- a/app/scripts/migrations/135.ts +++ b/app/scripts/migrations/135.ts @@ -24,8 +24,8 @@ export type VersionedData = { export const version = 135; function transformState(state: VersionedData['data']) { - console.log('Migration 135 state:', JSON.stringify(state, null, 2)); - console.log('Migration 135, Transform state input:', state); + console.debug('Migration 135 state:', JSON.stringify(state, null, 2)); + console.debug('Migration 135, Transform state input:', state); if ( !hasProperty(state, 'PreferencesController') || !isObject(state.PreferencesController) @@ -35,26 +35,26 @@ function transformState(state: VersionedData['data']) { `Invalid PreferencesController state: ${typeof state.PreferencesController}`, ), ); - console.log('Migration 135 - Invalid PreferencesController'); + console.debug('Migration 135 - Invalid PreferencesController'); return state; } const { PreferencesController } = state; const currentOptInStatus = PreferencesController?.smartTransactionsOptInStatus; - console.log('Migration 135 - Current STX Status:', currentOptInStatus); + console.debug('Migration 135 - Current STX Status:', currentOptInStatus); if (currentOptInStatus === undefined || currentOptInStatus === null) { - console.log('Migration 135 - Setting null/undefined status to true'); + console.debug('Migration 135 - Setting null/undefined status to true'); PreferencesController.smartTransactionsOptInStatus = true; } else if ( currentOptInStatus === false && !hasExistingSmartTransactions(state) ) { - console.log('Migration 135 - Setting false status to true (no existing transactions)'); + console.debug('Migration 135 - Setting false status to true (no existing transactions)'); PreferencesController.smartTransactionsOptInStatus = true; } - console.log('Migration 135 - Final State:', JSON.stringify(state, null, 2)); + console.debug('Migration 135 - Final State:', JSON.stringify(state, null, 2)); if (!state.PreferencesController.preferences) { state.PreferencesController.preferences = {}; } @@ -88,14 +88,14 @@ function hasExistingSmartTransactions(state: VersionedData['data']): boolean { export async function migrate( originalVersionedData: VersionedData, ): Promise { - console.log('=== MIGRATION 135 START ==='); - console.log('Original version:', originalVersionedData.meta.version); - console.log('Original data:', JSON.stringify(originalVersionedData.data, null, 2)); + console.debug('=== MIGRATION 135 START ==='); + console.debug('Original version:', originalVersionedData.meta.version); + console.debug('Original data:', JSON.stringify(originalVersionedData.data, null, 2)); const versionedData = cloneDeep(originalVersionedData); - console.log('STX status before:', versionedData.data?.PreferencesController?.smartTransactionsOptInStatus); + console.debug('STX status before:', versionedData.data?.PreferencesController?.smartTransactionsOptInStatus); versionedData.meta.version = version; transformState(versionedData.data); - console.log('STX status after:', versionedData.data?.PreferencesController?.smartTransactionsOptInStatus); - console.log('=== MIGRATION 135 END ==='); + console.debug('STX status after:', versionedData.data?.PreferencesController?.smartTransactionsOptInStatus); + console.debug('=== MIGRATION 135 END ==='); return versionedData; } diff --git a/ui/ducks/alerts/stx-migration.js b/ui/ducks/alerts/stx-migration.js index 8fb80f594206..791212fff29c 100644 --- a/ui/ducks/alerts/stx-migration.js +++ b/ui/ducks/alerts/stx-migration.js @@ -1,5 +1,6 @@ import { createSlice } from '@reduxjs/toolkit'; import { AlertTypes } from '../../../shared/constants/alerts'; +import * as actionConstants from '../../store/actionConstants'; import { ALERT_STATE } from './enums'; const name = AlertTypes.stxMigration; @@ -19,6 +20,13 @@ const slice = createSlice({ state.state = ALERT_STATE.CLOSED; }, }, + extraReducers: { + [actionConstants.UPDATE_METAMASK_STATE]: (state, action) => { + if (action.value?.preferences?.smartTransactionsOptInStatus === true) { + state.state = ALERT_STATE.OPEN; + } + }, + }, }); const { actions, reducer } = slice; diff --git a/ui/ducks/alerts/stx-migration.test.js b/ui/ducks/alerts/stx-migration.test.js new file mode 100644 index 000000000000..8ffca32a787c --- /dev/null +++ b/ui/ducks/alerts/stx-migration.test.js @@ -0,0 +1,75 @@ +import { AlertTypes } from '../../../shared/constants/alerts'; +import * as actionConstants from '../../store/actionConstants'; +import { ALERT_STATE } from './enums'; +import reducer, { + showSTXMigrationAlert, + dismissSTXMigrationAlert, + stxAlertIsOpen, +} from './stx-migration'; + +describe('STX Migration Alert', () => { + const mockState = { + metamask: { + alerts: { + [AlertTypes.stxMigration]: { + state: ALERT_STATE.OPEN, + }, + }, + }, + }; + + it('should initialize with CLOSED state', () => { + const result = reducer(undefined, {}); + expect(result.state).toStrictEqual(ALERT_STATE.CLOSED); + }); + + it('should handle showSTXMigrationAlert', () => { + const result = reducer( + { state: ALERT_STATE.CLOSED }, + showSTXMigrationAlert(), + ); + expect(result.state).toStrictEqual(ALERT_STATE.OPEN); + }); + + it('should handle dismissSTXMigrationAlert', () => { + const result = reducer( + { state: ALERT_STATE.OPEN }, + dismissSTXMigrationAlert(), + ); + expect(result.state).toStrictEqual(ALERT_STATE.CLOSED); + }); + + it('opens alert when smartTransactionsOptInStatus becomes true', () => { + const result = reducer( + { state: ALERT_STATE.CLOSED }, + { + type: actionConstants.UPDATE_METAMASK_STATE, + value: { + preferences: { + smartTransactionsOptInStatus: true, + }, + }, + }, + ); + expect(result.state).toStrictEqual(ALERT_STATE.OPEN); + }); + + describe('stxAlertIsOpen selector', () => { + it('should return true when alert is open', () => { + expect(stxAlertIsOpen(mockState)).toBe(true); + }); + + it('should return false when alert is closed', () => { + const closedState = { + metamask: { + alerts: { + [AlertTypes.stxMigration]: { + state: ALERT_STATE.CLOSED, + }, + }, + }, + }; + expect(stxAlertIsOpen(closedState)).toBe(false); + }); + }); +}); From 73a0f197f6281c39b7fbf1cec4e217809d9559df Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Wed, 4 Dec 2024 23:53:31 -0500 Subject: [PATCH 07/90] Add logs and alet to ensure component is mounting and state is as intended --- ui/ducks/alerts/stx-migration.js | 10 ++++++++++ .../components/stx-banner-alert/stx-banner-alert.js | 11 ++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/ui/ducks/alerts/stx-migration.js b/ui/ducks/alerts/stx-migration.js index 791212fff29c..4e2844226c97 100644 --- a/ui/ducks/alerts/stx-migration.js +++ b/ui/ducks/alerts/stx-migration.js @@ -22,9 +22,19 @@ const slice = createSlice({ }, extraReducers: { [actionConstants.UPDATE_METAMASK_STATE]: (state, action) => { + console.log('=== STX ALERT REDUCER ==='); + console.log('Current state:', state.state); + console.log('Action:', action.type); + console.log('Action value:', action.value); + console.log( + 'STX status:', + action.value?.preferences?.smartTransactionsOptInStatus, + ); if (action.value?.preferences?.smartTransactionsOptInStatus === true) { state.state = ALERT_STATE.OPEN; + console.log('Alert state changed to:', ALERT_STATE.OPEN); } + console.log('=== STX ALERT REDUCER END ==='); }, }, }); diff --git a/ui/pages/confirmations/components/stx-banner-alert/stx-banner-alert.js b/ui/pages/confirmations/components/stx-banner-alert/stx-banner-alert.js index 09f6d0c2479f..b7e658446ccd 100644 --- a/ui/pages/confirmations/components/stx-banner-alert/stx-banner-alert.js +++ b/ui/pages/confirmations/components/stx-banner-alert/stx-banner-alert.js @@ -16,8 +16,17 @@ import ZENDESK_URLS from '../../../../helpers/constants/zendesk-url'; const STXBannerAlert = () => { const dispatch = useDispatch(); const shouldShow = useSelector(stxAlertIsOpen); - const t = useI18nContext(); + console.log('=== STX BANNER COMPONENT ==='); + console.log('shouldShow:', shouldShow); + console.log( + 'Current state:', + useSelector((state) => state.metamask.alerts?.stxMigration), + ); + console.log('=== STX BANNER COMPONENT END ==='); + const t = useI18nContext(); + // eslint-disable-next-line no-alert, no-undef + alert(`STX Banner mounted: shouldShow = ${shouldShow}`); // Temporary debug if (!shouldShow) { return null; } From a3daae9f6c37ce3067d22b2cbed4a0cb813c418c Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Thu, 5 Dec 2024 00:12:08 -0500 Subject: [PATCH 08/90] remove alert and update logs --- ui/ducks/alerts/stx-migration.js | 2 ++ .../components/stx-banner-alert/stx-banner-alert.js | 3 +-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ui/ducks/alerts/stx-migration.js b/ui/ducks/alerts/stx-migration.js index 4e2844226c97..3e4f4296bfe4 100644 --- a/ui/ducks/alerts/stx-migration.js +++ b/ui/ducks/alerts/stx-migration.js @@ -23,6 +23,8 @@ const slice = createSlice({ extraReducers: { [actionConstants.UPDATE_METAMASK_STATE]: (state, action) => { console.log('=== STX ALERT REDUCER ==='); + console.log('Action Type:', actionConstants.UPDATE_METAMASK_STATE); // Log the constant + console.log('Incoming Action Type:', action.type); // Compare with incoming console.log('Current state:', state.state); console.log('Action:', action.type); console.log('Action value:', action.value); diff --git a/ui/pages/confirmations/components/stx-banner-alert/stx-banner-alert.js b/ui/pages/confirmations/components/stx-banner-alert/stx-banner-alert.js index b7e658446ccd..7f7898ce0bd1 100644 --- a/ui/pages/confirmations/components/stx-banner-alert/stx-banner-alert.js +++ b/ui/pages/confirmations/components/stx-banner-alert/stx-banner-alert.js @@ -25,8 +25,7 @@ const STXBannerAlert = () => { console.log('=== STX BANNER COMPONENT END ==='); const t = useI18nContext(); - // eslint-disable-next-line no-alert, no-undef - alert(`STX Banner mounted: shouldShow = ${shouldShow}`); // Temporary debug + if (!shouldShow) { return null; } From 85073df5e15cf5173afd92c8c15c3cd074da6c43 Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Thu, 5 Dec 2024 00:42:31 -0500 Subject: [PATCH 09/90] registering our stxMigration reducer in ducks index --- ui/ducks/index.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ui/ducks/index.js b/ui/ducks/index.js index deba3123916f..e9bc54c818eb 100644 --- a/ui/ducks/index.js +++ b/ui/ducks/index.js @@ -7,7 +7,11 @@ import domainReducer from './domains'; import appStateReducer from './app/app'; import confirmTransactionReducer from './confirm-transaction/confirm-transaction.duck'; import gasReducer from './gas/gas.duck'; -import { invalidCustomNetwork, unconnectedAccount } from './alerts'; +import { + invalidCustomNetwork, + unconnectedAccount, + stxMigration, +} from './alerts'; import swapsReducer from './swaps/swaps'; import bridgeReducer from './bridge/bridge'; import historyReducer from './history/history'; @@ -17,6 +21,7 @@ import confirmAlertsReducer from './confirm-alerts/confirm-alerts'; export default combineReducers({ [AlertTypes.invalidCustomNetwork]: invalidCustomNetwork, [AlertTypes.unconnectedAccount]: unconnectedAccount, + [AlertTypes.stxMigration]: stxMigration, activeTab: (s) => (s === undefined ? null : s), metamask: metamaskReducer, appState: appStateReducer, From 9b906cd6856d268829d19b4c673aea864a34727e Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Thu, 5 Dec 2024 01:11:52 -0500 Subject: [PATCH 10/90] Remove logs from migration script; update stx-migration logs to debug alert dismissal issue. --- app/scripts/migrations/135.ts | 14 -------------- ui/ducks/alerts/stx-migration.js | 18 ++++++------------ .../stx-banner-alert/stx-banner-alert.js | 17 ++++++++++------- 3 files changed, 16 insertions(+), 33 deletions(-) diff --git a/app/scripts/migrations/135.ts b/app/scripts/migrations/135.ts index f45d101ae8c5..b5c5a79dd0f4 100644 --- a/app/scripts/migrations/135.ts +++ b/app/scripts/migrations/135.ts @@ -24,8 +24,6 @@ export type VersionedData = { export const version = 135; function transformState(state: VersionedData['data']) { - console.debug('Migration 135 state:', JSON.stringify(state, null, 2)); - console.debug('Migration 135, Transform state input:', state); if ( !hasProperty(state, 'PreferencesController') || !isObject(state.PreferencesController) @@ -35,26 +33,20 @@ function transformState(state: VersionedData['data']) { `Invalid PreferencesController state: ${typeof state.PreferencesController}`, ), ); - console.debug('Migration 135 - Invalid PreferencesController'); return state; } const { PreferencesController } = state; const currentOptInStatus = PreferencesController?.smartTransactionsOptInStatus; - console.debug('Migration 135 - Current STX Status:', currentOptInStatus); - if (currentOptInStatus === undefined || currentOptInStatus === null) { - console.debug('Migration 135 - Setting null/undefined status to true'); PreferencesController.smartTransactionsOptInStatus = true; } else if ( currentOptInStatus === false && !hasExistingSmartTransactions(state) ) { - console.debug('Migration 135 - Setting false status to true (no existing transactions)'); PreferencesController.smartTransactionsOptInStatus = true; } - console.debug('Migration 135 - Final State:', JSON.stringify(state, null, 2)); if (!state.PreferencesController.preferences) { state.PreferencesController.preferences = {}; } @@ -88,14 +80,8 @@ function hasExistingSmartTransactions(state: VersionedData['data']): boolean { export async function migrate( originalVersionedData: VersionedData, ): Promise { - console.debug('=== MIGRATION 135 START ==='); - console.debug('Original version:', originalVersionedData.meta.version); - console.debug('Original data:', JSON.stringify(originalVersionedData.data, null, 2)); const versionedData = cloneDeep(originalVersionedData); - console.debug('STX status before:', versionedData.data?.PreferencesController?.smartTransactionsOptInStatus); versionedData.meta.version = version; transformState(versionedData.data); - console.debug('STX status after:', versionedData.data?.PreferencesController?.smartTransactionsOptInStatus); - console.debug('=== MIGRATION 135 END ==='); return versionedData; } diff --git a/ui/ducks/alerts/stx-migration.js b/ui/ducks/alerts/stx-migration.js index 3e4f4296bfe4..692ed2da3e71 100644 --- a/ui/ducks/alerts/stx-migration.js +++ b/ui/ducks/alerts/stx-migration.js @@ -17,26 +17,20 @@ const slice = createSlice({ state.state = ALERT_STATE.OPEN; }, dismissSTXMigrationAlert: (state) => { + console.log('Dismiss action received in reducer'); state.state = ALERT_STATE.CLOSED; + console.log('State updated to:', state.state); }, }, extraReducers: { [actionConstants.UPDATE_METAMASK_STATE]: (state, action) => { - console.log('=== STX ALERT REDUCER ==='); - console.log('Action Type:', actionConstants.UPDATE_METAMASK_STATE); // Log the constant - console.log('Incoming Action Type:', action.type); // Compare with incoming - console.log('Current state:', state.state); - console.log('Action:', action.type); - console.log('Action value:', action.value); - console.log( - 'STX status:', - action.value?.preferences?.smartTransactionsOptInStatus, - ); + console.log('=== STX REDUCER ==='); + console.log('STX Alert State:', state?.state); if (action.value?.preferences?.smartTransactionsOptInStatus === true) { state.state = ALERT_STATE.OPEN; console.log('Alert state changed to:', ALERT_STATE.OPEN); } - console.log('=== STX ALERT REDUCER END ==='); + console.log('=== STX REDUCER END ==='); }, }, }); @@ -46,7 +40,7 @@ const { actions, reducer } = slice; // Selectors export const getSTXAlertState = (state) => state.metamask.alerts?.[name]?.state; export const stxAlertIsOpen = (state) => - state.metamask.alerts?.[name]?.state === ALERT_STATE.OPEN; + state.stxMigration?.state === ALERT_STATE.OPEN; // Actions export const { showSTXMigrationAlert, dismissSTXMigrationAlert } = actions; diff --git a/ui/pages/confirmations/components/stx-banner-alert/stx-banner-alert.js b/ui/pages/confirmations/components/stx-banner-alert/stx-banner-alert.js index 7f7898ce0bd1..8a98e0648ebd 100644 --- a/ui/pages/confirmations/components/stx-banner-alert/stx-banner-alert.js +++ b/ui/pages/confirmations/components/stx-banner-alert/stx-banner-alert.js @@ -16,13 +16,12 @@ import ZENDESK_URLS from '../../../../helpers/constants/zendesk-url'; const STXBannerAlert = () => { const dispatch = useDispatch(); const shouldShow = useSelector(stxAlertIsOpen); - console.log('=== STX BANNER COMPONENT ==='); + const fullState = useSelector((state) => state); + + console.log('=== STX BANNER ==='); + console.log('Full Redux State:', fullState); console.log('shouldShow:', shouldShow); - console.log( - 'Current state:', - useSelector((state) => state.metamask.alerts?.stxMigration), - ); - console.log('=== STX BANNER COMPONENT END ==='); + console.log('=== STX BANNER END ==='); const t = useI18nContext(); @@ -33,7 +32,11 @@ const STXBannerAlert = () => { return ( dispatch(dismissSTXMigrationAlert())} + onClose={() => { + console.log('Dismiss clicked'); + dispatch(dismissSTXMigrationAlert()); + console.log('Dismiss action dispatched'); + }} data-testid="stx-banner-alert" > From cf23f7bd9c5a5e05a80c0ecdb366862596576482 Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Thu, 5 Dec 2024 08:56:29 -0500 Subject: [PATCH 11/90] update stx-migration in ducks to dismissAndDIsable alert state once the user has seen our message and has dismissed. --- ui/ducks/alerts/stx-migration.test.js | 124 ++++++++++++-------------- 1 file changed, 59 insertions(+), 65 deletions(-) diff --git a/ui/ducks/alerts/stx-migration.test.js b/ui/ducks/alerts/stx-migration.test.js index 8ffca32a787c..0f38956e509f 100644 --- a/ui/ducks/alerts/stx-migration.test.js +++ b/ui/ducks/alerts/stx-migration.test.js @@ -1,75 +1,69 @@ +import { createSlice } from '@reduxjs/toolkit'; +import { captureException } from '@sentry/browser'; import { AlertTypes } from '../../../shared/constants/alerts'; +import { setAlertEnabledness } from '../../store/actions'; import * as actionConstants from '../../store/actionConstants'; import { ALERT_STATE } from './enums'; -import reducer, { - showSTXMigrationAlert, - dismissSTXMigrationAlert, - stxAlertIsOpen, -} from './stx-migration'; -describe('STX Migration Alert', () => { - const mockState = { - metamask: { - alerts: { - [AlertTypes.stxMigration]: { - state: ALERT_STATE.OPEN, - }, - }, - }, - }; +const name = AlertTypes.stxMigration; - it('should initialize with CLOSED state', () => { - const result = reducer(undefined, {}); - expect(result.state).toStrictEqual(ALERT_STATE.CLOSED); - }); +const initialState = { + state: ALERT_STATE.CLOSED, +}; - it('should handle showSTXMigrationAlert', () => { - const result = reducer( - { state: ALERT_STATE.CLOSED }, - showSTXMigrationAlert(), - ); - expect(result.state).toStrictEqual(ALERT_STATE.OPEN); - }); +const slice = createSlice({ + name, + initialState, + reducers: { + showSTXMigrationAlert: (state) => { + state.state = ALERT_STATE.OPEN; + }, + dismissSTXMigrationAlert: (state) => { + state.state = ALERT_STATE.CLOSED; + }, + disableAlertRequested: (state) => { + state.state = ALERT_STATE.LOADING; + }, + disableAlertSucceeded: (state) => { + state.state = ALERT_STATE.CLOSED; + }, + disableAlertFailed: (state) => { + state.state = ALERT_STATE.ERROR; + }, + }, + extraReducers: { + [actionConstants.UPDATE_METAMASK_STATE]: (state, action) => { + if (action.value?.preferences?.smartTransactionsOptInStatus === true) { + state.state = ALERT_STATE.OPEN; + } + }, + }, +}); - it('should handle dismissSTXMigrationAlert', () => { - const result = reducer( - { state: ALERT_STATE.OPEN }, - dismissSTXMigrationAlert(), - ); - expect(result.state).toStrictEqual(ALERT_STATE.CLOSED); - }); +const { actions, reducer } = slice; - it('opens alert when smartTransactionsOptInStatus becomes true', () => { - const result = reducer( - { state: ALERT_STATE.CLOSED }, - { - type: actionConstants.UPDATE_METAMASK_STATE, - value: { - preferences: { - smartTransactionsOptInStatus: true, - }, - }, - }, - ); - expect(result.state).toStrictEqual(ALERT_STATE.OPEN); - }); +export const getSTXAlertState = (state) => state[name]?.state; +export const stxAlertIsOpen = (state) => + state[name]?.state === ALERT_STATE.OPEN; - describe('stxAlertIsOpen selector', () => { - it('should return true when alert is open', () => { - expect(stxAlertIsOpen(mockState)).toBe(true); - }); +export const { + showSTXMigrationAlert, + dismissSTXMigrationAlert, + disableAlertRequested, + disableAlertSucceeded, + disableAlertFailed, +} = actions; - it('should return false when alert is closed', () => { - const closedState = { - metamask: { - alerts: { - [AlertTypes.stxMigration]: { - state: ALERT_STATE.CLOSED, - }, - }, - }, - }; - expect(stxAlertIsOpen(closedState)).toBe(false); - }); - }); -}); +export const dismissAndDisableAlert = () => { + return async (dispatch) => { + try { + await dispatch(disableAlertRequested()); + await setAlertEnabledness(name, false); + await dispatch(disableAlertSucceeded()); + } catch (error) { + console.error(error); + captureException(error); + await dispatch(disableAlertFailed()); + } + }; +}; From a24e96354fac6adb5d49d896d241d05f472324d2 Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Thu, 5 Dec 2024 08:59:23 -0500 Subject: [PATCH 12/90] revert changes to wrong file --- ui/ducks/alerts/stx-migration.test.js | 124 ++++++++++++++------------ 1 file changed, 65 insertions(+), 59 deletions(-) diff --git a/ui/ducks/alerts/stx-migration.test.js b/ui/ducks/alerts/stx-migration.test.js index 0f38956e509f..8ffca32a787c 100644 --- a/ui/ducks/alerts/stx-migration.test.js +++ b/ui/ducks/alerts/stx-migration.test.js @@ -1,69 +1,75 @@ -import { createSlice } from '@reduxjs/toolkit'; -import { captureException } from '@sentry/browser'; import { AlertTypes } from '../../../shared/constants/alerts'; -import { setAlertEnabledness } from '../../store/actions'; import * as actionConstants from '../../store/actionConstants'; import { ALERT_STATE } from './enums'; +import reducer, { + showSTXMigrationAlert, + dismissSTXMigrationAlert, + stxAlertIsOpen, +} from './stx-migration'; -const name = AlertTypes.stxMigration; +describe('STX Migration Alert', () => { + const mockState = { + metamask: { + alerts: { + [AlertTypes.stxMigration]: { + state: ALERT_STATE.OPEN, + }, + }, + }, + }; -const initialState = { - state: ALERT_STATE.CLOSED, -}; + it('should initialize with CLOSED state', () => { + const result = reducer(undefined, {}); + expect(result.state).toStrictEqual(ALERT_STATE.CLOSED); + }); -const slice = createSlice({ - name, - initialState, - reducers: { - showSTXMigrationAlert: (state) => { - state.state = ALERT_STATE.OPEN; - }, - dismissSTXMigrationAlert: (state) => { - state.state = ALERT_STATE.CLOSED; - }, - disableAlertRequested: (state) => { - state.state = ALERT_STATE.LOADING; - }, - disableAlertSucceeded: (state) => { - state.state = ALERT_STATE.CLOSED; - }, - disableAlertFailed: (state) => { - state.state = ALERT_STATE.ERROR; - }, - }, - extraReducers: { - [actionConstants.UPDATE_METAMASK_STATE]: (state, action) => { - if (action.value?.preferences?.smartTransactionsOptInStatus === true) { - state.state = ALERT_STATE.OPEN; - } - }, - }, -}); + it('should handle showSTXMigrationAlert', () => { + const result = reducer( + { state: ALERT_STATE.CLOSED }, + showSTXMigrationAlert(), + ); + expect(result.state).toStrictEqual(ALERT_STATE.OPEN); + }); -const { actions, reducer } = slice; + it('should handle dismissSTXMigrationAlert', () => { + const result = reducer( + { state: ALERT_STATE.OPEN }, + dismissSTXMigrationAlert(), + ); + expect(result.state).toStrictEqual(ALERT_STATE.CLOSED); + }); -export const getSTXAlertState = (state) => state[name]?.state; -export const stxAlertIsOpen = (state) => - state[name]?.state === ALERT_STATE.OPEN; + it('opens alert when smartTransactionsOptInStatus becomes true', () => { + const result = reducer( + { state: ALERT_STATE.CLOSED }, + { + type: actionConstants.UPDATE_METAMASK_STATE, + value: { + preferences: { + smartTransactionsOptInStatus: true, + }, + }, + }, + ); + expect(result.state).toStrictEqual(ALERT_STATE.OPEN); + }); -export const { - showSTXMigrationAlert, - dismissSTXMigrationAlert, - disableAlertRequested, - disableAlertSucceeded, - disableAlertFailed, -} = actions; + describe('stxAlertIsOpen selector', () => { + it('should return true when alert is open', () => { + expect(stxAlertIsOpen(mockState)).toBe(true); + }); -export const dismissAndDisableAlert = () => { - return async (dispatch) => { - try { - await dispatch(disableAlertRequested()); - await setAlertEnabledness(name, false); - await dispatch(disableAlertSucceeded()); - } catch (error) { - console.error(error); - captureException(error); - await dispatch(disableAlertFailed()); - } - }; -}; + it('should return false when alert is closed', () => { + const closedState = { + metamask: { + alerts: { + [AlertTypes.stxMigration]: { + state: ALERT_STATE.CLOSED, + }, + }, + }, + }; + expect(stxAlertIsOpen(closedState)).toBe(false); + }); + }); +}); From 89fde17137191dbdd5d8ce00a768055f5a65083c Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Thu, 5 Dec 2024 09:19:49 -0500 Subject: [PATCH 13/90] update stx-migration ducks file to consider dismiss and disable alert. Update stx-migration ducks test. --- ui/ducks/alerts/stx-migration.js | 45 ++++++++++---- ui/ducks/alerts/stx-migration.test.js | 86 +++++++++++++++++++++++---- 2 files changed, 107 insertions(+), 24 deletions(-) diff --git a/ui/ducks/alerts/stx-migration.js b/ui/ducks/alerts/stx-migration.js index 692ed2da3e71..cb3f0d737fb5 100644 --- a/ui/ducks/alerts/stx-migration.js +++ b/ui/ducks/alerts/stx-migration.js @@ -1,5 +1,7 @@ import { createSlice } from '@reduxjs/toolkit'; +import { captureException } from '@sentry/browser'; import { AlertTypes } from '../../../shared/constants/alerts'; +import { setAlertEnabledness } from '../../store/actions'; import * as actionConstants from '../../store/actionConstants'; import { ALERT_STATE } from './enums'; @@ -17,32 +19,53 @@ const slice = createSlice({ state.state = ALERT_STATE.OPEN; }, dismissSTXMigrationAlert: (state) => { - console.log('Dismiss action received in reducer'); state.state = ALERT_STATE.CLOSED; - console.log('State updated to:', state.state); + }, + disableAlertRequested: (state) => { + state.state = ALERT_STATE.LOADING; + }, + disableAlertSucceeded: (state) => { + state.state = ALERT_STATE.CLOSED; + }, + disableAlertFailed: (state) => { + state.state = ALERT_STATE.ERROR; }, }, extraReducers: { [actionConstants.UPDATE_METAMASK_STATE]: (state, action) => { - console.log('=== STX REDUCER ==='); - console.log('STX Alert State:', state?.state); if (action.value?.preferences?.smartTransactionsOptInStatus === true) { state.state = ALERT_STATE.OPEN; - console.log('Alert state changed to:', ALERT_STATE.OPEN); } - console.log('=== STX REDUCER END ==='); }, }, }); const { actions, reducer } = slice; -// Selectors -export const getSTXAlertState = (state) => state.metamask.alerts?.[name]?.state; +export const getSTXAlertState = (state) => state[name]?.state; export const stxAlertIsOpen = (state) => - state.stxMigration?.state === ALERT_STATE.OPEN; + state[name]?.state === ALERT_STATE.OPEN; + +export const { + showSTXMigrationAlert, + dismissSTXMigrationAlert, + disableAlertRequested, + disableAlertSucceeded, + disableAlertFailed, +} = actions; -// Actions -export const { showSTXMigrationAlert, dismissSTXMigrationAlert } = actions; +export const dismissAndDisableAlert = () => { + return async (dispatch) => { + try { + await dispatch(disableAlertRequested()); + await setAlertEnabledness(name, false); + await dispatch(disableAlertSucceeded()); + } catch (error) { + console.error(error); + captureException(error); + await dispatch(disableAlertFailed()); + } + }; +}; export default reducer; diff --git a/ui/ducks/alerts/stx-migration.test.js b/ui/ducks/alerts/stx-migration.test.js index 8ffca32a787c..29be4618a33f 100644 --- a/ui/ducks/alerts/stx-migration.test.js +++ b/ui/ducks/alerts/stx-migration.test.js @@ -1,23 +1,37 @@ import { AlertTypes } from '../../../shared/constants/alerts'; import * as actionConstants from '../../store/actionConstants'; -import { ALERT_STATE } from './enums'; +import configureStore from '../../store/store'; +import { setAlertEnabledness } from '../../store/actions'; import reducer, { showSTXMigrationAlert, dismissSTXMigrationAlert, + dismissAndDisableAlert, stxAlertIsOpen, } from './stx-migration'; +import { ALERT_STATE } from './enums'; + +jest.mock('../../store/actions', () => ({ + setAlertEnabledness: jest.fn().mockResolvedValue(), +})); + +jest.mock('../../../store/store', () => { + return jest.fn().mockImplementation((state) => ({ + getState: () => state, + dispatch: jest.fn(), + })); +}); describe('STX Migration Alert', () => { const mockState = { - metamask: { - alerts: { - [AlertTypes.stxMigration]: { - state: ALERT_STATE.OPEN, - }, - }, + [AlertTypes.stxMigration]: { + state: ALERT_STATE.OPEN, }, }; + beforeEach(() => { + jest.clearAllMocks(); + }); + it('should initialize with CLOSED state', () => { const result = reducer(undefined, {}); expect(result.state).toStrictEqual(ALERT_STATE.CLOSED); @@ -61,15 +75,61 @@ describe('STX Migration Alert', () => { it('should return false when alert is closed', () => { const closedState = { - metamask: { - alerts: { - [AlertTypes.stxMigration]: { - state: ALERT_STATE.CLOSED, - }, - }, + [AlertTypes.stxMigration]: { + state: ALERT_STATE.CLOSED, }, }; expect(stxAlertIsOpen(closedState)).toBe(false); }); }); + + describe('dismissAndDisableAlert', () => { + it('should update alert state and preferences when disabling alert', async () => { + const store = configureStore(mockState); + await store.dispatch(dismissAndDisableAlert()); + + expect(setAlertEnabledness).toHaveBeenCalledWith( + AlertTypes.stxMigration, + false, + ); + expect(store.dispatch).toHaveBeenCalledWith( + expect.objectContaining({ + type: expect.stringContaining('disableAlertSucceeded'), + }), + ); + }); + + it('should handle errors when disabling alert fails', async () => { + const error = new Error('Failed to disable alert'); + setAlertEnabledness.mockRejectedValueOnce(error); + + const store = configureStore(mockState); + await store.dispatch(dismissAndDisableAlert()); + + expect(store.dispatch).toHaveBeenCalledWith( + expect.objectContaining({ + type: expect.stringContaining('disableAlertFailed'), + }), + ); + }); + + it('should transition through loading state', async () => { + const store = configureStore(mockState); + const dispatchPromise = store.dispatch(dismissAndDisableAlert()); + + expect(store.dispatch).toHaveBeenCalledWith( + expect.objectContaining({ + type: expect.stringContaining('disableAlertRequested'), + }), + ); + + await dispatchPromise; + + expect(store.dispatch).toHaveBeenCalledWith( + expect.objectContaining({ + type: expect.stringContaining('disableAlertSucceeded'), + }), + ); + }); + }); }); From 3a6e424728babc8912f1524018c721d3a88e38f8 Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Thu, 5 Dec 2024 10:34:10 -0500 Subject: [PATCH 14/90] update path to store in test file and directly tests the thunk behavior without complex store mocking. --- ui/ducks/alerts/stx-migration.test.js | 59 ++++++--------------------- 1 file changed, 13 insertions(+), 46 deletions(-) diff --git a/ui/ducks/alerts/stx-migration.test.js b/ui/ducks/alerts/stx-migration.test.js index 29be4618a33f..23361fb7d9b7 100644 --- a/ui/ducks/alerts/stx-migration.test.js +++ b/ui/ducks/alerts/stx-migration.test.js @@ -1,6 +1,5 @@ import { AlertTypes } from '../../../shared/constants/alerts'; import * as actionConstants from '../../store/actionConstants'; -import configureStore from '../../store/store'; import { setAlertEnabledness } from '../../store/actions'; import reducer, { showSTXMigrationAlert, @@ -14,13 +13,6 @@ jest.mock('../../store/actions', () => ({ setAlertEnabledness: jest.fn().mockResolvedValue(), })); -jest.mock('../../../store/store', () => { - return jest.fn().mockImplementation((state) => ({ - getState: () => state, - dispatch: jest.fn(), - })); -}); - describe('STX Migration Alert', () => { const mockState = { [AlertTypes.stxMigration]: { @@ -84,52 +76,27 @@ describe('STX Migration Alert', () => { }); describe('dismissAndDisableAlert', () => { - it('should update alert state and preferences when disabling alert', async () => { - const store = configureStore(mockState); - await store.dispatch(dismissAndDisableAlert()); + it('should handle disable alert flow', async () => { + const mockDispatch = jest.fn(); + await dismissAndDisableAlert()(mockDispatch); expect(setAlertEnabledness).toHaveBeenCalledWith( AlertTypes.stxMigration, false, ); - expect(store.dispatch).toHaveBeenCalledWith( - expect.objectContaining({ - type: expect.stringContaining('disableAlertSucceeded'), - }), - ); - }); - - it('should handle errors when disabling alert fails', async () => { - const error = new Error('Failed to disable alert'); - setAlertEnabledness.mockRejectedValueOnce(error); - - const store = configureStore(mockState); - await store.dispatch(dismissAndDisableAlert()); - - expect(store.dispatch).toHaveBeenCalledWith( - expect.objectContaining({ - type: expect.stringContaining('disableAlertFailed'), - }), - ); + expect(mockDispatch).toHaveBeenNthCalledWith(1, { + type: `${AlertTypes.stxMigration}/disableAlertRequested`, + }); }); - it('should transition through loading state', async () => { - const store = configureStore(mockState); - const dispatchPromise = store.dispatch(dismissAndDisableAlert()); - - expect(store.dispatch).toHaveBeenCalledWith( - expect.objectContaining({ - type: expect.stringContaining('disableAlertRequested'), - }), - ); - - await dispatchPromise; + it('should handle errors', async () => { + const mockDispatch = jest.fn(); + setAlertEnabledness.mockRejectedValueOnce(new Error()); + await dismissAndDisableAlert()(mockDispatch); - expect(store.dispatch).toHaveBeenCalledWith( - expect.objectContaining({ - type: expect.stringContaining('disableAlertSucceeded'), - }), - ); + expect(mockDispatch).toHaveBeenNthCalledWith(2, { + type: `${AlertTypes.stxMigration}/disableAlertFailed`, + }); }); }); }); From 3af6e58be08b4c1ceaf9d0489c9ebc17aea9d1f9 Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Thu, 5 Dec 2024 11:38:11 -0500 Subject: [PATCH 15/90] add logs to check extraReducer logic and state. --- ui/ducks/alerts/stx-migration.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/ui/ducks/alerts/stx-migration.js b/ui/ducks/alerts/stx-migration.js index cb3f0d737fb5..bf593db32ebc 100644 --- a/ui/ducks/alerts/stx-migration.js +++ b/ui/ducks/alerts/stx-migration.js @@ -33,9 +33,21 @@ const slice = createSlice({ }, extraReducers: { [actionConstants.UPDATE_METAMASK_STATE]: (state, action) => { - if (action.value?.preferences?.smartTransactionsOptInStatus === true) { + console.log('=== STX ALERT STATE UPDATE ==='); + console.log('Current state:', state.state); + console.log('Alert Enabledness:', action.value?.alertEnabledness); + console.log( + 'STX Status:', + action.value?.preferences?.smartTransactionsOptInStatus, + ); + if ( + action.value?.preferences?.smartTransactionsOptInStatus === true && + action.value?.alertEnabledness?.[AlertTypes.stxMigration] !== false + ) { state.state = ALERT_STATE.OPEN; + console.log('Setting state to OPEN'); } + console.log('=== STX ALERT STATE UPDATE END ==='); }, }, }); From ed3be1fbba8397f76923fc36e8d39be8bba682e8 Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Thu, 5 Dec 2024 17:00:55 -0500 Subject: [PATCH 16/90] Add permanent alert dismissal for MetaMask Smart Transactions onboarding message. When a user dismisses the alert (via close or "Learn more"), their preference is stored and persists across transaction sessions. The dismissal is handled through the alerts state system and uses the existing setAlertEnabledness functionality. Remove comments. --- ui/ducks/alerts/stx-migration.js | 30 +++++--------- ui/ducks/alerts/stx-migration.test.js | 40 ++++++++++++------- .../stx-banner-alert/stx-banner-alert.js | 15 +++---- 3 files changed, 39 insertions(+), 46 deletions(-) diff --git a/ui/ducks/alerts/stx-migration.js b/ui/ducks/alerts/stx-migration.js index bf593db32ebc..504f1a842ee8 100644 --- a/ui/ducks/alerts/stx-migration.js +++ b/ui/ducks/alerts/stx-migration.js @@ -15,12 +15,6 @@ const slice = createSlice({ name, initialState, reducers: { - showSTXMigrationAlert: (state) => { - state.state = ALERT_STATE.OPEN; - }, - dismissSTXMigrationAlert: (state) => { - state.state = ALERT_STATE.CLOSED; - }, disableAlertRequested: (state) => { state.state = ALERT_STATE.LOADING; }, @@ -31,30 +25,20 @@ const slice = createSlice({ state.state = ALERT_STATE.ERROR; }, }, - extraReducers: { - [actionConstants.UPDATE_METAMASK_STATE]: (state, action) => { - console.log('=== STX ALERT STATE UPDATE ==='); - console.log('Current state:', state.state); - console.log('Alert Enabledness:', action.value?.alertEnabledness); - console.log( - 'STX Status:', - action.value?.preferences?.smartTransactionsOptInStatus, - ); + extraReducers: (builder) => { + builder.addCase(actionConstants.UPDATE_METAMASK_STATE, (state, action) => { if ( action.value?.preferences?.smartTransactionsOptInStatus === true && action.value?.alertEnabledness?.[AlertTypes.stxMigration] !== false ) { state.state = ALERT_STATE.OPEN; - console.log('Setting state to OPEN'); } - console.log('=== STX ALERT STATE UPDATE END ==='); - }, + }); }, }); const { actions, reducer } = slice; -export const getSTXAlertState = (state) => state[name]?.state; export const stxAlertIsOpen = (state) => state[name]?.state === ALERT_STATE.OPEN; @@ -69,12 +53,16 @@ export const { export const dismissAndDisableAlert = () => { return async (dispatch) => { try { + // Show loading state await dispatch(disableAlertRequested()); - await setAlertEnabledness(name, false); + // Set alert enabledness to false (persistent setting) + await setAlertEnabledness(AlertTypes.stxMigration, false); + // Mark alert as successfully disabled await dispatch(disableAlertSucceeded()); } catch (error) { - console.error(error); + console.error('Failed to disable STX Migration alert:', error); captureException(error); + // Show an error state await dispatch(disableAlertFailed()); } }; diff --git a/ui/ducks/alerts/stx-migration.test.js b/ui/ducks/alerts/stx-migration.test.js index 23361fb7d9b7..24b86f383239 100644 --- a/ui/ducks/alerts/stx-migration.test.js +++ b/ui/ducks/alerts/stx-migration.test.js @@ -2,8 +2,6 @@ import { AlertTypes } from '../../../shared/constants/alerts'; import * as actionConstants from '../../store/actionConstants'; import { setAlertEnabledness } from '../../store/actions'; import reducer, { - showSTXMigrationAlert, - dismissSTXMigrationAlert, dismissAndDisableAlert, stxAlertIsOpen, } from './stx-migration'; @@ -29,23 +27,25 @@ describe('STX Migration Alert', () => { expect(result.state).toStrictEqual(ALERT_STATE.CLOSED); }); - it('should handle showSTXMigrationAlert', () => { + it('opens alert when smartTransactionsOptInStatus becomes true and alert is not disabled', () => { const result = reducer( { state: ALERT_STATE.CLOSED }, - showSTXMigrationAlert(), + { + type: actionConstants.UPDATE_METAMASK_STATE, + value: { + preferences: { + smartTransactionsOptInStatus: true, + }, + alertEnabledness: { + [AlertTypes.stxMigration]: true, + }, + }, + }, ); expect(result.state).toStrictEqual(ALERT_STATE.OPEN); }); - it('should handle dismissSTXMigrationAlert', () => { - const result = reducer( - { state: ALERT_STATE.OPEN }, - dismissSTXMigrationAlert(), - ); - expect(result.state).toStrictEqual(ALERT_STATE.CLOSED); - }); - - it('opens alert when smartTransactionsOptInStatus becomes true', () => { + it('keeps alert closed when alert is disabled', () => { const result = reducer( { state: ALERT_STATE.CLOSED }, { @@ -54,10 +54,13 @@ describe('STX Migration Alert', () => { preferences: { smartTransactionsOptInStatus: true, }, + alertEnabledness: { + [AlertTypes.stxMigration]: false, + }, }, }, ); - expect(result.state).toStrictEqual(ALERT_STATE.OPEN); + expect(result.state).toStrictEqual(ALERT_STATE.CLOSED); }); describe('stxAlertIsOpen selector', () => { @@ -87,13 +90,20 @@ describe('STX Migration Alert', () => { expect(mockDispatch).toHaveBeenNthCalledWith(1, { type: `${AlertTypes.stxMigration}/disableAlertRequested`, }); + expect(mockDispatch).toHaveBeenNthCalledWith(2, { + type: `${AlertTypes.stxMigration}/disableAlertSucceeded`, + }); }); it('should handle errors', async () => { const mockDispatch = jest.fn(); - setAlertEnabledness.mockRejectedValueOnce(new Error()); + const error = new Error('Failed to disable alert'); + setAlertEnabledness.mockRejectedValueOnce(error); await dismissAndDisableAlert()(mockDispatch); + expect(mockDispatch).toHaveBeenNthCalledWith(1, { + type: `${AlertTypes.stxMigration}/disableAlertRequested`, + }); expect(mockDispatch).toHaveBeenNthCalledWith(2, { type: `${AlertTypes.stxMigration}/disableAlertFailed`, }); diff --git a/ui/pages/confirmations/components/stx-banner-alert/stx-banner-alert.js b/ui/pages/confirmations/components/stx-banner-alert/stx-banner-alert.js index 8a98e0648ebd..d6cb67d91e38 100644 --- a/ui/pages/confirmations/components/stx-banner-alert/stx-banner-alert.js +++ b/ui/pages/confirmations/components/stx-banner-alert/stx-banner-alert.js @@ -9,19 +9,15 @@ import { } from '../../../../components/component-library'; import { stxAlertIsOpen, - dismissSTXMigrationAlert, + dismissAndDisableAlert, } from '../../../../ducks/alerts/stx-migration'; import ZENDESK_URLS from '../../../../helpers/constants/zendesk-url'; const STXBannerAlert = () => { const dispatch = useDispatch(); const shouldShow = useSelector(stxAlertIsOpen); - const fullState = useSelector((state) => state); - - console.log('=== STX BANNER ==='); - console.log('Full Redux State:', fullState); - console.log('shouldShow:', shouldShow); - console.log('=== STX BANNER END ==='); + // const fullState = useSelector((state) => state); + // console.log(fullState) const t = useI18nContext(); @@ -34,8 +30,7 @@ const STXBannerAlert = () => { severity={BannerAlertSeverity.Info} onClose={() => { console.log('Dismiss clicked'); - dispatch(dismissSTXMigrationAlert()); - console.log('Dismiss action dispatched'); + dispatch(dismissAndDisableAlert()); }} data-testid="stx-banner-alert" > @@ -43,7 +38,7 @@ const STXBannerAlert = () => { {t('smartTransactionsEnabledMessage')} dispatch(dismissSTXMigrationAlert())} + onClick={() => dispatch(dismissAndDisableAlert())} externalLink > {t('smartTransactionsLearnMore')} From 724d3e6801b342d1aebf6929f659ecfe71819194 Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Fri, 6 Dec 2024 04:40:15 -0500 Subject: [PATCH 17/90] With changes to permanent alert dismissal, we needed to update our tests for the STXBannerAlert and TransactionAlerts tests. --- .../stx-banner-alert/stx-banner-alert.test.js | 38 ++++++++++++++----- .../transaction-alerts.test.js | 11 +++--- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/ui/pages/confirmations/components/stx-banner-alert/stx-banner-alert.test.js b/ui/pages/confirmations/components/stx-banner-alert/stx-banner-alert.test.js index c538f0f48f0c..d66c0e5f3528 100644 --- a/ui/pages/confirmations/components/stx-banner-alert/stx-banner-alert.test.js +++ b/ui/pages/confirmations/components/stx-banner-alert/stx-banner-alert.test.js @@ -4,7 +4,19 @@ import { renderWithProvider } from '../../../../../test/jest/rendering'; import configureStore from '../../../../store/store'; import { AlertTypes } from '../../../../../shared/constants/alerts'; import { ALERT_STATE } from '../../../../ducks/alerts/enums'; -import { STXBannerAlert } from './stx-banner-alert'; +import STXBannerAlert from './stx-banner-alert'; + +// Mock the entire module +jest.mock('../../../../hooks/useI18nContext', () => ({ + useI18nContext: () => (key) => key, + __esModule: true, + default: () => (key) => key, +})); + +// Mock the setAlertEnabledness function +jest.mock('../../../../store/actions', () => ({ + setAlertEnabledness: jest.fn().mockResolvedValue(undefined), +})); describe('STXBannerAlert', () => { const mockState = { @@ -15,6 +27,9 @@ describe('STXBannerAlert', () => { }, }, }, + [AlertTypes.stxMigration]: { + state: ALERT_STATE.OPEN, + }, }; it('renders banner when alert is open', () => { @@ -37,6 +52,9 @@ describe('STXBannerAlert', () => { }, }, }, + [AlertTypes.stxMigration]: { + state: ALERT_STATE.CLOSED, + }, }; const store = configureStore(closedState); renderWithProvider(, store); @@ -44,27 +62,29 @@ describe('STXBannerAlert', () => { expect(screen.queryByTestId('stx-banner-alert')).not.toBeInTheDocument(); }); - it('dispatches dismissal action when close button clicked', () => { + it('dispatches dismissal action when close button clicked', async () => { const store = configureStore(mockState); renderWithProvider(, store); screen.getByRole('button', { name: /close/iu }).click(); + // Wait for the async action to complete + await new Promise((resolve) => setTimeout(resolve, 0)); + const state = store.getState(); - expect(state.metamask.alerts[AlertTypes.stxMigration].state).toBe( - ALERT_STATE.CLOSED, - ); + expect(state[AlertTypes.stxMigration].state).toBe(ALERT_STATE.CLOSED); }); - it('dispatches dismissal action when learn more link clicked', () => { + it('dispatches dismissal action when learn more link clicked', async () => { const store = configureStore(mockState); renderWithProvider(, store); screen.getByText('smartTransactionsLearnMore').click(); + // Wait for the async action to complete + await new Promise((resolve) => setTimeout(resolve, 0)); + const state = store.getState(); - expect(state.metamask.alerts[AlertTypes.stxMigration].state).toBe( - ALERT_STATE.CLOSED, - ); + expect(state[AlertTypes.stxMigration].state).toBe(ALERT_STATE.CLOSED); }); }); diff --git a/ui/pages/confirmations/components/transaction-alerts/transaction-alerts.test.js b/ui/pages/confirmations/components/transaction-alerts/transaction-alerts.test.js index f0ebdc8baa9c..5f7a96c8821c 100644 --- a/ui/pages/confirmations/components/transaction-alerts/transaction-alerts.test.js +++ b/ui/pages/confirmations/components/transaction-alerts/transaction-alerts.test.js @@ -35,11 +35,9 @@ const STATE_MOCK = { ...mockNetworkState({ chainId: CHAIN_ID_MOCK, }), - alerts: { - stxMigration: { - state: ALERT_STATE.OPEN, - }, - }, + }, + [AlertTypes.stxMigration]: { + state: ALERT_STATE.OPEN, }, }; @@ -590,6 +588,9 @@ describe('STX Migration Alert', () => { }, }, }, + [AlertTypes.stxMigration]: { + state: ALERT_STATE.CLOSED, + }, }; const store = configureStore(closedState); const { queryByTestId } = renderWithProvider( From 1df568e92e1fbe107067185b1b5f7494b2c3786f Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Fri, 6 Dec 2024 08:09:55 -0500 Subject: [PATCH 18/90] First stab at trying to implement alert for new confirmation/transaction flow. Does not let me close alert or show link. --- .../transactions/useSTXMigrationAlerts.ts | 36 +++++++++++++++++++ .../hooks/useConfirmationAlerts.ts | 4 +++ 2 files changed, 40 insertions(+) create mode 100644 ui/pages/confirmations/hooks/alerts/transactions/useSTXMigrationAlerts.ts diff --git a/ui/pages/confirmations/hooks/alerts/transactions/useSTXMigrationAlerts.ts b/ui/pages/confirmations/hooks/alerts/transactions/useSTXMigrationAlerts.ts new file mode 100644 index 000000000000..a1194f1d9338 --- /dev/null +++ b/ui/pages/confirmations/hooks/alerts/transactions/useSTXMigrationAlerts.ts @@ -0,0 +1,36 @@ +import { useMemo } from 'react'; +import { useSelector, useDispatch } from 'react-redux'; +import { useI18nContext } from '../../../../../hooks/useI18nContext'; +import { Severity } from '../../../../../helpers/constants/design-system'; +import { Alert } from '../../../../../ducks/confirm-alerts/confirm-alerts'; +import { stxAlertIsOpen, dismissAndDisableAlert } from '../../../../../ducks/alerts/stx-migration'; +import ZENDESK_URLS from '../../../../../helpers/constants/zendesk-url'; + +export function useSTXMigrationAlerts(): Alert[] { + const t = useI18nContext(); + const dispatch = useDispatch(); + const shouldShow = useSelector(stxAlertIsOpen); + + return useMemo(() => { + if (!shouldShow) { + return []; + } + + return [ + { + actions: [ + { + key: 'learnMore', + label: t('smartTransactionsLearnMore'), + url: ZENDESK_URLS.SMART_TRANSACTIONS_LEARN_MORE, + }, + ], + isBlocking: false, + key: 'stxMigration', + message: t('smartTransactionsEnabledMessage'), + severity: Severity.Info, + onClose: () => dispatch(dismissAndDisableAlert()), + }, + ]; + }, [shouldShow, t, dispatch]); +} diff --git a/ui/pages/confirmations/hooks/useConfirmationAlerts.ts b/ui/pages/confirmations/hooks/useConfirmationAlerts.ts index 382c7cdea511..fba46aefb8c2 100644 --- a/ui/pages/confirmations/hooks/useConfirmationAlerts.ts +++ b/ui/pages/confirmations/hooks/useConfirmationAlerts.ts @@ -18,6 +18,7 @@ import { useSigningOrSubmittingAlerts } from './alerts/transactions/useSigningOr import useConfirmationOriginAlerts from './alerts/useConfirmationOriginAlerts'; import useBlockaidAlerts from './alerts/useBlockaidAlerts'; import { useSelectedAccountAlerts } from './alerts/useSelectedAccountAlerts'; +import { useSTXMigrationAlerts } from './alerts/transactions/useSTXMigrationAlerts'; function useSignatureAlerts(): Alert[] { const accountMismatchAlerts = useAccountMismatchAlerts(); @@ -43,6 +44,7 @@ function useTransactionAlerts(): Alert[] { const signingOrSubmittingAlerts = useSigningOrSubmittingAlerts(); ///: END:ONLY_INCLUDE_IF const queuedConfirmationsAlerts = useQueuedConfirmationsAlerts(); + const stxMigrationAlerts = useSTXMigrationAlerts(); return useMemo( () => [ @@ -59,6 +61,7 @@ function useTransactionAlerts(): Alert[] { ...signingOrSubmittingAlerts, ///: END:ONLY_INCLUDE_IF ...queuedConfirmationsAlerts, + ...stxMigrationAlerts, ], [ gasEstimateFailedAlerts, @@ -74,6 +77,7 @@ function useTransactionAlerts(): Alert[] { signingOrSubmittingAlerts, ///: END:ONLY_INCLUDE_IF queuedConfirmationsAlerts, + stxMigrationAlerts, ], ); } From a6fa2399c2ff08dc8e29006f5c4a6c1d95e0a43c Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Fri, 6 Dec 2024 09:42:55 -0500 Subject: [PATCH 19/90] added an action to dismiss --- .../hooks/alerts/transactions/useSTXMigrationAlerts.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ui/pages/confirmations/hooks/alerts/transactions/useSTXMigrationAlerts.ts b/ui/pages/confirmations/hooks/alerts/transactions/useSTXMigrationAlerts.ts index a1194f1d9338..4bad5162800d 100644 --- a/ui/pages/confirmations/hooks/alerts/transactions/useSTXMigrationAlerts.ts +++ b/ui/pages/confirmations/hooks/alerts/transactions/useSTXMigrationAlerts.ts @@ -5,6 +5,7 @@ import { Severity } from '../../../../../helpers/constants/design-system'; import { Alert } from '../../../../../ducks/confirm-alerts/confirm-alerts'; import { stxAlertIsOpen, dismissAndDisableAlert } from '../../../../../ducks/alerts/stx-migration'; import ZENDESK_URLS from '../../../../../helpers/constants/zendesk-url'; +import { RowAlertKey } from '../../../../../components/app/confirm/info/row/constants'; export function useSTXMigrationAlerts(): Alert[] { const t = useI18nContext(); @@ -22,14 +23,17 @@ export function useSTXMigrationAlerts(): Alert[] { { key: 'learnMore', label: t('smartTransactionsLearnMore'), - url: ZENDESK_URLS.SMART_TRANSACTIONS_LEARN_MORE, + onClick: () => { + window.open(ZENDESK_URLS.SMART_TRANSACTIONS_LEARN_MORE, '_blank'); + dispatch(dismissAndDisableAlert()); + }, }, ], + field: RowAlertKey.FirstTimeInteraction, isBlocking: false, key: 'stxMigration', message: t('smartTransactionsEnabledMessage'), - severity: Severity.Info, - onClose: () => dispatch(dismissAndDisableAlert()), + severity: Severity.Warning, }, ]; }, [shouldShow, t, dispatch]); From 21a45a8bb1097b774d745b1785c5f1a981ebed33 Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Fri, 6 Dec 2024 11:40:05 -0500 Subject: [PATCH 20/90] feat: add STX migration toast to new confirmation flow --- .../confirm/stx-migration-toast/index.ts | 1 + .../stx-migration-toast-legacy.tsx | 54 +++++++++++++++++++ .../stx-migration-toast.tsx | 10 ++++ ui/pages/confirmations/confirm/confirm.tsx | 2 + 4 files changed, 67 insertions(+) create mode 100644 ui/pages/confirmations/components/confirm/stx-migration-toast/index.ts create mode 100644 ui/pages/confirmations/components/confirm/stx-migration-toast/stx-migration-toast-legacy.tsx create mode 100644 ui/pages/confirmations/components/confirm/stx-migration-toast/stx-migration-toast.tsx diff --git a/ui/pages/confirmations/components/confirm/stx-migration-toast/index.ts b/ui/pages/confirmations/components/confirm/stx-migration-toast/index.ts new file mode 100644 index 000000000000..a07695c37e71 --- /dev/null +++ b/ui/pages/confirmations/components/confirm/stx-migration-toast/index.ts @@ -0,0 +1 @@ +export { default } from './stx-migration-toast'; diff --git a/ui/pages/confirmations/components/confirm/stx-migration-toast/stx-migration-toast-legacy.tsx b/ui/pages/confirmations/components/confirm/stx-migration-toast/stx-migration-toast-legacy.tsx new file mode 100644 index 000000000000..8f15711f72d6 --- /dev/null +++ b/ui/pages/confirmations/components/confirm/stx-migration-toast/stx-migration-toast-legacy.tsx @@ -0,0 +1,54 @@ +import React, { useCallback, useState, useEffect } from 'react'; +import { useSelector, useDispatch } from 'react-redux'; +import { Box } from '../../../../../components/component-library'; +import { Toast } from '../../../../../components/multichain'; +import { useI18nContext } from '../../../../../hooks/useI18nContext'; +import { stxAlertIsOpen, dismissAndDisableAlert } from '../../../../../ducks/alerts/stx-migration'; +import ZENDESK_URLS from '../../../../../helpers/constants/zendesk-url'; + +const STXMigrationToastLegacy = () => { + const [toastVisible, setToastVisible] = useState(false); + const shouldShow = useSelector(stxAlertIsOpen); + const dispatch = useDispatch(); + const t = useI18nContext(); + + const hideToast = useCallback(() => { + setToastVisible(false); + dispatch(dismissAndDisableAlert()); + }, [dispatch]); + + const handleLearnMore = useCallback(() => { + window.open(ZENDESK_URLS.SMART_TRANSACTIONS_LEARN_MORE, '_blank'); + hideToast(); + }, [hideToast]); + + useEffect(() => { + let isMounted = true; + + if (shouldShow && isMounted) { + setToastVisible(true); + } + + return () => { + isMounted = false; + }; + }, [shouldShow]); + + if (!toastVisible) { + return null; + } + + return ( + + + + ); +}; + +export default STXMigrationToastLegacy; diff --git a/ui/pages/confirmations/components/confirm/stx-migration-toast/stx-migration-toast.tsx b/ui/pages/confirmations/components/confirm/stx-migration-toast/stx-migration-toast.tsx new file mode 100644 index 000000000000..a18fbdbc8779 --- /dev/null +++ b/ui/pages/confirmations/components/confirm/stx-migration-toast/stx-migration-toast.tsx @@ -0,0 +1,10 @@ +import React from 'react'; +import useCurrentConfirmation from '../../../hooks/useCurrentConfirmation'; +import STXMigrationToastLegacy from './stx-migration-toast-legacy'; + +const STXMigrationToast = () => { + const { currentConfirmation } = useCurrentConfirmation(); + return ; +}; + +export default STXMigrationToast; diff --git a/ui/pages/confirmations/confirm/confirm.tsx b/ui/pages/confirmations/confirm/confirm.tsx index 67df9ccfd222..afc244ae12d7 100644 --- a/ui/pages/confirmations/confirm/confirm.tsx +++ b/ui/pages/confirmations/confirm/confirm.tsx @@ -17,6 +17,7 @@ import { Info } from '../components/confirm/info'; import { LedgerInfo } from '../components/confirm/ledger-info'; import { Nav } from '../components/confirm/nav'; import { NetworkChangeToast } from '../components/confirm/network-change-toast'; +import STXMigrationToast from '../components/confirm/stx-migration-toast'; import { PluggableSection } from '../components/confirm/pluggable-section'; import ScrollToBottom from '../components/confirm/scroll-to-bottom'; import { Title } from '../components/confirm/title'; @@ -72,6 +73,7 @@ const Confirm = () => (
+ From da793a6db6aba163ade0ed9c1a66e3e941f6644e Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Fri, 6 Dec 2024 12:02:58 -0500 Subject: [PATCH 21/90] move toast to top of page and try to default to darkmode --- .../stx-migration-toast-legacy.tsx | 13 ++++++++++++- ui/pages/confirmations/confirm/confirm.tsx | 2 +- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/ui/pages/confirmations/components/confirm/stx-migration-toast/stx-migration-toast-legacy.tsx b/ui/pages/confirmations/components/confirm/stx-migration-toast/stx-migration-toast-legacy.tsx index 8f15711f72d6..28241e5f87ba 100644 --- a/ui/pages/confirmations/components/confirm/stx-migration-toast/stx-migration-toast-legacy.tsx +++ b/ui/pages/confirmations/components/confirm/stx-migration-toast/stx-migration-toast-legacy.tsx @@ -5,6 +5,7 @@ import { Toast } from '../../../../../components/multichain'; import { useI18nContext } from '../../../../../hooks/useI18nContext'; import { stxAlertIsOpen, dismissAndDisableAlert } from '../../../../../ducks/alerts/stx-migration'; import ZENDESK_URLS from '../../../../../helpers/constants/zendesk-url'; +import { Display } from '../../../../../helpers/constants/design-system'; const STXMigrationToastLegacy = () => { const [toastVisible, setToastVisible] = useState(false); @@ -39,7 +40,17 @@ const STXMigrationToastLegacy = () => { } return ( - + (
+
+
+
+
+
+
Date: Wed, 11 Dec 2024 11:17:53 -0500 Subject: [PATCH 39/90] fix: remove unused d.ts file no longer needed as SmartTransactionsBannerAlert is now written in TS, also fix lint error on stx-migration ducks test. --- ui/ducks/alerts/smart-transactions-migration.test.ts | 6 +----- .../smart-transactions-banner-alert.d.ts | 9 --------- .../smart-transactions-banner-alert.tsx | 4 ++-- 3 files changed, 3 insertions(+), 16 deletions(-) delete mode 100644 ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.d.ts diff --git a/ui/ducks/alerts/smart-transactions-migration.test.ts b/ui/ducks/alerts/smart-transactions-migration.test.ts index 890f90cb7406..daabb8a8bbe3 100644 --- a/ui/ducks/alerts/smart-transactions-migration.test.ts +++ b/ui/ducks/alerts/smart-transactions-migration.test.ts @@ -6,7 +6,6 @@ import reducer, { shouldShowSmartTransactionsMigrationAlert, } from './smart-transactions-migration'; import { ALERT_STATE } from './enums'; -import { SpyInstance } from 'jest-mock'; jest.mock('../../store/actions', () => ({ setAlertEnabledness: jest @@ -15,10 +14,7 @@ jest.mock('../../store/actions', () => ({ })); describe('Smart Transactions Migration Alert', () => { - let consoleErrorSpy: jest.SpyInstance< - void, - [message?: any, ...optionalParams: any[]] - >; + let consoleErrorSpy: jest.SpyInstance; const mockState = { [AlertTypes.smartTransactionsMigration]: { diff --git a/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.d.ts b/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.d.ts deleted file mode 100644 index 0bb367ecd307..000000000000 --- a/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.d.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { FC } from 'react'; - -interface SmartTransactionsBannerAlertProps { - marginType?: 'default' | 'none' | 'noTop' | 'onlyTop'; -} - -declare const SmartTransactionsBannerAlert: FC; - -export { SmartTransactionsBannerAlert }; diff --git a/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx b/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx index d4bf062b69ad..5f142bb27396 100644 --- a/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx +++ b/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx @@ -15,9 +15,9 @@ import { SMART_TRANSACTIONS_LEARN_MORE_URL } from '../../../../../shared/constan type MarginType = 'default' | 'none' | 'noTop' | 'onlyTop'; -interface SmartTransactionsBannerAlertProps { +type SmartTransactionsBannerAlertProps = { marginType?: MarginType; -} +}; export const SmartTransactionsBannerAlert: React.FC = React.memo(({ marginType = 'default' }) => { From 398bd780313281ad35d117fa6f3632efe7a3b66e Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Wed, 11 Dec 2024 14:57:14 -0500 Subject: [PATCH 40/90] fix: These are old tests planned for disable. The quicker way to solve this is to disable them with your PR. dBrochetto --- test/e2e/tests/metrics/swaps.spec.js | 2 +- test/e2e/tests/swaps/swap-eth.spec.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/e2e/tests/metrics/swaps.spec.js b/test/e2e/tests/metrics/swaps.spec.js index 6b73e3f400b7..cbb47d64ce8a 100644 --- a/test/e2e/tests/metrics/swaps.spec.js +++ b/test/e2e/tests/metrics/swaps.spec.js @@ -90,7 +90,7 @@ async function mockSegmentAndMetaswapRequests(mockServer) { ]; } -describe('Swap Eth for another Token @no-mmi', function () { +xdescribe('Swap Eth for another Token @no-mmi', function () { it('Completes a Swap between ETH and DAI after changing initial rate', async function () { const { initialBalanceInHex } = genRandInitBal(); diff --git a/test/e2e/tests/swaps/swap-eth.spec.ts b/test/e2e/tests/swaps/swap-eth.spec.ts index 18d049e5de16..cf7cefb9ca68 100644 --- a/test/e2e/tests/swaps/swap-eth.spec.ts +++ b/test/e2e/tests/swaps/swap-eth.spec.ts @@ -9,7 +9,7 @@ import { mockEthDaiTrade, } from './shared'; -describe('Swap Eth for another Token @no-mmi', function () { +xdescribe('Swap Eth for another Token @no-mmi', function () { it('Completes second Swaps while first swap is processing', async function () { withFixturesOptions.ganacheOptions.miner.blockTime = 10; From 11fe290e16d5b0ecbd236dd4beeefc226e40a862 Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Thu, 12 Dec 2024 07:54:43 -0500 Subject: [PATCH 41/90] fix: removed console.log accidentally left in. --- .../smart-transactions-banner-alert.tsx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx b/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx index 5f142bb27396..d8c06896cb9e 100644 --- a/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx +++ b/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx @@ -45,10 +45,7 @@ export const SmartTransactionsBannerAlert: React.FC { - console.log('Dismiss clicked'); - dispatch(dismissAndDisableAlert()); - }} + onClose={() => dispatch(dismissAndDisableAlert())} data-testid="smart-transactions-banner-alert" style={getMarginStyle()} > From 50be87afb6e43fe8779fbf776ea5bbb2c5b96fad Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Thu, 12 Dec 2024 08:07:22 -0500 Subject: [PATCH 42/90] This seems to be the correct way to skip these tests rather than `xdescribe` --- test/e2e/tests/metrics/swaps.spec.js | 4 +++- test/e2e/tests/swaps/swap-eth.spec.ts | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/test/e2e/tests/metrics/swaps.spec.js b/test/e2e/tests/metrics/swaps.spec.js index cbb47d64ce8a..a75d293771b8 100644 --- a/test/e2e/tests/metrics/swaps.spec.js +++ b/test/e2e/tests/metrics/swaps.spec.js @@ -90,7 +90,9 @@ async function mockSegmentAndMetaswapRequests(mockServer) { ]; } -xdescribe('Swap Eth for another Token @no-mmi', function () { +// TODO: (MM-PENDING) These tests are planned for deprecation as part of swaps testing revamp +// eslint-disable-next-line mocha/no-skipped-tests +describe.skip('Swap Eth for another Token @no-mmi', function () { it('Completes a Swap between ETH and DAI after changing initial rate', async function () { const { initialBalanceInHex } = genRandInitBal(); diff --git a/test/e2e/tests/swaps/swap-eth.spec.ts b/test/e2e/tests/swaps/swap-eth.spec.ts index cf7cefb9ca68..14464dee179d 100644 --- a/test/e2e/tests/swaps/swap-eth.spec.ts +++ b/test/e2e/tests/swaps/swap-eth.spec.ts @@ -9,7 +9,9 @@ import { mockEthDaiTrade, } from './shared'; -xdescribe('Swap Eth for another Token @no-mmi', function () { +// TODO: (MM-PENDING) These tests are planned for deprecation as part of swaps testing revamp +// eslint-disable-next-line mocha/no-skipped-tests +describe.skip('Swap Eth for another Token @no-mmi', function () { it('Completes second Swaps while first swap is processing', async function () { withFixturesOptions.ganacheOptions.miner.blockTime = 10; From 5368950b86e25c560fff379607d2a30f565c1057 Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Thu, 12 Dec 2024 09:25:04 -0500 Subject: [PATCH 43/90] refactor: simplify smart transactions migration alert Removed legacy alert reducers in favor of direct state access for smart transactions banner --- ui/ducks/alerts/index.js | 1 - .../smart-transactions-migration.test.ts | 129 ------------------ .../alerts/smart-transactions-migration.ts | 90 ------------ ui/ducks/index.js | 7 +- .../smart-transactions-banner-alert.test.tsx | 74 +++++----- .../smart-transactions-banner-alert.tsx | 43 ++++-- .../transaction-alerts.test.js | 12 +- 7 files changed, 84 insertions(+), 272 deletions(-) delete mode 100644 ui/ducks/alerts/smart-transactions-migration.test.ts delete mode 100644 ui/ducks/alerts/smart-transactions-migration.ts diff --git a/ui/ducks/alerts/index.js b/ui/ducks/alerts/index.js index f17bbe54010f..28dd8c8976d0 100644 --- a/ui/ducks/alerts/index.js +++ b/ui/ducks/alerts/index.js @@ -1,5 +1,4 @@ export { default as unconnectedAccount } from './unconnected-account'; export { default as invalidCustomNetwork } from './invalid-custom-network'; -export { default as smartTransactionsMigration } from './smart-transactions-migration'; export { ALERT_STATE } from './enums'; diff --git a/ui/ducks/alerts/smart-transactions-migration.test.ts b/ui/ducks/alerts/smart-transactions-migration.test.ts deleted file mode 100644 index daabb8a8bbe3..000000000000 --- a/ui/ducks/alerts/smart-transactions-migration.test.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { AlertTypes } from '../../../shared/constants/alerts'; -import * as actionConstants from '../../store/actionConstants'; -import { setAlertEnabledness } from '../../store/actions'; -import reducer, { - dismissAndDisableAlert, - shouldShowSmartTransactionsMigrationAlert, -} from './smart-transactions-migration'; -import { ALERT_STATE } from './enums'; - -jest.mock('../../store/actions', () => ({ - setAlertEnabledness: jest - .fn, [string, boolean]>() - .mockResolvedValue(undefined), -})); - -describe('Smart Transactions Migration Alert', () => { - let consoleErrorSpy: jest.SpyInstance; - - const mockState = { - [AlertTypes.smartTransactionsMigration]: { - state: ALERT_STATE.OPEN, - }, - }; - - beforeEach(() => { - jest.clearAllMocks(); - consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(); - }); - - afterEach(() => { - consoleErrorSpy.mockRestore(); - }); - - it('should initialize with CLOSED state', () => { - const result = reducer(undefined, { type: 'INIT' }); - expect(result.state).toStrictEqual(ALERT_STATE.CLOSED); - }); - - it('opens alert when smartTransactionsOptInStatus becomes true and alert is not disabled', () => { - const result = reducer( - { state: ALERT_STATE.CLOSED }, - { - type: actionConstants.UPDATE_METAMASK_STATE, - value: { - preferences: { - smartTransactionsOptInStatus: true, - }, - alertEnabledness: { - [AlertTypes.smartTransactionsMigration]: true, - }, - }, - }, - ); - expect(result.state).toStrictEqual(ALERT_STATE.OPEN); - }); - - it('keeps alert closed when alert is disabled', () => { - const result = reducer( - { state: ALERT_STATE.CLOSED }, - { - type: actionConstants.UPDATE_METAMASK_STATE, - value: { - preferences: { - smartTransactionsOptInStatus: true, - }, - alertEnabledness: { - [AlertTypes.smartTransactionsMigration]: false, - }, - }, - }, - ); - expect(result.state).toStrictEqual(ALERT_STATE.CLOSED); - }); - - describe('shouldShowSmartTransactionsMigrationAlert selector', () => { - it('should return true when alert is open', () => { - expect(shouldShowSmartTransactionsMigrationAlert(mockState)).toBe(true); - }); - - it('should return false when alert is closed', () => { - const closedState = { - [AlertTypes.smartTransactionsMigration]: { - state: ALERT_STATE.CLOSED, - }, - }; - expect(shouldShowSmartTransactionsMigrationAlert(closedState)).toBe( - false, - ); - }); - }); - - describe('dismissAndDisableAlert', () => { - it('should handle disable alert flow', async () => { - const mockDispatch = jest.fn(); - await dismissAndDisableAlert()(mockDispatch); - - expect(setAlertEnabledness).toHaveBeenCalledWith( - AlertTypes.smartTransactionsMigration, - false, - ); - expect(mockDispatch).toHaveBeenNthCalledWith(1, { - type: `${AlertTypes.smartTransactionsMigration}/disableAlertRequested`, - }); - expect(mockDispatch).toHaveBeenNthCalledWith(2, { - type: `${AlertTypes.smartTransactionsMigration}/disableAlertSucceeded`, - }); - }); - - it('should handle errors', async () => { - const mockDispatch = jest.fn(); - const error = new Error('Failed to disable alert'); - ( - setAlertEnabledness as jest.MockedFunction - ).mockRejectedValueOnce(error); - await dismissAndDisableAlert()(mockDispatch); - - expect(mockDispatch).toHaveBeenNthCalledWith(1, { - type: `${AlertTypes.smartTransactionsMigration}/disableAlertRequested`, - }); - expect(mockDispatch).toHaveBeenNthCalledWith(2, { - type: `${AlertTypes.smartTransactionsMigration}/disableAlertFailed`, - }); - expect(consoleErrorSpy).toHaveBeenCalledWith( - 'Failed to disable Smart Transactions Migration alert:', - error, - ); - }); - }); -}); diff --git a/ui/ducks/alerts/smart-transactions-migration.ts b/ui/ducks/alerts/smart-transactions-migration.ts deleted file mode 100644 index d1b0087c454a..000000000000 --- a/ui/ducks/alerts/smart-transactions-migration.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { createSlice, Action, Dispatch } from '@reduxjs/toolkit'; -import { captureException } from '@sentry/browser'; -import { AlertTypes } from '../../../shared/constants/alerts'; -import { setAlertEnabledness } from '../../store/actions'; -import * as actionConstants from '../../store/actionConstants'; -import { ALERT_STATE } from './enums'; - -const name = AlertTypes.smartTransactionsMigration; - -const initialState = { - state: ALERT_STATE.CLOSED, -}; - -type MetaMaskStateAction = Action< - typeof actionConstants.UPDATE_METAMASK_STATE -> & { - value: { - preferences?: { smartTransactionsOptInStatus?: boolean }; - alertEnabledness?: { [key: string]: boolean }; - }; -}; - -const slice = createSlice({ - name, - initialState, - reducers: { - disableAlertRequested: (state) => { - state.state = ALERT_STATE.LOADING; - }, - disableAlertSucceeded: (state) => { - state.state = ALERT_STATE.CLOSED; - }, - disableAlertFailed: (state) => { - state.state = ALERT_STATE.ERROR; - }, - }, - extraReducers: (builder) => { - builder.addCase( - actionConstants.UPDATE_METAMASK_STATE, - (state, action: MetaMaskStateAction) => { - if ( - action.value?.preferences?.smartTransactionsOptInStatus === true && - action.value?.alertEnabledness?.[ - AlertTypes.smartTransactionsMigration - ] !== false - ) { - state.state = ALERT_STATE.OPEN; - } - }, - ); - }, -}); - -const { actions, reducer } = slice; - -type RootState = { - [name]: typeof initialState; -}; - -export const shouldShowSmartTransactionsMigrationAlert = (state: RootState) => - state[name]?.state === ALERT_STATE.OPEN; - -export const { - disableAlertRequested, - disableAlertSucceeded, - disableAlertFailed, -} = actions; - -export const dismissAndDisableAlert = () => { - return async (dispatch: Dispatch) => { - try { - // Show loading state - await dispatch(disableAlertRequested()); - // Set alert enabledness to false (persistent setting) - await setAlertEnabledness(AlertTypes.smartTransactionsMigration, false); - // Mark alert as successfully disabled - await dispatch(disableAlertSucceeded()); - } catch (error) { - console.error( - 'Failed to disable Smart Transactions Migration alert:', - error, - ); - captureException(error); - // Show an error state - await dispatch(disableAlertFailed()); - } - }; -}; - -export default reducer; diff --git a/ui/ducks/index.js b/ui/ducks/index.js index 153086adf586..deba3123916f 100644 --- a/ui/ducks/index.js +++ b/ui/ducks/index.js @@ -7,11 +7,7 @@ import domainReducer from './domains'; import appStateReducer from './app/app'; import confirmTransactionReducer from './confirm-transaction/confirm-transaction.duck'; import gasReducer from './gas/gas.duck'; -import { - invalidCustomNetwork, - unconnectedAccount, - smartTransactionsMigration, -} from './alerts'; +import { invalidCustomNetwork, unconnectedAccount } from './alerts'; import swapsReducer from './swaps/swaps'; import bridgeReducer from './bridge/bridge'; import historyReducer from './history/history'; @@ -21,7 +17,6 @@ import confirmAlertsReducer from './confirm-alerts/confirm-alerts'; export default combineReducers({ [AlertTypes.invalidCustomNetwork]: invalidCustomNetwork, [AlertTypes.unconnectedAccount]: unconnectedAccount, - [AlertTypes.smartTransactionsMigration]: smartTransactionsMigration, activeTab: (s) => (s === undefined ? null : s), metamask: metamaskReducer, appState: appStateReducer, diff --git a/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.test.tsx b/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.test.tsx index ea873a7e9847..f9b641810e3f 100644 --- a/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.test.tsx +++ b/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.test.tsx @@ -3,7 +3,7 @@ import { screen } from '@testing-library/react'; import { renderWithProvider } from '../../../../../test/jest/rendering'; import configureStore from '../../../../store/store'; import { AlertTypes } from '../../../../../shared/constants/alerts'; -import { ALERT_STATE } from '../../../../ducks/alerts/enums'; +import { setAlertEnabledness } from '../../../../store/actions'; import { SmartTransactionsBannerAlert } from './smart-transactions-banner-alert'; jest.mock('../../../../hooks/useI18nContext', () => ({ @@ -12,25 +12,24 @@ jest.mock('../../../../hooks/useI18nContext', () => ({ default: () => (key: string) => key, })); +// Update the mock to return a plain action object jest.mock('../../../../store/actions', () => ({ - setAlertEnabledness: jest.fn().mockResolvedValue(undefined), + setAlertEnabledness: jest.fn(() => ({ type: 'mock-action' })), })); describe('SmartTransactionsBannerAlert', () => { const mockState = { metamask: { - alerts: { - [AlertTypes.smartTransactionsMigration]: { - state: ALERT_STATE.OPEN, - }, + alertEnabledness: { + [AlertTypes.smartTransactionsMigration]: true, + }, + preferences: { + smartTransactionsOptInStatus: true, }, - }, - [AlertTypes.smartTransactionsMigration]: { - state: ALERT_STATE.OPEN, }, }; - it('renders banner when alert is open', () => { + it('renders banner when alert is enabled and STX is opted in', () => { const store = configureStore(mockState); renderWithProvider(, store); @@ -41,20 +40,37 @@ describe('SmartTransactionsBannerAlert', () => { expect(screen.getByText('learnMore')).toBeInTheDocument(); }); - it('does not render when alert is closed', () => { - const closedState = { + it('does not render when alert is disabled', () => { + const disabledState = { metamask: { - alerts: { - [AlertTypes.smartTransactionsMigration]: { - state: ALERT_STATE.CLOSED, - }, + alertEnabledness: { + [AlertTypes.smartTransactionsMigration]: false, + }, + preferences: { + smartTransactionsOptInStatus: true, }, }, - [AlertTypes.smartTransactionsMigration]: { - state: ALERT_STATE.CLOSED, + }; + const store = configureStore(disabledState); + renderWithProvider(, store); + + expect( + screen.queryByTestId('smart-transactions-banner-alert'), + ).not.toBeInTheDocument(); + }); + + it('does not render when STX is not opted in', () => { + const notOptedInState = { + metamask: { + alertEnabledness: { + [AlertTypes.smartTransactionsMigration]: true, + }, + preferences: { + smartTransactionsOptInStatus: false, + }, }, }; - const store = configureStore(closedState); + const store = configureStore(notOptedInState); renderWithProvider(, store); expect( @@ -62,31 +78,27 @@ describe('SmartTransactionsBannerAlert', () => { ).not.toBeInTheDocument(); }); - it('dispatches dismissal action when close button clicked', async () => { + it('calls setAlertEnabledness when close button clicked', () => { const store = configureStore(mockState); renderWithProvider(, store); screen.getByRole('button', { name: /close/iu }).click(); - await new Promise((resolve) => setTimeout(resolve, 0)); - - const state = store.getState(); - expect(state[AlertTypes.smartTransactionsMigration].state).toBe( - ALERT_STATE.CLOSED, + expect(setAlertEnabledness).toHaveBeenCalledWith( + AlertTypes.smartTransactionsMigration, + false, ); }); - it('dispatches dismissal action when learn more link clicked', async () => { + it('calls setAlertEnabledness when learn more link clicked', () => { const store = configureStore(mockState); renderWithProvider(, store); screen.getByText('learnMore').click(); - await new Promise((resolve) => setTimeout(resolve, 0)); - - const state = store.getState(); - expect(state[AlertTypes.smartTransactionsMigration].state).toBe( - ALERT_STATE.CLOSED, + expect(setAlertEnabledness).toHaveBeenCalledWith( + AlertTypes.smartTransactionsMigration, + false, ); }); }); diff --git a/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx b/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx index d8c06896cb9e..d141e8d67886 100644 --- a/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx +++ b/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx @@ -7,10 +7,8 @@ import { Text, BannerAlertSeverity, } from '../../../../components/component-library'; -import { - shouldShowSmartTransactionsMigrationAlert, - dismissAndDisableAlert, -} from '../../../../ducks/alerts/smart-transactions-migration'; +import { setAlertEnabledness } from '../../../../store/actions'; +import { AlertTypes } from '../../../../../shared/constants/alerts'; import { SMART_TRANSACTIONS_LEARN_MORE_URL } from '../../../../../shared/constants/smartTransactions'; type MarginType = 'default' | 'none' | 'noTop' | 'onlyTop'; @@ -19,16 +17,45 @@ type SmartTransactionsBannerAlertProps = { marginType?: MarginType; }; +type MetaMaskState = { + alertEnabledness: { + [key: string]: boolean; + }; + preferences: { + smartTransactionsOptInStatus: boolean; + }; +}; + +type RootState = { + metamask: MetaMaskState; +}; + export const SmartTransactionsBannerAlert: React.FC = React.memo(({ marginType = 'default' }) => { const dispatch = useDispatch(); - const shouldShow = useSelector(shouldShowSmartTransactionsMigrationAlert); const t = useI18nContext(); - if (!shouldShow) { + const alertEnabled = useSelector( + (state: RootState) => + state.metamask.alertEnabledness?.[ + AlertTypes.smartTransactionsMigration + ] !== false, + ); + const smartTransactionsOptIn = useSelector( + (state: RootState) => + state.metamask.preferences?.smartTransactionsOptInStatus === true, + ); + + if (!alertEnabled || !smartTransactionsOptIn) { return null; } + const handleDismiss = () => { + dispatch( + setAlertEnabledness(AlertTypes.smartTransactionsMigration, false), + ); + }; + const getMarginStyle = () => { switch (marginType) { case 'none': @@ -45,7 +72,7 @@ export const SmartTransactionsBannerAlert: React.FC dispatch(dismissAndDisableAlert())} + onClose={handleDismiss} data-testid="smart-transactions-banner-alert" style={getMarginStyle()} > @@ -53,7 +80,7 @@ export const SmartTransactionsBannerAlert: React.FC dispatch(dismissAndDisableAlert())} + onClick={handleDismiss} externalLink > {t('learnMore')} diff --git a/ui/pages/confirmations/components/transaction-alerts/transaction-alerts.test.js b/ui/pages/confirmations/components/transaction-alerts/transaction-alerts.test.js index 0150aae7e45c..522578de73bd 100644 --- a/ui/pages/confirmations/components/transaction-alerts/transaction-alerts.test.js +++ b/ui/pages/confirmations/components/transaction-alerts/transaction-alerts.test.js @@ -582,14 +582,12 @@ describe('Smart Transactions Migration Alert', () => { ...STATE_MOCK, metamask: { ...STATE_MOCK.metamask, - alerts: { - [AlertTypes.smartTransactionsMigration]: { - state: ALERT_STATE.CLOSED, - }, + alertEnabledness: { + [AlertTypes.smartTransactionsMigration]: false, + }, + preferences: { + smartTransactionsOptInStatus: true, }, - }, - [AlertTypes.smartTransactionsMigration]: { - state: ALERT_STATE.CLOSED, }, }; const store = configureStore(closedState); From 2936c72f1d05a314703938b34f6ddc97215ffb0d Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Thu, 12 Dec 2024 09:30:24 -0500 Subject: [PATCH 44/90] fix: let's make the test descriptions more accurate to what we're actually testing --- .../components/transaction-alerts/transaction-alerts.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/pages/confirmations/components/transaction-alerts/transaction-alerts.test.js b/ui/pages/confirmations/components/transaction-alerts/transaction-alerts.test.js index 522578de73bd..99cd03d67284 100644 --- a/ui/pages/confirmations/components/transaction-alerts/transaction-alerts.test.js +++ b/ui/pages/confirmations/components/transaction-alerts/transaction-alerts.test.js @@ -565,7 +565,7 @@ describe('TransactionAlerts', () => { }); describe('Smart Transactions Migration Alert', () => { - it('should show smart transactions banner when shouldShowSmartTransactionsMigrationAlert is true', () => { + it('shows when alert is enabled and opted in', () => { const { getByTestId } = render({ componentProps: { txData: { @@ -577,7 +577,7 @@ describe('Smart Transactions Migration Alert', () => { expect(getByTestId('smart-transactions-banner-alert')).toBeInTheDocument(); }); - it('should not show smart transactions banner when shouldShowSmartTransactionsMigrationAlert is false', () => { + it('does not show when alert is disabled', () => { const closedState = { ...STATE_MOCK, metamask: { From a7f208fa85f4cf7363b202a492beb568d3b28f94 Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Thu, 12 Dec 2024 11:46:38 -0500 Subject: [PATCH 45/90] fix: update snapshot to include smartTransactionsOptInStatus --- ...rs-after-init-opt-in-background-state.json | 19 ++++++------------- .../errors-after-init-opt-in-ui-state.json | 17 +++++------------ 2 files changed, 11 insertions(+), 25 deletions(-) diff --git a/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-background-state.json b/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-background-state.json index cae1a6ae8951..091e0ffea5c3 100644 --- a/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-background-state.json +++ b/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-background-state.json @@ -63,14 +63,10 @@ "bridgeState": { "bridgeFeatureFlags": { "extensionConfig": { - "maxRefreshCount": "number", "refreshRate": "number", + "maxRefreshCount": "number", "support": "boolean", - "chains": { - "0x1": "object", - "0xa4b1": "object", - "0xe708": "object" - } + "chains": { "0x1": "object", "0xa4b1": "object", "0xe708": "object" } } }, "srcTokens": {}, @@ -242,9 +238,7 @@ "isRedesignedConfirmationsDeveloperEnabled": "boolean", "tokenSortConfig": "object", "shouldShowAggregatedBalancePopover": "boolean", - "tokenNetworkFilter": { - "0x539": "boolean" - }, + "tokenNetworkFilter": { "0x539": "boolean" }, "redesignedConfirmationsEnabled": true, "redesignedTransactionsEnabled": "boolean" }, @@ -260,7 +254,8 @@ "enableMV3TimestampSave": true, "useExternalServices": "boolean", "isMultiAccountBalancesEnabled": "boolean", - "showIncomingTransactions": "object" + "showIncomingTransactions": "object", + "smartTransactionsOptInStatus": "boolean" }, "QueuedRequestController": { "queuedRequestCount": 0 }, "RemoteFeatureFlagController": { @@ -330,9 +325,7 @@ "TokenBalancesController": { "tokenBalances": "object" }, "TokenListController": { "tokenList": "object", - "tokensChainsCache": { - "0x539": "object" - }, + "tokensChainsCache": { "0x539": "object" }, "preventPollingOnNetworkRestart": false }, "TokenRatesController": { "marketData": "object" }, diff --git a/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-ui-state.json b/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-ui-state.json index a306c63c70b6..1ad6883c79c9 100644 --- a/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-ui-state.json +++ b/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-ui-state.json @@ -37,9 +37,7 @@ "isRedesignedConfirmationsDeveloperEnabled": "boolean", "tokenSortConfig": "object", "shouldShowAggregatedBalancePopover": "boolean", - "tokenNetworkFilter": { - "0x539": "boolean" - }, + "tokenNetworkFilter": { "0x539": "boolean" }, "redesignedConfirmationsEnabled": true, "redesignedTransactionsEnabled": "boolean" }, @@ -147,6 +145,7 @@ "useExternalServices": "boolean", "isMultiAccountBalancesEnabled": "boolean", "showIncomingTransactions": "object", + "smartTransactionsOptInStatus": "boolean", "metaMetricsId": "fake-metrics-id", "marketingCampaignCookieId": null, "eventsBeforeMetricsOptIn": "object", @@ -176,9 +175,7 @@ "gasEstimateType": "none", "nonRPCGasFeeApisDisabled": "boolean", "tokenList": "object", - "tokensChainsCache": { - "0x539": "object" - }, + "tokensChainsCache": { "0x539": "object" }, "preventPollingOnNetworkRestart": false, "tokens": "object", "ignoredTokens": "object", @@ -280,14 +277,10 @@ "bridgeState": { "bridgeFeatureFlags": { "extensionConfig": { - "maxRefreshCount": "number", "refreshRate": "number", + "maxRefreshCount": "number", "support": "boolean", - "chains": { - "0x1": "object", - "0xa4b1": "object", - "0xe708": "object" - } + "chains": { "0x1": "object", "0xa4b1": "object", "0xe708": "object" } } }, "srcTokens": {}, From e8c85fd1eaec06fe8ce0ccfd2d8746357ca31a01 Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Thu, 12 Dec 2024 12:23:54 -0500 Subject: [PATCH 46/90] added snapshots for Banner Alert --- .../snap-ui-address.test.tsx.snap | 4 +- .../connect-accounts-modal.test.tsx.snap | 8 +- .../confirm-send-ether.test.js.snap | 35 +++ .../__snapshots__/confirm.test.tsx.snap | 234 +++++++++++++++++- 4 files changed, 269 insertions(+), 12 deletions(-) diff --git a/ui/components/app/snaps/snap-ui-address/__snapshots__/snap-ui-address.test.tsx.snap b/ui/components/app/snaps/snap-ui-address/__snapshots__/snap-ui-address.test.tsx.snap index deb95bd48555..13caa0c5dc82 100644 --- a/ui/components/app/snaps/snap-ui-address/__snapshots__/snap-ui-address.test.tsx.snap +++ b/ui/components/app/snaps/snap-ui-address/__snapshots__/snap-ui-address.test.tsx.snap @@ -172,7 +172,7 @@ exports[`SnapUIAddress renders Ethereum address 1`] = ` +
+ +
+

+ You're now protected with MetaMask Smart Transactions + + learn more + +

+
+ +
diff --git a/ui/pages/confirmations/confirm/__snapshots__/confirm.test.tsx.snap b/ui/pages/confirmations/confirm/__snapshots__/confirm.test.tsx.snap index f8e816085738..ab337f122329 100644 --- a/ui/pages/confirmations/confirm/__snapshots__/confirm.test.tsx.snap +++ b/ui/pages/confirmations/confirm/__snapshots__/confirm.test.tsx.snap @@ -118,7 +118,44 @@ exports[`Confirm matches snapshot for signature - personal sign type 1`] = `
+ > +
+ +
+

+ You're now protected with MetaMask Smart Transactions + + learn more + +

+
+ +
+
+ > +
+ +
+

+ You're now protected with MetaMask Smart Transactions + + learn more + +

+
+ +
+
+ > +
+ +
+

+ You're now protected with MetaMask Smart Transactions + + learn more + +

+
+ +
+
+ > +
+ +
+

+ You're now protected with MetaMask Smart Transactions + + learn more + +

+
+ +
+
+ > +
+ +
+

+ You're now protected with MetaMask Smart Transactions + + learn more + +

+
+ +
+
+ > +
+ +
+

+ You're now protected with MetaMask Smart Transactions + + learn more + +

+
+ +
+
Date: Thu, 12 Dec 2024 11:02:10 -0700 Subject: [PATCH 47/90] chore: updates snapshots for the connect-account-modal test --- .../__snapshots__/connect-accounts-modal.test.tsx.snap | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ui/components/multichain/connect-accounts-modal/__snapshots__/connect-accounts-modal.test.tsx.snap b/ui/components/multichain/connect-accounts-modal/__snapshots__/connect-accounts-modal.test.tsx.snap index b4a4836db2d6..0f4049b0c4e6 100644 --- a/ui/components/multichain/connect-accounts-modal/__snapshots__/connect-accounts-modal.test.tsx.snap +++ b/ui/components/multichain/connect-accounts-modal/__snapshots__/connect-accounts-modal.test.tsx.snap @@ -159,7 +159,7 @@ exports[`Connect More Accounts Modal should render correctly 1`] = ` Date: Thu, 12 Dec 2024 11:31:20 -0700 Subject: [PATCH 48/90] Revert "chore: updates snapshots for the connect-account-modal test" This reverts commit b2658939a7f31bd1e78c8d310b087093434762c6. --- .../__snapshots__/connect-accounts-modal.test.tsx.snap | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ui/components/multichain/connect-accounts-modal/__snapshots__/connect-accounts-modal.test.tsx.snap b/ui/components/multichain/connect-accounts-modal/__snapshots__/connect-accounts-modal.test.tsx.snap index 0f4049b0c4e6..b4a4836db2d6 100644 --- a/ui/components/multichain/connect-accounts-modal/__snapshots__/connect-accounts-modal.test.tsx.snap +++ b/ui/components/multichain/connect-accounts-modal/__snapshots__/connect-accounts-modal.test.tsx.snap @@ -159,7 +159,7 @@ exports[`Connect More Accounts Modal should render correctly 1`] = ` Date: Thu, 12 Dec 2024 14:31:48 -0500 Subject: [PATCH 49/90] fix: revert to ^HEAD on problematic test. --- .../__snapshots__/snap-ui-address.test.tsx.snap | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/components/app/snaps/snap-ui-address/__snapshots__/snap-ui-address.test.tsx.snap b/ui/components/app/snaps/snap-ui-address/__snapshots__/snap-ui-address.test.tsx.snap index 13caa0c5dc82..deb95bd48555 100644 --- a/ui/components/app/snaps/snap-ui-address/__snapshots__/snap-ui-address.test.tsx.snap +++ b/ui/components/app/snaps/snap-ui-address/__snapshots__/snap-ui-address.test.tsx.snap @@ -172,7 +172,7 @@ exports[`SnapUIAddress renders Ethereum address 1`] = ` Date: Thu, 12 Dec 2024 15:08:51 -0500 Subject: [PATCH 50/90] disable STX for these tests: adding the baseFixtureOptions with smartTransactionsOptInStatus: false and using it in all tests --- .../tests/swaps/swaps-notifications.spec.ts | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/test/e2e/tests/swaps/swaps-notifications.spec.ts b/test/e2e/tests/swaps/swaps-notifications.spec.ts index 134741d3683c..a36b083773b8 100644 --- a/test/e2e/tests/swaps/swaps-notifications.spec.ts +++ b/test/e2e/tests/swaps/swaps-notifications.spec.ts @@ -19,6 +19,21 @@ async function mockSwapsTransactionQuote(mockServer: Mockttp) { ]; } +// Add default state with STX disabled for all tests +const baseFixtureOptions = { + ...withFixturesOptions, + fixtures: { + ...withFixturesOptions.fixtures, + metamask: { + ...withFixturesOptions.fixtures?.metamask, + preferences: { + ...withFixturesOptions.fixtures?.metamask?.preferences, + smartTransactionsOptInStatus: false, + }, + }, + }, +}; + describe('Swaps - notifications @no-mmi', function () { async function mockTradesApiPriceSlippageError(mockServer: Mockttp) { await mockServer @@ -70,7 +85,7 @@ describe('Swaps - notifications @no-mmi', function () { it('tests notifications for verified token on 1 source and price difference', async function () { await withFixtures( { - ...withFixturesOptions, + ...baseFixtureOptions, testSpecificMock: mockTradesApiPriceSlippageError, title: this.test?.fullTitle(), }, @@ -107,6 +122,7 @@ describe('Swaps - notifications @no-mmi', function () { }, ); }); + it('tests a notification for not enough balance', async function () { const lowBalanceGanacheOptions = { accounts: [ @@ -120,7 +136,7 @@ describe('Swaps - notifications @no-mmi', function () { await withFixtures( { - ...withFixturesOptions, + ...baseFixtureOptions, ganacheOptions: lowBalanceGanacheOptions, testSpecificMock: mockSwapsTransactionQuote, title: this.test?.fullTitle(), @@ -149,10 +165,11 @@ describe('Swaps - notifications @no-mmi', function () { }, ); }); + it('tests notifications for token import', async function () { await withFixtures( { - ...withFixturesOptions, + ...baseFixtureOptions, title: this.test?.fullTitle(), }, async ({ driver }) => { @@ -171,10 +188,11 @@ describe('Swaps - notifications @no-mmi', function () { }, ); }); + it('tests notifications for slippage', async function () { await withFixtures( { - ...withFixturesOptions, + ...baseFixtureOptions, title: this.test?.fullTitle(), }, async ({ driver }) => { From 577cdee8746f5324a1267b6aa8e6e9f0ed33120d Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Thu, 12 Dec 2024 15:29:11 -0500 Subject: [PATCH 51/90] match the structure where metamask should ibe nested under data in our fixtures object. --- test/e2e/tests/swaps/swaps-notifications.spec.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/e2e/tests/swaps/swaps-notifications.spec.ts b/test/e2e/tests/swaps/swaps-notifications.spec.ts index a36b083773b8..d30a75b34fd4 100644 --- a/test/e2e/tests/swaps/swaps-notifications.spec.ts +++ b/test/e2e/tests/swaps/swaps-notifications.spec.ts @@ -23,12 +23,12 @@ async function mockSwapsTransactionQuote(mockServer: Mockttp) { const baseFixtureOptions = { ...withFixturesOptions, fixtures: { - ...withFixturesOptions.fixtures, - metamask: { - ...withFixturesOptions.fixtures?.metamask, - preferences: { - ...withFixturesOptions.fixtures?.metamask?.preferences, - smartTransactionsOptInStatus: false, + data: { + ...withFixturesOptions.fixtures?.data, + metamask: { + preferences: { + smartTransactionsOptInStatus: false, + }, }, }, }, From f24f686b9b416c98bd1a2e28ce905c548f83919e Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Thu, 12 Dec 2024 16:09:39 -0500 Subject: [PATCH 52/90] revert changes to `swaps-notifications.spec.ts` as test results did not improve on CI. --- .../tests/swaps/swaps-notifications.spec.ts | 26 +++---------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/test/e2e/tests/swaps/swaps-notifications.spec.ts b/test/e2e/tests/swaps/swaps-notifications.spec.ts index d30a75b34fd4..134741d3683c 100644 --- a/test/e2e/tests/swaps/swaps-notifications.spec.ts +++ b/test/e2e/tests/swaps/swaps-notifications.spec.ts @@ -19,21 +19,6 @@ async function mockSwapsTransactionQuote(mockServer: Mockttp) { ]; } -// Add default state with STX disabled for all tests -const baseFixtureOptions = { - ...withFixturesOptions, - fixtures: { - data: { - ...withFixturesOptions.fixtures?.data, - metamask: { - preferences: { - smartTransactionsOptInStatus: false, - }, - }, - }, - }, -}; - describe('Swaps - notifications @no-mmi', function () { async function mockTradesApiPriceSlippageError(mockServer: Mockttp) { await mockServer @@ -85,7 +70,7 @@ describe('Swaps - notifications @no-mmi', function () { it('tests notifications for verified token on 1 source and price difference', async function () { await withFixtures( { - ...baseFixtureOptions, + ...withFixturesOptions, testSpecificMock: mockTradesApiPriceSlippageError, title: this.test?.fullTitle(), }, @@ -122,7 +107,6 @@ describe('Swaps - notifications @no-mmi', function () { }, ); }); - it('tests a notification for not enough balance', async function () { const lowBalanceGanacheOptions = { accounts: [ @@ -136,7 +120,7 @@ describe('Swaps - notifications @no-mmi', function () { await withFixtures( { - ...baseFixtureOptions, + ...withFixturesOptions, ganacheOptions: lowBalanceGanacheOptions, testSpecificMock: mockSwapsTransactionQuote, title: this.test?.fullTitle(), @@ -165,11 +149,10 @@ describe('Swaps - notifications @no-mmi', function () { }, ); }); - it('tests notifications for token import', async function () { await withFixtures( { - ...baseFixtureOptions, + ...withFixturesOptions, title: this.test?.fullTitle(), }, async ({ driver }) => { @@ -188,11 +171,10 @@ describe('Swaps - notifications @no-mmi', function () { }, ); }); - it('tests notifications for slippage', async function () { await withFixtures( { - ...baseFixtureOptions, + ...withFixturesOptions, title: this.test?.fullTitle(), }, async ({ driver }) => { From a53cb5ebdc4a7851a152ab9f903fa2500008b54a Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Thu, 12 Dec 2024 17:43:01 -0500 Subject: [PATCH 53/90] Add logic to determine confirmationType in Wrapper --- ui/pages/confirmations/confirm/confirm.tsx | 27 +++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/ui/pages/confirmations/confirm/confirm.tsx b/ui/pages/confirmations/confirm/confirm.tsx index 094c8040a5aa..671a95a98478 100644 --- a/ui/pages/confirmations/confirm/confirm.tsx +++ b/ui/pages/confirmations/confirm/confirm.tsx @@ -45,6 +45,29 @@ const GasFeeContextProviderWrapper: React.FC<{ ); }; +const WrappedSmartTransactionsAlertBanner: React.FC = () => { + const { currentConfirmation } = useConfirmContext(); + const shouldRenderSmartTransactionsBannerAlert = () => { + if (!currentConfirmation) { + return false; + } + const { type } = currentConfirmation; + const allowedTransactionTypes = [ + 'simpleSend', + 'tokenMethodTransfer', + 'swap', + ]; + return allowedTransactionTypes.includes(type as string); + }; + return ( + + {shouldRenderSmartTransactionsBannerAlert() && ( + + )} + + ); +}; + const Confirm = () => ( @@ -55,9 +78,7 @@ const Confirm = () => (
- - - + { ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) From 32ad2531594befd06216ff14ebdd04c67491ded7 Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Thu, 12 Dec 2024 18:26:24 -0500 Subject: [PATCH 54/90] chore: Move all logic for conditionally rendering the SmartTransactionBanner Alert into itself. --- .../smart-transactions-banner-alert.tsx | 20 +++++++++++++- ui/pages/confirmations/confirm/confirm.tsx | 27 +++---------------- 2 files changed, 22 insertions(+), 25 deletions(-) diff --git a/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx b/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx index d141e8d67886..c7f2c0f726d7 100644 --- a/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx +++ b/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx @@ -10,6 +10,7 @@ import { import { setAlertEnabledness } from '../../../../store/actions'; import { AlertTypes } from '../../../../../shared/constants/alerts'; import { SMART_TRANSACTIONS_LEARN_MORE_URL } from '../../../../../shared/constants/smartTransactions'; +import { useConfirmContext } from '../../context/confirm'; type MarginType = 'default' | 'none' | 'noTop' | 'onlyTop'; @@ -35,6 +36,15 @@ export const SmartTransactionsBannerAlert: React.FC state.metamask.alertEnabledness?.[ @@ -46,7 +56,15 @@ export const SmartTransactionsBannerAlert: React.FC { - const { currentConfirmation } = useConfirmContext(); - const shouldRenderSmartTransactionsBannerAlert = () => { - if (!currentConfirmation) { - return false; - } - const { type } = currentConfirmation; - const allowedTransactionTypes = [ - 'simpleSend', - 'tokenMethodTransfer', - 'swap', - ]; - return allowedTransactionTypes.includes(type as string); - }; - return ( - - {shouldRenderSmartTransactionsBannerAlert() && ( - - )} - - ); -}; - const Confirm = () => ( @@ -78,7 +55,9 @@ const Confirm = () => (
- + + + { ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) From 0971419a01db8ad2fcd8f4390998adbbadd5fa56 Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Thu, 12 Dec 2024 21:18:32 -0500 Subject: [PATCH 55/90] chore: update SmartTransactionsBannerAlert to maintain backward compatibility with the existing test. --- .../smart-transactions-banner-alert.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx b/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx index c7f2c0f726d7..f525d8c5e340 100644 --- a/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx +++ b/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx @@ -57,8 +57,9 @@ export const SmartTransactionsBannerAlert: React.FC Date: Thu, 12 Dec 2024 22:14:49 -0500 Subject: [PATCH 56/90] fix: update smart-transaction-banner-alert test so it verifies our new context-aware functionality and keeps existing behavior. testing edge case: banner doesn't show when it shouldn't. test margin types systematically, and verifying that the banner handles being outside of ConfirmContext appropriately fix: update smart-transaction-banner-alert modified the shouldRender logic to handle no context differently. --- .../smart-transactions-banner-alert.test.tsx | 113 +++++++++++++++++- .../smart-transactions-banner-alert.tsx | 15 +-- 2 files changed, 120 insertions(+), 8 deletions(-) diff --git a/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.test.tsx b/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.test.tsx index f9b641810e3f..b7844c0690e3 100644 --- a/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.test.tsx +++ b/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.test.tsx @@ -1,22 +1,51 @@ import React from 'react'; +import type { Store } from '@reduxjs/toolkit'; import { screen } from '@testing-library/react'; +import { TransactionType } from '@metamask/transaction-controller'; +import { ConfirmContext } from '../../context/confirm'; +import type { Confirmation, SignatureRequestType } from '../../types/confirm'; import { renderWithProvider } from '../../../../../test/jest/rendering'; import configureStore from '../../../../store/store'; import { AlertTypes } from '../../../../../shared/constants/alerts'; import { setAlertEnabledness } from '../../../../store/actions'; import { SmartTransactionsBannerAlert } from './smart-transactions-banner-alert'; +type TestConfirmContextValue = { + currentConfirmation: Confirmation; + isScrollToBottomCompleted: boolean; + setIsScrollToBottomCompleted: (isScrollToBottomCompleted: boolean) => void; +}; + jest.mock('../../../../hooks/useI18nContext', () => ({ useI18nContext: () => (key: string) => key, __esModule: true, default: () => (key: string) => key, })); -// Update the mock to return a plain action object jest.mock('../../../../store/actions', () => ({ setAlertEnabledness: jest.fn(() => ({ type: 'mock-action' })), })); +const renderWithConfirmContext = ( + component: React.ReactElement, + store: Store, + confirmationValue: TestConfirmContextValue = { + currentConfirmation: { + type: TransactionType.simpleSend, + id: '1', // Required by SignatureRequestType + } as SignatureRequestType, + isScrollToBottomCompleted: true, + setIsScrollToBottomCompleted: () => undefined, + }, +) => { + return renderWithProvider( + + {component} + , + store, + ); +}; + describe('SmartTransactionsBannerAlert', () => { const mockState = { metamask: { @@ -101,4 +130,86 @@ describe('SmartTransactionsBannerAlert', () => { false, ); }); + + it('renders banner when inside ConfirmContext with supported transaction type', () => { + const store = configureStore(mockState); + renderWithConfirmContext(, store); + + expect( + screen.getByTestId('smart-transactions-banner-alert'), + ).toBeInTheDocument(); + expect(screen.getByText('smartTransactionsEnabled')).toBeInTheDocument(); + }); + + it('does not render banner for unsupported transaction types', () => { + const store = configureStore(mockState); + const unsupportedConfirmation: TestConfirmContextValue = { + currentConfirmation: { + type: TransactionType.signTypedData, // Using an unsupported type + id: '2', + } as SignatureRequestType, + isScrollToBottomCompleted: true, + setIsScrollToBottomCompleted: () => undefined, + }; + + renderWithConfirmContext( + , + store, + unsupportedConfirmation, + ); + + expect( + screen.queryByTestId('smart-transactions-banner-alert'), + ).not.toBeInTheDocument(); + }); + + describe('margin style tests', () => { + const store = configureStore(mockState); + + it('applies no styles with default margin type', () => { + renderWithConfirmContext(, store); + const alert = screen.getByTestId('smart-transactions-banner-alert'); + expect(alert).not.toHaveStyle({ margin: 0 }); + expect(alert).not.toHaveStyle({ marginTop: 0 }); + }); + + it('applies zero margin when marginType is "none"', () => { + renderWithConfirmContext( + , + store, + ); + const alert = screen.getByTestId('smart-transactions-banner-alert'); + expect(alert).toHaveStyle({ margin: 0 }); + }); + + it('applies zero top margin when marginType is "noTop"', () => { + renderWithConfirmContext( + , + store, + ); + const alert = screen.getByTestId('smart-transactions-banner-alert'); + expect(alert).toHaveStyle({ marginTop: 0 }); + }); + + it('applies only top margin when marginType is "onlyTop"', () => { + renderWithConfirmContext( + , + store, + ); + const alert = screen.getByTestId('smart-transactions-banner-alert'); + expect(alert).toHaveStyle({ margin: '16px 0px 0px 0px' }); + }); + }); + + it('handles being outside of ConfirmContext correctly', () => { + const store = configureStore(mockState); + + // Render without wrapping in ConfirmContext + renderWithProvider(, store); + + // Should still render if alertEnabled and smartTransactionsOptIn are true + expect( + screen.getByTestId('smart-transactions-banner-alert'), + ).toBeInTheDocument(); + }); }); diff --git a/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx b/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx index f525d8c5e340..25471bf46c8a 100644 --- a/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx +++ b/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx @@ -56,14 +56,15 @@ export const SmartTransactionsBannerAlert: React.FC Date: Fri, 13 Dec 2024 00:02:02 -0500 Subject: [PATCH 57/90] fix: auto-dismiss STX migration banner when user disables STX Add automatic dismissal of Smart Transactions migration banner when user manually disables Smart Transactions from settings, preventing stale or incorrect banner state. --- .../smart-transactions-banner-alert.test.tsx | 25 +++++++++++++++ .../smart-transactions-banner-alert.tsx | 32 ++++++++++++++----- 2 files changed, 49 insertions(+), 8 deletions(-) diff --git a/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.test.tsx b/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.test.tsx index b7844c0690e3..5f82ae7f85bd 100644 --- a/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.test.tsx +++ b/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.test.tsx @@ -212,4 +212,29 @@ describe('SmartTransactionsBannerAlert', () => { screen.getByTestId('smart-transactions-banner-alert'), ).toBeInTheDocument(); }); + + it('automatically dismisses banner when Smart Transactions is manually disabled', () => { + const store = configureStore({ + metamask: { + alertEnabledness: { + [AlertTypes.smartTransactionsMigration]: true, + }, + preferences: { + smartTransactionsOptInStatus: false, + }, + }, + }); + + // Clear any previous calls to our mock + jest.clearAllMocks(); + + renderWithConfirmContext(, store); + + // Verify it was called exactly once and with the right arguments + expect(setAlertEnabledness).toHaveBeenCalledTimes(1); + expect(setAlertEnabledness).toHaveBeenCalledWith( + AlertTypes.smartTransactionsMigration, + false, + ); + }); }); diff --git a/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx b/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx index 25471bf46c8a..b551bf349585 100644 --- a/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx +++ b/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx @@ -11,6 +11,7 @@ import { setAlertEnabledness } from '../../../../store/actions'; import { AlertTypes } from '../../../../../shared/constants/alerts'; import { SMART_TRANSACTIONS_LEARN_MORE_URL } from '../../../../../shared/constants/smartTransactions'; import { useConfirmContext } from '../../context/confirm'; +import { useCallback } from 'react'; type MarginType = 'default' | 'none' | 'noTop' | 'onlyTop'; @@ -56,11 +57,30 @@ export const SmartTransactionsBannerAlert: React.FC { + if (alertEnabled && !smartTransactionsOptIn) { + dispatch( + setAlertEnabledness(AlertTypes.smartTransactionsMigration, false) + ); + } + }, [alertEnabled, smartTransactionsOptIn, dispatch]); + + const handleDismiss = useCallback(() => { + dispatch( + setAlertEnabledness(AlertTypes.smartTransactionsMigration, false) + ); + }, [dispatch]); + + // // Check for mismatch immediately, not in an effect + // if (alertEnabled && !smartTransactionsOptIn) { + // handleDismiss(); + // } + // modify the shouldRender logic to handle no context differently: const shouldRender = - currentConfirmation === null // When not in ConfirmContext - ? alertEnabled && smartTransactionsOptIn // Use original conditions only - : alertEnabled && // When in ConfirmContext + currentConfirmation === null + ? alertEnabled && smartTransactionsOptIn + : alertEnabled && smartTransactionsOptIn && ['simpleSend', 'tokenMethodTransfer', 'swap'].includes( currentConfirmation.type as string, @@ -70,11 +90,7 @@ export const SmartTransactionsBannerAlert: React.FC { - dispatch( - setAlertEnabledness(AlertTypes.smartTransactionsMigration, false), - ); - }; + const getMarginStyle = () => { switch (marginType) { From 82b40d77e6a1a70344175e49abc079d420f81154 Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Fri, 13 Dec 2024 00:33:44 -0500 Subject: [PATCH 58/90] fix: handle STX banner dismiss when toggling STX off Automatically dismisses Smart Transactions migration banner when user manually disables Smart Transactions to prevent stale UI state. --- .../smart-transactions-banner-alert.tsx | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx b/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx index b551bf349585..a17e5b8a442e 100644 --- a/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx +++ b/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx @@ -59,16 +59,27 @@ export const SmartTransactionsBannerAlert: React.FC { if (alertEnabled && !smartTransactionsOptIn) { - dispatch( - setAlertEnabledness(AlertTypes.smartTransactionsMigration, false) - ); + dispatch({ + type: 'alert/dismiss', + payload: { + alertId: AlertTypes.smartTransactionsMigration, + enabled: false, + }, + }); + setAlertEnabledness(AlertTypes.smartTransactionsMigration, false); } }, [alertEnabled, smartTransactionsOptIn, dispatch]); + const handleDismiss = useCallback(() => { - dispatch( - setAlertEnabledness(AlertTypes.smartTransactionsMigration, false) - ); + dispatch({ + type: 'alert/dismiss', + payload: { + alertId: AlertTypes.smartTransactionsMigration, + enabled: false, + }, + }); + setAlertEnabledness(AlertTypes.smartTransactionsMigration, false); }, [dispatch]); // // Check for mismatch immediately, not in an effect @@ -82,7 +93,7 @@ export const SmartTransactionsBannerAlert: React.FC Date: Fri, 13 Dec 2024 13:00:03 -0500 Subject: [PATCH 59/90] fix: linting / TS errors --- .../smart-transactions-banner-alert.tsx | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx b/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx index a17e5b8a442e..24728098f4b6 100644 --- a/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx +++ b/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import React, { useCallback } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { useI18nContext } from '../../../../hooks/useI18nContext'; import { @@ -11,7 +11,6 @@ import { setAlertEnabledness } from '../../../../store/actions'; import { AlertTypes } from '../../../../../shared/constants/alerts'; import { SMART_TRANSACTIONS_LEARN_MORE_URL } from '../../../../../shared/constants/smartTransactions'; import { useConfirmContext } from '../../context/confirm'; -import { useCallback } from 'react'; type MarginType = 'default' | 'none' | 'noTop' | 'onlyTop'; @@ -37,13 +36,12 @@ export const SmartTransactionsBannerAlert: React.FC { dispatch({ type: 'alert/dismiss', @@ -82,27 +79,22 @@ export const SmartTransactionsBannerAlert: React.FC { switch (marginType) { case 'none': From 688f049002e56935c0957c81a300ff2a54adb400 Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Fri, 13 Dec 2024 15:43:58 -0500 Subject: [PATCH 60/90] fix: update snapshots for `snap-ui-address`, `connect-accounts-modal`, and `confirm` update `smart-transactions-banner-alert` (remove `as string`) to ensure confirm test passes update `confirm-transaction-base.test` to mock background connection for `setAlertEnabledness` --- .../snap-ui-address.test.tsx.snap | 4 +- .../connect-accounts-modal.test.tsx.snap | 8 +- .../smart-transactions-banner-alert.tsx | 3 +- .../confirm-transaction-base.test.js | 1 + .../__snapshots__/confirm.test.tsx.snap | 234 +----------------- 5 files changed, 15 insertions(+), 235 deletions(-) diff --git a/ui/components/app/snaps/snap-ui-address/__snapshots__/snap-ui-address.test.tsx.snap b/ui/components/app/snaps/snap-ui-address/__snapshots__/snap-ui-address.test.tsx.snap index deb95bd48555..13caa0c5dc82 100644 --- a/ui/components/app/snaps/snap-ui-address/__snapshots__/snap-ui-address.test.tsx.snap +++ b/ui/components/app/snaps/snap-ui-address/__snapshots__/snap-ui-address.test.tsx.snap @@ -172,7 +172,7 @@ exports[`SnapUIAddress renders Ethereum address 1`] = `
-
- -
-

- You're now protected with MetaMask Smart Transactions - - learn more - -

-
- -
-
+ />
-
- -
-

- You're now protected with MetaMask Smart Transactions - - learn more - -

-
- -
-
+ />
-
- -
-

- You're now protected with MetaMask Smart Transactions - - learn more - -

-
- -
-
+ />
-
- -
-

- You're now protected with MetaMask Smart Transactions - - learn more - -

-
- -
-
+ />
-
- -
-

- You're now protected with MetaMask Smart Transactions - - learn more - -

-
- -
-
+ />
-
- -
-

- You're now protected with MetaMask Smart Transactions - - learn more - -

-
- -
-
+ />
Date: Fri, 13 Dec 2024 17:15:33 -0500 Subject: [PATCH 61/90] fix: add `as string` back to satisfy linting --- .../smart-transactions-banner-alert.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx b/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx index 47241fdd86a6..f922a756fd56 100644 --- a/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx +++ b/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx @@ -90,7 +90,7 @@ export const SmartTransactionsBannerAlert: React.FC Date: Mon, 16 Dec 2024 11:55:46 -0500 Subject: [PATCH 62/90] fix: update snapshot for connect-account-modal to have the same translate value for CI --- .../__snapshots__/connect-accounts-modal.test.tsx.snap | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ui/components/multichain/connect-accounts-modal/__snapshots__/connect-accounts-modal.test.tsx.snap b/ui/components/multichain/connect-accounts-modal/__snapshots__/connect-accounts-modal.test.tsx.snap index 0f4049b0c4e6..b4a4836db2d6 100644 --- a/ui/components/multichain/connect-accounts-modal/__snapshots__/connect-accounts-modal.test.tsx.snap +++ b/ui/components/multichain/connect-accounts-modal/__snapshots__/connect-accounts-modal.test.tsx.snap @@ -159,7 +159,7 @@ exports[`Connect More Accounts Modal should render correctly 1`] = ` Date: Mon, 16 Dec 2024 12:10:03 -0500 Subject: [PATCH 63/90] fix: update snapshot to match CI transform for `snap-ui-address` --- .../__snapshots__/snap-ui-address.test.tsx.snap | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/components/app/snaps/snap-ui-address/__snapshots__/snap-ui-address.test.tsx.snap b/ui/components/app/snaps/snap-ui-address/__snapshots__/snap-ui-address.test.tsx.snap index 13caa0c5dc82..deb95bd48555 100644 --- a/ui/components/app/snaps/snap-ui-address/__snapshots__/snap-ui-address.test.tsx.snap +++ b/ui/components/app/snaps/snap-ui-address/__snapshots__/snap-ui-address.test.tsx.snap @@ -172,7 +172,7 @@ exports[`SnapUIAddress renders Ethereum address 1`] = ` Date: Mon, 16 Dec 2024 16:28:40 -0500 Subject: [PATCH 64/90] fix: update STX Banner Alert text to match new design mockups, ensure that text and links are as mockup shows, update test for STX Banner Alert component. --- app/_locales/en/messages.json | 10 ++++++-- .../smart-transactions-banner-alert.test.tsx | 25 +++++++++++++++---- .../smart-transactions-banner-alert.tsx | 11 +++++--- 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 4a5c3620494d..e74f6763e97b 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -5278,8 +5278,14 @@ "smartTransactions": { "message": "Smart Transactions" }, - "smartTransactionsEnabled": { - "message": "You're now protected with MetaMask Smart Transactions" + "smartTransactionsEnabledDescription": { + "message": " and MEV protection. Now on by default." + }, + "smartTransactionsEnabledLink": { + "message": "Higher success rates" + }, + "smartTransactionsEnabledTitle": { + "message": "Transactions just got smarter" }, "snapAccountCreated": { "message": "Account created" diff --git a/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.test.tsx b/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.test.tsx index 5f82ae7f85bd..9b2b8339df0f 100644 --- a/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.test.tsx +++ b/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.test.tsx @@ -65,8 +65,15 @@ describe('SmartTransactionsBannerAlert', () => { expect( screen.getByTestId('smart-transactions-banner-alert'), ).toBeInTheDocument(); - expect(screen.getByText('smartTransactionsEnabled')).toBeInTheDocument(); - expect(screen.getByText('learnMore')).toBeInTheDocument(); + expect( + screen.getByText('smartTransactionsEnabledTitle'), + ).toBeInTheDocument(); + expect( + screen.getByText('smartTransactionsEnabledDescription'), + ).toBeInTheDocument(); + expect( + screen.getByText('smartTransactionsEnabledLink'), + ).toBeInTheDocument(); }); it('does not render when alert is disabled', () => { @@ -119,11 +126,11 @@ describe('SmartTransactionsBannerAlert', () => { ); }); - it('calls setAlertEnabledness when learn more link clicked', () => { + it('calls setAlertEnabledness when (Higher success rates) link clicked', () => { const store = configureStore(mockState); renderWithProvider(, store); - screen.getByText('learnMore').click(); + screen.getByText('smartTransactionsEnabledLink').click(); expect(setAlertEnabledness).toHaveBeenCalledWith( AlertTypes.smartTransactionsMigration, @@ -138,7 +145,15 @@ describe('SmartTransactionsBannerAlert', () => { expect( screen.getByTestId('smart-transactions-banner-alert'), ).toBeInTheDocument(); - expect(screen.getByText('smartTransactionsEnabled')).toBeInTheDocument(); + expect( + screen.getByText('smartTransactionsEnabledTitle'), + ).toBeInTheDocument(); + expect( + screen.getByText('smartTransactionsEnabledDescription'), + ).toBeInTheDocument(); + expect( + screen.getByText('smartTransactionsEnabledLink'), + ).toBeInTheDocument(); }); it('does not render banner for unsupported transaction types', () => { diff --git a/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx b/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx index f922a756fd56..96a60041361f 100644 --- a/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx +++ b/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx @@ -10,6 +10,7 @@ import { import { setAlertEnabledness } from '../../../../store/actions'; import { AlertTypes } from '../../../../../shared/constants/alerts'; import { SMART_TRANSACTIONS_LEARN_MORE_URL } from '../../../../../shared/constants/smartTransactions'; +import { FontWeight } from '../../../../helpers/constants/design-system'; import { useConfirmContext } from '../../context/confirm'; type MarginType = 'default' | 'none' | 'noTop' | 'onlyTop'; @@ -88,7 +89,7 @@ export const SmartTransactionsBannerAlert: React.FC + + {t('smartTransactionsEnabledTitle')} + - {t('smartTransactionsEnabled')} - {t('learnMore')} + {t('smartTransactionsEnabledLink')} + {t('smartTransactionsEnabledDescription')} ); From 6e1f73eb736444f94c4a37a9ccff546c24578465 Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Tue, 17 Dec 2024 10:25:23 -0500 Subject: [PATCH 65/90] fix: improve STX banner display logic for new installs Add handling of Smart Transactions banner for fresh installs vs migrated users: - Add smartTransactionsMigrationApplied flag to preferences - Update migration 135 to set migration flag - Update SmartTransactionsBannerAlert to check migration status - Update tests to handle migration flag The banner will now show ONLY for users who have been migrated to STX, not for fresh installs. --- .../controllers/preferences-controller.ts | 7 +++ app/scripts/migrations/135.test.ts | 48 +++++++++++++++++-- app/scripts/migrations/135.ts | 2 + .../smart-transactions-banner-alert.test.tsx | 34 ++++++++++--- .../smart-transactions-banner-alert.tsx | 12 ++++- .../transaction-alerts.test.js | 29 ++++++++++- 6 files changed, 117 insertions(+), 15 deletions(-) diff --git a/app/scripts/controllers/preferences-controller.ts b/app/scripts/controllers/preferences-controller.ts index 34ac3f3fc3c8..217fe43b022d 100644 --- a/app/scripts/controllers/preferences-controller.ts +++ b/app/scripts/controllers/preferences-controller.ts @@ -104,6 +104,7 @@ export type Preferences = { showFiatInTestnets: boolean; showTestNetworks: boolean; smartTransactionsOptInStatus: boolean; + smartTransactionsMigrationApplied: boolean; showNativeTokenAsMainBalance: boolean; useNativeCurrencyAsPrimaryCurrency: boolean; hideZeroBalanceTokens: boolean; @@ -129,6 +130,7 @@ export type PreferencesControllerState = Omit< PreferencesState, | 'showTestNetworks' | 'smartTransactionsOptInStatus' + | 'smartTransactionsMigrationApplied' | 'privacyMode' | 'tokenSortConfig' | 'useMultiRpcMigration' @@ -217,6 +219,7 @@ export const getDefaultPreferencesControllerState = showFiatInTestnets: false, showTestNetworks: false, smartTransactionsOptInStatus: true, + smartTransactionsMigrationApplied: false, showNativeTokenAsMainBalance: false, useNativeCurrencyAsPrimaryCurrency: true, hideZeroBalanceTokens: false, @@ -411,6 +414,10 @@ const controllerMetadata = { persist: true, anonymous: true, }, + smartTransactionsMigrationApplied: { + persist: true, + anonymous: true, + }, }, }, ipfsGateway: { diff --git a/app/scripts/migrations/135.test.ts b/app/scripts/migrations/135.test.ts index 48a4d3cf1458..e846a5ef2d72 100644 --- a/app/scripts/migrations/135.test.ts +++ b/app/scripts/migrations/135.test.ts @@ -18,7 +18,7 @@ describe('migration #135', () => { expect(newStorage.meta).toStrictEqual({ version: 135 }); }); - it('should set stx opt-in to true when stx opt-in status is null', async () => { + it('should set stx opt-in to true and migration flag when stx opt-in status is null', async () => { const oldStorage: VersionedData = { meta: { version: prevVersion }, data: { @@ -32,9 +32,13 @@ describe('migration #135', () => { expect( newStorage.data.PreferencesController?.smartTransactionsOptInStatus, ).toBe(true); + expect( + newStorage.data.PreferencesController?.preferences + ?.smartTransactionsMigrationApplied, + ).toBe(true); }); - it('should set stx opt-in to true when stx opt-in status is undefined', async () => { + it('should set stx opt-in to true and migration flag when stx opt-in status is undefined', async () => { const oldStorage: VersionedData = { meta: { version: prevVersion }, data: { @@ -46,9 +50,13 @@ describe('migration #135', () => { expect( newStorage.data.PreferencesController?.smartTransactionsOptInStatus, ).toBe(true); + expect( + newStorage.data.PreferencesController?.preferences + ?.smartTransactionsMigrationApplied, + ).toBe(true); }); - it('should set stx opt-in to true when stx opt-in is false and no existing mainnet smart transactions', async () => { + it('should set stx opt-in to true and migration flag when stx opt-in is false and no existing mainnet smart transactions', async () => { const oldStorage: VersionedData = { meta: { version: prevVersion }, data: { @@ -70,9 +78,13 @@ describe('migration #135', () => { expect( newStorage.data.PreferencesController?.smartTransactionsOptInStatus, ).toBe(true); + expect( + newStorage.data.PreferencesController?.preferences + ?.smartTransactionsMigrationApplied, + ).toBe(true); }); - it('should not change stx opt-in when stx opt-in is false but has existing smart transactions', async () => { + it('should not change stx opt-in when stx opt-in is false but has existing smart transactions, but should set migration flag', async () => { const oldStorage: VersionedData = { meta: { version: prevVersion }, data: { @@ -93,9 +105,13 @@ describe('migration #135', () => { expect( newStorage.data.PreferencesController?.smartTransactionsOptInStatus, ).toBe(false); + expect( + newStorage.data.PreferencesController?.preferences + ?.smartTransactionsMigrationApplied, + ).toBe(true); }); - it('should not change stx opt-in when stx opt-in is already true', async () => { + it('should not change stx opt-in when stx opt-in is already true, but should set migration flag', async () => { const oldStorage: VersionedData = { meta: { version: prevVersion }, data: { @@ -109,6 +125,28 @@ describe('migration #135', () => { expect( newStorage.data.PreferencesController?.smartTransactionsOptInStatus, ).toBe(true); + expect( + newStorage.data.PreferencesController?.preferences + ?.smartTransactionsMigrationApplied, + ).toBe(true); + }); + + it('should initialize preferences object if it does not exist', async () => { + const oldStorage: VersionedData = { + meta: { version: prevVersion }, + data: { + PreferencesController: { + smartTransactionsOptInStatus: true, + }, + }, + }; + + const newStorage = await migrate(oldStorage); + expect(newStorage.data.PreferencesController?.preferences).toBeDefined(); + expect( + newStorage.data.PreferencesController?.preferences + ?.smartTransactionsMigrationApplied, + ).toBe(true); }); it('should capture exception if PreferencesController state is invalid', async () => { diff --git a/app/scripts/migrations/135.ts b/app/scripts/migrations/135.ts index 17a8bed0ee3b..d61744b26546 100644 --- a/app/scripts/migrations/135.ts +++ b/app/scripts/migrations/135.ts @@ -11,6 +11,7 @@ export type VersionedData = { PreferencesController?: { preferences?: { smartTransactionsOptInStatus?: boolean | null; + smartTransactionsMigrationApplied?: boolean; }; smartTransactionsOptInStatus?: boolean | null; }; @@ -54,6 +55,7 @@ function transformState(state: VersionedData['data']) { const { preferences } = state.PreferencesController; preferences.smartTransactionsOptInStatus = true; + preferences.smartTransactionsMigrationApplied = true; return state; } diff --git a/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.test.tsx b/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.test.tsx index 9b2b8339df0f..ab6f402c95f2 100644 --- a/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.test.tsx +++ b/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.test.tsx @@ -32,7 +32,7 @@ const renderWithConfirmContext = ( confirmationValue: TestConfirmContextValue = { currentConfirmation: { type: TransactionType.simpleSend, - id: '1', // Required by SignatureRequestType + id: '1', } as SignatureRequestType, isScrollToBottomCompleted: true, setIsScrollToBottomCompleted: () => undefined, @@ -54,11 +54,12 @@ describe('SmartTransactionsBannerAlert', () => { }, preferences: { smartTransactionsOptInStatus: true, + smartTransactionsMigrationApplied: true, }, }, }; - it('renders banner when alert is enabled and STX is opted in', () => { + it('renders banner when alert is enabled, STX is opted in, and migration is applied', () => { const store = configureStore(mockState); renderWithProvider(, store); @@ -84,6 +85,7 @@ describe('SmartTransactionsBannerAlert', () => { }, preferences: { smartTransactionsOptInStatus: true, + smartTransactionsMigrationApplied: true, }, }, }; @@ -103,6 +105,7 @@ describe('SmartTransactionsBannerAlert', () => { }, preferences: { smartTransactionsOptInStatus: false, + smartTransactionsMigrationApplied: true, }, }, }; @@ -114,6 +117,26 @@ describe('SmartTransactionsBannerAlert', () => { ).not.toBeInTheDocument(); }); + it('does not render when migration has not been applied', () => { + const noMigrationState = { + metamask: { + alertEnabledness: { + [AlertTypes.smartTransactionsMigration]: true, + }, + preferences: { + smartTransactionsOptInStatus: true, + smartTransactionsMigrationApplied: false, + }, + }, + }; + const store = configureStore(noMigrationState); + renderWithProvider(, store); + + expect( + screen.queryByTestId('smart-transactions-banner-alert'), + ).not.toBeInTheDocument(); + }); + it('calls setAlertEnabledness when close button clicked', () => { const store = configureStore(mockState); renderWithProvider(, store); @@ -160,7 +183,7 @@ describe('SmartTransactionsBannerAlert', () => { const store = configureStore(mockState); const unsupportedConfirmation: TestConfirmContextValue = { currentConfirmation: { - type: TransactionType.signTypedData, // Using an unsupported type + type: TransactionType.signTypedData, id: '2', } as SignatureRequestType, isScrollToBottomCompleted: true, @@ -219,10 +242,8 @@ describe('SmartTransactionsBannerAlert', () => { it('handles being outside of ConfirmContext correctly', () => { const store = configureStore(mockState); - // Render without wrapping in ConfirmContext renderWithProvider(, store); - // Should still render if alertEnabled and smartTransactionsOptIn are true expect( screen.getByTestId('smart-transactions-banner-alert'), ).toBeInTheDocument(); @@ -236,16 +257,15 @@ describe('SmartTransactionsBannerAlert', () => { }, preferences: { smartTransactionsOptInStatus: false, + smartTransactionsMigrationApplied: true, }, }, }); - // Clear any previous calls to our mock jest.clearAllMocks(); renderWithConfirmContext(, store); - // Verify it was called exactly once and with the right arguments expect(setAlertEnabledness).toHaveBeenCalledTimes(1); expect(setAlertEnabledness).toHaveBeenCalledWith( AlertTypes.smartTransactionsMigration, diff --git a/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx b/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx index 96a60041361f..0445b0dc44b0 100644 --- a/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx +++ b/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx @@ -25,6 +25,7 @@ type MetaMaskState = { }; preferences: { smartTransactionsOptInStatus: boolean; + smartTransactionsMigrationApplied: boolean; }; }; @@ -51,11 +52,17 @@ export const SmartTransactionsBannerAlert: React.FC state.metamask.preferences?.smartTransactionsOptInStatus === true, ); + const smartTransactionsMigrationApplied = useSelector( + (state: RootState) => + state.metamask.preferences?.smartTransactionsMigrationApplied === true, + ); + React.useEffect(() => { if (alertEnabled && !smartTransactionsOptIn) { dispatch({ @@ -82,9 +89,12 @@ export const SmartTransactionsBannerAlert: React.FC, store); } @@ -565,7 +570,7 @@ describe('TransactionAlerts', () => { }); describe('Smart Transactions Migration Alert', () => { - it('shows when alert is enabled and opted in', () => { + it('shows when alert is enabled, opted in, and migration applied', () => { const { getByTestId } = render({ componentProps: { txData: { @@ -573,6 +578,25 @@ describe('Smart Transactions Migration Alert', () => { txParams: { value: '0x1' }, }, }, + state: { + ...STATE_MOCK, // Keep existing mock state + metamask: { + ...STATE_MOCK.metamask, + networkConfigurationsByChainId: { + [CHAIN_ID_MOCK]: { + chainId: CHAIN_ID_MOCK, + // other required network properties + }, + }, + alertEnabledness: { + [AlertTypes.smartTransactionsMigration]: true, + }, + preferences: { + smartTransactionsOptInStatus: true, + smartTransactionsMigrationApplied: true, + }, + }, + }, }); expect(getByTestId('smart-transactions-banner-alert')).toBeInTheDocument(); }); @@ -587,6 +611,7 @@ describe('Smart Transactions Migration Alert', () => { }, preferences: { smartTransactionsOptInStatus: true, + smartTransactionsMigrationApplied: true, }, }, }; From 46f9ef51dee994a27a20f8ddd8c95af9fd812faf Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Tue, 17 Dec 2024 10:55:13 -0500 Subject: [PATCH 66/90] fix: update preferences-controller test because we added smartTransactionsMigrationApplied but didn't update the test expectations --- app/scripts/controllers/preferences-controller.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/scripts/controllers/preferences-controller.test.ts b/app/scripts/controllers/preferences-controller.test.ts index 39a2d49648b2..75f0fd27e742 100644 --- a/app/scripts/controllers/preferences-controller.test.ts +++ b/app/scripts/controllers/preferences-controller.test.ts @@ -733,6 +733,7 @@ describe('preferences controller', () => { privacyMode: false, showFiatInTestnets: false, showTestNetworks: false, + smartTransactionsMigrationApplied: false, // Add this line smartTransactionsOptInStatus: true, useNativeCurrencyAsPrimaryCurrency: true, hideZeroBalanceTokens: false, @@ -762,6 +763,7 @@ describe('preferences controller', () => { showExtensionInFullSizeView: false, showFiatInTestnets: false, showTestNetworks: false, + smartTransactionsMigrationApplied: false, // Add this line smartTransactionsOptInStatus: true, useNativeCurrencyAsPrimaryCurrency: true, hideZeroBalanceTokens: false, From 8c875b0e1c8cd5077fe487e5924417104e1afcca Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Tue, 17 Dec 2024 11:22:09 -0500 Subject: [PATCH 67/90] fix: update snapshot for `confirm-send-ether.test.js` --- .../confirm-send-ether.test.js.snap | 35 ------------------- 1 file changed, 35 deletions(-) diff --git a/ui/pages/confirmations/confirm-send-ether/__snapshots__/confirm-send-ether.test.js.snap b/ui/pages/confirmations/confirm-send-ether/__snapshots__/confirm-send-ether.test.js.snap index 1646d08ba398..3058b6fac001 100644 --- a/ui/pages/confirmations/confirm-send-ether/__snapshots__/confirm-send-ether.test.js.snap +++ b/ui/pages/confirmations/confirm-send-ether/__snapshots__/confirm-send-ether.test.js.snap @@ -320,41 +320,6 @@ exports[`ConfirmSendEther should render correct information for for confirm send
-
- -
-

- You're now protected with MetaMask Smart Transactions - - learn more - -

-
- -
From 0ed49c5b308b72fc6fc95807ef13021d36841352 Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Tue, 17 Dec 2024 14:17:29 -0500 Subject: [PATCH 68/90] fix: add test for prepare-swap-page.test.js --- .../prepare-swap-page/prepare-swap-page.js | 1 - .../prepare-swap-page.test.js | 56 +++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/ui/pages/swaps/prepare-swap-page/prepare-swap-page.js b/ui/pages/swaps/prepare-swap-page/prepare-swap-page.js index 4843c652ead5..6857bb10d79b 100644 --- a/ui/pages/swaps/prepare-swap-page/prepare-swap-page.js +++ b/ui/pages/swaps/prepare-swap-page/prepare-swap-page.js @@ -132,7 +132,6 @@ import { Text, TextField, TextFieldSize, - Box, } from '../../../components/component-library'; import { ModalContent } from '../../../components/component-library/modal-content/deprecated'; import { ModalHeader } from '../../../components/component-library/modal-header/deprecated'; diff --git a/ui/pages/swaps/prepare-swap-page/prepare-swap-page.test.js b/ui/pages/swaps/prepare-swap-page/prepare-swap-page.test.js index adb5b56ddd93..176d7d099fe2 100644 --- a/ui/pages/swaps/prepare-swap-page/prepare-swap-page.test.js +++ b/ui/pages/swaps/prepare-swap-page/prepare-swap-page.test.js @@ -268,4 +268,60 @@ describe('PrepareSwapPage', () => { expect(bridgeButton).toBeNull(); }); + + describe('Smart Transactions Migration Banner', () => { + it('shows banner when alert is enabled, opted in, and migration applied', () => { + const mockStore = createSwapsMockStore(); + const store = configureMockStore(middleware)({ + ...mockStore, + metamask: { + ...mockStore.metamask, + alertEnabledness: { + smartTransactionsMigration: true, + }, + preferences: { + smartTransactionsOptInStatus: true, + smartTransactionsMigrationApplied: true, + }, + }, + }); + + const props = createProps(); + const { getByTestId } = renderWithProvider( + , + store, + ); + + expect( + getByTestId('smart-transactions-banner-alert'), + ).toBeInTheDocument(); + }); + + it('does not show banner when alert is disabled', () => { + const mockStore = createSwapsMockStore(); + const store = configureMockStore(middleware)({ + ...mockStore, + metamask: { + ...mockStore.metamask, + alertEnabledness: { + smartTransactionsMigration: false, + }, + preferences: { + smartTransactionsOptInStatus: true, + smartTransactionsMigrationApplied: true, + }, + }, + }); + + const props = createProps(); + const { queryByTestId } = renderWithProvider( + , + store, + ); + + expect( + queryByTestId('smart-transactions-banner-alert'), + ).not.toBeInTheDocument(); + }); + }); }); From e743a15802084da52e5aafb2821a89cbe55ef59d Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Tue, 17 Dec 2024 15:22:15 -0500 Subject: [PATCH 69/90] fix: updated snapshots from failing tests. --- .../__snapshots__/snap-ui-address.test.tsx.snap | 4 ++-- .../__snapshots__/connect-accounts-modal.test.tsx.snap | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ui/components/app/snaps/snap-ui-address/__snapshots__/snap-ui-address.test.tsx.snap b/ui/components/app/snaps/snap-ui-address/__snapshots__/snap-ui-address.test.tsx.snap index deb95bd48555..13caa0c5dc82 100644 --- a/ui/components/app/snaps/snap-ui-address/__snapshots__/snap-ui-address.test.tsx.snap +++ b/ui/components/app/snaps/snap-ui-address/__snapshots__/snap-ui-address.test.tsx.snap @@ -172,7 +172,7 @@ exports[`SnapUIAddress renders Ethereum address 1`] = ` Date: Tue, 17 Dec 2024 16:39:17 -0500 Subject: [PATCH 70/90] fix: snapshot update for connect-accounts-modal --- .../__snapshots__/connect-accounts-modal.test.tsx.snap | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ui/components/multichain/connect-accounts-modal/__snapshots__/connect-accounts-modal.test.tsx.snap b/ui/components/multichain/connect-accounts-modal/__snapshots__/connect-accounts-modal.test.tsx.snap index 0f4049b0c4e6..b4a4836db2d6 100644 --- a/ui/components/multichain/connect-accounts-modal/__snapshots__/connect-accounts-modal.test.tsx.snap +++ b/ui/components/multichain/connect-accounts-modal/__snapshots__/connect-accounts-modal.test.tsx.snap @@ -159,7 +159,7 @@ exports[`Connect More Accounts Modal should render correctly 1`] = ` Date: Tue, 17 Dec 2024 16:54:10 -0500 Subject: [PATCH 71/90] fix: update snapshot for `snap-ui-address.test.tsx` --- .../__snapshots__/snap-ui-address.test.tsx.snap | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/components/app/snaps/snap-ui-address/__snapshots__/snap-ui-address.test.tsx.snap b/ui/components/app/snaps/snap-ui-address/__snapshots__/snap-ui-address.test.tsx.snap index 13caa0c5dc82..deb95bd48555 100644 --- a/ui/components/app/snaps/snap-ui-address/__snapshots__/snap-ui-address.test.tsx.snap +++ b/ui/components/app/snaps/snap-ui-address/__snapshots__/snap-ui-address.test.tsx.snap @@ -172,7 +172,7 @@ exports[`SnapUIAddress renders Ethereum address 1`] = ` Date: Wed, 18 Dec 2024 04:07:46 -0500 Subject: [PATCH 72/90] fix: add `smartTransactionsMigrationApplied` to `expectedMissingState` --- test/e2e/tests/metrics/errors.spec.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/e2e/tests/metrics/errors.spec.js b/test/e2e/tests/metrics/errors.spec.js index 12a44e26fbf1..c4c92f0e9803 100644 --- a/test/e2e/tests/metrics/errors.spec.js +++ b/test/e2e/tests/metrics/errors.spec.js @@ -890,6 +890,7 @@ describe('Sentry errors', function () { autoLockTimeLimit: true, // Initialized as undefined showConfirmationAdvancedDetails: true, privacyMode: false, + smartTransactionsMigrationApplied: true, }, smartTransactionsState: { fees: { From 258b0a0e5293673b1660d347986b8f888ce28375 Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Wed, 18 Dec 2024 05:25:48 -0500 Subject: [PATCH 73/90] fix: try adding withPreferencesController with smartTransactionsMigrationApplied added in error.spec.js --- test/e2e/tests/metrics/errors.spec.js | 63 ++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 11 deletions(-) diff --git a/test/e2e/tests/metrics/errors.spec.js b/test/e2e/tests/metrics/errors.spec.js index c4c92f0e9803..d78a089ef5c9 100644 --- a/test/e2e/tests/metrics/errors.spec.js +++ b/test/e2e/tests/metrics/errors.spec.js @@ -241,6 +241,9 @@ describe('Sentry errors', function () { metaMetricsId: null, participateInMetaMetrics: false, }) + .withPreferencesController({ + preferences: { smartTransactionsMigrationApplied: false }, + }) .build(), // Intentionally corrupt state to trigger migration error during initialization meta: undefined, @@ -275,7 +278,10 @@ describe('Sentry errors', function () { metaMetricsId: null, participateInMetaMetrics: false, }) - .build(), + .withPreferencesController({ + preferences: { smartTransactionsMigrationApplied: false }, + }) + .build(), ganacheOptions, title: this.test.fullTitle(), testSpecificMock: mockSentryTestError, @@ -313,6 +319,9 @@ describe('Sentry errors', function () { metaMetricsId: 'fake-metrics-id', participateInMetaMetrics: true, }) + .withPreferencesController({ + preferences: { smartTransactionsMigrationApplied: false }, + }) .build(), // Intentionally corrupt state to trigger migration error during initialization meta: undefined, @@ -359,6 +368,9 @@ describe('Sentry errors', function () { metaMetricsId: 'fake-metrics-id', participateInMetaMetrics: true, }) + .withPreferencesController({ + preferences: { smartTransactionsMigrationApplied: false }, + }) .build(), // Intentionally corrupt state to trigger migration error during initialization meta: undefined, @@ -422,6 +434,9 @@ describe('Sentry errors', function () { participateInMetaMetrics: true, }) .withBadPreferencesControllerState() + .withPreferencesController({ + preferences: { smartTransactionsMigrationApplied: false }, + }) .build(), }, ganacheOptions, @@ -471,7 +486,10 @@ describe('Sentry errors', function () { metaMetricsId: 'fake-metrics-id', participateInMetaMetrics: true, }) - .build(), + .withPreferencesController({ + preferences: { smartTransactionsMigrationApplied: false }, + }) + .build(), ganacheOptions, title: this.test.fullTitle(), testSpecificMock: mockSentryTestError, @@ -517,7 +535,10 @@ describe('Sentry errors', function () { metaMetricsId: 'fake-metrics-id', participateInMetaMetrics: true, }) - .build(), + .withPreferencesController({ + preferences: { smartTransactionsMigrationApplied: false }, + }) + .build(), ganacheOptions, title: this.test.fullTitle(), testSpecificMock: mockSentryTestError, @@ -582,7 +603,10 @@ describe('Sentry errors', function () { metaMetricsId: null, participateInMetaMetrics: false, }) - .build(), + .withPreferencesController({ + preferences: { smartTransactionsMigrationApplied: false }, + }) + .build(), ganacheOptions, title: this.test.fullTitle(), testSpecificMock: mockSentryTestError, @@ -617,7 +641,10 @@ describe('Sentry errors', function () { metaMetricsId: null, participateInMetaMetrics: false, }) - .build(), + .withPreferencesController({ + preferences: { smartTransactionsMigrationApplied: false }, + }) + .build(), ganacheOptions, title: this.test.fullTitle(), testSpecificMock: mockSentryTestError, @@ -653,7 +680,10 @@ describe('Sentry errors', function () { metaMetricsId: 'fake-metrics-id', participateInMetaMetrics: true, }) - .build(), + .withPreferencesController({ + preferences: { smartTransactionsMigrationApplied: false }, + }) + .build(), ganacheOptions, title: this.test.fullTitle(), testSpecificMock: mockSentryTestError, @@ -699,7 +729,10 @@ describe('Sentry errors', function () { metaMetricsId: 'fake-metrics-id', participateInMetaMetrics: true, }) - .build(), + .withPreferencesController({ + preferences: { smartTransactionsMigrationApplied: false }, + }) + .build(), ganacheOptions, title: this.test.fullTitle(), testSpecificMock: mockSentryTestError, @@ -762,7 +795,10 @@ describe('Sentry errors', function () { metaMetricsId: 'fake-metrics-id', participateInMetaMetrics: true, }) - .build(), + .withPreferencesController({ + preferences: { smartTransactionsMigrationApplied: false }, + }) + .build(), ganacheOptions, title: this.test.fullTitle(), testSpecificMock: mockSentryTestError, @@ -806,7 +842,10 @@ describe('Sentry errors', function () { metaMetricsId: 'fake-metrics-id', participateInMetaMetrics: true, }) - .build(), + .withPreferencesController({ + preferences: { smartTransactionsMigrationApplied: false }, + }) + .build(), ganacheOptions, title: this.test.fullTitle(), testSpecificMock: mockSentryTestError, @@ -890,7 +929,6 @@ describe('Sentry errors', function () { autoLockTimeLimit: true, // Initialized as undefined showConfirmationAdvancedDetails: true, privacyMode: false, - smartTransactionsMigrationApplied: true, }, smartTransactionsState: { fees: { @@ -916,7 +954,10 @@ describe('Sentry errors', function () { }; await withFixtures( { - fixtures: new FixtureBuilder().build(), + fixtures: new FixtureBuilder().withPreferencesController({ + preferences: { smartTransactionsMigrationApplied: false }, + }) + .build(), ganacheOptions, title: this.test.fullTitle(), manifestFlags: { From ae6d64eb91dee81a715c485b824534e135dfb1c2 Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Wed, 18 Dec 2024 05:29:45 -0500 Subject: [PATCH 74/90] fix: fix formatting on error.spec.js --- test/e2e/tests/metrics/errors.spec.js | 65 ++++++++++++++------------- 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/test/e2e/tests/metrics/errors.spec.js b/test/e2e/tests/metrics/errors.spec.js index d78a089ef5c9..5e8de0b8fbe9 100644 --- a/test/e2e/tests/metrics/errors.spec.js +++ b/test/e2e/tests/metrics/errors.spec.js @@ -279,9 +279,9 @@ describe('Sentry errors', function () { participateInMetaMetrics: false, }) .withPreferencesController({ - preferences: { smartTransactionsMigrationApplied: false }, - }) - .build(), + preferences: { smartTransactionsMigrationApplied: false }, + }) + .build(), ganacheOptions, title: this.test.fullTitle(), testSpecificMock: mockSentryTestError, @@ -487,9 +487,9 @@ describe('Sentry errors', function () { participateInMetaMetrics: true, }) .withPreferencesController({ - preferences: { smartTransactionsMigrationApplied: false }, - }) - .build(), + preferences: { smartTransactionsMigrationApplied: false }, + }) + .build(), ganacheOptions, title: this.test.fullTitle(), testSpecificMock: mockSentryTestError, @@ -536,9 +536,9 @@ describe('Sentry errors', function () { participateInMetaMetrics: true, }) .withPreferencesController({ - preferences: { smartTransactionsMigrationApplied: false }, - }) - .build(), + preferences: { smartTransactionsMigrationApplied: false }, + }) + .build(), ganacheOptions, title: this.test.fullTitle(), testSpecificMock: mockSentryTestError, @@ -604,9 +604,9 @@ describe('Sentry errors', function () { participateInMetaMetrics: false, }) .withPreferencesController({ - preferences: { smartTransactionsMigrationApplied: false }, - }) - .build(), + preferences: { smartTransactionsMigrationApplied: false }, + }) + .build(), ganacheOptions, title: this.test.fullTitle(), testSpecificMock: mockSentryTestError, @@ -642,9 +642,9 @@ describe('Sentry errors', function () { participateInMetaMetrics: false, }) .withPreferencesController({ - preferences: { smartTransactionsMigrationApplied: false }, - }) - .build(), + preferences: { smartTransactionsMigrationApplied: false }, + }) + .build(), ganacheOptions, title: this.test.fullTitle(), testSpecificMock: mockSentryTestError, @@ -681,9 +681,9 @@ describe('Sentry errors', function () { participateInMetaMetrics: true, }) .withPreferencesController({ - preferences: { smartTransactionsMigrationApplied: false }, - }) - .build(), + preferences: { smartTransactionsMigrationApplied: false }, + }) + .build(), ganacheOptions, title: this.test.fullTitle(), testSpecificMock: mockSentryTestError, @@ -730,9 +730,9 @@ describe('Sentry errors', function () { participateInMetaMetrics: true, }) .withPreferencesController({ - preferences: { smartTransactionsMigrationApplied: false }, - }) - .build(), + preferences: { smartTransactionsMigrationApplied: false }, + }) + .build(), ganacheOptions, title: this.test.fullTitle(), testSpecificMock: mockSentryTestError, @@ -796,9 +796,9 @@ describe('Sentry errors', function () { participateInMetaMetrics: true, }) .withPreferencesController({ - preferences: { smartTransactionsMigrationApplied: false }, - }) - .build(), + preferences: { smartTransactionsMigrationApplied: false }, + }) + .build(), ganacheOptions, title: this.test.fullTitle(), testSpecificMock: mockSentryTestError, @@ -843,9 +843,9 @@ describe('Sentry errors', function () { participateInMetaMetrics: true, }) .withPreferencesController({ - preferences: { smartTransactionsMigrationApplied: false }, - }) - .build(), + preferences: { smartTransactionsMigrationApplied: false }, + }) + .build(), ganacheOptions, title: this.test.fullTitle(), testSpecificMock: mockSentryTestError, @@ -954,10 +954,13 @@ describe('Sentry errors', function () { }; await withFixtures( { - fixtures: new FixtureBuilder().withPreferencesController({ - preferences: { smartTransactionsMigrationApplied: false }, - }) - .build(), + fixtures: new FixtureBuilder() + .withPreferencesController({ + preferences: { + smartTransactionsMigrationApplied: false, + }, + }) + .build(), ganacheOptions, title: this.test.fullTitle(), manifestFlags: { From c6b81f876bbbab135f36496a3013b3b483402c81 Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Wed, 18 Dec 2024 11:14:42 -0500 Subject: [PATCH 75/90] fix: reset `errors.spec.js` to version on main --- test/e2e/tests/metrics/errors.spec.js | 47 +-------------------------- 1 file changed, 1 insertion(+), 46 deletions(-) diff --git a/test/e2e/tests/metrics/errors.spec.js b/test/e2e/tests/metrics/errors.spec.js index 5e8de0b8fbe9..12a44e26fbf1 100644 --- a/test/e2e/tests/metrics/errors.spec.js +++ b/test/e2e/tests/metrics/errors.spec.js @@ -241,9 +241,6 @@ describe('Sentry errors', function () { metaMetricsId: null, participateInMetaMetrics: false, }) - .withPreferencesController({ - preferences: { smartTransactionsMigrationApplied: false }, - }) .build(), // Intentionally corrupt state to trigger migration error during initialization meta: undefined, @@ -278,9 +275,6 @@ describe('Sentry errors', function () { metaMetricsId: null, participateInMetaMetrics: false, }) - .withPreferencesController({ - preferences: { smartTransactionsMigrationApplied: false }, - }) .build(), ganacheOptions, title: this.test.fullTitle(), @@ -319,9 +313,6 @@ describe('Sentry errors', function () { metaMetricsId: 'fake-metrics-id', participateInMetaMetrics: true, }) - .withPreferencesController({ - preferences: { smartTransactionsMigrationApplied: false }, - }) .build(), // Intentionally corrupt state to trigger migration error during initialization meta: undefined, @@ -368,9 +359,6 @@ describe('Sentry errors', function () { metaMetricsId: 'fake-metrics-id', participateInMetaMetrics: true, }) - .withPreferencesController({ - preferences: { smartTransactionsMigrationApplied: false }, - }) .build(), // Intentionally corrupt state to trigger migration error during initialization meta: undefined, @@ -434,9 +422,6 @@ describe('Sentry errors', function () { participateInMetaMetrics: true, }) .withBadPreferencesControllerState() - .withPreferencesController({ - preferences: { smartTransactionsMigrationApplied: false }, - }) .build(), }, ganacheOptions, @@ -486,9 +471,6 @@ describe('Sentry errors', function () { metaMetricsId: 'fake-metrics-id', participateInMetaMetrics: true, }) - .withPreferencesController({ - preferences: { smartTransactionsMigrationApplied: false }, - }) .build(), ganacheOptions, title: this.test.fullTitle(), @@ -535,9 +517,6 @@ describe('Sentry errors', function () { metaMetricsId: 'fake-metrics-id', participateInMetaMetrics: true, }) - .withPreferencesController({ - preferences: { smartTransactionsMigrationApplied: false }, - }) .build(), ganacheOptions, title: this.test.fullTitle(), @@ -603,9 +582,6 @@ describe('Sentry errors', function () { metaMetricsId: null, participateInMetaMetrics: false, }) - .withPreferencesController({ - preferences: { smartTransactionsMigrationApplied: false }, - }) .build(), ganacheOptions, title: this.test.fullTitle(), @@ -641,9 +617,6 @@ describe('Sentry errors', function () { metaMetricsId: null, participateInMetaMetrics: false, }) - .withPreferencesController({ - preferences: { smartTransactionsMigrationApplied: false }, - }) .build(), ganacheOptions, title: this.test.fullTitle(), @@ -680,9 +653,6 @@ describe('Sentry errors', function () { metaMetricsId: 'fake-metrics-id', participateInMetaMetrics: true, }) - .withPreferencesController({ - preferences: { smartTransactionsMigrationApplied: false }, - }) .build(), ganacheOptions, title: this.test.fullTitle(), @@ -729,9 +699,6 @@ describe('Sentry errors', function () { metaMetricsId: 'fake-metrics-id', participateInMetaMetrics: true, }) - .withPreferencesController({ - preferences: { smartTransactionsMigrationApplied: false }, - }) .build(), ganacheOptions, title: this.test.fullTitle(), @@ -795,9 +762,6 @@ describe('Sentry errors', function () { metaMetricsId: 'fake-metrics-id', participateInMetaMetrics: true, }) - .withPreferencesController({ - preferences: { smartTransactionsMigrationApplied: false }, - }) .build(), ganacheOptions, title: this.test.fullTitle(), @@ -842,9 +806,6 @@ describe('Sentry errors', function () { metaMetricsId: 'fake-metrics-id', participateInMetaMetrics: true, }) - .withPreferencesController({ - preferences: { smartTransactionsMigrationApplied: false }, - }) .build(), ganacheOptions, title: this.test.fullTitle(), @@ -954,13 +915,7 @@ describe('Sentry errors', function () { }; await withFixtures( { - fixtures: new FixtureBuilder() - .withPreferencesController({ - preferences: { - smartTransactionsMigrationApplied: false, - }, - }) - .build(), + fixtures: new FixtureBuilder().build(), ganacheOptions, title: this.test.fullTitle(), manifestFlags: { From ba8f557fd71334082d17b4f155d526065df5138d Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Wed, 18 Dec 2024 14:56:48 -0500 Subject: [PATCH 76/90] fix: remove comments in preference-controller --- app/scripts/controllers/preferences-controller.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/scripts/controllers/preferences-controller.test.ts b/app/scripts/controllers/preferences-controller.test.ts index 75f0fd27e742..f30e938e635e 100644 --- a/app/scripts/controllers/preferences-controller.test.ts +++ b/app/scripts/controllers/preferences-controller.test.ts @@ -733,7 +733,7 @@ describe('preferences controller', () => { privacyMode: false, showFiatInTestnets: false, showTestNetworks: false, - smartTransactionsMigrationApplied: false, // Add this line + smartTransactionsMigrationApplied: false, smartTransactionsOptInStatus: true, useNativeCurrencyAsPrimaryCurrency: true, hideZeroBalanceTokens: false, @@ -763,7 +763,7 @@ describe('preferences controller', () => { showExtensionInFullSizeView: false, showFiatInTestnets: false, showTestNetworks: false, - smartTransactionsMigrationApplied: false, // Add this line + smartTransactionsMigrationApplied: false, smartTransactionsOptInStatus: true, useNativeCurrencyAsPrimaryCurrency: true, hideZeroBalanceTokens: false, From 80f264ad4ac88ed589ad15719027a1b475c4b789 Mon Sep 17 00:00:00 2001 From: httpjunkie Date: Wed, 18 Dec 2024 17:13:47 -0500 Subject: [PATCH 77/90] feat: update how we check for transaction confirmations --- .../smart-transactions-banner-alert.tsx | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx b/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx index 0445b0dc44b0..9747a300996a 100644 --- a/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx +++ b/ui/pages/confirmations/components/smart-transactions-banner-alert/smart-transactions-banner-alert.tsx @@ -1,5 +1,6 @@ import React, { useCallback } from 'react'; import { useSelector, useDispatch } from 'react-redux'; +import { TransactionType } from '@metamask/transaction-controller'; import { useI18nContext } from '../../../../hooks/useI18nContext'; import { BannerAlert, @@ -12,6 +13,7 @@ import { AlertTypes } from '../../../../../shared/constants/alerts'; import { SMART_TRANSACTIONS_LEARN_MORE_URL } from '../../../../../shared/constants/smartTransactions'; import { FontWeight } from '../../../../helpers/constants/design-system'; import { useConfirmContext } from '../../context/confirm'; +import { isCorrectDeveloperTransactionType } from '../../../../../shared/lib/confirmation.utils'; type MarginType = 'default' | 'none' | 'noTop' | 'onlyTop'; @@ -95,13 +97,9 @@ export const SmartTransactionsBannerAlert: React.FC Date: Wed, 18 Dec 2024 17:35:12 -0500 Subject: [PATCH 78/90] fix: update `confirm.test.tsx` and snapshot. --- .../__snapshots__/confirm.test.tsx.snap | 837 ++++++++++++++++++ .../confirmations/confirm/confirm.test.tsx | 40 + 2 files changed, 877 insertions(+) diff --git a/ui/pages/confirmations/confirm/__snapshots__/confirm.test.tsx.snap b/ui/pages/confirmations/confirm/__snapshots__/confirm.test.tsx.snap index f8e816085738..896d6d989ba3 100644 --- a/ui/pages/confirmations/confirm/__snapshots__/confirm.test.tsx.snap +++ b/ui/pages/confirmations/confirm/__snapshots__/confirm.test.tsx.snap @@ -3793,3 +3793,840 @@ exports[`Confirm should match snapshot signature - typed sign - order 1`] = `
`; + +exports[`Confirm should render SmartTransactionsBannerAlert for transaction types but not signature types 1`] = ` +
+
+
+
+
+
+
+
+ network logo +
+
+
+

+

+

+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+ +
+
+
+`; + +exports[`Confirm should render SmartTransactionsBannerAlert for transaction types but not signature types 2`] = ` +
+
+
+
+
+
+
+
+
+
+ Goerli logo +
+
+
+

+ Test Account +

+

+ Goerli +

+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+

+ Request from +

+
+
+ +
+
+
+
+
+

+ metamask.github.io +

+
+
+
+
+
+

+ Interacting with +

+
+
+
+
+
+
+
+

+ 0xCcCCc...ccccC +

+
+
+
+
+
+
+ +
+
+

+ Message +

+
+
+
+
+
+
+

+ Primary type: +

+
+
+
+

+ Mail +

+
+
+
+
+
+
+
+

+ Contents: +

+
+
+
+

+ Hello, Bob! +

+
+
+
+
+
+

+ From: +

+
+
+
+
+
+
+

+ Name: +

+
+
+
+

+ Cow +

+
+
+
+
+
+

+ Wallets: +

+
+
+
+
+
+
+

+ 0: +

+
+
+
+
+
+
+
+

+ 0xCD2a3...DD826 +

+
+
+
+
+
+
+

+ 1: +

+
+
+
+
+
+
+
+

+ 0xDeaDb...DbeeF +

+
+
+
+
+
+
+

+ 2: +

+
+
+
+
+
+
+
+

+ 0x06195...43896 +

+
+
+
+
+
+
+
+
+
+
+

+ To: +

+
+
+
+
+
+
+

+ 0: +

+
+
+
+
+
+
+

+ Name: +

+
+
+
+

+ Bob +

+
+
+
+
+
+

+ Wallets: +

+
+
+
+
+
+
+

+ 0: +

+
+
+
+
+
+
+
+

+ 0xbBbBB...bBBbB +

+
+
+
+
+
+
+

+ 1: +

+
+
+
+
+
+
+
+

+ 0xB0Bda...bEa57 +

+
+
+
+
+
+
+

+ 2: +

+
+
+
+
+
+
+
+

+ 0xB0B0b...00000 +

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+`; diff --git a/ui/pages/confirmations/confirm/confirm.test.tsx b/ui/pages/confirmations/confirm/confirm.test.tsx index 939ca8768afe..5adf7efbed78 100644 --- a/ui/pages/confirmations/confirm/confirm.test.tsx +++ b/ui/pages/confirmations/confirm/confirm.test.tsx @@ -182,4 +182,44 @@ describe('Confirm', () => { expect(container).toMatchSnapshot(); }); }); + + it('should render SmartTransactionsBannerAlert for transaction types but not signature types', async () => { + // Test with a transaction type + const mockStateTransaction = { + ...mockState, + metamask: { + ...mockState.metamask, + alertEnabledness: { + smartTransactionsMigration: true, + }, + preferences: { + smartTransactionsOptInStatus: true, + smartTransactionsMigrationApplied: true, + }, + }, + }; + + const mockStoreTransaction = + configureMockStore(middleware)(mockStateTransaction); + + await act(async () => { + const { container } = renderWithConfirmContextProvider( + , + mockStoreTransaction, + ); + expect(container).toMatchSnapshot(); + }); + + // Test with a signature type (reuse existing mock) + const mockStateTypedSign = getMockTypedSignConfirmState(); + const mockStoreSign = configureMockStore(middleware)(mockStateTypedSign); + + await act(async () => { + const { container } = renderWithConfirmContextProvider( + , + mockStoreSign, + ); + expect(container).toMatchSnapshot(); + }); + }); }); From 202e7d6a9071f785578c19662561124224ea234a Mon Sep 17 00:00:00 2001 From: dan437 <80175477+dan437@users.noreply.github.com> Date: Thu, 19 Dec 2024 11:11:30 +0100 Subject: [PATCH 79/90] Update snapshots for E2E tests Linting --- privacy-snapshot.json | 1 + .../errors-after-init-opt-in-background-state.json | 3 ++- .../state-snapshots/errors-after-init-opt-in-ui-state.json | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/privacy-snapshot.json b/privacy-snapshot.json index fc5dafb7333c..955f78000d4d 100644 --- a/privacy-snapshot.json +++ b/privacy-snapshot.json @@ -12,6 +12,7 @@ "bafkreifvhjdf6ve4jfv6qytqtux5nd4nwnelioeiqx5x2ez5yrgrzk7ypi.ipfs.dweb.link", "bafybeidxfmwycgzcp4v2togflpqh2gnibuexjy4m4qqwxp7nh3jx5zlh4y.ipfs.dweb.link", "bridge.api.cx.metamask.io", + "bridge.dev-api.cx.metamask.io", "cdn.segment.com", "cdn.segment.io", "cdnjs.cloudflare.com", diff --git a/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-background-state.json b/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-background-state.json index 091e0ffea5c3..71597008627f 100644 --- a/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-background-state.json +++ b/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-background-state.json @@ -240,7 +240,8 @@ "shouldShowAggregatedBalancePopover": "boolean", "tokenNetworkFilter": { "0x539": "boolean" }, "redesignedConfirmationsEnabled": true, - "redesignedTransactionsEnabled": "boolean" + "redesignedTransactionsEnabled": "boolean", + "smartTransactionsMigrationApplied": "boolean" }, "ipfsGateway": "string", "isIpfsGatewayEnabled": "boolean", diff --git a/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-ui-state.json b/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-ui-state.json index 1ad6883c79c9..fac848b88583 100644 --- a/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-ui-state.json +++ b/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-ui-state.json @@ -39,7 +39,8 @@ "shouldShowAggregatedBalancePopover": "boolean", "tokenNetworkFilter": { "0x539": "boolean" }, "redesignedConfirmationsEnabled": true, - "redesignedTransactionsEnabled": "boolean" + "redesignedTransactionsEnabled": "boolean", + "smartTransactionsMigrationApplied": "boolean" }, "firstTimeFlowType": "import", "completedOnboarding": true, From 4377a1b6fffbcfe3de8531b35010d1a08da07a91 Mon Sep 17 00:00:00 2001 From: dan437 <80175477+dan437@users.noreply.github.com> Date: Thu, 19 Dec 2024 12:17:48 +0100 Subject: [PATCH 80/90] Update a Jest snapshot --- .../confirmations/confirm/__snapshots__/confirm.test.tsx.snap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/pages/confirmations/confirm/__snapshots__/confirm.test.tsx.snap b/ui/pages/confirmations/confirm/__snapshots__/confirm.test.tsx.snap index cfd45d554732..85c6e24b3d78 100644 --- a/ui/pages/confirmations/confirm/__snapshots__/confirm.test.tsx.snap +++ b/ui/pages/confirmations/confirm/__snapshots__/confirm.test.tsx.snap @@ -4096,7 +4096,7 @@ exports[`Confirm should render SmartTransactionsBannerAlert for transaction type