Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion packages/eth-json-rpc-middleware/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@
},
"devDependencies": {
"@metamask/auto-changelog": "^3.4.4",
"@metamask/error-reporting-service": "^3.0.1",
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This dependency wasn't used at all.

"@metamask/network-controller": "^27.1.0",
"@ts-bridge/cli": "^0.6.4",
"@types/deep-freeze-strict": "^1.1.0",
Expand Down
10 changes: 2 additions & 8 deletions packages/gas-fee-controller/src/GasFeeController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,7 @@ const getRootMessenger = (): RootMessenger => {
MessengerActions<NetworkControllerMessenger>,
MessengerEvents<NetworkControllerMessenger>
>({ namespace: MOCK_ANY_NAMESPACE });
rootMessenger.registerActionHandler(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was only added to the test messenger, the controller doesn't actually use captureException.

'ErrorReportingService:captureException',
jest.fn(),
);

return rootMessenger;
};

Expand All @@ -93,10 +90,7 @@ const setupNetworkController = async ({
>({
namespace: 'NetworkController',
parent: rootMessenger,
});
rootMessenger.delegate({
messenger: networkControllerMessenger,
actions: ['ErrorReportingService:captureException'],
captureException: jest.fn(),
});

const infuraProjectId = '123';
Expand Down
5 changes: 5 additions & 0 deletions packages/multichain-account-service/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed

- Remove dependency on `@metamask/error-reporting-service` ([#7542](https://github.com/MetaMask/core/pull/7542))
- The service no longer needs `ErrorReportingService:captureException`.

## [4.1.0]

### Added
Expand Down
1 change: 0 additions & 1 deletion packages/multichain-account-service/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@
"@ethereumjs/util": "^9.1.0",
"@metamask/accounts-controller": "^35.0.0",
"@metamask/base-controller": "^9.0.0",
"@metamask/error-reporting-service": "^3.0.1",
"@metamask/eth-snap-keyring": "^18.0.0",
"@metamask/key-tree": "^10.1.1",
"@metamask/keyring-api": "^21.0.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,6 @@ function setup({
});

const serviceMessenger = getMultichainAccountServiceMessenger(messenger);
messenger.registerActionHandler(
'ErrorReportingService:captureException',
jest.fn(),
);

const wallet = new MultichainAccountWallet<Bip44Account<InternalAccount>>({
entropySource: MOCK_WALLET_1_ENTROPY_SOURCE,
Expand Down Expand Up @@ -228,13 +224,15 @@ describe('MultichainAccount', () => {
});
const providerError = new Error('Unable to create accounts');
providers[1].createAccounts.mockRejectedValueOnce(providerError);
const callSpy = jest.spyOn(messenger, 'call');
const captureExceptionSpy = jest.spyOn(messenger, 'captureException');
await group.alignAccounts();
expect(callSpy).toHaveBeenCalledWith(
'ErrorReportingService:captureException',
expect(captureExceptionSpy).toHaveBeenCalledWith(
new Error('Unable to align accounts with provider "Mocked Provider"'),
);
expect(callSpy.mock.lastCall[1]).toHaveProperty('cause', providerError);
expect(captureExceptionSpy.mock.lastCall[0]).toHaveProperty(
'cause',
providerError,
);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -265,10 +265,7 @@ export class MultichainAccountGroup<
provider: provider.getName(),
},
);
this.#messenger.call(
'ErrorReportingService:captureException',
sentryError,
);
this.#messenger.captureException?.(sentryError);
throw error;
}
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1041,6 +1041,8 @@ describe('MultichainAccountService', () => {

it('does not throw if any providers is throwing', async () => {
const rootMessenger = getRootMessenger();
const captureExceptionSpy = jest.spyOn(rootMessenger, 'captureException');

const { service, mocks } = await setup({
rootMessenger,
accounts: [MOCK_HD_ACCOUNT_1],
Expand All @@ -1049,19 +1051,13 @@ describe('MultichainAccountService', () => {
const providerError = new Error('Unable to resync accounts');
mocks.SolAccountProvider.resyncAccounts.mockRejectedValue(providerError);

const mockCaptureException = jest.fn();
rootMessenger.registerActionHandler(
'ErrorReportingService:captureException',
mockCaptureException,
);

await service.resyncAccounts(); // Should not throw.

expect(mocks.EvmAccountProvider.resyncAccounts).toHaveBeenCalled();
expect(mocks.SolAccountProvider.resyncAccounts).toHaveBeenCalled();

expect(mockCaptureException).toHaveBeenCalled();
expect(mockCaptureException.mock.lastCall[0]).toHaveProperty(
expect(captureExceptionSpy).toHaveBeenCalled();
expect(captureExceptionSpy.mock.lastCall[0]).toHaveProperty(
'cause',
providerError,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -254,10 +254,7 @@ export class MultichainAccountService {
const sentryError = createSentryError(errorMessage, error as Error, {
provider: provider.getName(),
});
this.#messenger.call(
'ErrorReportingService:captureException',
sentryError,
);
this.#messenger.captureException?.(sentryError);
}
}),
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,6 @@ function setup({

const serviceMessenger = getMultichainAccountServiceMessenger(messenger);

messenger.registerActionHandler(
'ErrorReportingService:captureException',
jest.fn(),
);

const wallet = new MultichainAccountWallet<Bip44Account<InternalAccount>>({
entropySource,
providers,
Expand Down Expand Up @@ -373,17 +368,19 @@ describe('MultichainAccountWallet', () => {
const [provider] = providers;
const providerError = new Error('Unable to create accounts');
provider.createAccounts.mockRejectedValueOnce(providerError);
const callSpy = jest.spyOn(messenger, 'call');
const captureExceptionSpy = jest.spyOn(messenger, 'captureException');
await expect(
wallet.createMultichainAccountGroup(groupIndex),
).rejects.toThrow(
'Unable to create multichain account group for index: 1',
);
expect(callSpy).toHaveBeenCalledWith(
'ErrorReportingService:captureException',
expect(captureExceptionSpy).toHaveBeenCalledWith(
new Error('Unable to create account with provider "Mocked Provider 0"'),
);
expect(callSpy.mock.lastCall[1]).toHaveProperty('cause', providerError);
expect(captureExceptionSpy.mock.lastCall[0]).toHaveProperty(
'cause',
providerError,
);
});

it('aggregates non-EVM failures when waiting for all providers', async () => {
Expand Down Expand Up @@ -732,15 +729,17 @@ describe('MultichainAccountWallet', () => {
});
const providerError = new Error('Unable to discover accounts');
providers[0].discoverAccounts.mockRejectedValueOnce(providerError);
const callSpy = jest.spyOn(messenger, 'call');
const captureExceptionSpy = jest.spyOn(messenger, 'captureException');
// Ensure the other provider stops immediately to finish the Promise.all
providers[1].discoverAccounts.mockResolvedValueOnce([]);
await wallet.discoverAccounts();
expect(callSpy).toHaveBeenCalledWith(
'ErrorReportingService:captureException',
expect(captureExceptionSpy).toHaveBeenCalledWith(
new Error('Unable to discover accounts'),
);
expect(callSpy.mock.lastCall[1]).toHaveProperty('cause', providerError);
expect(captureExceptionSpy.mock.lastCall[0]).toHaveProperty(
'cause',
providerError,
);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -259,10 +259,7 @@ export class MultichainAccountWallet<
provider: provider.getName(),
},
);
this.#messenger.call(
'ErrorReportingService:captureException',
sentryError,
);
this.#messenger.captureException?.(sentryError);
throw error;
}),
);
Expand Down Expand Up @@ -301,10 +298,7 @@ export class MultichainAccountWallet<
provider: provider.getName(),
},
);
this.#messenger.call(
'ErrorReportingService:captureException',
sentryError,
);
this.#messenger.captureException?.(sentryError);
});
});
}
Expand Down Expand Up @@ -448,10 +442,7 @@ export class MultichainAccountWallet<
provider: evmProvider.getName(),
},
);
this.#messenger.call(
'ErrorReportingService:captureException',
sentryError,
);
this.#messenger.captureException?.(sentryError);
throw new Error(errorMessage);
}

