From e39dd19fce7c9219dce1ea85f3086a65f6918ead Mon Sep 17 00:00:00 2001 From: ieow <4881057+ieow@users.noreply.github.com> Date: Tue, 24 Mar 2026 14:44:57 +0000 Subject: [PATCH] chore(runway): cherry-pick feat: legacy-ios-feature-flag cp-7.71.0 (#27848) ## **Description** Support webcredential for ios google login Part 2/4 - Add feature flag This pr add feature flag for the ios google login PR list Part 1/ 4 - https://github.com/MetaMask/metamask-mobile/pull/27741 Part 2/ 4 - https://github.com/MetaMask/metamask-mobile/pull/27848 Part 3/ 4 - https://github.com/MetaMask/metamask-mobile/pull/27850 Part 4/ 4 - TBA ## **Changelog** CHANGELOG entry: added legacyIosGoogleConfigEnabled feature flag ## **Related issues** Fixes: ## **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** ### **Before** ### **After** ## **Pre-merge author checklist** - [ ] 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). - [ ] I've completed the PR template to the best of my ability - [ ] I've included tests if applicable - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] 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. ## **Pre-merge reviewer checklist** - [ ] 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. --- > [!NOTE] > **Low Risk** > Low risk: adds a new remote feature flag and selector with env override, without changing authentication flow yet; main risk is misconfiguration since the selector defaults to enabled. > > **Overview** > Adds a new remote feature flag, `legacyIosGoogleConfigEnabled`, including registry metadata and a dedicated selector `selectLegacyIosGoogleConfigEnabled` (defaulting to `true`) that can be force-overridden via `MM_LEGACY_IOS_GOOGLE_CONFIG_ENABLED`. > > Includes unit tests covering default/remote/env override behavior, and updates `babel.config.tests.js` to avoid inlining env vars for the new selector and its tests. > > Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit ca7e8132c44d06ba009029b1f83eb4412e10006f. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot). --- app/constants/featureFlags.ts | 1 + .../legacyIosGoogleConfig/index.test.ts | 56 +++++++++++++++++++ .../legacyIosGoogleConfig/index.ts | 26 +++++++++ babel.config.tests.js | 2 + tests/feature-flags/feature-flag-registry.ts | 8 +++ 5 files changed, 93 insertions(+) create mode 100644 app/selectors/featureFlagController/legacyIosGoogleConfig/index.test.ts create mode 100644 app/selectors/featureFlagController/legacyIosGoogleConfig/index.ts diff --git a/app/constants/featureFlags.ts b/app/constants/featureFlags.ts index c443b3f9fd6..a439f406657 100644 --- a/app/constants/featureFlags.ts +++ b/app/constants/featureFlags.ts @@ -15,6 +15,7 @@ export enum FeatureFlagNames { tokenDetailsV2Buttons = 'tokenDetailsV2Buttons', tokenDetailsV2ButtonLayout = 'tokenDetailsV2ButtonLayout', complianceEnabled = 'complianceEnabled', + legacyIosGoogleConfigEnabled = 'legacyIosGoogleConfigEnabled', } export const DEFAULT_FEATURE_FLAG_VALUES: Partial< diff --git a/app/selectors/featureFlagController/legacyIosGoogleConfig/index.test.ts b/app/selectors/featureFlagController/legacyIosGoogleConfig/index.test.ts new file mode 100644 index 00000000000..3a507ff875a --- /dev/null +++ b/app/selectors/featureFlagController/legacyIosGoogleConfig/index.test.ts @@ -0,0 +1,56 @@ +import { + DEFAULT_LEGACY_IOS_GOOGLE_CONFIG_ENABLED, + selectLegacyIosGoogleConfigEnabled, +} from '.'; +import { FeatureFlagNames } from '../../../constants/featureFlags'; + +describe('Legacy iOS Google Config Feature Flag Selector', () => { + const originalEnv = process.env.MM_LEGACY_IOS_GOOGLE_CONFIG_ENABLED; + + beforeEach(() => { + delete process.env.MM_LEGACY_IOS_GOOGLE_CONFIG_ENABLED; + }); + + afterAll(() => { + if (originalEnv === undefined) { + delete process.env.MM_LEGACY_IOS_GOOGLE_CONFIG_ENABLED; + return; + } + + process.env.MM_LEGACY_IOS_GOOGLE_CONFIG_ENABLED = originalEnv; + }); + + it('returns the default value when the remote flag is missing', () => { + const result = selectLegacyIosGoogleConfigEnabled.resultFunc({}); + + expect(result).toBe(DEFAULT_LEGACY_IOS_GOOGLE_CONFIG_ENABLED); + }); + + it('returns the remote flag value when present', () => { + const result = selectLegacyIosGoogleConfigEnabled.resultFunc({ + [FeatureFlagNames.legacyIosGoogleConfigEnabled]: false, + }); + + expect(result).toBe(false); + }); + + it('allows the local env var to force enable the legacy config', () => { + process.env.MM_LEGACY_IOS_GOOGLE_CONFIG_ENABLED = 'true'; + + const result = selectLegacyIosGoogleConfigEnabled.resultFunc({ + [FeatureFlagNames.legacyIosGoogleConfigEnabled]: false, + }); + + expect(result).toBe(true); + }); + + it('allows the local env var to force disable the legacy config', () => { + process.env.MM_LEGACY_IOS_GOOGLE_CONFIG_ENABLED = 'false'; + + const result = selectLegacyIosGoogleConfigEnabled.resultFunc({ + [FeatureFlagNames.legacyIosGoogleConfigEnabled]: true, + }); + + expect(result).toBe(false); + }); +}); diff --git a/app/selectors/featureFlagController/legacyIosGoogleConfig/index.ts b/app/selectors/featureFlagController/legacyIosGoogleConfig/index.ts new file mode 100644 index 00000000000..be844dc3bd6 --- /dev/null +++ b/app/selectors/featureFlagController/legacyIosGoogleConfig/index.ts @@ -0,0 +1,26 @@ +import { hasProperty } from '@metamask/utils'; +import { createSelector } from 'reselect'; +import { FeatureFlagNames } from '../../../constants/featureFlags'; +import { getFeatureFlagValue } from '../env'; +import { selectRemoteFeatureFlags } from '..'; + +export const DEFAULT_LEGACY_IOS_GOOGLE_CONFIG_ENABLED = true; + +export const selectLegacyIosGoogleConfigEnabled = createSelector( + selectRemoteFeatureFlags, + (remoteFeatureFlags) => { + const remoteValue = hasProperty( + remoteFeatureFlags, + FeatureFlagNames.legacyIosGoogleConfigEnabled, + ) + ? Boolean( + remoteFeatureFlags[FeatureFlagNames.legacyIosGoogleConfigEnabled], + ) + : DEFAULT_LEGACY_IOS_GOOGLE_CONFIG_ENABLED; + return getFeatureFlagValue( + // Use direct env access so Babel can inline this value in app builds. + process.env.MM_LEGACY_IOS_GOOGLE_CONFIG_ENABLED, + remoteValue, + ); + }, +); diff --git a/babel.config.tests.js b/babel.config.tests.js index bf4dfe1bd1f..292e3151ff1 100644 --- a/babel.config.tests.js +++ b/babel.config.tests.js @@ -37,6 +37,8 @@ const newOverrides = [ 'app/components/UI/Ramp/hooks/useRampTokens.test.ts', 'app/components/Views/confirmations/hooks/pay/useTransactionPayWithdraw.ts', 'app/components/Views/confirmations/hooks/pay/useTransactionPayWithdraw.test.ts', + 'app/selectors/featureFlagController/legacyIosGoogleConfig/index.ts', + 'app/selectors/featureFlagController/legacyIosGoogleConfig/index.test.ts', 'app/util/environment.ts', 'app/util/environment.test.ts', 'app/core/Engine/controllers/rewards-controller/utils/rewards-api-url.ts', diff --git a/tests/feature-flags/feature-flag-registry.ts b/tests/feature-flags/feature-flag-registry.ts index bb05b3aa658..2c696a8020c 100644 --- a/tests/feature-flags/feature-flag-registry.ts +++ b/tests/feature-flags/feature-flag-registry.ts @@ -2829,6 +2829,14 @@ export const FEATURE_FLAG_REGISTRY: Record = { status: FeatureFlagStatus.Active, }, + legacyIosGoogleConfigEnabled: { + name: 'legacyIosGoogleConfigEnabled', + type: FeatureFlagType.Remote, + inProd: true, + productionDefault: true, + status: FeatureFlagStatus.Active, + }, + metalCardCheckoutEnabled: { name: 'metalCardCheckoutEnabled', type: FeatureFlagType.Remote,