diff --git a/shared/modules/object.utils.js b/shared/modules/object.utils.js index 24119be56..ce7eb1da1 100644 --- a/shared/modules/object.utils.js +++ b/shared/modules/object.utils.js @@ -7,6 +7,8 @@ * should be included, and a sub-mask implies the property should be further * masked according to that sub-mask. * + * If a property is not found in the last, its type is included instead. + * * @param {object} object - The object to mask * @param {Object} mask - The mask to apply to the object */ @@ -16,6 +18,8 @@ export function maskObject(object, mask) { state[key] = object[key]; } else if (mask[key]) { state[key] = maskObject(object[key], mask[key]); + } else { + state[key] = typeof object[key]; } return state; }, {}); diff --git a/test/e2e/tests/errors.spec.js b/test/e2e/tests/errors.spec.js index 8784ef168..3098a5083 100644 --- a/test/e2e/tests/errors.spec.js +++ b/test/e2e/tests/errors.spec.js @@ -1,42 +1,72 @@ const { resolve } = require('path'); const { promises: fs } = require('fs'); const { strict: assert } = require('assert'); -const { get, has, set } = require('lodash'); +const { get, has, set, unset } = require('lodash'); const { Browser } = require('selenium-webdriver'); const { format } = require('prettier'); const { convertToHexValue, withFixtures } = require('../helpers'); const FixtureBuilder = require('../fixture-builder'); -const backgroundDateFields = ['CurrencyController.conversionDate']; -const uiDateFields = ['metamask.conversionDate']; +const maskedBackgroundFields = [ + 'CurrencyController.conversionDate', // This is a timestamp that changes each run +]; +const maskedUiFields = [ + 'metamask.conversionDate', // This is a timestamp that changes each run +]; + +const removedBackgroundFields = [ + // This property is timing-dependent + 'AccountTracker.currentBlockGasLimit', + // These properties are set to undefined, causing inconsistencies between Chrome and Firefox + 'AppStateController.currentPopupId', + 'AppStateController.timeoutMinutes', + 'TokenListController.tokensChainsCache', +]; + +const removedUiFields = [ + // This property is timing-dependent + 'metamask.currentBlockGasLimit', + // These properties are set to undefined, causing inconsistencies between Chrome and Firefox + 'metamask.currentPopupId', + 'metamask.timeoutMinutes', + 'metamask.tokensChainsCache', +]; /** - * Transform date properties to value types, to ensure that state is - * consistent between test runs. + * Transform background state to make it consistent between test runs. * * @param {unknown} data - The data to transform */ -function transformBackgroundDates(data) { - for (const field of backgroundDateFields) { +function transformBackgroundState(data) { + for (const field of maskedBackgroundFields) { if (has(data, field)) { set(data, field, typeof get(data, field)); } } + for (const field of removedBackgroundFields) { + if (has(data, field)) { + unset(data, field); + } + } return data; } /** - * Transform date properties to value types, to ensure that state is - * consistent between test runs. + * Transform UI state to make it consistent between test runs. * * @param {unknown} data - The data to transform */ -function transformUiDates(data) { - for (const field of uiDateFields) { +function transformUiState(data) { + for (const field of maskedUiFields) { if (has(data, field)) { set(data, field, typeof get(data, field)); } } + for (const field of removedUiFields) { + if (has(data, field)) { + unset(data, field); + } + } return data; } @@ -257,7 +287,7 @@ describe('Sentry errors', function () { const mockJsonBody = JSON.parse(mockTextBody[2]); const appState = mockJsonBody?.extra?.appState; await matchesSnapshot({ - data: transformBackgroundDates(appState), + data: transformBackgroundState(appState), snapshot: 'errors-before-init-opt-in-background-state', }); }, @@ -342,7 +372,7 @@ describe('Sentry errors', function () { const mockJsonBody = JSON.parse(mockTextBody[2]); const appState = mockJsonBody?.extra?.appState; await matchesSnapshot({ - data: transformUiDates(appState), + data: transformUiState(appState), snapshot: 'errors-before-init-opt-in-ui-state', }); }, @@ -509,7 +539,7 @@ describe('Sentry errors', function () { 'Invalid version state', ); await matchesSnapshot({ - data: transformBackgroundDates(appState.store), + data: transformBackgroundState(appState.store), snapshot: 'errors-after-init-opt-in-background-state', }); }, @@ -603,7 +633,7 @@ describe('Sentry errors', function () { 'Invalid version state', ); await matchesSnapshot({ - data: transformUiDates(appState.store), + data: transformUiState(appState.store), snapshot: 'errors-after-init-opt-in-ui-state', }); }, diff --git a/test/e2e/tests/state-snapshots/errors-after-init-opt-in-background-state.json b/test/e2e/tests/state-snapshots/errors-after-init-opt-in-background-state.json index f41fee885..2f29cc98c 100644 --- a/test/e2e/tests/state-snapshots/errors-after-init-opt-in-background-state.json +++ b/test/e2e/tests/state-snapshots/errors-after-init-opt-in-background-state.json @@ -1,34 +1,81 @@ { - "AccountTracker": { "currentBlockGasLimit": "0x1c9c380" }, + "AccountTracker": { "accounts": "object" }, "AppStateController": { "connectedStatusPopoverHasBeenShown": true, - "defaultHomeActiveTabName": null + "defaultHomeActiveTabName": null, + "browserEnvironment": "object", + "popupGasPollTokens": "object", + "notificationGasPollTokens": "object", + "fullScreenGasPollTokens": "object", + "recoveryPhraseReminderHasBeenShown": "boolean", + "recoveryPhraseReminderLastShown": "number", + "outdatedBrowserWarningLastShown": "number", + "nftsDetectionNoticeDismissed": "boolean", + "showTestnetMessageInDropdown": "boolean", + "showBetaHeader": "boolean", + "showProductTour": "boolean", + "trezorModel": "object", + "nftsDropdownState": "object", + "termsOfUseLastAgreed": "number", + "qrHardware": "object", + "usedNetworks": "object", + "snapsInstallPrivacyWarningShown": "boolean", + "serviceWorkerLastActiveTime": "number" }, + "ApprovalController": "object", + "CachedBalancesController": "object", "CurrencyController": { "conversionDate": "number", "conversionRate": 1700, "nativeCurrency": "ETH", - "currentCurrency": "usd" + "currentCurrency": "usd", + "pendingCurrentCurrency": "object", + "pendingNativeCurrency": "object", + "usdConversionRate": "number" + }, + "DecryptMessageController": { + "unapprovedDecryptMsgs": "object", + "unapprovedDecryptMsgCount": 0 }, - "DecryptMessageController": { "unapprovedDecryptMsgCount": 0 }, "EncryptionPublicKeyController": { + "unapprovedEncryptionPublicKeyMsgs": "object", "unapprovedEncryptionPublicKeyMsgCount": 0 }, + "EnsController": "object", "MetaMetricsController": { "participateInMetaMetrics": true, - "metaMetricsId": "fake-metrics-id" + "metaMetricsId": "fake-metrics-id", + "eventsBeforeMetricsOptIn": "object", + "traits": "object", + "fragments": "object", + "segmentApiCalls": "object", + "previousUserTraits": "object" }, "NetworkController": { + "selectedNetworkClientId": "string", "networkId": "1337", "providerConfig": { + "chainId": "string", "nickname": "Localhost 8545", + "rpcPrefs": "object", + "rpcUrl": "string", "ticker": "ETH", - "type": "rpc" - } + "type": "rpc", + "id": "string" + }, + "networksMetadata": "object", + "networkConfigurations": "object" }, "SignatureController": { + "unapprovedMsgs": "object", + "unapprovedPersonalMsgs": "object", + "unapprovedTypedMessages": "object", "unapprovedMsgCount": 0, "unapprovedPersonalMsgCount": 0, "unapprovedTypedMessagesCount": 0 - } + }, + "SwapsController": "object", + "TokenRatesController": "object", + "TokensController": "object", + "TxController": "object" } diff --git a/test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json b/test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json index 4ecaa0417..129ae885a 100644 --- a/test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json +++ b/test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json @@ -1,16 +1,28 @@ { + "DNS": "object", + "activeTab": "object", + "appState": "object", + "confirmTransaction": "object", "gas": { "customData": { "price": null, "limit": null } }, "history": { "mostRecentOverviewPage": "/" }, + "invalidCustomNetwork": "object", + "localeMessages": "object", "metamask": { "isInitialized": true, "isUnlocked": false, "isAccountMenuOpen": false, + "isNetworkMenuOpen": "boolean", + "identities": "object", + "unapprovedTxs": "object", + "networkConfigurations": "object", + "addressBook": "object", + "contractExchangeRates": "object", + "pendingTokens": "object", "customNonceValue": "", "useBlockie": false, "featureFlags": { "showIncomingTransactions": true }, "welcomeScreenSeen": false, "currentLocale": "en", - "currentBlockGasLimit": "", "preferences": { "hideZeroBalanceTokens": false, "showFiatInTestnets": false, @@ -19,31 +31,89 @@ }, "firstTimeFlowType": "import", "completedOnboarding": true, + "knownMethodData": "object", + "use4ByteResolution": "boolean", "participateInMetaMetrics": true, "nextNonce": null, "conversionRate": 1300, "nativeCurrency": "ETH", "connectedStatusPopoverHasBeenShown": true, "defaultHomeActiveTabName": null, + "browserEnvironment": "object", + "popupGasPollTokens": "object", + "notificationGasPollTokens": "object", + "fullScreenGasPollTokens": "object", + "recoveryPhraseReminderHasBeenShown": "boolean", + "recoveryPhraseReminderLastShown": "number", + "outdatedBrowserWarningLastShown": "number", + "nftsDetectionNoticeDismissed": "boolean", + "showTestnetMessageInDropdown": "boolean", + "showBetaHeader": "boolean", + "showProductTour": "boolean", + "trezorModel": "object", + "nftsDropdownState": "object", + "termsOfUseLastAgreed": "number", + "qrHardware": "object", + "usedNetworks": "object", + "snapsInstallPrivacyWarningShown": "boolean", + "serviceWorkerLastActiveTime": "number", "currentAppVersion": "10.34.4", "previousAppVersion": "", "previousMigrationVersion": 0, "currentMigrationVersion": 94, + "selectedNetworkClientId": "string", "networkId": "1337", "providerConfig": { + "chainId": "string", "nickname": "Localhost 8545", + "rpcPrefs": "object", + "rpcUrl": "string", "ticker": "ETH", - "type": "rpc" + "type": "rpc", + "id": "string" }, + "networksMetadata": "object", + "cachedBalances": "object", + "keyringTypes": "object", + "keyrings": "object", "useNonceField": false, "usePhishDetect": true, + "dismissSeedBackUpReminder": "boolean", + "disabledRpcMethodPreferences": "object", + "useMultiAccountBalanceChecker": "boolean", + "useTokenDetection": "boolean", + "useNftDetection": "boolean", + "useCurrencyRateCheck": "boolean", + "openSeaEnabled": "boolean", + "advancedGasFee": "object", + "lostIdentities": "object", "forgottenPassword": false, "ipfsGateway": "dweb.link", + "useAddressBarEnsResolution": "boolean", + "infuraBlocked": "boolean", + "ledgerTransportType": "string", + "snapRegistryList": "object", + "transactionSecurityCheckEnabled": "boolean", + "theme": "string", + "isLineaMainnetReleased": "boolean", + "selectedAddress": "string", "metaMetricsId": "fake-metrics-id", + "eventsBeforeMetricsOptIn": "object", + "traits": "object", + "fragments": "object", + "segmentApiCalls": "object", + "previousUserTraits": "object", "conversionDate": "number", "currentCurrency": "usd", + "pendingCurrentCurrency": "object", + "pendingNativeCurrency": "object", + "usdConversionRate": "number", "alertEnabledness": { "unconnectedAccount": true, "web3ShimUsage": true }, + "unconnectedAccountAlertShownOrigins": "object", + "web3ShimUsageOrigins": "object", "seedPhraseBackedUp": true, + "onboardingTabs": "object", + "incomingTransactions": "object", "incomingTxLastFetchedBlockByChainId": { "0x1": null, "0xe708": null, @@ -51,11 +121,45 @@ "0xaa36a7": null, "0xe704": null }, + "subjects": "object", + "permissionHistory": "object", + "permissionActivityLog": "object", + "subjectMetadata": "object", + "announcements": "object", + "gasFeeEstimates": "object", + "estimatedGasFeeTimeBounds": "object", + "gasEstimateType": "string", + "tokenList": "object", + "preventPollingOnNetworkRestart": "boolean", + "tokens": "object", + "ignoredTokens": "object", + "detectedTokens": "object", + "allTokens": "object", + "allIgnoredTokens": "object", + "allDetectedTokens": "object", + "smartTransactionsState": "object", + "allNftContracts": "object", + "allNfts": "object", + "ignoredNfts": "object", + "accounts": "object", + "currentNetworkTxList": "object", + "unapprovedDecryptMsgs": "object", "unapprovedDecryptMsgCount": 0, + "unapprovedEncryptionPublicKeyMsgs": "object", "unapprovedEncryptionPublicKeyMsgCount": 0, + "unapprovedMsgs": "object", + "unapprovedPersonalMsgs": "object", + "unapprovedTypedMessages": "object", "unapprovedMsgCount": 0, "unapprovedPersonalMsgCount": 0, - "unapprovedTypedMessagesCount": 0 + "unapprovedTypedMessagesCount": 0, + "swapsState": "object", + "ensResolutionsByAddress": "object", + "pendingApprovals": "object", + "pendingApprovalCount": "number", + "approvalFlows": "object" }, + "send": "object", + "swaps": "object", "unconnectedAccount": { "state": "CLOSED" } }