From cc3ef534ade9fea138cc4cb257efb972b52e8a0a Mon Sep 17 00:00:00 2001 From: Danica Shen Date: Wed, 19 Jul 2023 20:56:31 +0100 Subject: [PATCH] feat(882): Ensure user's IP address is not leaked to third parties before opting-out (#20101) --- test/e2e/helpers.js | 12 ++--- test/e2e/metrics/permissions-approved.spec.js | 23 +--------- .../unlock-wallet.spec.js} | 45 ++++++++----------- test/e2e/metrics/wallet-created.spec.js | 37 ++++++++++++++- ui/pages/onboarding-flow/welcome/welcome.js | 1 + 5 files changed, 63 insertions(+), 55 deletions(-) rename test/e2e/{tests/metrics.spec.js => metrics/unlock-wallet.spec.js} (55%) diff --git a/test/e2e/helpers.js b/test/e2e/helpers.js index 2e7b224e9..b1e17b350 100644 --- a/test/e2e/helpers.js +++ b/test/e2e/helpers.js @@ -313,10 +313,10 @@ const onboardingBeginCreateNewWallet = async (driver) => { * Choose either "I Agree" or "No Thanks" on the MetaMetrics onboarding screen * * @param {WebDriver} driver - * @param {boolean} optin - true to opt into metrics, default is false + * @param {boolean} option - true to opt into metrics, default is false */ -const onboardingChooseMetametricsOption = async (driver, optin = false) => { - const optionIdentifier = optin ? 'i-agree' : 'no-thanks'; +const onboardingChooseMetametricsOption = async (driver, option = false) => { + const optionIdentifier = option ? 'i-agree' : 'no-thanks'; // metrics await driver.clickElement(`[data-testid="metametrics-${optionIdentifier}"]`); }; @@ -744,15 +744,17 @@ async function switchToNotificationWindow(driver) { * * @param {WebDriver} driver * @param {import('mockttp').Mockttp} mockedEndpoints + * @param {boolean} hasRequest * @returns {import('mockttp/dist/pluggable-admin').MockttpClientResponse[]} */ -async function getEventPayloads(driver, mockedEndpoints) { +async function getEventPayloads(driver, mockedEndpoints, hasRequest = true) { await driver.wait(async () => { let isPending = true; for (const mockedEndpoint of mockedEndpoints) { isPending = await mockedEndpoint.isPending(); } - return isPending === false; + + return isPending === !hasRequest; }, 10000); const mockedRequests = []; for (const mockedEndpoint of mockedEndpoints) { diff --git a/test/e2e/metrics/permissions-approved.spec.js b/test/e2e/metrics/permissions-approved.spec.js index df479b952..1a7b7cc71 100644 --- a/test/e2e/metrics/permissions-approved.spec.js +++ b/test/e2e/metrics/permissions-approved.spec.js @@ -5,6 +5,7 @@ const { withFixtures, openDapp, unlockWallet, + getEventPayloads, } = require('../helpers'); const FixtureBuilder = require('../fixture-builder'); @@ -43,28 +44,6 @@ async function mockSegment(mockServer) { ]; } -/** - * This method handles getting the mocked requests to the segment server - * - * @param {WebDriver} driver - * @param {import('mockttp').Mockttp} mockedEndpoints - * @returns {import('mockttp/dist/pluggable-admin').MockttpClientResponse[]} - */ -async function getEventPayloads(driver, mockedEndpoints) { - await driver.wait(async () => { - let isPending = true; - for (const mockedEndpoint of mockedEndpoints) { - isPending = await mockedEndpoint.isPending(); - } - return isPending === false; - }, 10000); - const mockedRequests = []; - for (const mockedEndpoint of mockedEndpoints) { - mockedRequests.push(...(await mockedEndpoint.getSeenRequests())); - } - return mockedRequests.map((req) => req.body.json.batch).flat(); -} - describe('Permissions Approved Event', function () { it('Successfully tracked when connecting to dapp', async function () { await withFixtures( diff --git a/test/e2e/tests/metrics.spec.js b/test/e2e/metrics/unlock-wallet.spec.js similarity index 55% rename from test/e2e/tests/metrics.spec.js rename to test/e2e/metrics/unlock-wallet.spec.js index ac99d3fe3..b980b0bb7 100644 --- a/test/e2e/tests/metrics.spec.js +++ b/test/e2e/metrics/unlock-wallet.spec.js @@ -1,8 +1,12 @@ const { strict: assert } = require('assert'); -const { convertToHexValue, withFixtures } = require('../helpers'); +const { + withFixtures, + unlockWallet, + defaultGanacheOptions, +} = require('../helpers'); const FixtureBuilder = require('../fixture-builder'); -describe('Segment metrics', function () { +describe('Unlock wallet', function () { async function mockSegment(mockServer) { return await mockServer .forPost('https://api.segment.io/v1/batch') @@ -14,15 +18,7 @@ describe('Segment metrics', function () { }; }); } - const ganacheOptions = { - accounts: [ - { - secretKey: - '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', - balance: convertToHexValue(25000000000000000000), - }, - ], - }; + it('should send first three Page metric events upon fullscreen page load', async function () { await withFixtures( { @@ -32,14 +28,13 @@ describe('Segment metrics', function () { participateInMetaMetrics: true, }) .build(), - ganacheOptions, + ganacheOptions: defaultGanacheOptions, title: this.test.title, testSpecificMock: mockSegment, }, async ({ driver, mockedEndpoint }) => { await driver.navigate(); - await driver.fill('#password', 'correct horse battery staple'); - await driver.press('#password', driver.Key.ENTER); + await unlockWallet(driver); await driver.wait(async () => { const isPending = await mockedEndpoint.isPending(); return isPending === false; @@ -47,19 +42,17 @@ describe('Segment metrics', function () { const mockedRequests = await mockedEndpoint.getSeenRequests(); assert.equal(mockedRequests.length, 3); const [firstMock, secondMock, thirdMock] = mockedRequests; - let [mockJson] = firstMock.body.json.batch; - let { title, path } = mockJson.context.page; - assert.equal(title, 'Home'); - assert.equal(path, '/'); - [mockJson] = secondMock.body.json.batch; - ({ title, path } = mockJson.context.page); - assert.equal(title, 'Unlock Page'); - assert.equal(path, '/unlock'); - [mockJson] = thirdMock.body.json.batch; - ({ title, path } = mockJson.context.page); - assert.equal(title, 'Home'); - assert.equal(path, '/'); + assertBatchValue(firstMock, 'Home', '/'); + assertBatchValue(secondMock, 'Unlock Page', '/unlock'); + assertBatchValue(thirdMock, 'Home', '/'); }, ); }); }); + +function assertBatchValue(mockRequest, assertedTitle, assertedPath) { + const [mockJson] = mockRequest.body.json.batch; + const { title, path } = mockJson.context.page; + assert.equal(title, assertedTitle); + assert.equal(path, assertedPath); +} diff --git a/test/e2e/metrics/wallet-created.spec.js b/test/e2e/metrics/wallet-created.spec.js index 8b04ee956..c1c573e00 100644 --- a/test/e2e/metrics/wallet-created.spec.js +++ b/test/e2e/metrics/wallet-created.spec.js @@ -48,8 +48,8 @@ async function mockSegment(mockServer) { ]; } -describe('Wallet Created Event', function () { - it('Successfully tracked when onboarding', async function () { +describe('Wallet Created Events', function () { + it('are sent when onboarding user who chooses to opt in metrics', async function () { await withFixtures( { fixtures: new FixtureBuilder({ onboarding: true }) @@ -73,6 +73,7 @@ describe('Wallet Created Event', function () { await onboardingPinExtension(driver); const events = await getEventPayloads(driver, mockedEndpoints); + assert.equal(events.length, 2); assert.deepStrictEqual(events[0].properties, { account_type: 'metamask', category: 'Onboarding', @@ -90,4 +91,36 @@ describe('Wallet Created Event', function () { }, ); }); + + it('are not sent when onboarding user who chooses to opt out metrics', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder({ onboarding: true }) + .withMetaMetricsController({ + metaMetricsId: 'fake-metrics-id', + }) + .build(), + defaultGanacheOptions, + title: this.test.title, + testSpecificMock: mockSegment, + }, + async ({ driver, mockedEndpoint: mockedEndpoints }) => { + await driver.navigate(); + await onboardingBeginCreateNewWallet(driver); + await onboardingChooseMetametricsOption(driver, false); + + await onboardingCreatePassword(driver, WALLET_PASSWORD); + await onboardingRevealAndConfirmSRP(driver); + await onboardingCompleteWalletCreation(driver); + await onboardingPinExtension(driver); + + const mockedRequests = await getEventPayloads( + driver, + mockedEndpoints, + false, + ); + assert.equal(mockedRequests.length, 0); + }, + ); + }); }); diff --git a/ui/pages/onboarding-flow/welcome/welcome.js b/ui/pages/onboarding-flow/welcome/welcome.js index 83b12dbbf..2808a8a1e 100644 --- a/ui/pages/onboarding-flow/welcome/welcome.js +++ b/ui/pages/onboarding-flow/welcome/welcome.js @@ -101,6 +101,7 @@ export default function OnboardingWelcome() { message_title: t('welcomeToMetaMask'), app_version: global?.platform?.getVersion(), }, + addEventBeforeMetricsOptIn: true, }); return (