diff --git a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlagsBase.js b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlagsBase.js index 5b3d461ff36a..050b003a2efe 100644 --- a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlagsBase.js +++ b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlagsBase.js @@ -18,6 +18,10 @@ import NativeReactNativeFeatureFlags from './specs/NativeReactNativeFeatureFlags const accessedFeatureFlags: Set = new Set(); let overrides: ?ReactNativeFeatureFlagsJsOnlyOverrides; +// This is a list of functions to clear the cached value for each feature flag +// getter. This is only used in development. +const clearCachedValuesFns: Array<() => void> = []; + export type Getter = () => T; // This defines the types for the overrides object, whose methods also receive @@ -33,6 +37,12 @@ function createGetter( ): Getter { let cachedValue: ?T; + if (__DEV__) { + clearCachedValuesFns.push(() => { + cachedValue = undefined; + }); + } + return () => { if (cachedValue == null) { cachedValue = customValueGetter() ?? defaultValue; @@ -115,3 +125,12 @@ function maybeLogUnavailableNativeModuleError(configName: string): void { ); } } + +export function dangerouslyResetForTesting(): void { + if (__DEV__) { + overrides = null; + accessedFeatureFlags.clear(); + reportedConfigNames.clear(); + clearCachedValuesFns.forEach(fn => fn()); + } +} diff --git a/packages/react-native/src/private/setup/__tests__/setUpDefaultReactNativeEnvironment-FeatureFlags-itest.js b/packages/react-native/src/private/setup/__tests__/setUpDefaultReactNativeEnvironment-FeatureFlags-itest.js new file mode 100644 index 000000000000..b6f7acd4be4b --- /dev/null +++ b/packages/react-native/src/private/setup/__tests__/setUpDefaultReactNativeEnvironment-FeatureFlags-itest.js @@ -0,0 +1,28 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +import * as ReactNativeFeatureFlags from '../../featureflags/ReactNativeFeatureFlags'; +import * as ReactNativeFeatureFlagsBase from '../../featureflags/ReactNativeFeatureFlagsBase'; +import setUpDefaultReactNativeEnvironment from 'react-native/src/private/setup/setUpDefaultReactNativeEnvironment'; + +describe('setUpReactNativeEnvironment', () => { + it('should not read any feature flags', () => { + ReactNativeFeatureFlagsBase.dangerouslyResetForTesting(); + + setUpDefaultReactNativeEnvironment(false); + + expect(() => { + // If any feature flags were read, this call would fail. + ReactNativeFeatureFlags.override({ + jsOnlyTestFlag: () => true, + }); + }).not.toThrow(); + }); +});