Expand Down Expand Up @@ -624,10 +615,7 @@ export class MultichainAccountWallet<
groupIndex: targetGroupIndex,
},
);
this.#messenger.call(
'ErrorReportingService:captureException',
sentryError,
);
this.#messenger.captureException?.(sentryError);
break;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -608,23 +608,18 @@ describe('SnapAccountProvider', () => {

it('creates new accounts if de-synced', async () => {
const { provider, messenger } = setup();
const captureExceptionSpy = jest.spyOn(messenger, 'captureException');
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Test spy timing prevents capturing captureException calls

The setup() function creates serviceMessenger as a child of the root messenger, at which point serviceMessenger.captureException is assigned a reference to the original jest.fn(). The setup() returns the root messenger, not serviceMessenger. When the test creates jest.spyOn(messenger, 'captureException') AFTER setup, it replaces the root messenger's property, but serviceMessenger.captureException still holds the original function reference. Since the provider uses serviceMessenger, the spy never captures the calls, causing test assertions to fail. This differs from the working pattern in MultichainAccountGroup.test.ts and MultichainAccountWallet.test.ts where setup() returns serviceMessenger directly.

Additional Locations (2)

Fix in Cursor Fix in Web


messenger.registerActionHandler(
'SnapController:handleRequest',
jest.fn().mockResolvedValue([mockAccounts[0]].map(asKeyringAccount)),
);

const mockCaptureException = jest.fn();
messenger.registerActionHandler(
'ErrorReportingService:captureException',
mockCaptureException,
);

const createAccountsSpy = jest.spyOn(provider, 'createAccounts');

await provider.resyncAccounts(mockAccounts);

expect(mockCaptureException).toHaveBeenCalledWith(
expect(captureExceptionSpy).toHaveBeenCalledWith(
new Error(
`Snap "${TEST_SNAP_ID}" has de-synced accounts, we'll attempt to re-sync them...`,
),
Expand All @@ -639,21 +634,16 @@ describe('SnapAccountProvider', () => {

it('reports an error if a Snap has more accounts than MetaMask', async () => {
const { provider, messenger } = setup();
const captureExceptionSpy = jest.spyOn(messenger, 'captureException');

messenger.registerActionHandler(
'SnapController:handleRequest',
jest.fn().mockResolvedValue(mockAccounts.map(asKeyringAccount)),
);

const mockCaptureException = jest.fn();
messenger.registerActionHandler(
'ErrorReportingService:captureException',
mockCaptureException,
);

await provider.resyncAccounts([mockAccounts[0]]); // Less accounts than the Snap

expect(mockCaptureException).toHaveBeenCalledWith(
expect(captureExceptionSpy).toHaveBeenCalledWith(
new Error(
`Snap "${TEST_SNAP_ID}" has de-synced accounts, Snap has more accounts than MetaMask!`,
),
Expand All @@ -662,18 +652,13 @@ describe('SnapAccountProvider', () => {

it('does not throw errors if any provider is not able to re-sync', async () => {
const { provider, messenger } = setup();
const captureExceptionSpy = jest.spyOn(messenger, 'captureException');

messenger.registerActionHandler(
'SnapController:handleRequest',
jest.fn().mockResolvedValue([mockAccounts[0]].map(asKeyringAccount)),
);

const mockCaptureException = jest.fn();
messenger.registerActionHandler(
'ErrorReportingService:captureException',
mockCaptureException,
);

const createAccountsSpy = jest.spyOn(provider, 'createAccounts');

const providerError = new Error('Unable to create accounts');
Expand All @@ -683,17 +668,17 @@ describe('SnapAccountProvider', () => {

expect(createAccountsSpy).toHaveBeenCalled();

expect(mockCaptureException).toHaveBeenNthCalledWith(
expect(captureExceptionSpy).toHaveBeenNthCalledWith(
1,
new Error(
`Snap "${TEST_SNAP_ID}" has de-synced accounts, we'll attempt to re-sync them...`,
),
);
expect(mockCaptureException).toHaveBeenNthCalledWith(
expect(captureExceptionSpy).toHaveBeenNthCalledWith(
2,
new Error('Unable to re-sync account: 0'),
);
expect(mockCaptureException.mock.lastCall[0]).toHaveProperty(
expect(captureExceptionSpy.mock.lastCall[0]).toHaveProperty(
'cause',
providerError,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,7 @@ export abstract class SnapAccountProvider extends BaseBip44AccountProvider {
// NOTE: This should never happen, but we want to report that kind of errors still
// in case states are de-sync.
if (localSnapAccounts.length < snapAccounts.size) {
this.messenger.call(
'ErrorReportingService:captureException',
this.messenger.captureException?.(
new Error(
`Snap "${this.snapId}" has de-synced accounts, Snap has more accounts than MetaMask!`,
),
Expand All @@ -163,8 +162,7 @@ export abstract class SnapAccountProvider extends BaseBip44AccountProvider {
if (localSnapAccounts.length > snapAccounts.size) {
// Accounts should never really be de-synced, so we want to log this to see how often this
// happens, cause that means that something else is buggy elsewhere...
this.messenger.call(
'ErrorReportingService:captureException',
this.messenger.captureException?.(
new Error(
`Snap "${this.snapId}" has de-synced accounts, we'll attempt to re-sync them...`,
),
Expand Down Expand Up @@ -200,10 +198,7 @@ export abstract class SnapAccountProvider extends BaseBip44AccountProvider {
groupIndex,
},
);
this.messenger.call(
'ErrorReportingService:captureException',
sentryError,
);
this.messenger.captureException?.(sentryError);
}
}),
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export type RootMessenger = Messenger<
export function getRootMessenger(): RootMessenger {
return new Messenger({
namespace: MOCK_ANY_NAMESPACE,
captureException: jest.fn(),
});
}

Expand Down Expand Up @@ -54,7 +55,6 @@ export function getMultichainAccountServiceMessenger(
'AccountsController:getAccount',
'AccountsController:getAccountByAddress',
'AccountsController:listMultichainAccounts',
'ErrorReportingService:captureException',
'SnapController:handleRequest',
'KeyringController:withKeyring',
'KeyringController:getState',
Expand Down
Loading
Loading