Skip to content

Commit 6390185

Browse files
runway-github[bot]baptiste-marchandjoaoloureirop
authored
chore(runway): cherry-pick fix: gate Social AI notification settings & bump notification-services-controller to 24.1.1 (#30629)
- fix: gate Social AI notification settings & bump notification-services-controller to 24.1.1 (#30528) <!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> Ensure the project uses the newer `@metamask/notification-services-controller` version and prevent Social AI notification controls from showing when the Social Leaderboard feature is disabled. ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/GE-244 ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk: UI visibility is now controlled by an existing remote feature flag and changes are covered by updated tests; dependency bump may have minor integration fallout but is limited in scope. > > **Overview** > **Gates the Social AI notification settings section** so it only appears when the `aiSocialLeaderboardEnabled` remote feature flag is enabled (via `selectSocialLeaderboardEnabled`). > > Updates unit/component-view tests and notification-state presets to cover both flag states, and adjusts the user-storage mock defaults for `marketing.inAppNotificationsEnabled`. > > Bumps `@metamask/notification-services-controller` to `24.1.1` (and updates lockfile accordingly). > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 445bca5. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> [a0b59b8](a0b59b8) Co-authored-by: Baptiste Marchand <75846779+baptiste-marchand@users.noreply.github.com> Co-authored-by: João Loureiro <175489935+joaoloureirop@users.noreply.github.com>
1 parent 36c9ca7 commit 6390185

7 files changed

Lines changed: 122 additions & 37 deletions

File tree

app/components/Views/Settings/NotificationsSettings/NotificationsSettings.view.test.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ describeForPlatforms('Notifications settings (toggles + visibility)', () => {
108108

109109
it('renders notification sections when notifications are enabled', async () => {
110110
const { getByTestId, getByText, findAllByText, findByText } =
111-
renderSettings();
111+
renderSettings({ socialLeaderboardEnabled: true });
112112

113113
expect(
114114
getByTestId(NotificationSettingsViewSelectorsIDs.NOTIFICATIONS_TOGGLE),
@@ -122,6 +122,17 @@ describeForPlatforms('Notifications settings (toggles + visibility)', () => {
122122
expect(getByText('Off')).toBeOnTheScreen();
123123
});
124124

125+
it('hides social AI section when social leaderboard feature flag is disabled', async () => {
126+
const { getByText, queryByText, findAllByText, findByText } =
127+
renderSettings({ socialLeaderboardEnabled: false });
128+
129+
expect(await findByText(SECTION_TITLES.walletActivity)).toBeOnTheScreen();
130+
expect(getByText(SECTION_TITLES.perps)).toBeOnTheScreen();
131+
expect(queryByText(SECTION_TITLES.socialAI)).toBeNull();
132+
expect(getByText(SECTION_TITLES.marketing)).toBeOnTheScreen();
133+
expect(await findAllByText('Push, In app')).toHaveLength(2);
134+
});
135+
125136
it('hides notification sections when main toggle is off', async () => {
126137
const { getByTestId, queryByText } = renderSettings({
127138
notificationsEnabled: false,

app/components/Views/Settings/NotificationsSettings/index.test.tsx

Lines changed: 76 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,64 @@ import { Props } from './NotificationsSettings.types';
66
import { MOCK_ACCOUNTS_CONTROLLER_STATE } from '../../../../util/test/accountsControllerTestUtils';
77
import { AvatarAccountType } from '../../../../component-library/components/Avatars/Avatar';
88
import { NotificationSettingsViewSelectorsIDs } from './NotificationSettingsView.testIds';
9+
import { strings } from '../../../../../locales/i18n';
10+
11+
jest.mock('react-native-device-info', () => ({
12+
getVersion: jest.fn().mockReturnValue('7.72.0'),
13+
}));
914

1015
jest.mock('../../../UI/Perps/selectors/featureFlags', () => ({
1116
selectPerpsEnabledFlag: jest.fn().mockReturnValue(true),
1217
}));
1318

14-
const mockInitialState = {
19+
const createMockState = ({
20+
notificationsEnabled = false,
21+
socialLeaderboardEnabled = false,
22+
} = {}) => ({
1523
settings: {
1624
avatarAccountType: AvatarAccountType.Maskicon,
1725
},
1826
engine: {
1927
backgroundState: {
2028
...backgroundState,
2129
AccountsController: MOCK_ACCOUNTS_CONTROLLER_STATE,
30+
NotificationServicesController: {
31+
...backgroundState.NotificationServicesController,
32+
isNotificationServicesEnabled: notificationsEnabled,
33+
},
34+
RemoteFeatureFlagController: {
35+
...backgroundState.RemoteFeatureFlagController,
36+
remoteFeatureFlags: {
37+
...backgroundState.RemoteFeatureFlagController.remoteFeatureFlags,
38+
aiSocialLeaderboardEnabled: {
39+
enabled: socialLeaderboardEnabled,
40+
minimumVersion: '0.0.1',
41+
},
42+
},
43+
},
2244
},
2345
},
24-
};
46+
});
47+
48+
const setOptions = jest.fn();
49+
50+
const renderNotificationsSettings = (
51+
state = createMockState(),
52+
navigation = {
53+
setOptions,
54+
goBack: jest.fn(),
55+
navigate: jest.fn(),
56+
} as unknown as Props['navigation'],
57+
) =>
58+
renderWithProvider(
59+
<NotificationsSettings
60+
navigation={navigation}
61+
route={{} as unknown as Props['route']}
62+
/>,
63+
{
64+
state,
65+
},
66+
);
2567

2668
jest.mock('@react-navigation/native', () => {
2769
const actualNav = jest.requireActual('@react-navigation/native');
@@ -76,25 +118,42 @@ jest.mock('./hooks/useNotificationStoragePreferences', () => ({
76118
}),
77119
}));
78120

79-
const setOptions = jest.fn();
121+
const socialAISectionTitle = strings(
122+
'app_settings.notifications_opts.social_ai_title',
123+
);
80124

81125
describe('NotificationsSettings', () => {
82-
it('renders correctly', () => {
83-
const { getByTestId } = renderWithProvider(
84-
<NotificationsSettings
85-
navigation={
86-
{
87-
setOptions,
88-
} as unknown as Props['navigation']
89-
}
90-
route={{} as unknown as Props['route']}
91-
/>,
92-
{
93-
state: mockInitialState,
94-
},
95-
);
126+
beforeEach(() => {
127+
jest.clearAllMocks();
128+
});
129+
130+
it('renders main notifications toggle', () => {
131+
const { getByTestId } = renderNotificationsSettings();
132+
96133
expect(
97134
getByTestId(NotificationSettingsViewSelectorsIDs.NOTIFICATIONS_TOGGLE),
98135
).toBeOnTheScreen();
99136
});
137+
138+
it('renders social AI section when social leaderboard feature flag is enabled', () => {
139+
const state = createMockState({
140+
notificationsEnabled: true,
141+
socialLeaderboardEnabled: true,
142+
});
143+
144+
const { getByText } = renderNotificationsSettings(state);
145+
146+
expect(getByText(socialAISectionTitle)).toBeOnTheScreen();
147+
});
148+
149+
it('hides social AI section when social leaderboard feature flag is disabled', () => {
150+
const state = createMockState({
151+
notificationsEnabled: true,
152+
socialLeaderboardEnabled: false,
153+
});
154+
155+
const { queryByText } = renderNotificationsSettings(state);
156+
157+
expect(queryByText(socialAISectionTitle)).toBeNull();
158+
});
100159
});

app/components/Views/Settings/NotificationsSettings/index.tsx

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import SwitchLoadingModal from '../../../UI/Notification/SwitchLoadingModal';
1212
import { Props } from './NotificationsSettings.types';
1313

1414
import { selectIsMetamaskNotificationsEnabled } from '../../../../selectors/notifications';
15+
import { selectSocialLeaderboardEnabled } from '../../../../selectors/featureFlagController/socialLeaderboard';
1516

1617
import Routes from '../../../../constants/navigation/Routes';
1718

@@ -96,6 +97,9 @@ const NotificationsSettings = ({ navigation }: Props) => {
9697
const isMetamaskNotificationsEnabled = useSelector(
9798
selectIsMetamaskNotificationsEnabled,
9899
);
100+
const isSocialLeaderboardEnabled = useSelector(
101+
selectSocialLeaderboardEnabled,
102+
);
99103

100104
const loadingText = useSwitchNotificationLoadingText();
101105
const { preferences } = useNotificationStoragePreferences();
@@ -155,18 +159,22 @@ const NotificationsSettings = ({ navigation }: Props) => {
155159
}
156160
/>
157161

158-
<NotificationRow
159-
title={strings('app_settings.notifications_opts.social_ai_title')}
160-
status={getStatusText(preferences?.socialAI)}
161-
iconName={IconName.Ai}
162-
onPress={() =>
163-
navigateToSection(
164-
'socialAI',
165-
strings('app_settings.notifications_opts.social_ai_title'),
166-
strings('app_settings.notifications_opts.social_ai_desc'),
167-
)
168-
}
169-
/>
162+
{isSocialLeaderboardEnabled && (
163+
<NotificationRow
164+
title={strings(
165+
'app_settings.notifications_opts.social_ai_title',
166+
)}
167+
status={getStatusText(preferences?.socialAI)}
168+
iconName={IconName.Ai}
169+
onPress={() =>
170+
navigateToSection(
171+
'socialAI',
172+
strings('app_settings.notifications_opts.social_ai_title'),
173+
strings('app_settings.notifications_opts.social_ai_desc'),
174+
)
175+
}
176+
/>
177+
)}
170178

171179
<NotificationRow
172180
title={strings('app_settings.notifications_opts.marketing_title')}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@
310310
"@metamask/native-utils": "^0.8.0",
311311
"@metamask/network-controller": "^31.0.0",
312312
"@metamask/network-enablement-controller": "^5.1.0",
313-
"@metamask/notification-services-controller": "^24.0.0",
313+
"@metamask/notification-services-controller": "24.1.1",
314314
"@metamask/permission-controller": "^13.1.1",
315315
"@metamask/phishing-controller": "^17.1.1",
316316
"@metamask/post-message-stream": "^10.0.0",

tests/api-mocking/mock-responses/defaults/user-storage.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ const notificationPreferences = {
2828
},
2929
],
3030
},
31+
// Feature announcements are controlled by marketing in-app preferences.
3132
marketing: {
32-
inAppNotificationsEnabled: false,
33+
inAppNotificationsEnabled: true,
3334
pushNotificationsEnabled: false,
3435
},
3536
perps: {

tests/component-view/presets/notifications.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ interface NotificationsPresetOptions {
4242
notificationsEnabled?: boolean;
4343
featureAnnouncementsEnabled?: boolean;
4444
pushEnabled?: boolean;
45+
socialLeaderboardEnabled?: boolean;
4546
notifications?: typeof MOCK_NOTIFICATIONS;
4647
}
4748

@@ -62,6 +63,7 @@ export function buildNotificationsState(
6263
notificationsEnabled = true,
6364
featureAnnouncementsEnabled = true,
6465
pushEnabled = true,
66+
socialLeaderboardEnabled = false,
6567
notifications = MOCK_NOTIFICATIONS,
6668
} = options;
6769

@@ -93,6 +95,10 @@ export function buildNotificationsState(
9395
RemoteFeatureFlagController: {
9496
remoteFeatureFlags: {
9597
assetsNotificationsEnabled: true,
98+
aiSocialLeaderboardEnabled: {
99+
enabled: socialLeaderboardEnabled,
100+
minimumVersion: '0.0.1',
101+
},
96102
},
97103
},
98104
AccountsController: {

yarn.lock

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9275,9 +9275,9 @@ __metadata:
92759275
languageName: node
92769276
linkType: hard
92779277

9278-
"@metamask/notification-services-controller@npm:^24.0.0":
9279-
version: 24.1.0
9280-
resolution: "@metamask/notification-services-controller@npm:24.1.0"
9278+
"@metamask/notification-services-controller@npm:24.1.1":
9279+
version: 24.1.1
9280+
resolution: "@metamask/notification-services-controller@npm:24.1.1"
92819281
dependencies:
92829282
"@contentful/rich-text-html-renderer": "npm:^16.5.2"
92839283
"@metamask/authenticated-user-storage": "npm:^2.0.0"
@@ -9293,7 +9293,7 @@ __metadata:
92939293
loglevel: "npm:^1.8.1"
92949294
semver: "npm:^7.6.3"
92959295
uuid: "npm:^8.3.2"
9296-
checksum: 10/c8bcfcc7e9178eee8789ef4417636ac583e597639596c85eac82e5703c5d59fb8e4762e0d1fe71005320bedb11ea5893431ee540f0d268bcecf10bb226d7af33
9296+
checksum: 10/8f5249dea67dc7168c9254fde1de81e24483f9b054ba1ac282c36849e2090515f0cff0ed7cd4beaf6aefed6382f966277e02d3259f69aea67dee1c84c2ec7400
92979297
languageName: node
92989298
linkType: hard
92999299

@@ -35288,7 +35288,7 @@ __metadata:
3528835288
"@metamask/native-utils": "npm:^0.8.0"
3528935289
"@metamask/network-controller": "npm:^31.0.0"
3529035290
"@metamask/network-enablement-controller": "npm:^5.1.0"
35291-
"@metamask/notification-services-controller": "npm:^24.0.0"
35291+
"@metamask/notification-services-controller": "npm:24.1.1"
3529235292
"@metamask/object-multiplex": "npm:^1.1.0"
3529335293
"@metamask/permission-controller": "npm:^13.1.1"
3529435294
"@metamask/phishing-controller": "npm:^17.1.1"

0 commit comments

Comments
 (0)