Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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 @@ -11,6 +11,7 @@
import { MOCK_ANY_NAMESPACE, MockAnyNamespace } from '@metamask/messenger';
import { selectAssetsAccountApiBalancesEnabled } from '../../../selectors/featureFlagController/assetsAccountApiBalances';
import { selectBasicFunctionalityEnabled } from '../../../selectors/settings';
import { selectIsControllerDeprecated } from '../../../selectors/featureFlagController/assetsUnifyState';

jest.mock('@metamask/assets-controllers');

Expand All @@ -25,6 +26,14 @@
selectBasicFunctionalityEnabled: jest.fn().mockReturnValue(true),
}));

jest.mock('../../../selectors/featureFlagController/assetsUnifyState', () => ({
selectIsControllerDeprecated: jest.fn().mockReturnValue(() => false),
}));

jest.mock('../../../store', () => ({
store: { getState: jest.fn().mockReturnValue({}) },
}));

function getInitRequestMock(): jest.Mocked<
MessengerClientInitRequest<AccountTrackerControllerMessenger>
> {
Expand Down Expand Up @@ -68,6 +77,7 @@
accountsApiChainIds: expect.any(Function),
allowExternalServices: expect.any(Function),
isHomepageSectionsV1Enabled: expect.any(Function),
isDeprecated: expect.any(Function),
}),
);
});
Expand Down Expand Up @@ -113,4 +123,35 @@
expect(allowExternalServices()).toBe(false);
expect(selectBasicFunctionalityEnabled).toHaveBeenCalled();
});

