Skip to content
Open
Show file tree
Hide file tree
Changes from 6 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
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ import { AccountsChangedCAEvents } from '../../services/accounts/events/accounts
import { RequestAccountPermissionHandler } from '../../services/web3/handlers/wallet_requestAccountPermission';
import { WalletGetNetworkStateHandler } from '~/services/network/handlers/wallet_getNetworkState';
import { NetworkStateChangedEvents } from '~/services/network/events/networkStateChanged';
import { AvalancheSetLanguageHandler } from '~/services/settings/handlers/avalanche_setLanguage';
import { AvalancheGetSettingsHandler } from '~/services/settings/handlers/avalanche_getSettings';
import { AvalancheSetCurrencyHandler } from '~/services/settings/handlers/avalanche_setCurrency';
import { SettingsUpdatedEventsCore } from '~/services/settings/events/settingsUpdatedEventCore';

/**
* TODO: GENERATE THIS FILE AS PART OF THE BUILD PROCESS
Expand Down Expand Up @@ -88,6 +92,9 @@ const SHARED_HANDLERS = [
token: 'DAppRequestHandler',
useToken: WalletGetNetworkStateHandler,
},
{ token: 'DAppRequestHandler', useToken: AvalancheSetLanguageHandler },
{ token: 'DAppRequestHandler', useToken: AvalancheGetSettingsHandler },
{ token: 'DAppRequestHandler', useToken: AvalancheSetCurrencyHandler },
];

const LEGACY_REQUEST_HANDLERS = [
Expand Down Expand Up @@ -131,5 +138,6 @@ export class DappRequestHandlerRegistry {}
{ token: 'DAppEventEmitter', useToken: ChainChangedEvents },
{ token: 'DAppEventEmitter', useToken: ActionEvents },
{ token: 'DAppEventEmitter', useToken: NetworkStateChangedEvents },
{ token: 'DAppEventEmitter', useToken: SettingsUpdatedEventsCore },
])
export class DappEventEmitterRegistry {}
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,9 @@ const CORE_METHODS = Object.freeze([
DAppProviderRequest.BITCOIN_SEND_TRANSACTION,
DAppProviderRequest.WALLET_RENAME,
DAppProviderRequest.WALLET_GET_NETWORK_STATE,
DAppProviderRequest.AVALANCHE_SET_LANGUAGE,
DAppProviderRequest.AVALANCHE_GET_SETTINGS,
DAppProviderRequest.AVALANCHE_SET_CURRENCY,
]);

export function PermissionMiddleware(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import {
ConnectionInfo,
DAppEventEmitter,
ExtensionConnectionEvent,
SettingsEvents,
Web3Event,
} from '@core/types';
import { isSyncDomain } from '@core/common';
import { EventEmitter } from 'events';
import { SettingsService } from '../SettingsService';
import { singleton } from 'tsyringe';

@singleton()
export class SettingsUpdatedEventsCore implements DAppEventEmitter {
private eventEmitter = new EventEmitter();
private _connectionInfo?: ConnectionInfo;

setConnectionInfo(connectionInfo: ConnectionInfo) {
this._connectionInfo = connectionInfo;
}

constructor(private settingsService: SettingsService) {
this.settingsService.addListener(
SettingsEvents.SETTINGS_UPDATED,
(settings) => {
// Emit web3 event (for dApps) - only for Core Suite domains
if (
this._connectionInfo?.domain &&
isSyncDomain(this._connectionInfo.domain)
) {
this.eventEmitter.emit('update', {
method: Web3Event.SETTINGS_CHANGED,
params: settings,
});
}
},
);
}

addListener(handler: (event: ExtensionConnectionEvent) => void): void {
this.eventEmitter.on('update', handler);
}

removeListener(
handler: (event: ExtensionConnectionEvent<any>) => void,
): void {
this.eventEmitter.off('update', handler);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,284 @@
import {
DAppProviderRequest,
Languages,
CURRENCIES,
SettingsState,
AnalyticsConsent,
} from '@core/types';
import { AvalancheGetSettingsHandler } from './avalanche_getSettings';
import { buildRpcCall } from '@shared/tests/test-utils';
import { SettingsService } from '../SettingsService';

describe('packages/service-worker/src/services/settings/handlers/avalanche_getSettings', () => {
const getSettingsMock = jest.fn();
const settingsServiceMock = {
getSettings: getSettingsMock,
} as unknown as SettingsService;

const handler = new AvalancheGetSettingsHandler(settingsServiceMock);

const createRequest = () => ({
id: '123',
method: DAppProviderRequest.AVALANCHE_GET_SETTINGS,
});

const mockSettingsState: SettingsState = {
currency: CURRENCIES.USD,
customTokens: {},
showTokensWithoutBalances: true,
theme: 'LIGHT',
tokensVisibility: {},
collectiblesVisibility: {},
analyticsConsent: AnalyticsConsent.Approved,
language: Languages.EN,
coreAssistant: true,
preferredView: 'floating',
showTrendingTokens: true,
};

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

describe('handleAuthenticated', () => {
it('should successfully return settings', async () => {
const request = createRequest();
getSettingsMock.mockResolvedValueOnce(mockSettingsState);

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

expect(getSettingsMock).toHaveBeenCalledTimes(1);
expect(getSettingsMock).toHaveBeenCalledWith();
expect(result).toEqual({
...request,
result: mockSettingsState,
});
});

it('should return settings with EUR currency', async () => {
const request = createRequest();
const settingsWithEur = {
...mockSettingsState,
currency: CURRENCIES.EUR,
};
getSettingsMock.mockResolvedValueOnce(settingsWithEur);

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

expect(result).toEqual({
...request,
result: settingsWithEur,
});
});

it('should return settings with dark theme', async () => {
const request = createRequest();
const settingsWithDarkTheme = {
...mockSettingsState,
theme: 'DARK',
};
getSettingsMock.mockResolvedValueOnce(settingsWithDarkTheme);

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

expect(result).toEqual({
...request,
result: settingsWithDarkTheme,
});
});

it('should return settings with different language', async () => {
const request = createRequest();
const settingsWithSpanish = {
...mockSettingsState,
language: Languages.ES,
};
getSettingsMock.mockResolvedValueOnce(settingsWithSpanish);

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

expect(result).toEqual({
...request,
result: settingsWithSpanish,
});
});

it('should return settings with showTokensWithoutBalances false', async () => {
const request = createRequest();
const settingsWithHiddenTokens = {
...mockSettingsState,
showTokensWithoutBalances: false,
};
getSettingsMock.mockResolvedValueOnce(settingsWithHiddenTokens);

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

expect(result).toEqual({
...request,
result: settingsWithHiddenTokens,
});
});

it('should return settings with coreAssistant disabled', async () => {
const request = createRequest();
const settingsWithoutAssistant = {
...mockSettingsState,
coreAssistant: false,
};
getSettingsMock.mockResolvedValueOnce(settingsWithoutAssistant);

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

expect(result).toEqual({
...request,
result: settingsWithoutAssistant,
});
});

it('should return settings with showTrendingTokens false', async () => {
const request = createRequest();
const settingsWithoutTrending = {
...mockSettingsState,
showTrendingTokens: false,
};
getSettingsMock.mockResolvedValueOnce(settingsWithoutTrending);

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

expect(result).toEqual({
...request,
result: settingsWithoutTrending,
});
});

it('should return settings with analytics consent denied', async () => {
const request = createRequest();
const settingsWithDeniedConsent = {
...mockSettingsState,
analyticsConsent: AnalyticsConsent.Denied,
};
getSettingsMock.mockResolvedValueOnce(settingsWithDeniedConsent);

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

expect(result).toEqual({
...request,
result: settingsWithDeniedConsent,
});
});

it('should return settings with analytics consent pending', async () => {
const request = createRequest();
const settingsWithPendingConsent = {
...mockSettingsState,
analyticsConsent: AnalyticsConsent.Pending,
};
getSettingsMock.mockResolvedValueOnce(settingsWithPendingConsent);

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

expect(result).toEqual({
...request,
result: settingsWithPendingConsent,
});
});

it('should return settings with custom tokens', async () => {
const request = createRequest();
const settingsWithCustomTokens = {
...mockSettingsState,
customTokens: {
'43114': {
'0x123': {
address: '0x123',
symbol: 'TEST',
decimals: 18,
},
},
},
};
getSettingsMock.mockResolvedValueOnce(settingsWithCustomTokens);

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

expect(result).toEqual({
...request,
result: settingsWithCustomTokens,
});
});

it('should return settings with tokens visibility configuration', async () => {
const request = createRequest();
const settingsWithVisibility = {
...mockSettingsState,
tokensVisibility: {
'43114': {
'0x123': false,
},
},
};
getSettingsMock.mockResolvedValueOnce(settingsWithVisibility);

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

expect(result).toEqual({
...request,
result: settingsWithVisibility,
});
});

it('should return settings with collectibles visibility configuration', async () => {
const request = createRequest();
const settingsWithCollectiblesVisibility = {
...mockSettingsState,
collectiblesVisibility: {
'43114': {
'0xabc': false,
},
},
};
getSettingsMock.mockResolvedValueOnce(settingsWithCollectiblesVisibility);

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

expect(result).toEqual({
...request,
result: settingsWithCollectiblesVisibility,
});
});

it('should return error when settingsService.getSettings throws an error', async () => {
const request = createRequest();
const error = new Error('Failed to retrieve settings');
getSettingsMock.mockRejectedValueOnce(error);

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

expect(getSettingsMock).toHaveBeenCalledTimes(1);
expect(result).toEqual({
...request,
error: error.toString(),
});
});
});

describe('handleUnauthenticated', () => {
it('should return error when account is not connected', async () => {
const request = createRequest();
const result = await handler.handleUnauthenticated(buildRpcCall(request));

expect(getSettingsMock).not.toHaveBeenCalled();
expect(result).toEqual({
...request,
error: 'account not connected',
});
});

it('should not call getSettings when unauthenticated', async () => {
const request = createRequest();
await handler.handleUnauthenticated(buildRpcCall(request));

expect(getSettingsMock).not.toHaveBeenCalled();
});
});
});
Loading
Loading