Skip to content

feat(identity): create metametrics event library for profile-sync-controller #6044

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 5 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/profile-sync-controller/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Add MetaMetrics event library to standardize event properties across clients ([#6044](https://github.com/MetaMask/core/pull/6044))

## [19.0.0]

### Changed
Expand Down
1 change: 1 addition & 0 deletions packages/profile-sync-controller/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * as SDK from './sdk';
export * as AuthenticationController from './controllers/authentication';
export * as UserStorageController from './controllers/user-storage';
export * as MetaMetrics from './shared/metametrics';
200 changes: 200 additions & 0 deletions packages/profile-sync-controller/src/shared/metametrics.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
import {
BackupAndSyncFeatureNames,
BackupAndSyncActions,
BackupAndSyncEventProperties,
createBackupAndSyncEventProperties,
type BackupAndSyncFeatureName,
type BackupAndSyncAction,
} from './metametrics';

describe('BackupAndSync MetaMetrics Library', () => {
describe('BackupAndSyncFeatureNames', () => {
it('should have the correct feature names', () => {
expect(BackupAndSyncFeatureNames.BACKUP_AND_SYNC).toBe('Backup And Sync');
expect(BackupAndSyncFeatureNames.ACCOUNT_SYNCING).toBe('Account Syncing');
expect(BackupAndSyncFeatureNames.CONTACT_SYNCING).toBe('Contact Syncing');
expect(BackupAndSyncFeatureNames.NETWORK_SYNCING).toBe('Network Syncing');
expect(BackupAndSyncFeatureNames.AUTHENTICATION).toBe('Authentication');
});
});

describe('BackupAndSyncActions', () => {
it('should have the correct action names', () => {
expect(BackupAndSyncActions.ACCOUNTS_SYNC_ADDED).toBe(
'Accounts Sync Added',
);
expect(BackupAndSyncActions.ACCOUNTS_SYNC_NAME_UPDATED).toBe(
'Accounts Sync Name Updated',
);
expect(BackupAndSyncActions.ACCOUNTS_SYNC_ERRONEOUS_SITUATION).toBe(
'Accounts Sync Erroneous Situation',
);
expect(BackupAndSyncActions.CONTACTS_SYNC_CONTACT_UPDATED).toBe(
'Contacts Sync Contact Updated',
);
expect(BackupAndSyncActions.CONTACTS_SYNC_CONTACT_DELETED).toBe(
'Contacts Sync Contact Deleted',
);
expect(BackupAndSyncActions.CONTACTS_SYNC_ERRONEOUS_SITUATION).toBe(
'Contacts Sync Erroneous Situation',
);
});
});

describe('createBackupAndSyncEventProperties', () => {
it('should create event properties with feature name and action', () => {
const properties = createBackupAndSyncEventProperties(
BackupAndSyncFeatureNames.BACKUP_AND_SYNC,
BackupAndSyncActions.CONTACTS_SYNC_CONTACT_UPDATED,
{ profile_id: 'test-profile-id' },
);

expect(properties).toStrictEqual({
feature_name: 'Backup And Sync',
action: 'Contacts Sync Contact Updated',
profile_id: 'test-profile-id',
});
});

it('should work without additional properties', () => {
const properties = createBackupAndSyncEventProperties(
BackupAndSyncFeatureNames.BACKUP_AND_SYNC,
BackupAndSyncActions.CONTACTS_SYNC_CONTACT_UPDATED,
);

expect(properties).toStrictEqual({
feature_name: 'Backup And Sync',
action: 'Contacts Sync Contact Updated',
});
});
});

describe('BackupAndSyncEventProperties', () => {
describe('ACCOUNT_ADDED', () => {
it('should create account added properties', () => {
const properties =
BackupAndSyncEventProperties.ACCOUNT_ADDED('test-profile-id');
expect(properties).toStrictEqual({
profile_id: 'test-profile-id',
});
});
});

describe('ACCOUNT_NAME_UPDATED', () => {
it('should create account name updated properties', () => {
const properties =
BackupAndSyncEventProperties.ACCOUNT_NAME_UPDATED('test-profile-id');
expect(properties).toStrictEqual({
profile_id: 'test-profile-id',
});
});
});

describe('ACCOUNT_SYNC_ERROR', () => {
it('should create account sync error properties', () => {
const properties = BackupAndSyncEventProperties.ACCOUNT_SYNC_ERROR(
'test-profile-id',
'test error message',
);
expect(properties).toStrictEqual({
profile_id: 'test-profile-id',
situation_message: 'test error message',
});
});
});

describe('CONTACT_UPDATED', () => {
it('should create contact updated properties', () => {
const properties =
BackupAndSyncEventProperties.CONTACT_UPDATED('test-profile-id');
expect(properties).toStrictEqual({
feature_name: 'Backup And Sync',
action: 'Contacts Sync Contact Updated',
profile_id: 'test-profile-id',
});
});
});

describe('CONTACT_DELETED', () => {
it('should create contact deleted properties', () => {
const properties =
BackupAndSyncEventProperties.CONTACT_DELETED('test-profile-id');
expect(properties).toStrictEqual({
feature_name: 'Backup And Sync',
action: 'Contacts Sync Contact Deleted',
profile_id: 'test-profile-id',
});
});
});

describe('CONTACT_SYNC_ERROR', () => {
it('should create contact sync error properties', () => {
const properties = BackupAndSyncEventProperties.CONTACT_SYNC_ERROR(
'test-profile-id',
'test error message',
);
expect(properties).toStrictEqual({
feature_name: 'Backup And Sync',
action: 'Contacts Sync Erroneous Situation',
profile_id: 'test-profile-id',
additional_description: 'test error message',
});
});
});

describe('NETWORK_ADDED', () => {
it('should create network added properties', () => {
const properties = BackupAndSyncEventProperties.NETWORK_ADDED(
'test-profile-id',
'0x1',
);
expect(properties).toStrictEqual({
profile_id: 'test-profile-id',
chain_id: '0x1',
});
});
});

describe('NETWORK_UPDATED', () => {
it('should create network updated properties', () => {
const properties = BackupAndSyncEventProperties.NETWORK_UPDATED(
'test-profile-id',
'0x1',
);
expect(properties).toStrictEqual({
profile_id: 'test-profile-id',
chain_id: '0x1',
});
});
});

describe('NETWORK_REMOVED', () => {
it('should create network removed properties', () => {
const properties = BackupAndSyncEventProperties.NETWORK_REMOVED(
'test-profile-id',
'0x1',
);
expect(properties).toStrictEqual({
profile_id: 'test-profile-id',
chain_id: '0x1',
});
});
});
});

describe('Type safety', () => {
it('should enforce correct feature name types', () => {
// This should compile without errors
const validFeatureName: BackupAndSyncFeatureName =
BackupAndSyncFeatureNames.BACKUP_AND_SYNC;
expect(validFeatureName).toBe('Backup And Sync');
});

it('should enforce correct action types', () => {
// This should compile without errors
const validAction: BackupAndSyncAction =
BackupAndSyncActions.CONTACTS_SYNC_CONTACT_UPDATED;
expect(validAction).toBe('Contacts Sync Contact Updated');
});
});
});
138 changes: 138 additions & 0 deletions packages/profile-sync-controller/src/shared/metametrics.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/**
* MetaMetrics event constants for profile-sync-controller
*
* This library provides standardized constants for MetaMetrics events
* to avoid magic strings and ensure consistency across clients.
*/

/**
* Feature names used in profile-sync-controller MetaMetrics events
*/
export const BackupAndSyncFeatureNames = {
/**
* The main backup and sync feature
*/
BACKUP_AND_SYNC: 'Backup And Sync',
/**
* Account syncing functionality
*/
ACCOUNT_SYNCING: 'Account Syncing',
/**
* Contact syncing functionality
*/
CONTACT_SYNCING: 'Contact Syncing',
/**
* Network syncing functionality
*/
NETWORK_SYNCING: 'Network Syncing',
/**
* Authentication functionality
*/
AUTHENTICATION: 'Authentication',
} as const;

/**
* Actions used in profile-sync-controller MetaMetrics events
*/
export const BackupAndSyncActions = {
// Account syncing actions
ACCOUNTS_SYNC_ADDED: 'Accounts Sync Added',
ACCOUNTS_SYNC_NAME_UPDATED: 'Accounts Sync Name Updated',
ACCOUNTS_SYNC_ERRONEOUS_SITUATION: 'Accounts Sync Erroneous Situation',

// Contact syncing actions
CONTACTS_SYNC_CONTACT_UPDATED: 'Contacts Sync Contact Updated',
CONTACTS_SYNC_CONTACT_DELETED: 'Contacts Sync Contact Deleted',
CONTACTS_SYNC_ERRONEOUS_SITUATION: 'Contacts Sync Erroneous Situation',

// Network syncing actions
NETWORK_SYNC_ADDED: 'Network Sync Added',
NETWORK_SYNC_UPDATED: 'Network Sync Updated',
NETWORK_SYNC_REMOVED: 'Network Sync Removed',

// Authentication actions
SIGN_IN: 'Sign In',
SIGN_OUT: 'Sign Out',
AUTHENTICATION_FAILED: 'Authentication Failed',
} as const;

/**
* Type definitions for the constants to ensure type safety
*/
export type BackupAndSyncFeatureName =
(typeof BackupAndSyncFeatureNames)[keyof typeof BackupAndSyncFeatureNames];
export type BackupAndSyncAction =
(typeof BackupAndSyncActions)[keyof typeof BackupAndSyncActions];

/**
* Helper function to create standardized MetaMetrics event properties
* for profile-sync-controller events
*
* @param featureName - The feature name to use in the event properties
* @param action - The action to use in the event properties
* @param additionalProperties - Optional additional properties to include
* @returns An object containing the standardized event properties
*/
export const createBackupAndSyncEventProperties = (
featureName: BackupAndSyncFeatureName,
action: BackupAndSyncAction,
additionalProperties?: Record<string, unknown>,
) => ({
feature_name: featureName,
action,
...additionalProperties,
});

/**
* Pre-defined event property sets for common profile-sync-controller events
*/
export const BackupAndSyncEventProperties = {
// Account syncing events
ACCOUNT_ADDED: (profileId: string) => ({
profile_id: profileId,
}),
ACCOUNT_NAME_UPDATED: (profileId: string) => ({
profile_id: profileId,
}),
ACCOUNT_SYNC_ERROR: (profileId: string, situationMessage: string) => ({
profile_id: profileId,
situation_message: situationMessage,
}),

// Contact syncing events
CONTACT_UPDATED: (profileId: string) =>
createBackupAndSyncEventProperties(
BackupAndSyncFeatureNames.BACKUP_AND_SYNC,
BackupAndSyncActions.CONTACTS_SYNC_CONTACT_UPDATED,
{ profile_id: profileId },
),
CONTACT_DELETED: (profileId: string) =>
createBackupAndSyncEventProperties(
BackupAndSyncFeatureNames.BACKUP_AND_SYNC,
BackupAndSyncActions.CONTACTS_SYNC_CONTACT_DELETED,
{ profile_id: profileId },
),
CONTACT_SYNC_ERROR: (profileId: string, situationMessage: string) =>
createBackupAndSyncEventProperties(
BackupAndSyncFeatureNames.BACKUP_AND_SYNC,
BackupAndSyncActions.CONTACTS_SYNC_ERRONEOUS_SITUATION,
{
profile_id: profileId,
additional_description: situationMessage,
},
),

// Network syncing events
NETWORK_ADDED: (profileId: string, chainId: string) => ({
profile_id: profileId,
chain_id: chainId,
}),
NETWORK_UPDATED: (profileId: string, chainId: string) => ({
profile_id: profileId,
chain_id: chainId,
}),
NETWORK_REMOVED: (profileId: string, chainId: string) => ({
profile_id: profileId,
chain_id: chainId,
}),
} as const;
Loading