Adds displayName to EventComponent and EventTarget (#15268)
* Adds displayName to EventComponent and EventTarget
Dominic Gannaway committed
Apr 3, 2019 at 12:24 UTC
89064fe68d1f26da78c541a9c64ee093322b9766
10 files changed
+183
-1
packages/react-dom/src/events/__tests__/DOMEventResponderSystem-test.internal.js
+1
@@ -21,6 +21,7 @@ function createReactEventComponent(targetEventTypes, handleEvent) {
21
22
return {
23
$$typeof: Symbol.for('react.event_component'),
24
+ displayName: 'TestEventComponent',
25
props: null,
26
responder: testEventResponder,
27
};
packages/react-events/src/Drag.js
+1
@@ -211,6 +211,7 @@ const DragResponder = {
211
212
export default {
213
$$typeof: REACT_EVENT_COMPONENT_TYPE,
214
+ displayName: 'Drag',
215
props: null,
216
responder: DragResponder,
217
};
packages/react-events/src/Focus.js
+1
@@ -122,6 +122,7 @@ const FocusResponder = {
122
123
export default {
124
$$typeof: REACT_EVENT_COMPONENT_TYPE,
125
+ displayName: 'Focus',
126
props: null,
127
responder: FocusResponder,
128
};
packages/react-events/src/Hover.js
+1
@@ -204,6 +204,7 @@ const HoverResponder = {
204
205
export default {
206
$$typeof: REACT_EVENT_COMPONENT_TYPE,
207
+ displayName: 'Hover',
208
props: null,
209
responder: HoverResponder,
210
};
packages/react-events/src/Press.js
+1
@@ -395,6 +395,7 @@ const PressResponder = {
395
396
export default {
397
$$typeof: REACT_EVENT_COMPONENT_TYPE,
398
+ displayName: 'Press',
399
props: null,
400
responder: PressResponder,
401
};
packages/react-events/src/Swipe.js
+1
@@ -239,6 +239,7 @@ const SwipeResponder = {
239
240
export default {
241
$$typeof: REACT_EVENT_COMPONENT_TYPE,
242
+ displayName: 'Swipe',
243
props: null,
244
responder: SwipeResponder,
245
};
packages/react-events/src/__tests__/Press-test.internal.js
+4
@@ -394,4 +394,8 @@ describe('Event responder: Press', () => {
394
expect(events).toEqual(['keydown', 'inner: onPress', 'outer: onPress']);
395
});
396
});
397
+
398
+ it('expect displayName to show up for event component', () => {
399
+ expect(Press.displayName).toBe('Press');
400
+ });
401
});
packages/react-reconciler/src/__tests__/ReactFiberEvents-test-internal.js
+148
-1
@@ -29,6 +29,7 @@ const noOpResponder = {
29
function createReactEventComponent() {
30
return {
31
$$typeof: ReactSymbols.REACT_EVENT_COMPONENT_TYPE,
32
+ displayName: 'TestEventComponent',
33
props: null,
34
responder: noOpResponder,
35
};
@@ -37,6 +38,7 @@ function createReactEventComponent() {
38
function createReactEventTarget() {
39
return {
40
$$typeof: ReactSymbols.REACT_EVENT_TARGET_TYPE,
41
+ displayName: 'TestEventTarget',
42
type: Symbol.for('react.event_target.test'),
43
};
44
}
@@ -392,6 +394,54 @@ describe('ReactFiberEvents', () => {
394
'Warning: validateDOMNesting: React event targets must not have event components as children.',
395
);
396
});
397
+
398
+ it('should error with a component stack contains the names of the event components and event targets', () => {
399
+ let componentStackMessage;
400
+
401
+ function ErrorComponent() {
402
+ throw new Error('Failed!');
403
+ }
404
+
405
+ const Test = () => (
406
+ <EventComponent>
407
+ <EventTarget>
408
+ <span>
409
+ <ErrorComponent />
410
+ </span>
411
+ </EventTarget>
412
+ </EventComponent>
413
+ );
414
+
415
+ class Wrapper extends React.Component {
416
+ state = {
417
+ error: null,
418
+ };
419
+
420
+ componentDidCatch(error, errMessage) {
421
+ componentStackMessage = errMessage.componentStack;
422
+ this.setState({
423
+ error,
424
+ });
425
+ }
426
+
427
+ render() {
428
+ if (this.state.error) {
429
+ return null;
430
+ }
431
+ return <Test />;
432
+ }
433
+ }
434
+
435
+ ReactNoop.render(<Wrapper />);
436
+ expect(Scheduler).toFlushWithoutYielding();
437
+
438
+ expect(componentStackMessage.includes('ErrorComponent')).toBe(true);
439
+ expect(componentStackMessage.includes('span')).toBe(true);
440
+ expect(componentStackMessage.includes('TestEventTarget')).toBe(true);
441
+ expect(componentStackMessage.includes('TestEventComponent')).toBe(true);
442
+ expect(componentStackMessage.includes('Test')).toBe(true);
443
+ expect(componentStackMessage.includes('Wrapper')).toBe(true);
444
+ });
445
});
446
447
describe('TestRenderer', () => {
@@ -570,7 +620,7 @@ describe('ReactFiberEvents', () => {
620
error: null,
621
};
622
573
- componentDidCatch(error) {
623
+ componentDidCatch(error, errStack) {
624
this.setState({
625
error,
626
});
@@ -734,6 +784,55 @@ describe('ReactFiberEvents', () => {
784
'Warning: validateDOMNesting: React event targets must not have event components as children.',
785
);
786
});
787
+
788
+ it('should error with a component stack contains the names of the event components and event targets', () => {
789
+ let componentStackMessage;
790
+
791
+ function ErrorComponent() {
792
+ throw new Error('Failed!');
793
+ }
794
+
795
+ const Test = () => (
796
+ <EventComponent>
797
+ <EventTarget>
798
+ <span>
799
+ <ErrorComponent />
800
+ </span>
801
+ </EventTarget>
802
+ </EventComponent>
803
+ );
804
+
805
+ class Wrapper extends React.Component {
806
+ state = {
807
+ error: null,
808
+ };
809
+
810
+ componentDidCatch(error, errMessage) {
811
+ componentStackMessage = errMessage.componentStack;
812
+ this.setState({
813
+ error,
814
+ });
815
+ }
816
+
817
+ render() {
818
+ if (this.state.error) {
819
+ return null;
820
+ }
821
+ return <Test />;
822
+ }
823
+ }
824
+
825
+ const root = ReactTestRenderer.create(null);
826
+ root.update(<Wrapper />);
827
+ expect(Scheduler).toFlushWithoutYielding();
828
+
829
+ expect(componentStackMessage.includes('ErrorComponent')).toBe(true);
830
+ expect(componentStackMessage.includes('span')).toBe(true);
831
+ expect(componentStackMessage.includes('TestEventTarget')).toBe(true);
832
+ expect(componentStackMessage.includes('TestEventComponent')).toBe(true);
833
+ expect(componentStackMessage.includes('Test')).toBe(true);
834
+ expect(componentStackMessage.includes('Wrapper')).toBe(true);
835
+ });
836
});
837
838
describe('ReactDOM', () => {
@@ -1053,6 +1152,54 @@ describe('ReactFiberEvents', () => {
1152
'Warning: validateDOMNesting: React event targets must not have event components as children.',
1153
);
1154
});
1155
+
1156
+ it('should error with a component stack contains the names of the event components and event targets', () => {
1157
+ let componentStackMessage;
1158
+
1159
+ function ErrorComponent() {
1160
+ throw new Error('Failed!');
1161
+ }
1162
+
1163
+ const Test = () => (
1164
+ <EventComponent>
1165
+ <EventTarget>
1166
+ <span>
1167
+ <ErrorComponent />
1168
+ </span>
1169
+ </EventTarget>
1170
+ </EventComponent>
1171
+ );
1172
+
1173
+ class Wrapper extends React.Component {
1174
+ state = {
1175
+ error: null,
1176
+ };
1177
+
1178
+ componentDidCatch(error, errMessage) {
1179
+ componentStackMessage = errMessage.componentStack;
1180
+ this.setState({
1181
+ error,
1182
+ });
1183
+ }
1184
+
1185
+ render() {
1186
+ if (this.state.error) {
1187
+ return null;
1188
+ }
1189
+ return <Test />;
1190
+ }
1191
+ }
1192
+
1193
+ const container = document.createElement('div');
1194
+ ReactDOM.render(<Wrapper />, container);
1195
+
1196
+ expect(componentStackMessage.includes('ErrorComponent')).toBe(true);
1197
+ expect(componentStackMessage.includes('span')).toBe(true);
1198
+ expect(componentStackMessage.includes('TestEventTarget')).toBe(true);
1199
+ expect(componentStackMessage.includes('TestEventComponent')).toBe(true);
1200
+ expect(componentStackMessage.includes('Test')).toBe(true);
1201
+ expect(componentStackMessage.includes('Wrapper')).toBe(true);
1202
+ });
1203
});
1204
1205
describe('ReactDOMServer', () => {
packages/shared/ReactTypes.js
+2
@@ -93,11 +93,13 @@ export type ReactEventResponder = {
93
94
export type ReactEventComponent = {|
95
$$typeof: Symbol | number,
96
+ displayName?: string,
97
props: null | Object,
98
responder: ReactEventResponder,
99
|};
100
101
export type ReactEventTarget = {|
102
$$typeof: Symbol | number,
103
+ displayName?: string,
104
type: Symbol | number,
105
|};
packages/shared/getComponentName.js
+23
@@ -22,8 +22,12 @@ import {
22
REACT_STRICT_MODE_TYPE,
23
REACT_SUSPENSE_TYPE,
24
REACT_LAZY_TYPE,
25
+ REACT_EVENT_COMPONENT_TYPE,
26
+ REACT_EVENT_TARGET_TYPE,
27
+ REACT_EVENT_TARGET_TOUCH_HIT,
28
} from 'shared/ReactSymbols';
29
import {refineResolvedLazyComponent} from 'shared/ReactLazyComponent';
30
+import type {ReactEventComponent, ReactEventTarget} from 'shared/ReactTypes';
31
32
function getWrappedName(
33
outerType: mixed,
@@ -87,6 +91,25 @@ function getComponentName(type: mixed): string | null {
91
if (resolvedThenable) {
92
return getComponentName(resolvedThenable);
93
}
94
+ break;
95
+ }
96
+ case REACT_EVENT_COMPONENT_TYPE: {
97
+ const eventComponent = ((type: any): ReactEventComponent);
98
+ const displayName = eventComponent.displayName;
99
+ if (displayName !== undefined) {
100
+ return displayName;
101
+ }
102
+ break;
103
+ }
104
+ case REACT_EVENT_TARGET_TYPE: {
105
+ const eventTarget = ((type: any): ReactEventTarget);
106
+ if (eventTarget.type === REACT_EVENT_TARGET_TOUCH_HIT) {
107
+ return 'TouchHitTarget';
108
+ }
109
+ const displayName = eventTarget.displayName;
110
+ if (displayName !== undefined) {
111
+ return displayName;
112
+ }
113
}
114
}
115
}