Skip to content

Commit 99f753d

Browse files
committed
Metrics adjustments (#15313)
* Don't send errors to sentry if users have not opted-in to participate in metametrics * Don't capture opt-out metrics * Move the metrics-opt in screen to immediately after the welcome screen * Ensure that global.getSentryState is set in the background * Fix e2e tests after rearranging onboardin flow * Fix unit tests * More e2e test fixes * Remove unnecessary wrappers around capture exception
1 parent d35d3ca commit 99f753d

File tree

14 files changed

+103
-80
lines changed

14 files changed

+103
-80
lines changed

app/scripts/background.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,14 @@ import {
2424
REJECT_NOTFICIATION_CLOSE_SIG,
2525
} from '../../shared/constants/metametrics';
2626
import { isManifestV3 } from '../../shared/modules/mv3.utils';
27+
import { maskObject } from '../../shared/modules/object.utils';
2728
import migrations from './migrations';
2829
import Migrator from './lib/migrator';
2930
import ExtensionPlatform from './platforms/extension';
3031
import LocalStore from './lib/local-store';
3132
import ReadOnlyNetworkStore from './lib/network-store';
33+
import { SENTRY_STATE } from './lib/setupSentry';
34+
3235
import createStreamSink from './lib/createStreamSink';
3336
import NotificationManager, {
3437
NOTIFICATION_MANAGER_EVENTS,
@@ -353,6 +356,8 @@ function setupController(initState, initLangCode, remoteSourcePort) {
353356
},
354357
);
355358

359+
setupSentryGetStateGlobal(controller.store);
360+
356361
/**
357362
* Assigns the given state to the versioned object (with metadata), and returns that.
358363
*
@@ -755,3 +760,15 @@ browser.runtime.onInstalled.addListener(({ reason }) => {
755760
platform.openExtensionInBrowser();
756761
}
757762
});
763+
764+
function setupSentryGetStateGlobal(store) {
765+
global.getSentryState = function () {
766+
const fullState = store.getState();
767+
const debugState = maskObject(fullState, SENTRY_STATE);
768+
return {
769+
browser: window.navigator.userAgent,
770+
store: debugState,
771+
version: global.platform.getVersion(),
772+
};
773+
};
774+
}

app/scripts/lib/setupSentry.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,17 @@ export default function setupSentry({ release, getState }) {
103103
environment,
104104
integrations: [new Dedupe(), new ExtraErrorData()],
105105
release,
106-
beforeSend: (report) => rewriteReport(report),
106+
beforeSend: (report) => {
107+
if (getState) {
108+
const appState = getState();
109+
if (!appState?.store?.metamask?.participateInMetaMetrics) {
110+
return null;
111+
}
112+
} else {
113+
return null;
114+
}
115+
return rewriteReport(report);
116+
},
107117
});
108118

109119
function rewriteReport(report) {

shared/modules/object.utils.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/**
2+
* Return a "masked" copy of the given object.
3+
*
4+
* The returned object includes only the properties present in the mask. The
5+
* mask is an object that mirrors the structure of the given object, except
6+
* the only values are `true` or a sub-mask. `true` implies the property
7+
* should be included, and a sub-mask implies the property should be further
8+
* masked according to that sub-mask.
9+
*
10+
* @param {Object} object - The object to mask
11+
* @param {Object<Object|boolean>} mask - The mask to apply to the object
12+
*/
13+
export function maskObject(object, mask) {
14+
return Object.keys(object).reduce((state, key) => {
15+
if (mask[key] === true) {
16+
state[key] = object[key];
17+
} else if (mask[key]) {
18+
state[key] = maskObject(object[key], mask[key]);
19+
}
20+
return state;
21+
}, {});
22+
}

test/e2e/helpers.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -237,12 +237,12 @@ const completeImportSRPOnboardingFlow = async (
237237
tag: 'button',
238238
});
239239

240-
// clicks the "Import Wallet" option
241-
await driver.clickElement({ text: 'Import wallet', tag: 'button' });
242-
243240
// clicks the "No thanks" option on the metametrics opt-in screen
244241
await driver.clickElement('.btn-secondary');
245242

