RN: Hoist Reflection from Verification
Summary: Hoists the call to `getNativeComponentAttributes` out of the verification function so that it's easier to keep track of when this function is and is not called. The purpose of this will become clearer in a future refactor. Changelog: [Internal] Reviewed By: ejanzer Differential Revision: D25072600 fbshipit-source-id: bc42461baae3476fa7ecb6186c4256dd23921ed5
This commit is contained in:
Родитель
9611a7b43e
Коммит
69b4611049
|
@ -10,12 +10,13 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const getNativeComponentAttributes = require('../../ReactNative/getNativeComponentAttributes');
|
||||
jest.dontMock('../verifyComponentAttributeEquivalence');
|
||||
|
||||
const verifyComponentAttributeEquivalence = require('../verifyComponentAttributeEquivalence')
|
||||
.default;
|
||||
|
||||
jest.dontMock('../verifyComponentAttributeEquivalence');
|
||||
jest.mock('../../ReactNative/getNativeComponentAttributes', () => () => ({
|
||||
const TestComponentNativeViewConfig = {
|
||||
uiViewClassName: 'TestComponent',
|
||||
NativeProps: {
|
||||
value: 'BOOL',
|
||||
},
|
||||
|
@ -40,62 +41,63 @@ jest.mock('../../ReactNative/getNativeComponentAttributes', () => () => ({
|
|||
},
|
||||
transform: 'CATransform3D',
|
||||
},
|
||||
}));
|
||||
};
|
||||
|
||||
describe('verifyComponentAttributeEquivalence', () => {
|
||||
beforeEach(() => {
|
||||
global.__DEV__ = true;
|
||||
console.error = jest.fn();
|
||||
jest.resetModules();
|
||||
});
|
||||
|
||||
describe('verifyComponentAttributeEquivalence', () => {
|
||||
test('should not verify in prod', () => {
|
||||
it('should not verify in prod', () => {
|
||||
global.__DEV__ = false;
|
||||
verifyComponentAttributeEquivalence('TestComponent', {});
|
||||
verifyComponentAttributeEquivalence(TestComponentNativeViewConfig, {});
|
||||
});
|
||||
|
||||
test('should not error with native config that is a subset of the given config', () => {
|
||||
const configWithAdditionalProperties = getNativeComponentAttributes(
|
||||
'TestComponent',
|
||||
);
|
||||
|
||||
configWithAdditionalProperties.bubblingEventTypes.topFocus = {
|
||||
it('should not error with native config that is a subset of the given config', () => {
|
||||
const configWithAdditionalProperties = {
|
||||
...TestComponentNativeViewConfig,
|
||||
bubblingEventTypes: {
|
||||
...TestComponentNativeViewConfig.bubblingEventTypes,
|
||||
topFocus: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: 'onFocus',
|
||||
captured: 'onFocusCapture',
|
||||
},
|
||||
};
|
||||
|
||||
configWithAdditionalProperties.directEventTypes.topSlidingComplete = {
|
||||
},
|
||||
},
|
||||
directEventTypes: {
|
||||
...TestComponentNativeViewConfig.directEventTypes,
|
||||
topSlidingComplete: {
|
||||
registrationName: 'onSlidingComplete',
|
||||
},
|
||||
},
|
||||
validAttributes: {
|
||||
...TestComponentNativeViewConfig.validAttributes,
|
||||
active: true,
|
||||
},
|
||||
};
|
||||
|
||||
configWithAdditionalProperties.validAttributes.active = true;
|
||||
|
||||
verifyComponentAttributeEquivalence(
|
||||
'TestComponent',
|
||||
configWithAdditionalProperties,
|
||||
);
|
||||
verifyComponentAttributeEquivalence(
|
||||
'TestComponent',
|
||||
TestComponentNativeViewConfig,
|
||||
configWithAdditionalProperties,
|
||||
);
|
||||
|
||||
expect(console.error).not.toBeCalled();
|
||||
});
|
||||
|
||||
test('should error if given config is missing native config properties', () => {
|
||||
verifyComponentAttributeEquivalence('TestComponent', {});
|
||||
it('should error if given config is missing native config properties', () => {
|
||||
verifyComponentAttributeEquivalence(TestComponentNativeViewConfig, {});
|
||||
|
||||
expect(console.error).toBeCalledTimes(3);
|
||||
expect(console.error).toBeCalledWith(
|
||||
'TestComponent generated view config for directEventTypes does not match native, missing: topAccessibilityAction',
|
||||
"'TestComponent' has a view config that does not match native. 'validAttributes' is missing: borderColor, style",
|
||||
);
|
||||
expect(console.error).toBeCalledWith(
|
||||
'TestComponent generated view config for bubblingEventTypes does not match native, missing: topChange',
|
||||
"'TestComponent' has a view config that does not match native. 'bubblingEventTypes' is missing: topChange",
|
||||
);
|
||||
expect(console.error).toBeCalledWith(
|
||||
'TestComponent generated view config for validAttributes does not match native, missing: borderColor style',
|
||||
"'TestComponent' has a view config that does not match native. 'directEventTypes' is missing: topAccessibilityAction",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -10,8 +10,9 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const ReactNativeViewConfigRegistry = require('../Renderer/shims/ReactNativeViewConfigRegistry');
|
||||
const ReactNativeViewViewConfig = require('../Components/View/ReactNativeViewViewConfig');
|
||||
import ReactNativeViewConfigRegistry from '../Renderer/shims/ReactNativeViewConfigRegistry';
|
||||
import ReactNativeViewViewConfig from '../Components/View/ReactNativeViewViewConfig';
|
||||
import getNativeComponentAttributes from '../ReactNative/getNativeComponentAttributes';
|
||||
import verifyComponentAttributeEquivalence from './verifyComponentAttributeEquivalence';
|
||||
|
||||
export type GeneratedViewConfig = {
|
||||
|
@ -47,7 +48,7 @@ function registerGeneratedViewConfig(
|
|||
componentName: string,
|
||||
viewConfig: GeneratedViewConfig,
|
||||
) {
|
||||
const mergedViewConfig = {
|
||||
const staticViewConfig = {
|
||||
uiViewClassName: componentName,
|
||||
Commands: {},
|
||||
/* $FlowFixMe(>=0.122.0 site=react_native_fb) This comment suppresses an
|
||||
|
@ -75,10 +76,12 @@ function registerGeneratedViewConfig(
|
|||
|
||||
ReactNativeViewConfigRegistry.register(componentName, () => {
|
||||
if (!global.RN$Bridgeless) {
|
||||
verifyComponentAttributeEquivalence(componentName, mergedViewConfig);
|
||||
const nativeViewConfig = getNativeComponentAttributes(componentName);
|
||||
|
||||
verifyComponentAttributeEquivalence(nativeViewConfig, staticViewConfig);
|
||||
}
|
||||
|
||||
return mergedViewConfig;
|
||||
return staticViewConfig;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -10,8 +10,6 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const getNativeComponentAttributes = require('../ReactNative/getNativeComponentAttributes');
|
||||
|
||||
import ReactNativeViewViewConfig from '../Components/View/ReactNativeViewViewConfig';
|
||||
import type {ReactNativeBaseComponentViewConfig} from '../Renderer/shims/ReactNativeTypes';
|
||||
|
||||
|
@ -41,26 +39,27 @@ const IGNORED_KEYS = ['transform', 'hitSlop'];
|
|||
* years from now...
|
||||
*/
|
||||
export default function verifyComponentAttributeEquivalence(
|
||||
componentName: string,
|
||||
config: ReactNativeBaseComponentViewConfig<>,
|
||||
nativeViewConfig: ReactNativeBaseComponentViewConfig<>,
|
||||
staticViewConfig: ReactNativeBaseComponentViewConfig<>,
|
||||
) {
|
||||
const nativeAttributes = getNativeComponentAttributes(componentName);
|
||||
|
||||
['validAttributes', 'bubblingEventTypes', 'directEventTypes'].forEach(
|
||||
prop => {
|
||||
const diffKeys = Object.keys(
|
||||
lefthandObjectDiff(nativeAttributes[prop], config[prop]),
|
||||
for (const prop of [
|
||||
'validAttributes',
|
||||
'bubblingEventTypes',
|
||||
'directEventTypes',
|
||||
]) {
|
||||
const diff = Object.keys(
|
||||
lefthandObjectDiff(nativeViewConfig[prop], staticViewConfig[prop]),
|
||||
);
|
||||
|
||||
if (diffKeys.length) {
|
||||
if (diff.length > 0) {
|
||||
const name =
|
||||
staticViewConfig.uiViewClassName ?? nativeViewConfig.uiViewClassName;
|
||||
console.error(
|
||||
`${componentName} generated view config for ${prop} does not match native, missing: ${diffKeys.join(
|
||||
' ',
|
||||
)}`,
|
||||
`'${name}' has a view config that does not match native. ` +
|
||||
`'${prop}' is missing: ${diff.join(', ')}`,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function lefthandObjectDiff(leftObj: Object, rightObj: Object): Object {
|
||||
|
|
Загрузка…
Ссылка в новой задаче