Skip to content

Commit 55fca7f

Browse files
vincentriemerfacebook-github-bot
authored andcommitted
Add PointerOver/PointerOut handling test
Summary: Changelog: [RNTester][Internal] - Add PointerOver/PointerOut handling test This diff adds another platform test based on WPT testcase for mouseover/mouseout events but instead applied to pointerover/pointerout events recently implemented for RN. Reviewed By: lunaleaps Differential Revision: D40359286 fbshipit-source-id: 672f413f56faca55b9d838150fb66de66d78d6f2
1 parent 0481948 commit 55fca7f

File tree

2 files changed

+237
-0
lines changed

2 files changed

+237
-0
lines changed
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @format
8+
* @flow
9+
*/
10+
11+
import type {PlatformTestComponentBaseProps} from '../PlatformTest/RNTesterPlatformTestTypes';
12+
import type {PointerEvent} from 'react-native/Libraries/Types/CoreEventTypes';
13+
import type {HostComponent} from 'react-native/Libraries/Renderer/shims/ReactNativeTypes';
14+
15+
import RNTesterPlatformTest from '../PlatformTest/RNTesterPlatformTest';
16+
import * as React from 'react';
17+
import {useRef, useCallback} from 'react';
18+
import {StyleSheet, View} from 'react-native';
19+
20+
function getNativeTagFromHostElement(
21+
elem: ?React.ElementRef<HostComponent<mixed>> | number,
22+
): ?number {
23+
if (typeof elem === 'number') {
24+
return elem;
25+
}
26+
if (elem != null) {
27+
// $FlowExpectedError - accessing non-public property
28+
return elem._nativeTag;
29+
}
30+
return undefined;
31+
}
32+
33+
const styles = StyleSheet.create({
34+
outer: {
35+
padding: 40,
36+
height: 60,
37+
backgroundColor: 'blue',
38+
},
39+
inner: {
40+
padding: 40,
41+
height: 60,
42+
backgroundColor: 'green',
43+
},
44+
released: {
45+
padding: 40,
46+
height: 60,
47+
backgroundColor: 'yellow',
48+
},
49+
});
50+
51+
// adapted from https://github.com/web-platform-tests/wpt/blob/master/uievents/order-of-events/mouse-events/mouseover-out.html
52+
function PointerEventPointerOverOutTestCase(
53+
props: PlatformTestComponentBaseProps,
54+
) {
55+
const {harness} = props;
56+
57+
const t = harness.useAsyncTest('PointerOver/Out events');
58+
59+
const innerNativeTagRef = useRef(-1);
60+
const outerNativeTagRef = useRef(-1);
61+
62+
const handleInnerRefCallback = useCallback(elem => {
63+
const nativeTag = getNativeTagFromHostElement(elem);
64+
innerNativeTagRef.current = nativeTag != null ? nativeTag : -1;
65+
}, []);
66+
const handleOuterRefCallback = useCallback(elem => {
67+
const nativeTag = getNativeTagFromHostElement(elem);
68+
outerNativeTagRef.current = nativeTag != null ? nativeTag : -1;
69+
}, []);
70+
71+
const innerOverRef = useRef(0);
72+
const innerOutRef = useRef(0);
73+
74+
const outerOwnOverRef = useRef(0);
75+
const outerOwnOutRef = useRef(0);
76+
const outerOverRef = useRef(0);
77+
const outerOutRef = useRef(0);
78+
79+
const innerPointerOverHandler = useCallback(
80+
(e: PointerEvent) => {
81+
t.step(({assert_equals, assert_true}) => {
82+
assert_equals(
83+
innerOverRef.current,
84+
innerOutRef.current,
85+
'pointerover is recieved before pointerout',
86+
);
87+
switch (innerOverRef.current) {
88+
case 0: {
89+
assert_equals(
90+
outerOwnOverRef.current,
91+
1,
92+
'should have triggered a pointerover in the outer before',
93+
);
94+
break;
95+
}
96+
case 1: {
97+
assert_equals(
98+
outerOwnOverRef.current,
99+
1,
100+
'should have not triggered a pointerover in the outer before',
101+
);
102+
break;
103+
}
104+
default: {
105+
assert_true(false, 'should not get more than two mouseovers');
106+
}
107+
}
108+
});
109+
innerOverRef.current++;
110+
},
111+
[t],
112+
);
113+
const innerPointerOutHandler = useCallback(
114+
(e: PointerEvent) => {
115+
t.step(({assert_equals, assert_true}) => {
116+
assert_equals(
117+
innerOverRef.current,
118+
innerOutRef.current + 1,
119+
'pointerout is received after pointerover',
120+
);
121+
switch (innerOutRef.current) {
122+
case 0: {
123+
assert_equals(
124+
outerOwnOutRef.current,
125+
1,
126+
'pointerout should have been received in the parent when hovering over this element',
127+
);
128+
break;
129+
}
130+
case 1: {
131+
break;
132+
}
133+
default: {
134+
assert_true(false, 'should not get more than two pointerouts');
135+
}
136+
}
137+
});
138+
innerOutRef.current++;
139+
},
140+
[t],
141+
);
142+
143+
const outerPointerOverHandler = useCallback(
144+
(e: PointerEvent) => {
145+
const eventElemTag = getNativeTagFromHostElement(e.target);
146+
t.step(({assert_equals}) => {
147+
if (eventElemTag === outerNativeTagRef.current) {
148+
assert_equals(
149+
outerOwnOverRef.current,
150+
outerOwnOutRef.current,
151+
'outer: pointerover is recieved before pointerout',
152+
);
153+
outerOwnOverRef.current++;
154+
} else {
155+
assert_equals(
156+
outerOverRef.current - outerOwnOverRef.current,
157+
innerOverRef.current - 1,
158+
'pointerover: should only receive this via bubbling',
159+
);
160+
}
161+
});
162+
outerOverRef.current++;
163+
},
164+
[t],
165+
);
166+
const outerPointerOutHandler = useCallback(
167+
(e: PointerEvent) => {
168+
const eventElemTag = getNativeTagFromHostElement(e.target);
169+
t.step(({assert_equals}) => {
170+
if (eventElemTag === outerNativeTagRef.current) {
171+
assert_equals(
172+
outerOwnOverRef.current,
173+
outerOwnOutRef.current + 1,
174+
'outer: pointerout is recieved after pointerover',
175+
);
176+
if (outerOwnOutRef.current === 1) {
177+
assert_equals(innerOutRef.current, 2, 'inner should be done now');
178+
t.done();
179+
}
180+
outerOwnOutRef.current++;
181+
} else {
182+
assert_equals(
183+
outerOutRef.current - outerOwnOutRef.current,
184+
innerOutRef.current - 1,
185+
'pointerout: should only recieve this via bubbling',
186+
);
187+
}
188+
});
189+
outerOutRef.current++;
190+
},
191+
[t],
192+
);
193+
194+
return (
195+
<>
196+
<View
197+
ref={handleOuterRefCallback}
198+
onPointerOver={outerPointerOverHandler}
199+
onPointerOut={outerPointerOutHandler}
200+
style={styles.outer}>
201+
<View
202+
ref={handleInnerRefCallback}
203+
onPointerOver={innerPointerOverHandler}
204+
onPointerOut={innerPointerOutHandler}
205+
style={styles.inner}
206+
/>
207+
</View>
208+
<View style={styles.released} />
209+
</>
210+
);
211+
}
212+
213+
type Props = $ReadOnly<{}>;
214+
export default function PointerEventPointerOverOut(
215+
props: Props,
216+
): React.MixedElement {
217+
return (
218+
<RNTesterPlatformTest
219+
component={PointerEventPointerOverOutTestCase}
220+
description=""
221+
instructions={[
222+
'Move your mouse over the blue view, later over the green one, later over the yellow one.',
223+
'Move the mouse from the yellow view to the green one, later to the blue one, and later over this paragraph.',
224+
]}
225+
title="PointerOver/PointerOut handling"
226+
/>
227+
);
228+
}

