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
4 changes: 4 additions & 0 deletions packages/snap-account-service/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- We now check if the keyring is available before delegating those messages.
- We still auto-create the keyring in some specific calls (e.g `notify:accountCreated`).

## Removed

- Removed `init` in favor of synchronous initialization when constructing the service ([#8877](https://github.com/MetaMask/core/pull/8877))

## [0.2.0]

### Added
Expand Down
34 changes: 1 addition & 33 deletions packages/snap-account-service/src/SnapAccountService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -472,22 +472,12 @@ function setup({
const MOCK_SNAP_ID = 'npm:@metamask/mock-snap' as SnapId;

describe('SnapAccountService', () => {
describe('init', () => {
it('resolves without throwing', async () => {
const { service } = setup();

expect(await service.init()).toBeUndefined();
});
});

describe('getSnaps', () => {
it('exposes tracked Snaps seeded by init', async () => {
it('exposes tracked Snaps seeded from construction', () => {
const { service } = setup({
runnableSnaps: [buildSnap(MOCK_SNAP_ID, true)],
});

await service.init();

expect(service.getSnaps()).toStrictEqual([MOCK_SNAP_ID]);
});
});
Expand All @@ -496,18 +486,6 @@ describe('SnapAccountService', () => {
it('throws when the Snap is not tracked', async () => {
const { service } = setup();

await service.init();

await expect(service.ensureReady(MOCK_SNAP_ID)).rejects.toThrow(
`Unknown snap: "${MOCK_SNAP_ID}"`,
);
});

it('throws before init even for runnable Snaps', async () => {
const { service } = setup({
runnableSnaps: [buildSnap(MOCK_SNAP_ID, true)],
});

await expect(service.ensureReady(MOCK_SNAP_ID)).rejects.toThrow(
`Unknown snap: "${MOCK_SNAP_ID}"`,
);
Expand All @@ -518,8 +496,6 @@ describe('SnapAccountService', () => {
runnableSnaps: [buildSnap(MOCK_SNAP_ID, true)],
});

await service.init();

expect(await service.ensureReady(MOCK_SNAP_ID)).toBeUndefined();
});

Expand All @@ -529,8 +505,6 @@ describe('SnapAccountService', () => {
runnableSnaps: [buildSnap(MOCK_SNAP_ID, true)],
});

await service.init();

let resolved = false;
const ensurePromise = service.ensureReady(MOCK_SNAP_ID).then(() => {
resolved = true;
Expand All @@ -551,8 +525,6 @@ describe('SnapAccountService', () => {
runnableSnaps: [buildSnap(MOCK_SNAP_ID, true)],
});

await service.init();

let resolved = false;
const ensurePromise = service.ensureReady(MOCK_SNAP_ID).then(() => {
resolved = true;
Expand Down Expand Up @@ -580,8 +552,6 @@ describe('SnapAccountService', () => {
},
});

await service.init();

jest.useFakeTimers();
const ensurePromise = service.ensureReady(MOCK_SNAP_ID);
// Attach rejection handler before advancing timers to avoid unhandled rejection.
Expand Down Expand Up @@ -610,8 +580,6 @@ describe('SnapAccountService', () => {
config: { snapPlatformWatcher: { ensureOnboardingComplete } },
});

await service.init();

let resolved = false;
const ensurePromise = service.ensureReady(MOCK_SNAP_ID).then(() => {
resolved = true;
Expand Down
11 changes: 0 additions & 11 deletions packages/snap-account-service/src/SnapAccountService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -267,17 +267,6 @@ export class SnapAccountService {
}
}

/**
* Initializes the snap account service.
*
* Seeds the internal set of account-management Snaps from
* `SnapController:getRunnableSnaps`, then starts processing lifecycle
* events.
*/
async init(): Promise<void> {
await this.#tracker.init();
}

/**
* Returns the IDs of all currently tracked account-management Snaps —
* Snaps that are installed, enabled, not blocked, and have the
Expand Down
113 changes: 16 additions & 97 deletions packages/snap-account-service/src/SnapTracker.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,168 +206,91 @@ const MOCK_SNAP_ID = 'npm:@metamask/mock-snap' as SnapId;
const MOCK_OTHER_SNAP_ID = 'npm:@metamask/other-snap' as SnapId;

describe('SnapTracker', () => {
describe('init', () => {
it('resolves without throwing', async () => {
const { tracker } = setup();

expect(await tracker.init()).toBeUndefined();
});

it('does not re-init if already initialized', async () => {
const { tracker, mocks } = setup();

expect(await tracker.init()).toBeUndefined();
expect(mocks.SnapController.getRunnableSnaps).toHaveBeenCalledTimes(1);

expect(await tracker.init()).toBeUndefined();
expect(mocks.SnapController.getRunnableSnaps).toHaveBeenCalledTimes(1); // Still only called once.
});

it('seeds tracked Snaps from getRunnableSnaps, filtering out non-keyring Snaps', async () => {
describe('getSnaps', () => {
it('returns seeded Snaps from construction, filtering out non-keyring Snaps', () => {
const { tracker } = setup({
runnableSnaps: [
buildSnap(MOCK_SNAP_ID, true),
buildSnap(MOCK_OTHER_SNAP_ID, false),
],
});

await tracker.init();

expect(tracker.getSnaps()).toStrictEqual([MOCK_SNAP_ID]);
});
});

describe('getSnaps', () => {
it('returns an empty array before init', () => {
const { tracker } = setup({
runnableSnaps: [buildSnap(MOCK_SNAP_ID, true)],
});
it('returns an empty array when there are no runnable account-management Snaps', () => {
const { tracker } = setup();

expect(tracker.getSnaps()).toStrictEqual([]);
});
});

describe('canUse', () => {
it('returns false before init', () => {
const { tracker } = setup({
runnableSnaps: [buildSnap(MOCK_SNAP_ID, true)],
});

expect(tracker.canUse(MOCK_SNAP_ID)).toBe(false);
});

it('returns true for a tracked Snap', async () => {
it('returns true for a Snap seeded during construction', () => {
const { tracker } = setup({
runnableSnaps: [buildSnap(MOCK_SNAP_ID, true)],
});

await tracker.init();

expect(tracker.canUse(MOCK_SNAP_ID)).toBe(true);
});

it('returns false for an untracked Snap', async () => {
it('returns false for an untracked Snap', () => {
const { tracker } = setup();

await tracker.init();

expect(tracker.canUse(MOCK_SNAP_ID)).toBe(false);
});
});

describe('lifecycle events', () => {
it('ignores add events received before init', async () => {
const { tracker, rootMessenger } = setup();

publishSnapInstalled(rootMessenger, buildSnap(MOCK_SNAP_ID, true));

await tracker.init();

expect(tracker.getSnaps()).toStrictEqual([]);
});

it('ignores remove events received before init', async () => {
const { tracker, rootMessenger } = setup({
runnableSnaps: [buildSnap(MOCK_SNAP_ID, true)],
});

publishSnapUninstalled(rootMessenger, buildSnap(MOCK_SNAP_ID, true));

await tracker.init();

expect(tracker.getSnaps()).toStrictEqual([MOCK_SNAP_ID]);
});

it('adds a Snap on snapInstalled when it has the keyring endowment', async () => {
it('adds a Snap on snapInstalled when it has the keyring endowment', () => {
const { tracker, rootMessenger } = setup();

await tracker.init();
publishSnapInstalled(rootMessenger, buildSnap(MOCK_SNAP_ID, true));

expect(tracker.getSnaps()).toStrictEqual([MOCK_SNAP_ID]);
});

it('does not add a Snap on snapInstalled when it lacks the keyring endowment', async () => {
it('does not add a Snap on snapInstalled when it lacks the keyring endowment', () => {
const { tracker, rootMessenger } = setup();

await tracker.init();
publishSnapInstalled(rootMessenger, buildSnap(MOCK_SNAP_ID, false));

expect(tracker.getSnaps()).toStrictEqual([]);
});

it('adds a Snap on snapEnabled when it has the keyring endowment', async () => {
it('adds a Snap on snapEnabled when it has the keyring endowment', () => {
const { tracker, rootMessenger } = setup();

await tracker.init();
publishSnapEnabled(rootMessenger, buildSnap(MOCK_SNAP_ID, true));

expect(tracker.getSnaps()).toStrictEqual([MOCK_SNAP_ID]);
});

it('removes a Snap on snapDisabled', async () => {
it('removes a Snap on snapDisabled', () => {
const { tracker, rootMessenger } = setup({
runnableSnaps: [buildSnap(MOCK_SNAP_ID, true)],
});

await tracker.init();
expect(tracker.getSnaps()).toStrictEqual([MOCK_SNAP_ID]);

publishSnapDisabled(rootMessenger, buildSnap(MOCK_SNAP_ID, true));

expect(tracker.getSnaps()).toStrictEqual([]);
});

it('removes a Snap on snapBlocked', async () => {
it('removes a Snap on snapBlocked', () => {
const { tracker, rootMessenger } = setup({
runnableSnaps: [buildSnap(MOCK_SNAP_ID, true)],
});

await tracker.init();
publishSnapBlocked(rootMessenger, MOCK_SNAP_ID);

expect(tracker.getSnaps()).toStrictEqual([]);
});

it('ignores snapUnblocked received before init', async () => {
const { tracker, rootMessenger, mocks } = setup();

mocks.SnapController.getSnap.mockReturnValue({
...buildSnap(MOCK_SNAP_ID, true),
enabled: true,
blocked: false,
} as TruncatedSnap);
publishSnapUnblocked(rootMessenger, MOCK_SNAP_ID);

await tracker.init();

expect(tracker.getSnaps()).toStrictEqual([]);
});

it('re-adds a Snap on snapUnblocked when it is enabled and has the keyring endowment', async () => {
it('re-adds a Snap on snapUnblocked when it is enabled and has the keyring endowment', () => {
const { tracker, rootMessenger, mocks } = setup();

await tracker.init();
mocks.SnapController.getSnap.mockReturnValue({
...buildSnap(MOCK_SNAP_ID, true),
enabled: true,
Expand All @@ -379,10 +302,9 @@ describe('SnapTracker', () => {
expect(tracker.getSnaps()).toStrictEqual([MOCK_SNAP_ID]);
});

it('does not re-add a Snap on snapUnblocked when it is disabled', async () => {
it('does not re-add a Snap on snapUnblocked when it is disabled', () => {
const { tracker, rootMessenger, mocks } = setup();

await tracker.init();
mocks.SnapController.getSnap.mockReturnValue({
...buildSnap(MOCK_SNAP_ID, true),
enabled: false,
Expand All @@ -394,10 +316,9 @@ describe('SnapTracker', () => {
expect(tracker.getSnaps()).toStrictEqual([]);
});

it('does not re-add a Snap on snapUnblocked when it lacks the keyring endowment', async () => {
it('does not re-add a Snap on snapUnblocked when it lacks the keyring endowment', () => {
const { tracker, rootMessenger, mocks } = setup();

await tracker.init();
mocks.SnapController.getSnap.mockReturnValue({
...buildSnap(MOCK_SNAP_ID, false),
enabled: true,
Expand All @@ -409,21 +330,19 @@ describe('SnapTracker', () => {
expect(tracker.getSnaps()).toStrictEqual([]);
});

it('does not re-add a Snap on snapUnblocked when getSnap returns null', async () => {
it('does not re-add a Snap on snapUnblocked when getSnap returns null', () => {
const { tracker, rootMessenger } = setup();

await tracker.init();
publishSnapUnblocked(rootMessenger, MOCK_SNAP_ID);

expect(tracker.getSnaps()).toStrictEqual([]);
});

it('removes a Snap on snapUninstalled', async () => {
it('removes a Snap on snapUninstalled', () => {
const { tracker, rootMessenger } = setup({
runnableSnaps: [buildSnap(MOCK_SNAP_ID, true)],
});

await tracker.init();
publishSnapUninstalled(rootMessenger, buildSnap(MOCK_SNAP_ID, true));

expect(tracker.getSnaps()).toStrictEqual([]);
Expand Down
Loading
Loading