From acfdc9760b4dc55d192b08de42b2c45e5e5bb531 Mon Sep 17 00:00:00 2001 From: Ricky Date: Wed, 18 Sep 2019 15:31:00 +0100 Subject: [PATCH] [React Native] Fix for view config registrations (#16821) --- .../ReactNativeViewConfigRegistry.js | 5 ++- .../ReactNativeEvents-test.internal.js | 43 +++++++++++++++++++ .../ReactNativeViewConfigRegistry.js | 5 ++- 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/packages/react-native-renderer/src/__mocks__/react-native/Libraries/ReactPrivate/ReactNativeViewConfigRegistry.js b/packages/react-native-renderer/src/__mocks__/react-native/Libraries/ReactPrivate/ReactNativeViewConfigRegistry.js index 77424ad510513..05c8b93c9ee58 100644 --- a/packages/react-native-renderer/src/__mocks__/react-native/Libraries/ReactPrivate/ReactNativeViewConfigRegistry.js +++ b/packages/react-native-renderer/src/__mocks__/react-native/Libraries/ReactPrivate/ReactNativeViewConfigRegistry.js @@ -101,10 +101,13 @@ exports.get = function(name: string): ReactNativeBaseComponentViewConfig<> { : '', ); } - viewConfigCallbacks.set(name, null); viewConfig = callback(); processEventTypes(viewConfig); viewConfigs.set(name, viewConfig); + + // Clear the callback after the config is set so that + // we don't mask any errors during registration. + viewConfigCallbacks.set(name, null); } else { viewConfig = viewConfigs.get(name); } diff --git a/packages/react-native-renderer/src/__tests__/ReactNativeEvents-test.internal.js b/packages/react-native-renderer/src/__tests__/ReactNativeEvents-test.internal.js index e9de5541a3af0..805acff53ef49 100644 --- a/packages/react-native-renderer/src/__tests__/ReactNativeEvents-test.internal.js +++ b/packages/react-native-renderer/src/__tests__/ReactNativeEvents-test.internal.js @@ -75,6 +75,49 @@ beforeEach(() => { .ReactNativeViewConfigRegistry.register; }); +it('fails to register the same event name with different types', () => { + const InvalidEvents = createReactNativeComponentClass('InvalidEvents', () => { + if (!__DEV__) { + // Simulate a registration error in prod. + throw new Error('Event cannot be both direct and bubbling: topChange'); + } + + // This view config has the same bubbling and direct event name + // which will fail to register in developement. + return { + uiViewClassName: 'InvalidEvents', + validAttributes: { + onChange: true, + }, + bubblingEventTypes: { + topChange: { + phasedRegistrationNames: { + bubbled: 'onChange', + captured: 'onChangeCapture', + }, + }, + }, + directEventTypes: { + topChange: { + registrationName: 'onChange', + }, + }, + }; + }); + + // The first time this renders, + // we attempt to register the view config and fail. + expect(() => ReactNative.render(, 1)).toThrow( + 'Event cannot be both direct and bubbling: topChange', + ); + + // Continue to re-register the config and + // fail so that we don't mask the above failure. + expect(() => ReactNative.render(, 1)).toThrow( + 'Event cannot be both direct and bubbling: topChange', + ); +}); + it('fails if unknown/unsupported event types are dispatched', () => { expect(RCTEventEmitter.register).toHaveBeenCalledTimes(1); const EventEmitter = RCTEventEmitter.register.mock.calls[0][0]; diff --git a/scripts/rollup/shims/react-native/ReactNativeViewConfigRegistry.js b/scripts/rollup/shims/react-native/ReactNativeViewConfigRegistry.js index 5ebc0d36d39fe..7290c84546c50 100644 --- a/scripts/rollup/shims/react-native/ReactNativeViewConfigRegistry.js +++ b/scripts/rollup/shims/react-native/ReactNativeViewConfigRegistry.js @@ -98,10 +98,13 @@ exports.get = function(name: string): ReactNativeBaseComponentViewConfig<> { : '', ); } - viewConfigCallbacks.set(name, null); viewConfig = callback(); processEventTypes(viewConfig); viewConfigs.set(name, viewConfig); + + // Clear the callback after the config is set so that + // we don't mask any errors during registration. + viewConfigCallbacks.set(name, null); } else { viewConfig = viewConfigs.get(name); }