packages/rn-tester/js/examples/Experimental/W3CPointerEventsExample.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import PointerEventPointerMoveOnChordedMouseButton from './W3CPointerEventPlatfo
2121
import PointerEventPointerMoveAcross from './W3CPointerEventPlatformTests/PointerEventPointerMoveAcross';
2222
import PointerEventPointerMoveEventOrder from './W3CPointerEventPlatformTests/PointerEventPointerMoveEventOrder';
2323
import PointerEventPointerMoveBetween from './W3CPointerEventPlatformTests/PointerEventPointerMoveBetween';
24+
import PointerEventPointerOverOut from './W3CPointerEventPlatformTests/PointerEventPointerOverOut';
2425
import EventfulView from './W3CPointerEventsEventfulView';
2526
import ManyPointersPropertiesExample from './Compatibility/ManyPointersPropertiesExample';
2627

@@ -214,6 +215,14 @@ export default {
214215
return <PointerEventPointerMoveBetween />;
215216
},
216217
},
218+
{
219+
name: 'pointerevent_pointerover_out',
220+
description: '',
221+
title: 'WPT: PointerOver/PointerOut handling',
222+
render(): React.Node {
223+
return <PointerEventPointerOverOut />;
224+
},
225+
},
217226
{
218227
name: 'relative',
219228
description: 'Children laid out using relative positioning',

0 commit comments

Comments
 (0)