Skip to content

Commit

Permalink
test: update tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Prithpal-Sooriya committed Dec 18, 2024
1 parent 5b9d745 commit 6ddd4ed
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type {
} from '@metamask/keyring-controller';
import type { UserStorageController } from '@metamask/profile-sync-controller';
import { AuthenticationController } from '@metamask/profile-sync-controller';
import log from 'loglevel';

import { createMockSnapNotification } from './__fixtures__';
import {
Expand Down Expand Up @@ -36,6 +37,8 @@ import type {
NotificationServicesPushControllerEnablePushNotifications,
NotificationServicesPushControllerDisablePushNotifications,
NotificationServicesPushControllerUpdateTriggerPushNotifications,
NotificationServicesControllerMessenger,
NotificationServicesControllerState,
} from './NotificationServicesController';
import { processFeatureAnnouncement } from './processors';
import { processNotification } from './processors/process-notifications';
Expand All @@ -55,6 +58,11 @@ const featureAnnouncementsEnv = {
platform: 'extension' as const,
};

// Testing util to clean up verbose logs when testing errors
const mockErrorLog = () =>
jest.spyOn(log, 'error').mockImplementation(jest.fn());
const mockWarnLog = () => jest.spyOn(log, 'warn').mockImplementation(jest.fn());

describe('metamask-notifications - constructor()', () => {
const arrangeMocks = () => {
const messengerMocks = mockNotificationMessenger();
Expand Down Expand Up @@ -294,6 +302,7 @@ describe('metamask-notifications - createOnChainTriggers()', () => {

it('throws if not given a valid auth & storage key', async () => {
const mocks = arrangeMocks();
mockErrorLog();
const controller = new NotificationServicesController({
messenger: mocks.messenger,
env: { featureAnnouncements: featureAnnouncementsEnv },
Expand Down Expand Up @@ -377,6 +386,7 @@ describe('metamask-notifications - deleteOnChainTriggersByAccount', () => {

it('throws errors when invalid auth and storage', async () => {
const mocks = arrangeMocks();
mockErrorLog();
const controller = new NotificationServicesController({
messenger: mocks.messenger,
env: { featureAnnouncements: featureAnnouncementsEnv },
Expand Down Expand Up @@ -431,6 +441,7 @@ describe('metamask-notifications - updateOnChainTriggersByAccount()', () => {

it('throws errors when invalid auth and storage', async () => {
const mocks = arrangeMocks();
mockErrorLog();
const controller = new NotificationServicesController({
messenger: mocks.messenger,
env: { featureAnnouncements: featureAnnouncementsEnv },
Expand Down Expand Up @@ -477,68 +488,87 @@ describe('metamask-notifications - fetchAndUpdateMetamaskNotifications()', () =>
};
};

it('processes and shows feature announcements, wallet and snap notifications', async () => {
const {
messenger,
mockFeatureAnnouncementAPIResult,
mockListNotificationsAPIResult,
} = arrangeMocks();

const snapNotification = createMockSnapNotification();
const processedSnapNotification = processSnapNotification(snapNotification);

const arrangeController = (
messenger: NotificationServicesControllerMessenger,
overrideState?: Partial<NotificationServicesControllerState>,
) => {
const controller = new NotificationServicesController({
messenger,
env: { featureAnnouncements: featureAnnouncementsEnv },
state: {
...defaultState,
isNotificationServicesEnabled: true,
isFeatureAnnouncementsEnabled: true,
metamaskNotificationsList: [processedSnapNotification],
...overrideState,
},
});

return controller;
};

it('processes and shows all notifications (announcements, wallet, and snap notifications)', async () => {
const { messenger } = arrangeMocks();
const controller = arrangeController(messenger, {
metamaskNotificationsList: [
processSnapNotification(createMockSnapNotification()),
],
});

const result = await controller.fetchAndUpdateMetamaskNotifications();

// Should have 1 feature announcement and 1 wallet notification
expect(result).toHaveLength(3);
// Should have 1 feature announcement
expect(
result.find(
(n) => n.id === mockFeatureAnnouncementAPIResult.items?.[0].fields.id,
),
).toBeDefined();
result.filter((n) => n.type === TRIGGER_TYPES.FEATURES_ANNOUNCEMENT),
).toHaveLength(1);

// Should have 1 Wallet Notification
expect(
result.find((n) => n.id === mockListNotificationsAPIResult[0].id),
).toBeDefined();
expect(result.find((n) => n.type === TRIGGER_TYPES.SNAP)).toBeDefined();
result.filter((n) => n.type === TRIGGER_TYPES.ETH_SENT),
).toHaveLength(1);

// State is also updated
expect(controller.state.metamaskNotificationsList).toHaveLength(3);
});
// Should have 1 Snap Notification
expect(result.filter((n) => n.type === TRIGGER_TYPES.SNAP)).toHaveLength(1);

it('only fetches and processes feature announcements if not authenticated', async () => {
const { messenger, mockGetBearerToken, mockFeatureAnnouncementAPIResult } =
arrangeMocks();
mockGetBearerToken.mockRejectedValue(
new Error('MOCK - failed to get access token'),
);
// Total notification length = 3
expect(result).toHaveLength(3);
});

const controller = new NotificationServicesController({
messenger,
env: { featureAnnouncements: featureAnnouncementsEnv },
state: { ...defaultState, isFeatureAnnouncementsEnabled: true },
it('does not fetch feature announcements or wallet notifications if notifications are disabled globally', async () => {
const { messenger, ...mocks } = arrangeMocks();
const controller = arrangeController(messenger, {
isNotificationServicesEnabled: false,
metamaskNotificationsList: [
processSnapNotification(createMockSnapNotification()),
],
});

// Should only have feature announcement
const result = await controller.fetchAndUpdateMetamaskNotifications();

// Should only contain snap notification
// As this is not controlled by the global notification switch
expect(result).toHaveLength(1);
expect(result.filter((n) => n.type === TRIGGER_TYPES.SNAP)).toHaveLength(1);

// APIs should not have been called
expect(mocks.mockFeatureAnnouncementsAPI.isDone()).toBe(false);
expect(mocks.mockListNotificationsAPI.isDone()).toBe(false);
});

it('should not fetch feature announcements if disabled', async () => {
const { messenger, ...mocks } = arrangeMocks();
const controller = arrangeController(messenger, {
isFeatureAnnouncementsEnabled: false,
});

const result = await controller.fetchAndUpdateMetamaskNotifications();

// Should not have any feature announcements
expect(
result.find(
(n) => n.id === mockFeatureAnnouncementAPIResult.items?.[0].fields.id,
),
).toBeDefined();
result.filter((n) => n.type === TRIGGER_TYPES.FEATURES_ANNOUNCEMENT),
).toHaveLength(0);

// State is also updated
expect(controller.state.metamaskNotificationsList).toHaveLength(1);
// Should not have called feature announcement API
expect(mocks.mockFeatureAnnouncementsAPI.isDone()).toBe(false);
});
});

Expand Down Expand Up @@ -720,6 +750,8 @@ describe('metamask-notifications - markMetamaskNotificationsAsRead()', () => {
messenger,
env: { featureAnnouncements: featureAnnouncementsEnv },
});
mockErrorLog();
mockWarnLog();

await controller.markMetamaskNotificationsAsRead([
processNotification(createMockFeatureAnnouncementRaw()),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ControllerMessenger } from '@metamask/base-controller';
import type { AuthenticationController } from '@metamask/profile-sync-controller';
import log from 'loglevel';

import NotificationServicesPushController from './NotificationServicesPushController';
import type {
Expand All @@ -10,6 +11,10 @@ import type {
import * as services from './services/services';
import type { PushNotificationEnv } from './types';

// Testing util to clean up verbose logs when testing errors
const mockErrorLog = () =>
jest.spyOn(log, 'error').mockImplementation(jest.fn());

const MOCK_JWT = 'mockJwt';
const MOCK_FCM_TOKEN = 'mockFcmToken';
const MOCK_MOBILE_FCM_TOKEN = 'mockMobileFcmToken';
Expand Down Expand Up @@ -90,6 +95,7 @@ describe('NotificationServicesPushController', () => {

it('should fail if a jwt token is not provided', async () => {
arrangeServicesMocks();
mockErrorLog();
const { controller, messenger } = arrangeMockMessenger();
mockAuthBearerTokenCall(messenger).mockResolvedValue(
null as unknown as string,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import log from 'loglevel';

import {
mockEndpointGetPushNotificationLinks,
mockEndpointUpdatePushNotificationLinks,
Expand All @@ -13,6 +15,10 @@ import {
updateTriggerPushNotifications,
} from './services';

// Testing util to clean up verbose logs when testing errors
const mockErrorLog = () =>
jest.spyOn(log, 'error').mockImplementation(jest.fn());

const MOCK_REG_TOKEN = 'REG_TOKEN';
const MOCK_NEW_REG_TOKEN = 'NEW_REG_TOKEN';
const MOCK_MOBILE_FCM_TOKEN = 'mockMobileFcmToken';
Expand All @@ -31,6 +37,7 @@ describe('NotificationServicesPushController Services', () => {

it('should return null if given a bad response', async () => {
const mockAPI = mockEndpointGetPushNotificationLinks({ status: 500 });
mockErrorLog();
const result = await getPushNotificationLinks(MOCK_JWT);
expect(mockAPI.isDone()).toBe(true);
expect(result).toBeNull();
Expand Down Expand Up @@ -108,6 +115,7 @@ describe('NotificationServicesPushController Services', () => {

it('should successfully call APIs and add provided mobile fcmToken', async () => {
const { mobileParams, apis } = arrangeMocks();
mockErrorLog();
const result = await activatePushNotifications(mobileParams);

expect(apis.mockGet.isDone()).toBe(true);
Expand All @@ -119,6 +127,7 @@ describe('NotificationServicesPushController Services', () => {

it('should return null if unable to get links from API', async () => {
const { params, apis } = arrangeMocks({ mockGet: { status: 500 } });
mockErrorLog();
const result = await activatePushNotifications(params);

expect(apis.mockGet.isDone()).toBe(true);
Expand Down Expand Up @@ -177,6 +186,7 @@ describe('NotificationServicesPushController Services', () => {

it('should return early when there is no registration token to delete', async () => {
const { params, apis } = arrangeMocks();
mockErrorLog();
const result = await deactivatePushNotifications({
...params,
regToken: '',
Expand All @@ -191,6 +201,7 @@ describe('NotificationServicesPushController Services', () => {

it('should return false when unable to get links api', async () => {
const { params, apis } = arrangeMocks({ mockGet: { status: 500 } });
mockErrorLog();
const result = await deactivatePushNotifications(params);

expect(apis.mockGet.isDone()).toBe(true);
Expand Down Expand Up @@ -250,6 +261,7 @@ describe('NotificationServicesPushController Services', () => {

it('should update trigger links and replace existing reg token', async () => {
const { params, apis } = arrangeMocks();
mockErrorLog();
const result = await updateTriggerPushNotifications(params);

expect(apis.mockGet.isDone()).toBe(true);
Expand All @@ -263,6 +275,7 @@ describe('NotificationServicesPushController Services', () => {

it('should return early if fails to get links api', async () => {
const { params, apis } = arrangeMocks({ mockGet: { status: 500 } });
mockErrorLog();
const result = await updateTriggerPushNotifications(params);

expect(apis.mockGet.isDone()).toBe(true);
Expand Down

0 comments on commit 6ddd4ed

Please sign in to comment.