Skip to content

Commit 466f7a0

Browse files
lunaleapsfacebook-github-bot
authored andcommitted
Create IntersectionObserver benchmark (facebook#50023)
Summary: Add benchmarks for Intersection Observer Differential Revision: D66847629
1 parent f4d2d39 commit 466f7a0

File tree

1 file changed

+304
-0
lines changed

1 file changed

+304
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
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+
* @flow strict-local
8+
* @format
9+
* @oncall react_native
10+
* @fantom_flags enableAccessToHostTreeInFabric:true
11+
*/
12+
13+
import type IntersectionObserverType from '../IntersectionObserver';
14+
import type {Root} from '@react-native/fantom';
15+
16+
import ScrollView from '../../../../../Libraries/Components/ScrollView/ScrollView';
17+
import View from '../../../../../Libraries/Components/View/View';
18+
import setUpIntersectionObserver from '../../../setup/setUpIntersectionObserver';
19+
import ensureInstance from '../../../utilities/ensureInstance';
20+
import ReactNativeElement from '../../dom/nodes/ReactNativeElement';
21+
import * as Fantom from '@react-native/fantom';
22+
import * as React from 'react';
23+
24+
import '../../../../../Libraries/Core/InitializeCore.js';
25+
26+
declare const IntersectionObserver: Class<IntersectionObserverType>;
27+
28+
setUpIntersectionObserver();
29+
30+
let maybeNode;
31+
let node: ReactNativeElement;
32+
33+
let maybeScrollViewNode;
34+
let scrollViewNode: ReactNativeElement;
35+
let observer: IntersectionObserverType;
36+
const root = Fantom.createRoot();
37+
let mockCallback = jest.fn();
38+
let ROOT_HEIGHT = 0;
39+
let SCROLL_INCREMENT = 0;
40+
41+
function setupScrollConstants(renderedRoot: Root) {
42+
const {height} =
43+
renderedRoot.document.documentElement.getBoundingClientRect();
44+
ROOT_HEIGHT = height;
45+
SCROLL_INCREMENT = ROOT_HEIGHT / 3;
46+
}
47+
48+
Fantom.unstable_benchmark
49+
.suite('IntersectionObserver')
50+
.test(
51+
'Create IntersectionObserver',
52+
() => {
53+
Fantom.runTask(() => {
54+
observer = new IntersectionObserver(mockCallback, {});
55+
});
56+
},
57+
{
58+
beforeEach: () => {
59+
mockCallback = jest.fn();
60+
},
61+
afterEach: () => {
62+
Fantom.runTask(() => {
63+
observer.disconnect();
64+
});
65+
},
66+
},
67+
)
68+
.test(
69+
'Observe a mounted view',
70+
() => {
71+
Fantom.runTask(() => {
72+
observer.observe(node);
73+
});
74+
},
75+
{
76+
beforeEach: () => {
77+
mockCallback = jest.fn();
78+
Fantom.runTask(() => {
79+
root.render(
80+
<View
81+
ref={receivedNode => {
82+
maybeNode = receivedNode;
83+
}}
84+
/>,
85+
);
86+
observer = new IntersectionObserver(mockCallback, {});
87+
});
88+
node = ensureInstance(maybeNode, ReactNativeElement);
89+
},
90+
afterEach: () => {
91+
Fantom.runTask(() => {
92+
observer.disconnect();
93+
root.render(<></>);
94+
});
95+
},
96+
},
97+
)
98+
.test(
99+
'ScrollView no intersection, no observation',
100+
() => {
101+
for (let i = 1; i <= 3; i++) {
102+
Fantom.scrollTo(scrollViewNode, {
103+
x: 0,
104+
y: i * SCROLL_INCREMENT,
105+
});
106+
}
107+
},
108+
{
109+
beforeAll: () => {
110+
Fantom.runTask(() => {
111+
root.render(<></>);
112+
});
113+
setupScrollConstants(root);
114+
},
115+
beforeEach: () => {
116+
Fantom.runTask(() => {
117+
root.render(
118+
<ScrollView
119+
ref={receivedNode => {
120+
maybeScrollViewNode = receivedNode;
121+
}}>
122+
<View style={{width: 100, height: ROOT_HEIGHT * 2}} />
123+
<View style={{width: 100, height: 100}} />
124+
</ScrollView>,
125+
);
126+
});
127+
scrollViewNode = ensureInstance(
128+
maybeScrollViewNode,
129+
ReactNativeElement,
130+
);
131+
},
132+
afterEach: () => {
133+
Fantom.runTask(() => {
134+
root.render(<></>);
135+
});
136+
},
137+
},
138+
)
139+
140+
.test(
141+
'ScrollView intersection, no observation',
142+
() => {
143+
for (let i = 1; i <= 3; i++) {
144+
Fantom.scrollTo(scrollViewNode, {
145+
x: 0,
146+
y: i * SCROLL_INCREMENT,
147+
});
148+
}
149+
},
150+
{
151+
beforeAll: () => {
152+
Fantom.runTask(() => {
153+
root.render(<></>);
154+
});
155+
setupScrollConstants(root);
156+
},
157+
beforeEach: () => {
158+
Fantom.runTask(() => {
159+
root.render(
160+
<ScrollView
161+
ref={receivedNode => {
162+
maybeScrollViewNode = receivedNode;
163+
}}>
164+
<View style={{width: 100, height: ROOT_HEIGHT * 1.6}} />
165+
<View style={{width: 100, height: 100}} />
166+
</ScrollView>,
167+
);
168+
});
169+
scrollViewNode = ensureInstance(
170+
maybeScrollViewNode,
171+
ReactNativeElement,
172+
);
173+
},
174+
afterEach: () => {
175+
Fantom.runTask(() => {
176+
root.render(<></>);
177+
});
178+
},
179+
},
180+
)
181+
.test(
182+
'ScrollView no intersection, observation',
183+
() => {
184+
for (let i = 1; i <= 3; i++) {
185+
Fantom.scrollTo(scrollViewNode, {
186+
x: 0,
187+
y: i * SCROLL_INCREMENT,
188+
});
189+
}
190+
},
191+
{
192+
beforeAll: () => {
193+
Fantom.runTask(() => {
194+
root.render(<></>);
195+
});
196+
setupScrollConstants(root);
197+
},
198+
beforeEach: () => {
199+
mockCallback = jest.fn();
200+
201+
Fantom.runTask(() => {
202+
root.render(
203+
<ScrollView
204+
ref={receivedNode => {
205+
maybeScrollViewNode = receivedNode;
206+
}}>
207+
<View style={{width: 100, height: ROOT_HEIGHT * 2}} />
208+
<View
209+
ref={receivedNode => {
210+
maybeNode = receivedNode;
211+
}}
212+
style={{width: 100, height: 100}}
213+
/>
214+
</ScrollView>,
215+
);
216+
});
217+
scrollViewNode = ensureInstance(
218+
maybeScrollViewNode,
219+
ReactNativeElement,
220+
);
221+
node = ensureInstance(maybeNode, ReactNativeElement);
222+
Fantom.runTask(() => {
223+
observer = new IntersectionObserver(mockCallback, {});
224+
observer.observe(node);
225+
});
226+
},
227+
afterEach: () => {
228+
expect(mockCallback.mock.calls.length).toBe(1);
229+
230+
const [entries] = mockCallback.mock.lastCall;
231+
expect(entries.length).toBe(1);
232+
expect(entries[0].isIntersecting).toBe(false);
233+
234+
Fantom.runTask(() => {
235+
observer.disconnect();
236+
root.render(<></>);
237+
});
238+
},
239+
},
240+
)
241+
.test(
242+
'ScrollView intersection, observation',
243+
() => {
244+
for (let i = 1; i <= 3; i++) {
245+
Fantom.scrollTo(scrollViewNode, {
246+
x: 0,
247+
y: i * SCROLL_INCREMENT,
248+
});
249+
}
250+
},
251+
{
252+
beforeAll: () => {
253+
Fantom.runTask(() => {
254+
root.render(<></>);
255+
});
256+
setupScrollConstants(root);
257+
},
258+
beforeEach: () => {
259+
mockCallback = jest.fn();
260+
261+
Fantom.runTask(() => {
262+
root.render(
263+
<ScrollView
264+
ref={receivedNode => {
265+
maybeScrollViewNode = receivedNode;
266+
}}>
267+
<View style={{width: 100, height: ROOT_HEIGHT * 1.6}} />
268+
<View
269+
ref={receivedNode => {
270+
maybeNode = receivedNode;
271+
}}
272+
style={{width: 100, height: 100}}
273+
/>
274+
</ScrollView>,
275+
);
276+
});
277+
scrollViewNode = ensureInstance(
278+
maybeScrollViewNode,
279+
ReactNativeElement,
280+
);
281+
node = ensureInstance(maybeNode, ReactNativeElement);
282+
Fantom.runTask(() => {
283+
observer = new IntersectionObserver(mockCallback, {threshold: 1});
284+
observer.observe(node);
285+
});
286+
},
287+
afterEach: () => {
288+
expect(mockCallback.mock.calls.length).toBe(2);
289+
290+
const [nonIntersectingEntries] = mockCallback.mock.calls[0];
291+
expect(nonIntersectingEntries.length).toBe(1);
292+
expect(nonIntersectingEntries[0].isIntersecting).toBe(false);
293+
294+
const [intersectingEntries] = mockCallback.mock.calls[1];
295+
expect(intersectingEntries.length).toBe(1);
296+
expect(intersectingEntries[0].isIntersecting).toBe(true);
297+
298+
Fantom.runTask(() => {
299+
observer.disconnect();
300+
root.render(<></>);
301+
});
302+
},
303+
},
304+
);

0 commit comments

Comments
 (0)