describe('isDeprecated', () => {
it('returns false when AccountTrackerController is not deprecated', () => {
jest.mocked(selectIsControllerDeprecated).mockReturnValue(() => false);

Check failure on line 129 in app/core/Engine/controllers/account-tracker-controller-init.test.ts

View workflow job for this annotation

GitHub Actions / Run `lint:tsc`

Argument of type '() => false' is not assignable to parameter of type '((state: StateWithPartialEngine) => boolean) & { clearCache: () => void; resultsCount: () => number; resetResultsCount: () => void; } & { resultFunc: (resultFuncArgs_0: { [x: string]: Json; }) => boolean; ... 6 more ...; resetDependencyRecomputations: () => void; } & { ...; }'.

accountTrackerControllerInit(getInitRequestMock());

const controllerMock = jest.mocked(AccountTrackerController);
const { isDeprecated } = controllerMock.mock.calls[0][0] as {
isDeprecated: () => boolean;
};

expect(isDeprecated()).toBe(false);
expect(selectIsControllerDeprecated).toHaveBeenCalledWith(
'AccountTrackerController',
);
});

it('returns true when AccountTrackerController is deprecated', () => {
jest.mocked(selectIsControllerDeprecated).mockReturnValue(() => true);

Check failure on line 145 in app/core/Engine/controllers/account-tracker-controller-init.test.ts

View workflow job for this annotation

GitHub Actions / Run `lint:tsc`

Argument of type '() => true' is not assignable to parameter of type '((state: StateWithPartialEngine) => boolean) & { clearCache: () => void; resultsCount: () => number; resetResultsCount: () => void; } & { resultFunc: (resultFuncArgs_0: { [x: string]: Json; }) => boolean; ... 6 more ...; resetDependencyRecomputations: () => void; } & { ...; }'.

accountTrackerControllerInit(getInitRequestMock());

const controllerMock = jest.mocked(AccountTrackerController);
const { isDeprecated } = controllerMock.mock.calls[0][0] as {
isDeprecated: () => boolean;
};

expect(isDeprecated()).toBe(true);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import {
} from '@metamask/assets-controllers';
import { selectAssetsAccountApiBalancesEnabled } from '../../../selectors/featureFlagController/assetsAccountApiBalances';
import { selectBasicFunctionalityEnabled } from '../../../selectors/settings';
import { selectIsControllerDeprecated } from '../../../selectors/featureFlagController/assetsUnifyState';
import { store } from '../../../store';

/**
* Initialize the accountTracker controller.
*
Expand Down Expand Up @@ -34,6 +37,10 @@ export const accountTrackerControllerInit: MessengerClientInitFunction<
selectAssetsAccountApiBalancesEnabled(getState()) as `0x${string}`[],
allowExternalServices: () => selectBasicFunctionalityEnabled(getState()),
isHomepageSectionsV1Enabled: () => true,
isDeprecated: () =>
selectIsControllerDeprecated('AccountTrackerController')(
store.getState(),
),
});

return {
Expand Down
108 changes: 108 additions & 0 deletions app/selectors/featureFlagController/assetsUnifyState/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import {
selectIsAssetsUnifyStateEnabled,
isAssetsUnifyStateFeatureEnabled,
getIsDeprecatedController,
selectIsControllerDeprecated,
AssetsUnifyStateFeatureFlag,
ASSETS_UNIFY_STATE_FLAG,
ASSETS_UNIFY_STATE_FEATURE_VERSION_1,
Expand Down Expand Up @@ -95,3 +97,109 @@ describe('selectIsAssetsUnifyStateEnabled', () => {
expect(selectIsAssetsUnifyStateEnabled(mockedState)).toBe(false);
});
});

describe('getIsDeprecatedController', () => {
it('returns true when the controller is listed in deprecatedControllers', () => {
const flag: AssetsUnifyStateFeatureFlag = {
enabled: true,
featureVersion: ASSETS_UNIFY_STATE_FEATURE_VERSION_1,
deprecatedControllers: ['AccountTrackerController'],
};

expect(getIsDeprecatedController(flag, 'AccountTrackerController')).toBe(
true,
);
});

it('returns false when the controller is not listed in deprecatedControllers', () => {
const flag: AssetsUnifyStateFeatureFlag = {
enabled: true,
featureVersion: ASSETS_UNIFY_STATE_FEATURE_VERSION_1,
deprecatedControllers: ['SomeOtherController'],
};

expect(getIsDeprecatedController(flag, 'AccountTrackerController')).toBe(
false,
);
});

it('returns false when deprecatedControllers is empty', () => {
const flag: AssetsUnifyStateFeatureFlag = {
enabled: true,
featureVersion: ASSETS_UNIFY_STATE_FEATURE_VERSION_1,
deprecatedControllers: [],
};

expect(getIsDeprecatedController(flag, 'AccountTrackerController')).toBe(
false,
);
});

it('returns false when deprecatedControllers is absent', () => {
const flag: AssetsUnifyStateFeatureFlag = {
enabled: true,
featureVersion: ASSETS_UNIFY_STATE_FEATURE_VERSION_1,
};

expect(getIsDeprecatedController(flag, 'AccountTrackerController')).toBe(
false,
);
});

it('returns false when flagValue is undefined', () => {
expect(
getIsDeprecatedController(undefined, 'AccountTrackerController'),
).toBe(false);
});

it('returns false when flagValue is null', () => {
expect(getIsDeprecatedController(null, 'AccountTrackerController')).toBe(
false,
);
});
});

describe('selectIsControllerDeprecated', () => {
it('returns true when the controller is listed in deprecatedControllers', () => {
const mockedState = mockStateWith({
enabled: true,
featureVersion: ASSETS_UNIFY_STATE_FEATURE_VERSION_1,
deprecatedControllers: ['AccountTrackerController'],
});

expect(
selectIsControllerDeprecated('AccountTrackerController')(mockedState),
).toBe(true);
});

it('returns false when deprecatedControllers is empty', () => {
const mockedState = mockStateWith({
enabled: true,
featureVersion: ASSETS_UNIFY_STATE_FEATURE_VERSION_1,
deprecatedControllers: [],
});

expect(
selectIsControllerDeprecated('AccountTrackerController')(mockedState),
).toBe(false);
});

it('returns false when deprecatedControllers is absent', () => {
const mockedState = mockStateWith({
enabled: true,
featureVersion: ASSETS_UNIFY_STATE_FEATURE_VERSION_1,
});

expect(
selectIsControllerDeprecated('AccountTrackerController')(mockedState),
).toBe(false);
});

it('returns false when the flag is missing from state', () => {
expect(
selectIsControllerDeprecated('AccountTrackerController')(
mockedUndefinedFlagsState,
),
).toBe(false);
});
});
28 changes: 28 additions & 0 deletions app/selectors/featureFlagController/assetsUnifyState/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { selectRemoteFeatureFlags } from '..';
export interface AssetsUnifyStateFeatureFlag {
enabled: boolean;
featureVersion: string | null;
deprecatedControllers?: string[];
}

export const ASSETS_UNIFY_STATE_FLAG = 'assetsUnifyState';
Expand Down Expand Up @@ -35,6 +36,33 @@ export const isAssetsUnifyStateFeatureEnabled = (
);
};

/**
* Checks if a controller is deprecated based on the assets unify state feature flag.
*
* @param flagValue - The raw feature flag value.
* @param controllerName - The name of the controller to check.
* @returns True if the controller is listed in deprecatedControllers, false otherwise.
*/
export const getIsDeprecatedController = (
flagValue: unknown,
controllerName: string,
): boolean => {
if (!flagValue || typeof flagValue !== 'object') return false;
const parsed = flagValue as AssetsUnifyStateFeatureFlag;
return parsed.deprecatedControllers?.includes(controllerName) ?? false;
};
Comment thread
cursor[bot] marked this conversation as resolved.

/**
* Selector factory to check if a specific controller is deprecated.
*
* @param controllerName - The name of the controller to check.
* @returns A selector that returns true if the controller is deprecated.
*/
export const selectIsControllerDeprecated = (controllerName: string) =>
createSelector(selectRemoteFeatureFlags, (flags) =>
getIsDeprecatedController(flags[ASSETS_UNIFY_STATE_FLAG], controllerName),
);

/**
* Selector to check if the assets unify state feature is enabled.
* @returns Boolean indicating if the assets unify state feature is enabled.
Expand Down
7 changes: 7 additions & 0 deletions tests/feature-flags/feature-flag-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,13 @@ export const FEATURE_FLAG_REGISTRY: Record<string, FeatureFlagRegistryEntry> = {
enabled: false,
featureVersion: null,
minimumVersion: null,
deprecatedControllers: [],
},
'8.3.0': {
enabled: true,
featureVersion: '1',
minimumVersion: '8.3.0',
deprecatedControllers: [],
},
},
},
Expand Down
Loading