Skip to content

Commit

Permalink
fix: (Delete) update tests, logic update in handler, UI update
Browse files Browse the repository at this point in the history
  • Loading branch information
frichards committed Dec 18, 2024
1 parent 6192af5 commit 6fc133f
Show file tree
Hide file tree
Showing 4 changed files with 314 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,63 @@ import { DAppProviderRequest } from '@src/background/connections/dAppConnection/
import { openApprovalWindow } from '@src/background/runtime/openApprovalWindow';
import { DEFERRED_RESPONSE } from '@src/background/connections/middlewares/models';

import { Account } from '../models';
import {
type Accounts,
AccountType,
type ImportedAccount,
type PrimaryAccount,
} from '../models';
import { canSkipApproval } from '@src/utils/canSkipApproval';
import { AvalancheDeleteAccountsHandler } from './avalanche_deleteAccounts';
import type { WalletDetails } from '../../wallet/models';

jest.mock('@src/utils/canSkipApproval');
jest.mock('@src/background/runtime/openApprovalWindow');

describe('src/background/services/accounts/handlers/avalanche_deleteAccounts', () => {
const deleteAccounts = jest.fn();
const getAccountByID = jest.fn();
const getAccounts = jest.fn();

const accountServiceMock = {
getAccountByID,
deleteAccounts,
getAccounts,
} as any;

const getPrimaryWalletsDetails = jest.fn();

const secretsServiceMock = {
getPrimaryWalletsDetails,
} as any;
const wallet = {
id: 'walletId',
name: 'test wallet',
} as WalletDetails;

const primaryAccount = {
id: 'primaryAccountId',
name: 'account name',
walletId: wallet.id,
type: AccountType.PRIMARY,
} as PrimaryAccount;
const primaryAccount2 = {
id: 'primaryAccountId2',
name: 'account name2',
walletId: wallet.id,
type: AccountType.PRIMARY,
} as PrimaryAccount;
const importedAccount = {
id: 'importedAccountId',
name: 'account name',
} as ImportedAccount;

beforeEach(() => {
jest.resetAllMocks();
});

it('returns error when domain info is not known', async () => {
const handler = new AvalancheDeleteAccountsHandler({} as any);
const handler = new AvalancheDeleteAccountsHandler({} as any, {} as any);
const request = {
id: '123',
method: DAppProviderRequest.ACCOUNTS_DELETE,
Expand All @@ -40,26 +75,48 @@ describe('src/background/services/accounts/handlers/avalanche_deleteAccounts', (
});

it('prompts approval for non-core requests', async () => {
const handler = new AvalancheDeleteAccountsHandler(accountServiceMock);
const handler = new AvalancheDeleteAccountsHandler(
accountServiceMock,
secretsServiceMock
);

jest.mocked(canSkipApproval).mockResolvedValueOnce(false);

getAccountByID.mockImplementation((id) => {
if (id === primaryAccount2.id) {
return primaryAccount2;
}
return importedAccount;
});
getAccounts.mockReturnValue({
primary: { [wallet.id]: [primaryAccount, primaryAccount2] },
imported: { [importedAccount.id]: importedAccount },
} as Accounts);

getPrimaryWalletsDetails.mockResolvedValue([wallet]);

const request = {
id: '123',
method: DAppProviderRequest.ACCOUNTS_DELETE,
params: [['accountId']],
params: [[primaryAccount2.id, importedAccount.id]],
site: {
domain: 'google.com',
tabId: 1,
},
} as any;
jest.mocked(canSkipApproval).mockResolvedValueOnce(false);
const account = { id: 'accountId', name: 'account name' } as Account;
getAccountByID.mockReturnValueOnce(account);

const result = await handler.handleAuthenticated(buildRpcCall(request));

expect(openApprovalWindow).toHaveBeenCalledWith(
expect.objectContaining({
displayData: {
accounts: { accountId: { id: 'accountId', name: 'account name' } },
accounts: {
primary: {
[wallet.id]: [primaryAccount2],
},
imported: [importedAccount],
wallet: { [wallet.id]: wallet.name },
},
},
}),
'deleteAccounts'
Expand All @@ -69,50 +126,163 @@ describe('src/background/services/accounts/handlers/avalanche_deleteAccounts', (
});

it('does not prompt approval for core suite', async () => {
const handler = new AvalancheDeleteAccountsHandler(accountServiceMock);
const handler = new AvalancheDeleteAccountsHandler(
accountServiceMock,
secretsServiceMock
);

jest.mocked(canSkipApproval).mockResolvedValueOnce(true);

getAccountByID.mockReturnValueOnce(primaryAccount);
getAccounts.mockReturnValue({
primary: { [wallet.id]: [primaryAccount] },
imported: { [importedAccount.id]: importedAccount },
} as Accounts);

getPrimaryWalletsDetails.mockResolvedValue([wallet]);
const request = {
id: '123',
method: DAppProviderRequest.ACCOUNTS_DELETE,
params: [['accountId']],
params: [[primaryAccount.id]],
site: {
domain: 'core.app',
tabId: 1,
},
} as any;

jest.mocked(canSkipApproval).mockResolvedValueOnce(true);
const account = { id: 'accountId', name: 'old name' } as Account;
getAccountByID.mockReturnValueOnce(account);

const result = await handler.handleAuthenticated(buildRpcCall(request));

expect(openApprovalWindow).not.toHaveBeenCalled();
expect(deleteAccounts).toHaveBeenCalledTimes(1);
expect(deleteAccounts).toHaveBeenCalledWith(['accountId']);
expect(deleteAccounts).toHaveBeenCalledWith([primaryAccount.id]);
expect(result).toEqual({ ...request, result: null });
});

it('returns error when deleting accounts fails', async () => {
jest.mocked(canSkipApproval).mockResolvedValueOnce(true);

const handler = new AvalancheDeleteAccountsHandler({
getAccountByID: jest.fn().mockReturnValueOnce({}),
deleteAccounts: jest.fn().mockRejectedValueOnce(new Error('some error')),
} as any);
const handler = new AvalancheDeleteAccountsHandler(
accountServiceMock,
secretsServiceMock
);

getAccountByID.mockReturnValueOnce(primaryAccount);
getAccounts.mockReturnValue({
primary: { [wallet.id]: [primaryAccount] },
imported: { [importedAccount.id]: importedAccount },
} as Accounts);

getPrimaryWalletsDetails.mockResolvedValue([wallet]);
const request = {
id: '123',
method: DAppProviderRequest.ACCOUNTS_DELETE,
params: [['accountId']],
params: [[primaryAccount.id]],
site: {
domain: 'core.app',
tabId: 1,
},
} as any;

deleteAccounts.mockRejectedValueOnce(new Error('some error'));
const result = await handler.handleAuthenticated(buildRpcCall(request));
expect(result).toEqual({
...request,
error: ethErrors.rpc.internal('Account removing failed'),
});
});

it('returns error when no accounts were found using account IDs in request param', async () => {
jest.mocked(canSkipApproval).mockResolvedValueOnce(true);

const handler = new AvalancheDeleteAccountsHandler(
accountServiceMock,
secretsServiceMock
);

getAccountByID.mockReturnValueOnce(undefined);

const request = {
id: '123',
method: DAppProviderRequest.ACCOUNTS_DELETE,
params: [['wrongId']],
site: {
domain: 'core.app',
tabId: 1,
},
} as any;
const result = await handler.handleAuthenticated(buildRpcCall(request));
expect(result).toEqual({
...request,
error: ethErrors.rpc.internal('No account with specified IDs'),
});
});

it('returns error when all accounts will be deleted', async () => {
jest.mocked(canSkipApproval).mockResolvedValueOnce(true);

const handler = new AvalancheDeleteAccountsHandler(
accountServiceMock,
secretsServiceMock
);

getAccountByID.mockImplementation((id) => {
if (id === primaryAccount.id) {
return primaryAccount;
}
return importedAccount;
});
getAccounts.mockReturnValue({
primary: { [wallet.id]: [primaryAccount] },
imported: { [importedAccount.id]: importedAccount },
} as Accounts);

const request = {
id: '123',
method: DAppProviderRequest.ACCOUNTS_DELETE,
params: [[primaryAccount.id, importedAccount.id]],
site: {
domain: 'core.app',
tabId: 1,
},
} as any;
const result = await handler.handleAuthenticated(buildRpcCall(request));
expect(result).toEqual({
...request,
error: ethErrors.rpc.internal('Cannot delete all accounts'),
});
});

it('returns error when requested account is not the last index in the wallet', async () => {
const handler = new AvalancheDeleteAccountsHandler(
accountServiceMock,
secretsServiceMock
);

jest.mocked(canSkipApproval).mockResolvedValueOnce(false);

getAccountByID.mockReturnValue(primaryAccount);
getAccounts.mockReturnValue({
primary: { [wallet.id]: [primaryAccount, primaryAccount2] },
imported: {},
} as Accounts);

getPrimaryWalletsDetails.mockResolvedValue([wallet]);

const request = {
id: '123',
method: DAppProviderRequest.ACCOUNTS_DELETE,
params: [[primaryAccount.id]],
site: {
domain: 'google.com',
tabId: 1,
},
} as any;

const result = await handler.handleAuthenticated(buildRpcCall(request));
expect(result).toEqual({
...request,
error: ethErrors.rpc.internal(
'Only the last account of the wallet can be removed'
),
});
});
});
Loading

0 comments on commit 6fc133f

Please sign in to comment.