diff --git a/packages/react-native/Libraries/Core/setUpGlobals.js b/packages/react-native/Libraries/Core/setUpGlobals.js index 74d8786131dd..0418fc0246ad 100644 --- a/packages/react-native/Libraries/Core/setUpGlobals.js +++ b/packages/react-native/Libraries/Core/setUpGlobals.js @@ -15,14 +15,19 @@ * Sets up global variables for React Native. * You can use this module directly, or just require InitializeCore. */ -if (global.window === undefined) { +if (globalThis.window === undefined) { // $FlowExpectedError[cannot-write] The global isn't writable anywhere but here, where we define it. - global.window = global; + Object.defineProperty(globalThis, 'window', { + value: globalThis, + configurable: false, + enumerable: true, + writable: false, + }); } -if (global.self === undefined) { +if (globalThis.self === undefined) { // $FlowExpectedError[cannot-write] The global isn't writable anywhere but here, where we define it. - global.self = global; + globalThis.self = globalThis; } // Set up process diff --git a/packages/react-native/Libraries/Core/setUpNavigator.js b/packages/react-native/Libraries/Core/setUpNavigator.js index bcf2cbd597b5..1917abd5202c 100644 --- a/packages/react-native/Libraries/Core/setUpNavigator.js +++ b/packages/react-native/Libraries/Core/setUpNavigator.js @@ -15,7 +15,12 @@ const {polyfillObjectProperty} = require('../Utilities/PolyfillFunctions'); const navigator = global.navigator; if (navigator === undefined) { // $FlowExpectedError[cannot-write] The global isn't writable anywhere but here, where we define it. - global.navigator = {product: 'ReactNative'}; + Object.defineProperty(global, 'navigator', { + value: {product: 'ReactNative'}, + configurable: true, + enumerable: true, + writable: false, + }); } else { // see https://github.com/facebook/react-native/issues/10881 polyfillObjectProperty(navigator, 'product', () => 'ReactNative'); diff --git a/packages/react-native/src/private/setup/__tests__/setUpDefaultReactNativeEnvironment-Globals-itest.js b/packages/react-native/src/private/setup/__tests__/setUpDefaultReactNativeEnvironment-Globals-itest.js index c319ddbdc061..2172cb72b6a4 100644 --- a/packages/react-native/src/private/setup/__tests__/setUpDefaultReactNativeEnvironment-Globals-itest.js +++ b/packages/react-native/src/private/setup/__tests__/setUpDefaultReactNativeEnvironment-Globals-itest.js @@ -14,6 +14,25 @@ import '@react-native/fantom/src/setUpDefaultReactNativeEnvironment'; declare var PerformanceObserverEntryList: unknown; declare var EventCounts: unknown; +function expectGlobalDescriptorToMatch( + name: string, + expected: { + enumerable: boolean, + configurable: boolean, + writable: boolean, + }, +) { + const descriptor = Object.getOwnPropertyDescriptor(globalThis, name); + if (descriptor == null) { + throw new Error(`Expected globalThis.${name} to be defined`); + } + expect({ + enumerable: descriptor.enumerable, + configurable: descriptor.configurable, + writable: descriptor.writable, + }).toEqual(expected); +} + describe('setUpDefaultReactNativeEnvironment (globals)', () => { describe('global object', () => { it('should be exposed as globalThis, global, window and self', () => { @@ -23,6 +42,56 @@ describe('setUpDefaultReactNativeEnvironment (globals)', () => { }); }); + describe('property descriptors', () => { + it('should define window as enumerable but not configurable or writable', () => { + expectGlobalDescriptorToMatch('window', { + enumerable: true, + configurable: false, + writable: false, + }); + }); + + it('should define self as configurable, enumerable and writable', () => { + expectGlobalDescriptorToMatch('self', { + enumerable: true, + configurable: true, + writable: true, + }); + }); + + it('should define navigator as configurable and enumerable but not writable', () => { + expectGlobalDescriptorToMatch('navigator', { + enumerable: true, + configurable: true, + writable: false, + }); + }); + + it('should define Infinity as not configurable, writable or enumerable', () => { + expectGlobalDescriptorToMatch('Infinity', { + enumerable: false, + configurable: false, + writable: false, + }); + }); + + it('should define NaN as not configurable, writable or enumerable', () => { + expectGlobalDescriptorToMatch('NaN', { + enumerable: false, + configurable: false, + writable: false, + }); + }); + + it('should define undefined as not configurable, writable or enumerable', () => { + expectGlobalDescriptorToMatch('undefined', { + enumerable: false, + configurable: false, + writable: false, + }); + }); + }); + describe('environment', () => { it('should provide process.env.NODE_ENV', () => { expect(process.env.NODE_ENV).toBe('development');