1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-01 13:47:06 +01:00
metamask-extension/test/e2e/tests/errors.spec.js
Mark Stacey 507c2cb475
Capture Sentry errors prior to initialization (#20265)
* Capture Sentry errors prior to initialization

Sentry errors captured before/during the wallet initialization are
currently not captured because we don't have the controller state yet
to determine whether the user has consented.

The Sentry setup has been updated to check the persisted state for
whether the user has consented, as a fallback in case the controller
state hasn't been initialized yet. This ensures that we capture errors
during initialization if the user has opted in.

* Always await async check for whether the user has opted in

* Remove unused import

* Update JSDoc return type

* Remove unused driver method

* Fix metametrics controller unit tests

* Fix e2e tests

* Fix e2e test on Firefox

* Start session upon install rather than toggle
2023-07-31 18:49:32 -02:30

189 lines
6.4 KiB
JavaScript

const { strict: assert } = require('assert');
const { Browser } = require('selenium-webdriver');
const { convertToHexValue, withFixtures } = require('../helpers');
const FixtureBuilder = require('../fixture-builder');
describe('Sentry errors', function () {
const migrationError =
process.env.SELENIUM_BROWSER === Browser.CHROME
? `Cannot read properties of undefined (reading 'version')`
: 'meta is undefined';
async function mockSentryMigratorError(mockServer) {
return await mockServer
.forPost('https://sentry.io/api/0000000/envelope/')
.withBodyIncluding(migrationError)
.thenCallback(() => {
return {
statusCode: 200,
json: {},
};
});
}
async function mockSentryTestError(mockServer) {
return await mockServer
.forPost('https://sentry.io/api/0000000/envelope/')
.withBodyIncluding('Test Error')
.thenCallback(() => {
return {
statusCode: 200,
json: {},
};
});
}
const ganacheOptions = {
accounts: [
{
secretKey:
'0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC',
balance: convertToHexValue(25000000000000000000),
},
],
};
describe('before initialization', function () {
it('should NOT send error events when participateInMetaMetrics is false', async function () {
await withFixtures(
{
fixtures: {
...new FixtureBuilder()
.withMetaMetricsController({
metaMetricsId: null,
participateInMetaMetrics: false,
})
.build(),
// Intentionally corrupt state to trigger migration error during initialization
meta: undefined,
},
ganacheOptions,
title: this.test.title,
failOnConsoleError: false,
testSpecificMock: mockSentryMigratorError,
},
async ({ driver, mockedEndpoint }) => {
await driver.navigate();
// Wait for Sentry request
await driver.delay(3000);
const isPending = await mockedEndpoint.isPending();
assert.ok(
isPending,
'A request to sentry was sent when it should not have been',
);
},
);
});
it('should send error events', async function () {
await withFixtures(
{
fixtures: {
...new FixtureBuilder()
.withMetaMetricsController({
metaMetricsId: 'fake-metrics-id',
participateInMetaMetrics: true,
})
.build(),
// Intentionally corrupt state to trigger migration error during initialization
meta: undefined,
},
ganacheOptions,
title: this.test.title,
failOnConsoleError: false,
testSpecificMock: mockSentryMigratorError,
},
async ({ driver, mockedEndpoint }) => {
await driver.navigate();
// Wait for Sentry request
await driver.wait(async () => {
const isPending = await mockedEndpoint.isPending();
return isPending === false;
}, 3000);
const [mockedRequest] = await mockedEndpoint.getSeenRequests();
const mockTextBody = mockedRequest.body.text.split('\n');
const mockJsonBody = JSON.parse(mockTextBody[2]);
const { level } = mockJsonBody;
const [{ type, value }] = mockJsonBody.exception.values;
// Verify request
assert.equal(type, 'TypeError');
assert(value.includes(migrationError));
assert.equal(level, 'error');
},
);
});
});
describe('after initialization', function () {
it('should NOT send error events when participateInMetaMetrics is false', async function () {
await withFixtures(
{
fixtures: new FixtureBuilder()
.withMetaMetricsController({
metaMetricsId: null,
participateInMetaMetrics: false,
})
.build(),
ganacheOptions,
title: this.test.title,
failOnConsoleError: false,
testSpecificMock: mockSentryTestError,
},
async ({ driver, mockedEndpoint }) => {
await driver.navigate();
await driver.fill('#password', 'correct horse battery staple');
await driver.press('#password', driver.Key.ENTER);
// Trigger error
driver.executeScript('window.stateHooks.throwTestError()');
driver.delay(3000);
// Wait for Sentry request
const isPending = await mockedEndpoint.isPending();
assert.ok(
isPending,
'A request to sentry was sent when it should not have been',
);
},
);
});
it('should send error events', async function () {
await withFixtures(
{
fixtures: new FixtureBuilder()
.withMetaMetricsController({
metaMetricsId: 'fake-metrics-id',
participateInMetaMetrics: true,
})
.build(),
ganacheOptions,
title: this.test.title,
failOnConsoleError: false,
testSpecificMock: mockSentryTestError,
},
async ({ driver, mockedEndpoint }) => {
await driver.navigate();
await driver.fill('#password', 'correct horse battery staple');
await driver.press('#password', driver.Key.ENTER);
// Trigger error
driver.executeScript('window.stateHooks.throwTestError()');
// Wait for Sentry request
await driver.wait(async () => {
const isPending = await mockedEndpoint.isPending();
return isPending === false;
}, 10000);
const [mockedRequest] = await mockedEndpoint.getSeenRequests();
const mockTextBody = mockedRequest.body.text.split('\n');
const mockJsonBody = JSON.parse(mockTextBody[2]);
const { level, extra } = mockJsonBody;
const [{ type, value }] = mockJsonBody.exception.values;
const { participateInMetaMetrics } = extra.appState.store.metamask;
// Verify request
assert.equal(type, 'TestError');
assert.equal(value, 'Test Error');
assert.equal(level, 'error');
assert.equal(participateInMetaMetrics, true);
},
);
});
});
});