Skip to content

Commit

Permalink
Add types of hidden properties to Sentry data (#20457)
Browse files Browse the repository at this point in the history
* Add types of hidden properties to Sentry data

The masked wallet state object sent to Sentry has been updated to
include the type of each property omitted from the mask. This lets us
at least see the full state shape, making it easier to see when errors
are caused by invalid state.

Relates to #20449

* Remove inconsistent state snapshot properties

The state snapshot tests have been updated to exclude properties that
were shown to differ between runs.
  • Loading branch information
Gudahtt authored and danjm committed Aug 17, 2023
1 parent dc7ebe9 commit 805ce29
Show file tree
Hide file tree
Showing 4 changed files with 211 additions and 26 deletions.
4 changes: 4 additions & 0 deletions shared/modules/object.utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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<object | boolean>} mask - The mask to apply to the object
*/
Expand All @@ -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;
}, {});
Expand Down
60 changes: 45 additions & 15 deletions test/e2e/tests/errors.spec.js
Original file line number Diff line number Diff line change
@@ -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;
}

Expand Down Expand Up @@ -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',
});
},
Expand Down Expand Up @@ -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',
});
},
Expand Down Expand Up @@ -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',
});
},
Expand Down Expand Up @@ -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',
});
},
Expand Down
Original file line number Diff line number Diff line change
@@ -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"
}
110 changes: 107 additions & 3 deletions test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -19,43 +31,135 @@
},
"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,
"0x5": null,
"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" }
}

0 comments on commit 805ce29

Please sign in to comment.