243+
// clicks the "Import Wallet" option
244+
await driver.clickElement({ text: 'Import wallet', tag: 'button' });
245+
246246
// Import Secret Recovery Phrase
247247
await driver.pasteIntoField(
248248
'[data-testid="import-srp__srp-word-0"]',
@@ -279,12 +279,12 @@ const completeImportSRPOnboardingFlowWordByWord = async (
279279
tag: 'button',
280280
});
281281

282-
// clicks the "Import Wallet" option
283-
await driver.clickElement({ text: 'Import wallet', tag: 'button' });
284-
285282
// clicks the "No thanks" option on the metametrics opt-in screen
286283
await driver.clickElement('.btn-secondary');
287284

285+
// clicks the "Import Wallet" option
286+
await driver.clickElement({ text: 'Import wallet', tag: 'button' });
287+
288288
const words = seedPhrase.split(' ');
289289
for (const word of words) {
290290
await driver.pasteIntoField(

test/e2e/metamask-ui.spec.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,13 +99,13 @@ describe('MetaMask', function () {
9999
await driver.delay(largeDelayMs);
100100
});
101101

102-
it('clicks the "Create New Wallet" option', async function () {
103-
await driver.clickElement({ text: 'Create a Wallet', tag: 'button' });
102+
it('clicks the "No thanks" option on the metametrics opt-in screen', async function () {
103+
await driver.clickElement('.btn-secondary');
104104
await driver.delay(largeDelayMs);
105105
});
106106

107-
it('clicks the "No thanks" option on the metametrics opt-in screen', async function () {
108-
await driver.clickElement('.btn-secondary');
107+
it('clicks the "Create New Wallet" option', async function () {
108+
await driver.clickElement({ text: 'Create a Wallet', tag: 'button' });
109109
await driver.delay(largeDelayMs);
110110
});
111111

test/e2e/tests/incremental-security.spec.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,12 @@ describe('Incremental Security', function () {
3838
tag: 'button',
3939
});
4040

41-
// clicks the "Create New Wallet" option
42-
await driver.clickElement({ text: 'Create a Wallet', tag: 'button' });
43-
4441
// clicks the "No thanks" option on the metametrics opt-in screen
4542
await driver.clickElement('.btn-secondary');
4643

44+
// clicks the "Create New Wallet" option
45+
await driver.clickElement({ text: 'Create a Wallet', tag: 'button' });
46+
4747
// accepts a secure password
4848
await driver.fill(
4949
'.first-time-flow__form #create-password',

test/e2e/tests/metamask-responsive-ui.spec.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,12 +87,12 @@ describe('MetaMask Responsive UI', function () {
8787
});
8888
await driver.delay(tinyDelayMs);
8989

90-
// clicks the "Create New Wallet" option
91-
await driver.clickElement({ text: 'Create a Wallet', tag: 'button' });
92-
9390
// clicks the "I Agree" option on the metametrics opt-in screen
9491
await driver.clickElement('.btn-primary');
9592

93+
// clicks the "Create New Wallet" option
94+
await driver.clickElement({ text: 'Create a Wallet', tag: 'button' });
95+
9696
// accepts a secure password
9797
await driver.fill(
9898
'.first-time-flow__form #create-password',

ui/index.js

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import browser from 'webextension-polyfill';
77

88
import { getEnvironmentType } from '../app/scripts/lib/util';
99
import { ALERT_TYPES } from '../shared/constants/alerts';
10+
import { maskObject } from '../shared/modules/object.utils';
1011
import { SENTRY_STATE } from '../app/scripts/lib/setupSentry';
1112
import { ENVIRONMENT_TYPE_POPUP } from '../shared/constants/app';
1213
import * as actions from './store/actions';
@@ -171,29 +172,6 @@ async function startApp(metamaskState, backgroundConnection, opts) {
171172
return store;
172173
}
173174

174-
/**
175-
* Return a "masked" copy of the given object.
176-
*
177-
* The returned object includes only the properties present in the mask. The
178-
* mask is an object that mirrors the structure of the given object, except
179-
* the only values are `true` or a sub-mask. `true` implies the property
180-
* should be included, and a sub-mask implies the property should be further
181-
* masked according to that sub-mask.
182-
*
183-
* @param {Object} object - The object to mask
184-
* @param {Object<Object|boolean>} mask - The mask to apply to the object
185-
*/
186-
function maskObject(object, mask) {
187-
return Object.keys(object).reduce((state, key) => {
188-
if (mask[key] === true) {
189-
state[key] = object[key];
190-
} else if (mask[key]) {
191-
state[key] = maskObject(object[key], mask[key]);
192-
}
193-
return state;
194-
}, {});
195-
}
196-
197175
function setupDebuggingHelpers(store) {
198176
window.getCleanAppState = async function () {
199177
const state = clone(store.getState());

ui/pages/first-time-flow/metametrics-opt-in/metametrics-opt-in.component.js

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ import PropTypes from 'prop-types';
33
import MetaFoxLogo from '../../../components/ui/metafox-logo';
44
import PageContainerFooter from '../../../components/ui/page-container/page-container-footer';
55
import { EVENT } from '../../../../shared/constants/metametrics';
6+
import { INITIALIZE_SELECT_ACTION_ROUTE } from '../../../helpers/constants/routes';
67

78
export default class MetaMetricsOptIn extends Component {
89
static propTypes = {
910
history: PropTypes.object,
1011
setParticipateInMetaMetrics: PropTypes.func,
11-
nextRoute: PropTypes.string,
1212
firstTimeSelectionMetaMetricsName: PropTypes.string,
1313
participateInMetaMetrics: PropTypes.bool,
1414
};
@@ -21,7 +21,6 @@ export default class MetaMetricsOptIn extends Component {
2121
render() {
2222
const { trackEvent, t } = this.context;
2323
const {
24-
nextRoute,
2524
history,
2625
setParticipateInMetaMetrics,
2726
firstTimeSelectionMetaMetricsName,
@@ -105,29 +104,7 @@ export default class MetaMetricsOptIn extends Component {
105104
onCancel={async () => {
106105
await setParticipateInMetaMetrics(false);
107106

108-
try {
109-
if (
110-
participateInMetaMetrics === null ||
111-
participateInMetaMetrics === true
112-
) {
113-
await trackEvent(
114-
{
115-
category: EVENT.CATEGORIES.ONBOARDING,
116-
event: 'Metrics Opt Out',
117-
properties: {
118-
action: 'Metrics Option',
119-
legacy_event: true,
120-
},
121-
},
122-
{
123-
isOptIn: true,
124-
flushImmediately: true,
125-
},
126-
);
127-
}
128-
} finally {
129-
history.push(nextRoute);
130-
}
107+
history.push(INITIALIZE_SELECT_ACTION_ROUTE);
131108
}}
132109
cancelText={t('noThanks')}
133110
hideCancel={false}
@@ -177,7 +154,7 @@ export default class MetaMetricsOptIn extends Component {
177154
);
178155
await Promise.all(metrics);
179156
} finally {
180-
history.push(nextRoute);
157+
history.push(INITIALIZE_SELECT_ACTION_ROUTE);
181158
}
182159
}}
183160
submitText={t('affirmAgree')}

ui/pages/first-time-flow/metametrics-opt-in/metametrics-opt-in.container.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { connect } from 'react-redux';
22
import { setParticipateInMetaMetrics } from '../../../store/actions';
3-
import { getFirstTimeFlowTypeRoute } from '../../../selectors';
43
import MetaMetricsOptIn from './metametrics-opt-in.component';
54

65
const firstTimeFlowTypeNameMap = {
@@ -12,7 +11,6 @@ const mapStateToProps = (state) => {
1211
const { firstTimeFlowType, participateInMetaMetrics } = state.metamask;
1312

1413
return {
15-
nextRoute: getFirstTimeFlowTypeRoute(state),
1614
firstTimeSelectionMetaMetricsName:
1715
firstTimeFlowTypeNameMap[firstTimeFlowType],
1816
participateInMetaMetrics,

0 commit comments

Comments
 (0)