Improve pattern to access host instances in tests (#50938)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/50938

Changelog: [internal]

No more `maybeNode`s. Using ref objects makes the tests cleaner and the JSX easier to read than injecting lambdas.

This speaks for itself:
* 617 lines added
* 1393 lines removed

{F1977434870}

Reviewed By: lenaic

Differential Revision: D73659018

fbshipit-source-id: d1c23e6457bb1d351ce02b9f6fa8778b06ee0e55
This commit is contained in:
Rubén Norte
2025-04-25 09:22:02 -07:00
committed by Facebook GitHub Bot
parent 12b4a0f4f3
commit 2489308871
14 changed files with 617 additions and 1393 deletions
+36 -84
View File
@@ -12,6 +12,7 @@
import 'react-native/Libraries/Core/InitializeCore';
import type {Root} from '@react-native/fantom';
import type {HostInstance} from 'react-native';
import * as Fantom from '@react-native/fantom';
import * as React from 'react';
@@ -421,22 +422,16 @@ describe('Fantom', () => {
describe('runOnUIThread + enqueueNativeEvent', () => {
it('sends event without payload', () => {
const root = Fantom.createRoot();
let maybeNode;
let focusEvent = jest.fn();
const ref = React.createRef<HostInstance>();
Fantom.runTask(() => {
root.render(
<TextInput
onFocus={focusEvent}
ref={node => {
maybeNode = node;
}}
/>,
);
root.render(<TextInput onFocus={focusEvent} ref={ref} />);
});
const element = ensureInstance(maybeNode, ReactNativeElement);
const element = ensureInstance(ref.current, ReactNativeElement);
expect(focusEvent).toHaveBeenCalledTimes(0);
@@ -454,7 +449,7 @@ describe('Fantom', () => {
it('sends event with payload', () => {
const root = Fantom.createRoot();
let maybeNode;
const ref = React.createRef<HostInstance>();
const onChange = jest.fn();
Fantom.runTask(() => {
@@ -463,14 +458,12 @@ describe('Fantom', () => {
onChange={event => {
onChange(event.nativeEvent);
}}
ref={node => {
maybeNode = node;
}}
ref={ref}
/>,
);
});
const element = ensureInstance(maybeNode, ReactNativeElement);
const element = ensureInstance(ref.current, ReactNativeElement);
Fantom.runOnUIThread(() => {
Fantom.enqueueNativeEvent(element, 'change', {
@@ -487,7 +480,7 @@ describe('Fantom', () => {
it('it batches events with isUnique option', () => {
const root = Fantom.createRoot();
let maybeNode;
const ref = React.createRef<HostInstance>();
const onScroll = jest.fn();
Fantom.runTask(() => {
@@ -496,14 +489,12 @@ describe('Fantom', () => {
onScroll={event => {
onScroll(event.nativeEvent);
}}
ref={node => {
maybeNode = node;
}}
ref={ref}
/>,
);
});
const element = ensureInstance(maybeNode, ReactNativeElement);
const element = ensureInstance(ref.current, ReactNativeElement);
Fantom.runOnUIThread(() => {
Fantom.enqueueNativeEvent(element, 'scroll', {
@@ -541,22 +532,15 @@ describe('Fantom', () => {
describe('dispatchNativeEvent', () => {
it('flushes the event and runs the work loop', () => {
const root = Fantom.createRoot();
let maybeNode;
const ref = React.createRef<HostInstance>();
let focusEvent = jest.fn();
Fantom.runTask(() => {
root.render(
<TextInput
onFocus={focusEvent}
ref={node => {
maybeNode = node;
}}
/>,
);
root.render(<TextInput onFocus={focusEvent} ref={ref} />);
});
const element = ensureInstance(maybeNode, ReactNativeElement);
const element = ensureInstance(ref.current, ReactNativeElement);
expect(focusEvent).toHaveBeenCalledTimes(0);
@@ -569,19 +553,13 @@ describe('Fantom', () => {
describe('enqueueScrollEvent', () => {
it('throws error if called on node that is not scroll view', () => {
const root = Fantom.createRoot();
let maybeNode;
const ref = React.createRef<HostInstance>();
Fantom.runTask(() => {
root.render(
<View
ref={node => {
maybeNode = node;
}}
/>,
);
root.render(<View ref={ref} />);
});
const element = ensureInstance(maybeNode, ReactNativeElement);
const element = ensureInstance(ref.current, ReactNativeElement);
expect(() => {
Fantom.runOnUIThread(() => {
@@ -597,8 +575,8 @@ describe('Fantom', () => {
it('delivers onScroll event and affects position of elements on screen', () => {
const root = Fantom.createRoot();
let maybeScrollViewNode;
let maybeNode;
const viewRef = React.createRef<HostInstance>();
const scrollViewRef = React.createRef<HostInstance>();
const onScroll = jest.fn();
Fantom.runTask(() => {
@@ -607,21 +585,14 @@ describe('Fantom', () => {
onScroll={event => {
onScroll(event.nativeEvent);
}}
ref={node => {
maybeScrollViewNode = node;
}}>
<View
style={{width: 1, height: 2, top: 3}}
ref={node => {
maybeNode = node;
}}
/>
ref={scrollViewRef}>
<View style={{width: 1, height: 2, top: 3}} ref={viewRef} />
</ScrollView>,
);
});
const scrollViewElement = ensureInstance(
maybeScrollViewNode,
scrollViewRef.current,
ReactNativeElement,
);
@@ -636,7 +607,7 @@ describe('Fantom', () => {
expect(onScroll).toHaveBeenCalledTimes(1);
const viewElement = ensureInstance(maybeNode, ReactNativeElement);
const viewElement = ensureInstance(viewRef.current, ReactNativeElement);
let rect;
@@ -673,19 +644,13 @@ describe('Fantom', () => {
describe('scrollTo', () => {
it('throws error if called on node that is not scroll view', () => {
const root = Fantom.createRoot();
let maybeNode;
const ref = React.createRef<HostInstance>();
Fantom.runTask(() => {
root.render(
<View
ref={node => {
maybeNode = node;
}}
/>,
);
root.render(<View ref={ref} />);
});
const element = ensureInstance(maybeNode, ReactNativeElement);
const element = ensureInstance(ref.current, ReactNativeElement);
expect(() => {
Fantom.scrollTo(element, {
@@ -699,8 +664,8 @@ describe('Fantom', () => {
it('delivers onScroll event and affects position of elements on screen', () => {
const root = Fantom.createRoot();
let maybeScrollViewNode;
let maybeNode;
const scrollViewRef = React.createRef<HostInstance>();
const viewRef = React.createRef<HostInstance>();
const onScroll = jest.fn();
Fantom.runTask(() => {
@@ -709,21 +674,14 @@ describe('Fantom', () => {
onScroll={event => {
onScroll(event.nativeEvent);
}}
ref={node => {
maybeScrollViewNode = node;
}}>
<View
style={{width: 1, height: 2, top: 3}}
ref={node => {
maybeNode = node;
}}
/>
ref={scrollViewRef}>
<View style={{width: 1, height: 2, top: 3}} ref={viewRef} />
</ScrollView>,
);
});
const scrollViewElement = ensureInstance(
maybeScrollViewNode,
scrollViewRef.current,
ReactNativeElement,
);
@@ -738,7 +696,7 @@ describe('Fantom', () => {
expect(onScroll).toHaveBeenCalledTimes(1);
const viewElement = ensureInstance(maybeNode, ReactNativeElement);
const viewElement = ensureInstance(viewRef.current, ReactNativeElement);
let rect;
@@ -798,19 +756,13 @@ describe('Fantom', () => {
describe('enqueueModalSizeUpdate', () => {
it('throws error if called on node that is not <Modal />', () => {
const root = Fantom.createRoot();
let maybeNode;
const ref = React.createRef<HostInstance>();
Fantom.runTask(() => {
root.render(
<View
ref={node => {
maybeNode = node;
}}
/>,
);
root.render(<View ref={ref} />);
});
const element = ensureInstance(maybeNode, ReactNativeElement);
const element = ensureInstance(ref.current, ReactNativeElement);
expect(() => {
Fantom.runOnUIThread(() => {
@@ -832,7 +784,7 @@ describe('Fantom', () => {
Fantom.runTask(() => {
root.render(
<Modal
ref={(node: ?React.ElementRef<typeof Modal>) => {
ref={(node: ?HostInstance) => {
maybeModalNode = node;
}}>
<View
@@ -11,6 +11,8 @@
import 'react-native/Libraries/Core/InitializeCore';
import type {HostInstance} from 'react-native';
import ensureInstance from '../../../../src/private/__tests__/utilities/ensureInstance';
import * as Fantom from '@react-native/fantom';
import * as React from 'react';
@@ -20,7 +22,7 @@ import ReactNativeElement from 'react-native/src/private/webapis/dom/nodes/React
describe('onScroll', () => {
it('delivers onScroll event', () => {
const root = Fantom.createRoot();
let maybeNode;
const scrollViewRef = React.createRef<HostInstance>();
const onScroll = jest.fn();
Fantom.runTask(() => {
@@ -29,14 +31,12 @@ describe('onScroll', () => {
onScroll={event => {
onScroll(event.nativeEvent);
}}
ref={node => {
maybeNode = node;
}}
ref={scrollViewRef}
/>,
);
});
const element = ensureInstance(maybeNode, ReactNativeElement);
const element = ensureInstance(scrollViewRef.current, ReactNativeElement);
Fantom.runOnUIThread(() => {
Fantom.enqueueNativeEvent(
@@ -66,7 +66,7 @@ describe('onScroll', () => {
it('batches onScroll event per UI tick', () => {
const root = Fantom.createRoot();
let maybeNode;
const scrollViewRef = React.createRef<HostInstance>();
const onScroll = jest.fn();
Fantom.runTask(() => {
@@ -75,14 +75,12 @@ describe('onScroll', () => {
onScroll={event => {
onScroll(event.nativeEvent);
}}
ref={node => {
maybeNode = node;
}}
ref={scrollViewRef}
/>,
);
});
const element = ensureInstance(maybeNode, ReactNativeElement);
const element = ensureInstance(scrollViewRef.current, ReactNativeElement);
Fantom.runOnUIThread(() => {
Fantom.enqueueNativeEvent(element, 'scroll', {
@@ -14,6 +14,8 @@
import 'react-native/Libraries/Core/InitializeCore.js';
import type {HostInstance} from 'react-native';
import ensureInstance from '../../../../src/private/__tests__/utilities/ensureInstance';
import * as Fantom from '@react-native/fantom';
import * as React from 'react';
@@ -22,15 +24,11 @@ import ReactNativeElement from 'react-native/src/private/webapis/dom/nodes/React
test('basic culling', () => {
const root = Fantom.createRoot({viewportWidth: 100, viewportHeight: 100});
let maybeNode;
const nodeRef = React.createRef<HostInstance>();
Fantom.runTask(() => {
root.render(
<ScrollView
style={{height: 100, width: 100}}
ref={node => {
maybeNode = node;
}}>
<ScrollView style={{height: 100, width: 100}} ref={nodeRef}>
<View
nativeID={'child'}
style={{height: 10, width: 10, marginTop: 45}}
@@ -49,7 +47,7 @@ test('basic culling', () => {
'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}',
]);
const element = ensureInstance(maybeNode, ReactNativeElement);
const element = ensureInstance(nodeRef.current, ReactNativeElement);
Fantom.scrollTo(element, {
x: 0,
@@ -80,15 +78,11 @@ test('basic culling', () => {
test('recursive culling', () => {
const root = Fantom.createRoot({viewportHeight: 100, viewportWidth: 100});
let maybeNode;
const nodeRef = React.createRef<HostInstance>();
Fantom.runTask(() => {
root.render(
<ScrollView
style={{height: 100, width: 100}}
ref={node => {
maybeNode = node;
}}>
<ScrollView style={{height: 100, width: 100}} ref={nodeRef}>
<View
nativeID={'element A'}
style={{height: 30, width: 30, marginTop: 25}}>
@@ -125,7 +119,7 @@ test('recursive culling', () => {
'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}',
]);
const element = ensureInstance(maybeNode, ReactNativeElement);
const element = ensureInstance(nodeRef.current, ReactNativeElement);
// === Scroll down to the edge of child AA ===
Fantom.scrollTo(element, {
@@ -241,16 +235,14 @@ test('recursive culling', () => {
test('recursive culling when initial offset is negative', () => {
const root = Fantom.createRoot({viewportHeight: 874, viewportWidth: 402});
let maybeNode;
const nodeRef = React.createRef<HostInstance>();
Fantom.runTask(() => {
root.render(
<ScrollView
style={{height: 874, width: 402}}
contentOffset={{x: 0, y: -10000}}
ref={node => {
maybeNode = node;
}}>
ref={nodeRef}>
<View
nativeID={'child A'}
style={{height: 100, width: 100, marginTop: 235}}
@@ -274,7 +266,7 @@ test('recursive culling when initial offset is negative', () => {
'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}',
]);
const element = ensureInstance(maybeNode, ReactNativeElement);
const element = ensureInstance(nodeRef.current, ReactNativeElement);
Fantom.scrollTo(element, {
x: 0,
@@ -298,15 +290,11 @@ test('recursive culling when initial offset is negative', () => {
test('deep nesting', () => {
const root = Fantom.createRoot({viewportHeight: 100, viewportWidth: 100});
let maybeNode;
const nodeRef = React.createRef<HostInstance>();
Fantom.runTask(() => {
root.render(
<ScrollView
style={{height: 100, width: 100}}
ref={node => {
maybeNode = node;
}}>
<ScrollView style={{height: 100, width: 100}} ref={nodeRef}>
<View
nativeID={'element A'}
style={{height: 10, width: 100, marginTop: 30}}
@@ -341,7 +329,7 @@ test('deep nesting', () => {
'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}',
]);
const element = ensureInstance(maybeNode, ReactNativeElement);
const element = ensureInstance(nodeRef.current, ReactNativeElement);
Fantom.scrollTo(element, {
x: 0,
@@ -469,16 +457,14 @@ test('adding new item into area that is culled', () => {
});
test('initial render', () => {
let maybeNode;
const nodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot({viewportHeight: 100, viewportWidth: 100});
Fantom.runTask(() => {
root.render(
<ScrollView
contentOffset={{x: 0, y: 45}}
ref={node => {
maybeNode = node;
}}
ref={nodeRef}
style={{height: 100, width: 100}}>
<View nativeID={'element A'} style={{height: 50, width: 100}} />
<View
@@ -504,7 +490,7 @@ test('initial render', () => {
'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}',
]);
const element = ensureInstance(maybeNode, ReactNativeElement);
const element = ensureInstance(nodeRef.current, ReactNativeElement);
Fantom.scrollTo(element, {
x: 0,
@@ -555,16 +541,12 @@ test('unmounting culled elements', () => {
// TODO: only elements in ScrollView are culled.
test('basic culling smaller ScrollView', () => {
let maybeNode;
const nodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot({viewportWidth: 100, viewportHeight: 100});
Fantom.runTask(() => {
root.render(
<ScrollView
ref={node => {
maybeNode = node;
}}
style={{height: 50, width: 50, marginTop: 25}}>
<ScrollView ref={nodeRef} style={{height: 50, width: 50, marginTop: 25}}>
<View nativeID={'element 1'} style={{height: 10, width: 10}} />
</ScrollView>,
);
@@ -580,7 +562,7 @@ test('basic culling smaller ScrollView', () => {
'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}',
]);
const element = ensureInstance(maybeNode, ReactNativeElement);
const element = ensureInstance(nodeRef.current, ReactNativeElement);
Fantom.scrollTo(element, {
x: 0,
@@ -617,15 +599,11 @@ test('views are not culled when outside of viewport', () => {
test('culling with transform move', () => {
const root = Fantom.createRoot({viewportWidth: 100, viewportHeight: 100});
let maybeNode;
const nodeRef = React.createRef<HostInstance>();
Fantom.runTask(() => {
root.render(
<ScrollView
style={{height: 100, width: 100}}
ref={node => {
maybeNode = node;
}}>
<ScrollView style={{height: 100, width: 100}} ref={nodeRef}>
<View
nativeID={'child'}
style={{
@@ -647,7 +625,7 @@ test('culling with transform move', () => {
'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}',
]);
const element = ensureInstance(maybeNode, ReactNativeElement);
const element = ensureInstance(nodeRef.current, ReactNativeElement);
Fantom.scrollTo(element, {
x: 0,
@@ -663,15 +641,11 @@ test('culling with transform move', () => {
test('culling with recursive transform move', () => {
const root = Fantom.createRoot({viewportWidth: 100, viewportHeight: 100});
let maybeNode;
const nodeRef = React.createRef<HostInstance>();
Fantom.runTask(() => {
root.render(
<ScrollView
style={{height: 100, width: 100}}
ref={node => {
maybeNode = node;
}}>
<ScrollView style={{height: 100, width: 100}} ref={nodeRef}>
<View style={{transform: [{translateY: 11}]}}>
<View
nativeID={'child'}
@@ -696,7 +670,7 @@ test('culling with recursive transform move', () => {
'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}',
]);
const element = ensureInstance(maybeNode, ReactNativeElement);
const element = ensureInstance(nodeRef.current, ReactNativeElement);
Fantom.scrollTo(element, {
x: 0,
@@ -712,15 +686,11 @@ test('culling with recursive transform move', () => {
test('culling with transform scale', () => {
const root = Fantom.createRoot({viewportWidth: 100, viewportHeight: 100});
let maybeNode;
const nodeRef = React.createRef<HostInstance>();
Fantom.runTask(() => {
root.render(
<ScrollView
style={{height: 100, width: 100}}
ref={node => {
maybeNode = node;
}}>
<ScrollView style={{height: 100, width: 100}} ref={nodeRef}>
<View
nativeID={'child'}
style={{
@@ -744,7 +714,7 @@ test('culling with transform scale', () => {
'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}',
]);
const element = ensureInstance(maybeNode, ReactNativeElement);
const element = ensureInstance(nodeRef.current, ReactNativeElement);
Fantom.scrollTo(element, {
x: 0,
@@ -791,7 +761,7 @@ test('culling when ScrollView parent has transform', () => {
test('culling inside of Modal', () => {
const root = Fantom.createRoot({viewportWidth: 100, viewportHeight: 100});
let maybeNode;
const nodeRef = React.createRef<HostInstance>();
Fantom.runTask(() => {
root.render(
@@ -800,16 +770,12 @@ test('culling inside of Modal', () => {
<ScrollView
contentOffset={{x: 0, y: 100}}
style={{height: 100, width: 100}}>
<Modal
ref={(node: ?React.ElementRef<typeof Modal>) => {
maybeNode = node;
}}
/>
<Modal ref={nodeRef} />
</ScrollView>,
);
});
const element = ensureInstance(maybeNode, ReactNativeElement);
const element = ensureInstance(nodeRef.current, ReactNativeElement);
Fantom.runOnUIThread(() => {
Fantom.enqueueModalSizeUpdate(element, {
@@ -836,10 +802,7 @@ test('culling inside of Modal', () => {
<ScrollView
contentOffset={{x: 0, y: 100}}
style={{height: 100, width: 100}}>
<Modal
ref={(node: ?React.ElementRef<typeof Modal>) => {
maybeNode = node;
}}>
<Modal ref={nodeRef}>
<View
nativeID={'child'}
style={{height: 10, width: 10, marginTop: 45}}
@@ -858,15 +821,11 @@ test('culling inside of Modal', () => {
describe('reparenting', () => {
test('view flattening with culling', () => {
const root = Fantom.createRoot({viewportWidth: 100, viewportHeight: 100});
let maybeNode;
const nodeRef = React.createRef<HostInstance>();
Fantom.runTask(() => {
root.render(
<ScrollView
style={{height: 100, width: 100}}
ref={node => {
maybeNode = node;
}}>
<ScrollView style={{height: 100, width: 100}} ref={nodeRef}>
<View
style={{
marginTop: 150,
@@ -888,7 +847,7 @@ describe('reparenting', () => {
'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}',
]);
const element = ensureInstance(maybeNode, ReactNativeElement);
const element = ensureInstance(nodeRef.current, ReactNativeElement);
Fantom.scrollTo(element, {
x: 0,
@@ -904,11 +863,7 @@ describe('reparenting', () => {
// force view to be unflattened.
Fantom.runTask(() => {
root.render(
<ScrollView
style={{height: 100, width: 100}}
ref={node => {
maybeNode = node;
}}>
<ScrollView style={{height: 100, width: 100}} ref={nodeRef}>
<View
style={{
marginTop: 150,
@@ -934,11 +889,7 @@ describe('reparenting', () => {
// force view to be flattened.
Fantom.runTask(() => {
root.render(
<ScrollView
style={{height: 100, width: 100}}
ref={node => {
maybeNode = node;
}}>
<ScrollView style={{height: 100, width: 100}} ref={nodeRef}>
<View
style={{
marginTop: 150,
@@ -1339,16 +1290,14 @@ describe('reparenting', () => {
'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}',
]);
let maybeNode = null;
const nodeRef = React.createRef<HostInstance>();
// Now update opacity to unflattned the container and add a child that has a culled descendant.
Fantom.runTask(() => {
root.render(
<ScrollView
style={{height: 100, width: 100}}
ref={node => {
maybeNode = node;
}}
ref={nodeRef}
contentOffset={{x: 0, y: 111}}>
<View
style={{
@@ -1385,7 +1334,7 @@ describe('reparenting', () => {
'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}',
]);
const element = ensureInstance(maybeNode, ReactNativeElement);
const element = ensureInstance(nodeRef.current, ReactNativeElement);
// Scroll down to see the grandchild.
Fantom.scrollTo(element, {
@@ -1509,16 +1458,14 @@ describe('reparenting', () => {
'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}',
]);
let maybeNode = null;
const nodeRef = React.createRef<HostInstance>();
// Now change unflattened view container to flattened and change its child to be unflattened.
Fantom.runTask(() => {
root.render(
<ScrollView
style={{height: 100, width: 100}}
ref={node => {
maybeNode = node;
}}
ref={nodeRef}
contentOffset={{x: 0, y: 60}}>
<View
style={{
@@ -1547,7 +1494,7 @@ describe('reparenting', () => {
'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}',
]);
const element = ensureInstance(maybeNode, ReactNativeElement);
const element = ensureInstance(nodeRef.current, ReactNativeElement);
// Scroll to reveal grandchild.
Fantom.scrollTo(element, {
@@ -1601,16 +1548,14 @@ describe('reparenting', () => {
'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}',
]);
let maybeNode = null;
const nodeRef = React.createRef<HostInstance>();
// Now change unflattened view container to flattened and change its child to be unflattened.
Fantom.runTask(() => {
root.render(
<ScrollView
style={{height: 100, width: 100}}
ref={node => {
maybeNode = node;
}}
ref={nodeRef}
contentOffset={{x: 0, y: 60}}>
<View
style={{
@@ -1639,7 +1584,7 @@ describe('reparenting', () => {
'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}',
]);
const element = ensureInstance(maybeNode, ReactNativeElement);
const element = ensureInstance(nodeRef.current, ReactNativeElement);
// Scroll to reveal grandchild.
Fantom.scrollTo(element, {
@@ -11,6 +11,8 @@
import 'react-native/Libraries/Core/InitializeCore';
import type {HostInstance} from 'react-native';
import ensureInstance from '../../../../src/private/__tests__/utilities/ensureInstance';
import * as Fantom from '@react-native/fantom';
import * as React from 'react';
@@ -100,24 +102,18 @@ describe('focus view command', () => {
describe('focus and blur event', () => {
it('sends focus and blur events', () => {
const root = Fantom.createRoot();
let maybeNode;
const nodeRef = React.createRef<HostInstance>();
let focusEvent = jest.fn();
let blurEvent = jest.fn();
Fantom.runTask(() => {
root.render(
<TextInput
onFocus={focusEvent}
onBlur={blurEvent}
ref={node => {
maybeNode = node;
}}
/>,
<TextInput onFocus={focusEvent} onBlur={blurEvent} ref={nodeRef} />,
);
});
const element = ensureInstance(maybeNode, ReactNativeElement);
const element = ensureInstance(nodeRef.current, ReactNativeElement);
expect(focusEvent).toHaveBeenCalledTimes(0);
expect(blurEvent).toHaveBeenCalledTimes(0);
@@ -149,7 +145,7 @@ describe('focus and blur event', () => {
describe('onChange', () => {
it('delivers onChange event', () => {
const root = Fantom.createRoot();
let maybeNode;
const nodeRef = React.createRef<HostInstance>();
const onChange = jest.fn();
Fantom.runTask(() => {
@@ -158,14 +154,12 @@ describe('onChange', () => {
onChange={event => {
onChange(event.nativeEvent);
}}
ref={node => {
maybeNode = node;
}}
ref={nodeRef}
/>,
);
});
const element = ensureInstance(maybeNode, ReactNativeElement);
const element = ensureInstance(nodeRef.current, ReactNativeElement);
Fantom.runOnUIThread(() => {
Fantom.enqueueNativeEvent(element, 'change', {
@@ -184,21 +178,14 @@ describe('onChange', () => {
describe('onChangeText', () => {
it('delivers onChangeText event', () => {
const root = Fantom.createRoot();
let maybeNode;
const nodeRef = React.createRef<HostInstance>();
const onChangeText = jest.fn();
Fantom.runTask(() => {
root.render(
<TextInput
onChangeText={onChangeText}
ref={node => {
maybeNode = node;
}}
/>,
);
root.render(<TextInput onChangeText={onChangeText} ref={nodeRef} />);
});
const element = ensureInstance(maybeNode, ReactNativeElement);
const element = ensureInstance(nodeRef.current, ReactNativeElement);
Fantom.runOnUIThread(() => {
Fantom.enqueueNativeEvent(element, 'change', {
@@ -11,6 +11,8 @@
import 'react-native/Libraries/Core/InitializeCore';
import type {HostInstance} from 'react-native';
import ensureInstance from '../../../src/private/__tests__/utilities/ensureInstance';
import * as Fantom from '@react-native/fantom';
import * as React from 'react';
@@ -26,9 +28,9 @@ function ensureReactNativeElement(value: mixed): ReactNativeElement {
describe('discrete event category', () => {
it('interrupts React rendering and higher priority update is committed first', () => {
const root = Fantom.createRoot();
let maybeTextInputNode;
let importantTextNode;
let deferredTextNode;
const textInputRef = React.createRef<HostInstance>();
const importantTextNodeRef = React.createRef<HostInstance>();
const deferredTextNodeRef = React.createRef<HostInstance>();
let interruptRendering = false;
let effectMock = jest.fn();
let afterUpdate;
@@ -40,7 +42,7 @@ describe('discrete event category', () => {
if (interruptRendering) {
interruptRendering = false;
const element = ensureReactNativeElement(maybeTextInputNode);
const element = ensureReactNativeElement(textInputRef.current);
Fantom.runOnUIThread(() => {
Fantom.enqueueNativeEvent(
element,
@@ -64,24 +66,9 @@ describe('discrete event category', () => {
return (
<>
<TextInput
onChangeText={setText}
ref={node => {
maybeTextInputNode = node;
}}
/>
<Text
ref={node => {
importantTextNode = node;
}}>
Important text: {text}
</Text>
<Text
ref={node => {
deferredTextNode = node;
}}>
Deferred text: {deferredText}
</Text>
<TextInput onChangeText={setText} ref={textInputRef} />
<Text ref={importantTextNodeRef}>Important text: {text}</Text>
<Text ref={deferredTextNodeRef}>Deferred text: {deferredText}</Text>
</>
);
}
@@ -90,10 +77,12 @@ describe('discrete event category', () => {
root.render(<App text={'first render'} />);
});
const importantTextNativeElement =
ensureReactNativeElement(importantTextNode);
const deferredTextNativeElement =
ensureReactNativeElement(deferredTextNode);
const importantTextNativeElement = ensureReactNativeElement(
importantTextNodeRef.current,
);
const deferredTextNativeElement = ensureReactNativeElement(
deferredTextNodeRef.current,
);
expect(importantTextNativeElement.textContent).toBe(
'Important text: initial text',
@@ -146,9 +135,9 @@ describe('discrete event category', () => {
describe('continuous event category', () => {
it('interrupts React rendering but update from continous event is delayed', () => {
const root = Fantom.createRoot();
let maybeTextInputNode;
let importantTextNode;
let deferredTextNode;
const textInputRef = React.createRef<HostInstance>();
const importantTextNodeRef = React.createRef<HostInstance>();
const deferredTextNodeRef = React.createRef<HostInstance>();
let interruptRendering = false;
let effectMock = jest.fn();
@@ -159,7 +148,7 @@ describe('continuous event category', () => {
if (interruptRendering) {
interruptRendering = false;
const element = ensureReactNativeElement(maybeTextInputNode);
const element = ensureReactNativeElement(textInputRef.current);
Fantom.runOnUIThread(() => {
Fantom.enqueueNativeEvent(
element,
@@ -188,22 +177,10 @@ describe('continuous event category', () => {
`start: ${event.nativeEvent.selection.start}, end: ${event.nativeEvent.selection.end}`,
);
}}
ref={node => {
maybeTextInputNode = node;
}}
ref={textInputRef}
/>
<Text
ref={node => {
importantTextNode = node;
}}>
Important text: {text}
</Text>
<Text
ref={node => {
deferredTextNode = node;
}}>
Deferred text: {deferredText}
</Text>
<Text ref={importantTextNodeRef}>Important text: {text}</Text>
<Text ref={deferredTextNodeRef}>Deferred text: {deferredText}</Text>
</>
);
}
@@ -212,10 +189,12 @@ describe('continuous event category', () => {
root.render(<App text={'first render'} />);
});
const importantTextNativeElement =
ensureReactNativeElement(importantTextNode);
const deferredTextNativeElement =
ensureReactNativeElement(deferredTextNode);
const importantTextNativeElement = ensureReactNativeElement(
importantTextNodeRef.current,
);
const deferredTextNativeElement = ensureReactNativeElement(
deferredTextNodeRef.current,
);
expect(importantTextNativeElement.textContent).toBe(
'Important text: initial text',
@@ -12,6 +12,8 @@
import 'react-native/Libraries/Core/InitializeCore';
import type {HostInstance} from 'react-native';
import ensureInstance from '../../../src/private/__tests__/utilities/ensureInstance';
import * as Fantom from '@react-native/fantom';
import * as React from 'react';
@@ -24,23 +26,19 @@ NativeFantomForcedCloneCommitHook.setup();
describe('ScrollViewShadowNode', () => {
it('maintains state after commit hook processing', () => {
const root = Fantom.createRoot();
let maybeScrollViewNode;
const scrollViewRef = React.createRef<HostInstance>();
Fantom.runTask(() => {
root.render(
<View>
<ScrollView
ref={node => {
maybeScrollViewNode = node;
}}
/>
<ScrollView ref={scrollViewRef} />
<View nativeID="to-be-cloned-in-the-commit-hook" />
</View>,
);
});
const scrollViewElement = ensureInstance(
maybeScrollViewNode,
scrollViewRef.current,
ReactNativeElement,
);
@@ -13,6 +13,8 @@
import 'react-native/Libraries/Core/InitializeCore';
import type {HostInstance} from 'react-native';
import ensureInstance from '../../../__tests__/utilities/ensureInstance';
import * as Fantom from '@react-native/fantom';
import * as React from 'react';
@@ -24,14 +26,12 @@ describe('UIConsistency', () => {
it('should provide consistent data from the tree within the same synchronous function', () => {
const root = Fantom.createRoot();
let maybeScrollViewNode;
const scrollViewRef = React.createRef<HostInstance>();
Fantom.runTask(() => {
root.render(
<ScrollView
ref={node => {
maybeScrollViewNode = node;
}}
ref={scrollViewRef}
style={{height: 100}}
contentContainerStyle={{height: 1000}}
/>,
@@ -39,7 +39,7 @@ describe('UIConsistency', () => {
});
const scrollViewNode = ensureInstance(
maybeScrollViewNode,
scrollViewRef.current,
ReactNativeElement,
);
@@ -59,14 +59,12 @@ describe('UIConsistency', () => {
it('should provide up-to-date data in the first access to the tree', () => {
const root = Fantom.createRoot();
let maybeScrollViewNode;
const scrollViewRef = React.createRef<HostInstance>();
Fantom.runTask(() => {
root.render(
<ScrollView
ref={node => {
maybeScrollViewNode = node;
}}
ref={scrollViewRef}
style={{height: 100}}
contentContainerStyle={{height: 1000}}
/>,
@@ -74,7 +72,7 @@ describe('UIConsistency', () => {
});
const scrollViewNode = ensureInstance(
maybeScrollViewNode,
scrollViewRef.current,
ReactNativeElement,
);
@@ -93,7 +91,7 @@ describe('UIConsistency', () => {
it('should provide up-to-date data after commit', () => {
const root = Fantom.createRoot();
let maybeScrollViewNode;
const scrollViewRef = React.createRef<HostInstance>();
function InnerComponent(props: {
text: string,
@@ -114,9 +112,7 @@ describe('UIConsistency', () => {
Fantom.runTask(() => {
root.render(
<ScrollView
ref={node => {
maybeScrollViewNode = node;
}}
ref={scrollViewRef}
style={{height: 100}}
contentContainerStyle={{height: 1000}}>
<InnerComponent text="A" />
@@ -125,7 +121,7 @@ describe('UIConsistency', () => {
});
const scrollViewNode = ensureInstance(
maybeScrollViewNode,
scrollViewRef.current,
ReactNativeElement,
);
@@ -12,6 +12,8 @@
import 'react-native/Libraries/Core/InitializeCore';
import type {HostInstance} from 'react-native';
import ensureInstance from '../../../__tests__/utilities/ensureInstance';
import * as Fantom from '@react-native/fantom';
import * as React from 'react';
@@ -354,14 +356,12 @@ test('parent-child switching from flattened-unflattened to unflattened-flattened
describe('reconciliation of setNativeProps and React commit', () => {
it('props set by setNativeProps must not be overriden by React commit', () => {
const root = Fantom.createRoot();
let maybeNode;
const nodeRef = React.createRef<HostInstance>();
Fantom.runTask(() => {
root.render(
<View
ref={node => {
maybeNode = node;
}}
ref={nodeRef}
nativeID="first native id"
testID="first test id"
/>,
@@ -378,7 +378,7 @@ describe('reconciliation of setNativeProps and React commit', () => {
<rn-view nativeID={'first native id'} testID={'first test id'} />,
);
const element = ensureInstance(maybeNode, ReactNativeElement);
const element = ensureInstance(nodeRef.current, ReactNativeElement);
Fantom.runTask(() => {
// Calling `setNativeProps` forces bug https://github.com/facebook/react-native/issues/47476 to manifest.
@@ -401,9 +401,7 @@ describe('reconciliation of setNativeProps and React commit', () => {
Fantom.runTask(() => {
root.render(
<View
ref={node => {
maybeNode = node;
}}
ref={nodeRef}
nativeID="second native id"
// testID was changed by `setNativeProps` and React does not know about it.
// Therefore, it will treat testID as unchanged.
@@ -426,17 +424,10 @@ describe('reconciliation of setNativeProps and React commit', () => {
it('allows React commit to override value set by setNativeProps', () => {
const root = Fantom.createRoot();
let maybeNode;
const nodeRef = React.createRef<HostInstance>();
Fantom.runTask(() => {
root.render(
<View
ref={node => {
maybeNode = node;
}}
nativeID="first native id"
/>,
);
root.render(<View ref={nodeRef} nativeID="first native id" />);
});
expect(
@@ -447,7 +438,7 @@ describe('reconciliation of setNativeProps and React commit', () => {
.toJSX(),
).toEqual(<rn-view nativeID={'first native id'} />);
const element = ensureInstance(maybeNode, ReactNativeElement);
const element = ensureInstance(nodeRef.current, ReactNativeElement);
Fantom.runTask(() => {
element.setNativeProps({nativeID: 'second native id'});
@@ -462,14 +453,7 @@ describe('reconciliation of setNativeProps and React commit', () => {
).toEqual(<rn-view nativeID={'second native id'} />);
Fantom.runTask(() => {
root.render(
<View
ref={node => {
maybeNode = node;
}}
nativeID="third native id"
/>,
);
root.render(<View ref={nodeRef} nativeID="third native id" />);
});
expect(
@@ -11,6 +11,8 @@
import 'react-native/Libraries/Core/InitializeCore';
import type {HostInstance} from 'react-native';
import ensureInstance from '../../../../__tests__/utilities/ensureInstance';
import isUnreachable from '../../../../__tests__/utilities/isUnreachable';
import * as Fantom from '@react-native/fantom';
@@ -23,20 +25,14 @@ import ReadOnlyNode from 'react-native/src/private/webapis/dom/nodes/ReadOnlyNod
describe('ReactNativeDocument', () => {
it('is connected until the surface is destroyed', () => {
let lastNode;
const nodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
ref={node => {
lastNode = node;
}}
/>,
);
root.render(<View ref={nodeRef} />);
});
const element = ensureInstance(lastNode, ReactNativeElement);
const element = ensureInstance(nodeRef.current, ReactNativeElement);
const document = ensureInstance(element.ownerDocument, ReactNativeDocument);
expect(document.isConnected).toBe(true);
@@ -55,20 +51,14 @@ describe('ReactNativeDocument', () => {
});
it('allows traversal as a regular node', () => {
let lastNode;
const nodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
ref={node => {
lastNode = node;
}}
/>,
);
root.render(<View ref={nodeRef} />);
});
const element = ensureInstance(lastNode, ReactNativeElement);
const element = ensureInstance(nodeRef.current, ReactNativeElement);
const document = ensureInstance(element.ownerDocument, ReactNativeDocument);
expect(document.childNodes.length).toBe(1);
@@ -80,20 +70,14 @@ describe('ReactNativeDocument', () => {
});
it('allows traversal through document-specific methods', () => {
let lastNode;
const nodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
ref={node => {
lastNode = node;
}}
/>,
);
root.render(<View ref={nodeRef} />);
});
const element = ensureInstance(lastNode, ReactNativeElement);
const element = ensureInstance(nodeRef.current, ReactNativeElement);
const document = ensureInstance(element.ownerDocument, ReactNativeDocument);
expect(document.childElementCount).toBe(1);
@@ -104,20 +88,14 @@ describe('ReactNativeDocument', () => {
});
it('implements the abstract methods from ReadOnlyNode', () => {
let lastNode;
const nodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
ref={node => {
lastNode = node;
}}
/>,
);
root.render(<View ref={nodeRef} />);
});
const element = ensureInstance(lastNode, ReactNativeElement);
const element = ensureInstance(nodeRef.current, ReactNativeElement);
const document = ensureInstance(element.ownerDocument, ReactNativeDocument);
expect(document.nodeName).toBe('#document');
@@ -127,20 +105,14 @@ describe('ReactNativeDocument', () => {
});
it('provides a documentElement node that behaves like a regular element', () => {
let lastNode;
const nodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot({viewportWidth: 200, viewportHeight: 100});
Fantom.runTask(() => {
root.render(
<View
ref={node => {
lastNode = node;
}}
/>,
);
root.render(<View ref={nodeRef} />);
});
const element = ensureInstance(lastNode, ReactNativeElement);
const element = ensureInstance(nodeRef.current, ReactNativeElement);
const document = ensureInstance(element.ownerDocument, ReactNativeDocument);
const {x, y, width, height} =
@@ -153,20 +125,14 @@ describe('ReactNativeDocument', () => {
});
it('implements compareDocumentPosition correctly', () => {
let lastNode;
const nodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
ref={node => {
lastNode = node;
}}
/>,
);
root.render(<View ref={nodeRef} />);
});
const element = ensureInstance(lastNode, ReactNativeElement);
const element = ensureInstance(nodeRef.current, ReactNativeElement);
const document = ensureInstance(element.ownerDocument, ReactNativeDocument);
const documentElement = document.documentElement;
@@ -206,17 +172,11 @@ describe('ReactNativeDocument', () => {
});
it('is released when the root is destroyed', () => {
let lastNode;
const nodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
ref={node => {
lastNode = node;
}}
/>,
);
root.render(<View ref={nodeRef} />);
});
let maybeWeakNode;
@@ -224,11 +184,13 @@ describe('ReactNativeDocument', () => {
Fantom.runTask(() => {
maybeWeakDocument = new WeakRef(
ensureInstance(
ensureInstance(lastNode, ReactNativeElement).ownerDocument,
ensureInstance(nodeRef.current, ReactNativeElement).ownerDocument,
ReactNativeDocument,
),
);
maybeWeakNode = new WeakRef(ensureInstance(lastNode, ReactNativeElement));
maybeWeakNode = new WeakRef(
ensureInstance(nodeRef.current, ReactNativeElement),
);
});
const weakDocument = nullthrows(maybeWeakDocument);
@@ -241,7 +203,7 @@ describe('ReactNativeDocument', () => {
root.destroy();
});
expect(lastNode).toBe(null);
expect(nodeRef.current).toBe(null);
expect(isUnreachable(weakDocument)).toBe(true);
expect(isUnreachable(weakNode)).toBe(true);
});
@@ -11,6 +11,8 @@
import 'react-native/Libraries/Core/InitializeCore';
import type {HostInstance} from 'react-native';
import ensureInstance from '../../../../__tests__/utilities/ensureInstance';
import * as Fantom from '@react-native/fantom';
import * as React from 'react';
@@ -33,82 +35,51 @@ function ensureReactNativeElement(value: mixed): ReactNativeElement {
describe('ReactNativeElement', () => {
it('should be used to create public instances when the `enableAccessToHostTreeInFabric` feature flag is enabled', () => {
let node;
const ref = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
ref={receivedNode => {
node = receivedNode;
}}
/>,
);
root.render(<View ref={ref} />);
});
expect(node).toBeInstanceOf(ReactNativeElement);
expect(ref.current).toBeInstanceOf(ReactNativeElement);
});
describe('extends `ReadOnlyNode`', () => {
it('should be an instance of `ReadOnlyNode`', () => {
let lastNode;
const ref = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
ref={node => {
lastNode = node;
}}
/>,
);
root.render(<View ref={ref} />);
});
expect(lastNode).toBeInstanceOf(ReadOnlyNode);
expect(ref.current).toBeInstanceOf(ReadOnlyNode);
});
describe('nodeType', () => {
it('returns ReadOnlyNode.ELEMENT_NODE', () => {
let lastParentNode;
let lastChildNodeA;
let lastChildNodeB;
let lastChildNodeC;
const parentRef = React.createRef<HostInstance>();
const childNodeARef = React.createRef<HostInstance>();
const childNodeBRef = React.createRef<HostInstance>();
const childNodeCRef = React.createRef<HostInstance>();
// Initial render with 3 children
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
key="parent"
ref={node => {
lastParentNode = node;
}}>
<View
key="childA"
ref={node => {
lastChildNodeA = node;
}}
/>
<View
key="childB"
ref={node => {
lastChildNodeB = node;
}}
/>
<View
key="childC"
ref={node => {
lastChildNodeC = node;
}}
/>
<View key="parent" ref={parentRef}>
<View key="childA" ref={childNodeARef} />
<View key="childB" ref={childNodeBRef} />
<View key="childC" ref={childNodeCRef} />
</View>,
);
});
const parentNode = ensureReactNativeElement(lastParentNode);
const childNodeA = ensureReactNativeElement(lastChildNodeA);
const childNodeB = ensureReactNativeElement(lastChildNodeB);
const childNodeC = ensureReactNativeElement(lastChildNodeC);
const parentNode = ensureReactNativeElement(parentRef.current);
const childNodeA = ensureReactNativeElement(childNodeARef.current);
const childNodeB = ensureReactNativeElement(childNodeBRef.current);
const childNodeC = ensureReactNativeElement(childNodeCRef.current);
expect(parentNode.nodeType).toBe(ReadOnlyNode.ELEMENT_NODE);
expect(childNodeA.nodeType).toBe(ReadOnlyNode.ELEMENT_NODE);
@@ -119,46 +90,27 @@ describe('ReactNativeElement', () => {
describe('nodeValue', () => {
it('returns null', () => {
let lastParentNode;
let lastChildNodeA;
let lastChildNodeB;
let lastChildNodeC;
const parentRef = React.createRef<HostInstance>();
const childNodeARef = React.createRef<HostInstance>();
const childNodeBRef = React.createRef<HostInstance>();
const childNodeCRef = React.createRef<HostInstance>();
// Initial render with 3 children
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
key="parent"
ref={node => {
lastParentNode = node;
}}>
<View
key="childA"
ref={node => {
lastChildNodeA = node;
}}
/>
<View
key="childB"
ref={node => {
lastChildNodeB = node;
}}
/>
<View
key="childC"
ref={node => {
lastChildNodeC = node;
}}
/>
<View key="parent" ref={parentRef}>
<View key="childA" ref={childNodeARef} />
<View key="childB" ref={childNodeBRef} />
<View key="childC" ref={childNodeCRef} />
</View>,
);
});
const parentNode = ensureReactNativeElement(lastParentNode);
const childNodeA = ensureReactNativeElement(lastChildNodeA);
const childNodeB = ensureReactNativeElement(lastChildNodeB);
const childNodeC = ensureReactNativeElement(lastChildNodeC);
const parentNode = ensureReactNativeElement(parentRef.current);
const childNodeA = ensureReactNativeElement(childNodeARef.current);
const childNodeB = ensureReactNativeElement(childNodeBRef.current);
const childNodeC = ensureReactNativeElement(childNodeCRef.current);
expect(parentNode.nodeValue).toBe(null);
expect(childNodeA.nodeValue).toBe(null);
@@ -169,46 +121,27 @@ describe('ReactNativeElement', () => {
describe('childNodes / hasChildNodes()', () => {
it('returns updated child nodes information', () => {
let lastParentNode;
let lastChildNodeA;
let lastChildNodeB;
let lastChildNodeC;
const parentRef = React.createRef<HostInstance>();
const childNodeARef = React.createRef<HostInstance>();
const childNodeBRef = React.createRef<HostInstance>();
const childNodeCRef = React.createRef<HostInstance>();
// Initial render with 3 children
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
key="parent"
ref={node => {
lastParentNode = node;
}}>
<View
key="childA"
ref={node => {
lastChildNodeA = node;
}}
/>
<View
key="childB"
ref={node => {
lastChildNodeB = node;
}}
/>
<View
key="childC"
ref={node => {
lastChildNodeC = node;
}}
/>
<View key="parent" ref={parentRef}>
<View key="childA" ref={childNodeARef} />
<View key="childB" ref={childNodeBRef} />
<View key="childC" ref={childNodeCRef} />
</View>,
);
});
const parentNode = ensureReactNativeElement(lastParentNode);
const childNodeA = ensureReactNativeElement(lastChildNodeA);
const childNodeB = ensureReactNativeElement(lastChildNodeB);
const childNodeC = ensureReactNativeElement(lastChildNodeC);
const parentNode = ensureReactNativeElement(parentRef.current);
const childNodeA = ensureReactNativeElement(childNodeARef.current);
const childNodeB = ensureReactNativeElement(childNodeBRef.current);
const childNodeC = ensureReactNativeElement(childNodeCRef.current);
const childNodes = parentNode.childNodes;
expect(childNodes).toBeInstanceOf(NodeList);
@@ -253,47 +186,29 @@ describe('ReactNativeElement', () => {
describe('getRootNode()', () => {
// This is the desired implementation (not implemented yet).
it('returns a root node representing the document', () => {
let lastParentANode;
let lastParentBNode;
let lastChildANode;
let lastChildBNode;
const parentANodeRef = React.createRef<HostInstance>();
const parentBNodeRef = React.createRef<HostInstance>();
const childANodeRef = React.createRef<HostInstance>();
const childBNodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<>
<View
key="parentA"
ref={node => {
lastParentANode = node;
}}>
<View
key="childA"
ref={node => {
lastChildANode = node;
}}
/>
<View key="parentA" ref={parentANodeRef}>
<View key="childA" ref={childANodeRef} />
</View>
<View
key="parentB"
ref={node => {
lastParentBNode = node;
}}>
<View
key="childB"
ref={node => {
lastChildBNode = node;
}}
/>
<View key="parentB" ref={parentBNodeRef}>
<View key="childB" ref={childBNodeRef} />
</View>
</>,
);
});
const parentANode = ensureReactNativeElement(lastParentANode);
const childANode = ensureReactNativeElement(lastChildANode);
const parentBNode = ensureReactNativeElement(lastParentBNode);
const childBNode = ensureReactNativeElement(lastChildBNode);
const parentANode = ensureReactNativeElement(parentANodeRef.current);
const childANode = ensureReactNativeElement(childANodeRef.current);
const parentBNode = ensureReactNativeElement(parentBNodeRef.current);
const childBNode = ensureReactNativeElement(childBNodeRef.current);
expect(childANode.getRootNode()).toBe(childBNode.getRootNode());
const document = childANode.getRootNode();
@@ -329,46 +244,27 @@ describe('ReactNativeElement', () => {
describe('firstChild / lastChild / previousSibling / nextSibling / parentNode / parentElement', () => {
it('return updated relative nodes', () => {
let lastParentNode;
let lastChildNodeA;
let lastChildNodeB;
let lastChildNodeC;
const parentRef = React.createRef<HostInstance>();
const childNodeARef = React.createRef<HostInstance>();
const childNodeBRef = React.createRef<HostInstance>();
const childNodeCRef = React.createRef<HostInstance>();
// Initial render with 3 children
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
key="parent"
ref={node => {
lastParentNode = node;
}}>
<View
key="childA"
ref={node => {
lastChildNodeA = node;
}}
/>
<View
key="childB"
ref={node => {
lastChildNodeB = node;
}}
/>
<View
key="childC"
ref={node => {
lastChildNodeC = node;
}}
/>
<View key="parent" ref={parentRef}>
<View key="childA" ref={childNodeARef} />
<View key="childB" ref={childNodeBRef} />
<View key="childC" ref={childNodeCRef} />
</View>,
);
});
const parentNode = ensureReactNativeElement(lastParentNode);
const childNodeA = ensureReactNativeElement(lastChildNodeA);
const childNodeB = ensureReactNativeElement(lastChildNodeB);
const childNodeC = ensureReactNativeElement(lastChildNodeC);
const parentNode = ensureReactNativeElement(parentRef.current);
const childNodeA = ensureReactNativeElement(childNodeARef.current);
const childNodeB = ensureReactNativeElement(childNodeBRef.current);
const childNodeC = ensureReactNativeElement(childNodeCRef.current);
expect(parentNode.isConnected).toBe(true);
expect(parentNode.firstChild).toBe(childNodeA);
@@ -486,54 +382,32 @@ describe('ReactNativeElement', () => {
describe('compareDocumentPosition / contains', () => {
it('handles containment, order and connection', () => {
let lastParentNode;
let lastChildNodeA;
let lastChildNodeAA;
let lastChildNodeB;
let lastChildNodeBB;
const parentRef = React.createRef<HostInstance>();
const childNodeARef = React.createRef<HostInstance>();
const childNodeAARef = React.createRef<HostInstance>();
const childNodeBRef = React.createRef<HostInstance>();
const childNodeBBRef = React.createRef<HostInstance>();
// Initial render with 2 children
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
key="parent"
ref={node => {
lastParentNode = node;
}}>
<View
key="childA"
ref={node => {
lastChildNodeA = node;
}}>
<View
key="childAA"
ref={node => {
lastChildNodeAA = node;
}}
/>
<View key="parent" ref={parentRef}>
<View key="childA" ref={childNodeARef}>
<View key="childAA" ref={childNodeAARef} />
</View>
<View
key="childB"
ref={node => {
lastChildNodeB = node;
}}>
<View
key="childBB"
ref={node => {
lastChildNodeBB = node;
}}
/>
<View key="childB" ref={childNodeBRef}>
<View key="childBB" ref={childNodeBBRef} />
</View>
</View>,
);
});
const parentNode = ensureReactNativeElement(lastParentNode);
const childNodeA = ensureReactNativeElement(lastChildNodeA);
const childNodeAA = ensureReactNativeElement(lastChildNodeAA);
const childNodeB = ensureReactNativeElement(lastChildNodeB);
const childNodeBB = ensureReactNativeElement(lastChildNodeBB);
const parentNode = ensureReactNativeElement(parentRef.current);
const childNodeA = ensureReactNativeElement(childNodeARef.current);
const childNodeAA = ensureReactNativeElement(childNodeAARef.current);
const childNodeB = ensureReactNativeElement(childNodeBRef.current);
const childNodeBB = ensureReactNativeElement(childNodeBBRef.current);
// Node/self
expect(parentNode.compareDocumentPosition(parentNode)).toBe(0);
@@ -617,24 +491,22 @@ describe('ReactNativeElement', () => {
expect(childNodeBB.compareDocumentPosition(childNodeBB)).toBe(0);
expect(childNodeBB.contains(childNodeBB)).toBe(true);
let lastAltParentNode;
const altParentNodeRef = React.createRef<HostInstance>();
// Similar structure in a different tree
const root2 = Fantom.createRoot();
Fantom.runTask(() => {
root2.render(
<View
key="altParent"
ref={node => {
lastAltParentNode = node;
}}>
<View key="altParent" ref={altParentNodeRef}>
<View key="childA" />
<View key="childB" />
</View>,
);
});
const altParentNode = ensureReactNativeElement(lastAltParentNode);
const altParentNode = ensureReactNativeElement(
altParentNodeRef.current,
);
// Node/same position in different tree
expect(altParentNode.compareDocumentPosition(parentNode)).toBe(
@@ -676,64 +548,45 @@ describe('ReactNativeElement', () => {
describe('extends `ReadOnlyElement`', () => {
it('should be an instance of `ReadOnlyElement`', () => {
let lastNode;
const ref = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
ref={node => {
lastNode = node;
}}
/>,
);
root.render(<View ref={ref} />);
});
expect(lastNode).toBeInstanceOf(ReadOnlyElement);
expect(ref.current).toBeInstanceOf(ReadOnlyElement);
});
describe('children / childElementCount', () => {
it('return updated element children information', () => {
let lastParentElement;
let lastChildElementA;
let lastChildElementB;
let lastChildElementC;
const parentRef = React.createRef<HostInstance>();
const childElementARef = React.createRef<HostInstance>();
const childElementBRef = React.createRef<HostInstance>();
const childElementCRef = React.createRef<HostInstance>();
// Initial render with 3 children
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
key="parent"
ref={element => {
lastParentElement = element;
}}>
<View
key="childA"
ref={element => {
lastChildElementA = element;
}}
/>
<View
key="childB"
ref={element => {
lastChildElementB = element;
}}
/>
<View
key="childC"
ref={element => {
lastChildElementC = element;
}}
/>
<View key="parent" ref={parentRef}>
<View key="childA" ref={childElementARef} />
<View key="childB" ref={childElementBRef} />
<View key="childC" ref={childElementCRef} />
</View>,
);
});
const parentElement = ensureReactNativeElement(lastParentElement);
const childElementA = ensureReactNativeElement(lastChildElementA);
const childElementB = ensureReactNativeElement(lastChildElementB);
const childElementC = ensureReactNativeElement(lastChildElementC);
const parentElement = ensureReactNativeElement(parentRef.current);
const childElementA = ensureReactNativeElement(
childElementARef.current,
);
const childElementB = ensureReactNativeElement(
childElementBRef.current,
);
const childElementC = ensureReactNativeElement(
childElementCRef.current,
);
const children = parentElement.children;
expect(children).toBeInstanceOf(HTMLCollection);
@@ -777,46 +630,33 @@ describe('ReactNativeElement', () => {
describe('firstElementChild / lastElementChild / previousElementSibling / nextElementSibling', () => {
it('return updated relative elements', () => {
let lastParentElement;
let lastChildElementA;
let lastChildElementB;
let lastChildElementC;
const parentRef = React.createRef<HostInstance>();
const childElementARef = React.createRef<HostInstance>();
const childElementBRef = React.createRef<HostInstance>();
const childElementCRef = React.createRef<HostInstance>();
// Initial render with 3 children
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
key="parent"
ref={element => {
lastParentElement = element;
}}>
<View
key="childA"
ref={element => {
lastChildElementA = element;
}}
/>
<View
key="childB"
ref={element => {
lastChildElementB = element;
}}
/>
<View
key="childC"
ref={element => {
lastChildElementC = element;
}}
/>
<View key="parent" ref={parentRef}>
<View key="childA" ref={childElementARef} />
<View key="childB" ref={childElementBRef} />
<View key="childC" ref={childElementCRef} />
</View>,
);
});
const parentElement = ensureReactNativeElement(lastParentElement);
const childElementA = ensureReactNativeElement(lastChildElementA);
const childElementB = ensureReactNativeElement(lastChildElementB);
const childElementC = ensureReactNativeElement(lastChildElementC);
const parentElement = ensureReactNativeElement(parentRef.current);
const childElementA = ensureReactNativeElement(
childElementARef.current,
);
const childElementB = ensureReactNativeElement(
childElementBRef.current,
);
const childElementC = ensureReactNativeElement(
childElementCRef.current,
);
expect(parentElement.firstElementChild).toBe(childElementA);
expect(parentElement.lastElementChild).toBe(childElementC);
@@ -902,36 +742,28 @@ describe('ReactNativeElement', () => {
describe('textContent', () => {
it('should return the concatenated values of all its text node descendants (using DFS)', () => {
let lastParentNode;
let lastChildNodeA;
const parentRef = React.createRef<HostInstance>();
const childNodeARef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
key="parent"
ref={node => {
lastParentNode = node;
}}>
<View key="parent" ref={parentRef}>
<NativeText>Hello </NativeText>
<View
key="childA"
ref={node => {
lastChildNodeA = node;
}}>
<View key="childA" ref={childNodeARef}>
<NativeText>world!</NativeText>
</View>
</View>,
);
});
const parentNode = ensureReactNativeElement(lastParentNode);
const childNodeA = ensureReactNativeElement(lastChildNodeA);
const parentNode = ensureReactNativeElement(parentRef.current);
const childNodeA = ensureReactNativeElement(childNodeARef.current);
expect(parentNode.textContent).toBe('Hello world!');
expect(childNodeA.textContent).toBe('world!');
let lastChildNodeB;
const childNodeBRef = React.createRef<HostInstance>();
Fantom.runTask(() => {
root.render(
<View key="parent">
@@ -939,11 +771,7 @@ describe('ReactNativeElement', () => {
<View key="childA">
<NativeText>world </NativeText>
</View>
<View
key="childB"
ref={node => {
lastChildNodeB = node;
}}>
<View key="childB" ref={childNodeBRef}>
<View key="childBB">
<NativeText>
again
@@ -955,7 +783,7 @@ describe('ReactNativeElement', () => {
);
});
const childNodeB = ensureReactNativeElement(lastChildNodeB);
const childNodeB = ensureReactNativeElement(childNodeBRef.current);
expect(parentNode.textContent).toBe('Hello world again and again!');
expect(childNodeA.textContent).toBe('world ');
@@ -965,7 +793,7 @@ describe('ReactNativeElement', () => {
describe('getBoundingClientRect', () => {
it('returns a DOMRect with its size and position, or an empty DOMRect when disconnected', () => {
let lastElement;
const elementRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
@@ -980,14 +808,12 @@ describe('ReactNativeElement', () => {
width: 50.3,
height: 100.4,
}}
ref={element => {
lastElement = element;
}}
ref={elementRef}
/>,
);
});
const element = ensureReactNativeElement(lastElement);
const element = ensureReactNativeElement(elementRef.current);
const boundingClientRect = element.getBoundingClientRect();
expect(boundingClientRect).toBeInstanceOf(DOMRect);
@@ -1011,7 +837,7 @@ describe('ReactNativeElement', () => {
describe('scrollLeft / scrollTop', () => {
it('return the scroll position on each axis', () => {
let lastElement;
const elementRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
@@ -1019,14 +845,12 @@ describe('ReactNativeElement', () => {
<ScrollView
key="parent"
contentOffset={{x: 5.1, y: 10.2}}
ref={element => {
lastElement = element;
}}
ref={elementRef}
/>,
);
});
const element = ensureReactNativeElement(lastElement);
const element = ensureReactNativeElement(elementRef.current);
expect(element.scrollLeft).toBeCloseTo(5.1);
expect(element.scrollTop).toBeCloseTo(10.2);
@@ -1042,7 +866,7 @@ describe('ReactNativeElement', () => {
describe('scrollWidth / scrollHeight', () => {
it('return the scroll size on each axis', () => {
let lastElement;
const elementRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
@@ -1050,15 +874,13 @@ describe('ReactNativeElement', () => {
<ScrollView
key="parent"
style={{width: 100, height: 100}}
ref={element => {
lastElement = element;
}}>
ref={elementRef}>
<View style={{width: 200, height: 1500}} />
</ScrollView>,
);
});
const element = ensureReactNativeElement(lastElement);
const element = ensureReactNativeElement(elementRef.current);
expect(element.scrollWidth).toBe(200);
expect(element.scrollHeight).toBe(1500);
@@ -1074,7 +896,7 @@ describe('ReactNativeElement', () => {
describe('clientWidth / clientHeight', () => {
it('return the inner size of the node', () => {
let lastElement;
const elementRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
@@ -1085,14 +907,12 @@ describe('ReactNativeElement', () => {
width: 200,
height: 250,
}}
ref={element => {
lastElement = element;
}}
ref={elementRef}
/>,
);
});
const element = ensureReactNativeElement(lastElement);
const element = ensureReactNativeElement(elementRef.current);
expect(element.clientWidth).toBe(200);
expect(element.clientHeight).toBe(250);
@@ -1108,7 +928,7 @@ describe('ReactNativeElement', () => {
describe('clientLeft / clientTop', () => {
it('return the border size of the node', () => {
let lastElement;
const elementRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
@@ -1119,14 +939,12 @@ describe('ReactNativeElement', () => {
borderTopWidth: 250,
borderLeftWidth: 200,
}}
ref={element => {
lastElement = element;
}}
ref={elementRef}
/>,
);
});
const element = ensureReactNativeElement(lastElement);
const element = ensureReactNativeElement(elementRef.current);
expect(element.clientLeft).toBe(200);
expect(element.clientTop).toBe(250);
@@ -1142,7 +960,7 @@ describe('ReactNativeElement', () => {
describe('id', () => {
it('returns the current `id` prop from the node', () => {
let lastElement;
const elementRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
@@ -1150,20 +968,18 @@ describe('ReactNativeElement', () => {
<View
key="parent"
id="<react-native-element-id>"
ref={element => {
lastElement = element;
}}
ref={elementRef}
/>,
);
});
const element = ensureReactNativeElement(lastElement);
const element = ensureReactNativeElement(elementRef.current);
expect(element.id).toBe('<react-native-element-id>');
});
it('returns the current `nativeID` prop from the node', () => {
let lastElement;
const elementRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
@@ -1171,14 +987,12 @@ describe('ReactNativeElement', () => {
<View
key="parent"
nativeID="<react-native-element-id>"
ref={element => {
lastElement = element;
}}
ref={elementRef}
/>,
);
});
const element = ensureReactNativeElement(lastElement);
const element = ensureReactNativeElement(elementRef.current);
expect(element.id).toBe('<react-native-element-id>');
});
@@ -1186,20 +1000,14 @@ describe('ReactNativeElement', () => {
describe('tagName', () => {
it('returns the normalized tag name for the node', () => {
let lastElement;
const elementRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
ref={element => {
lastElement = element;
}}
/>,
);
root.render(<View ref={elementRef} />);
});
const element = ensureReactNativeElement(lastElement);
const element = ensureReactNativeElement(elementRef.current);
expect(element.tagName).toBe('RN:View');
});
@@ -1208,27 +1016,21 @@ describe('ReactNativeElement', () => {
describe('extends `ReactNativeElement`', () => {
it('should be an instance of `ReactNativeElement`', () => {
let lastNode;
const ref = React.createRef<HostInstance>();
// Initial render with 3 children
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
ref={node => {
lastNode = node;
}}
/>,
);
root.render(<View ref={ref} />);
});
const node = ensureReactNativeElement(lastNode);
const node = ensureReactNativeElement(ref.current);
expect(node).toBeInstanceOf(ReactNativeElement);
});
describe('offsetWidth / offsetHeight', () => {
it('return the rounded width and height, or 0 when disconnected', () => {
let lastElement;
const elementRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
@@ -1242,14 +1044,12 @@ describe('ReactNativeElement', () => {
width: 50.3,
height: 100.5,
}}
ref={element => {
lastElement = element;
}}
ref={elementRef}
/>,
);
});
const element = ensureReactNativeElement(lastElement);
const element = ensureReactNativeElement(elementRef.current);
expect(element.offsetWidth).toBe(50);
expect(element.offsetHeight).toBe(100);
@@ -1265,31 +1065,25 @@ describe('ReactNativeElement', () => {
describe('offsetParent / offsetTop / offsetLeft', () => {
it('retun the rounded offset values and the parent, or null and zeros when disconnected or hidden', () => {
let lastParentElement;
let lastElement;
const parentRef = React.createRef<HostInstance>();
const elementRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
key="parent"
ref={element => {
lastParentElement = element;
}}>
<View key="parent" ref={parentRef}>
<View
key="child"
style={{marginTop: 10.6, marginLeft: 5.1}}
ref={element => {
lastElement = element;
}}
ref={elementRef}
/>
</View>,
);
});
const parentElement = ensureReactNativeElement(lastParentElement);
const element = ensureReactNativeElement(lastElement);
const parentElement = ensureReactNativeElement(parentRef.current);
const element = ensureReactNativeElement(elementRef.current);
expect(element.offsetTop).toBe(11);
expect(element.offsetLeft).toBe(5);
@@ -11,6 +11,8 @@
import 'react-native/Libraries/Core/InitializeCore';
import type {HostInstance} from 'react-native';
import ensureInstance from '../../../../__tests__/utilities/ensureInstance';
import * as Fantom from '@react-native/fantom';
import invariant from 'invariant';
@@ -34,22 +36,15 @@ function ensureReactNativeElement(value: mixed): ReactNativeElement {
describe('ReadOnlyText', () => {
it('should be used to create public text instances when the `enableAccessToHostTreeInFabric` feature flag is enabled', () => {
let lastParentNode;
const parentNodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<NativeText
ref={node => {
lastParentNode = node;
}}>
Some text
</NativeText>,
);
root.render(<NativeText ref={parentNodeRef}>Some text</NativeText>);
});
const parentNode = ensureReadOnlyNode(lastParentNode);
const parentNode = ensureReadOnlyNode(parentNodeRef.current);
const textNode = parentNode.childNodes[0];
expect(textNode).toBeInstanceOf(ReadOnlyText);
@@ -58,22 +53,15 @@ describe('ReadOnlyText', () => {
describe('extends `ReadOnlyNode`', () => {
describe('nodeName', () => {
it('returns "#text"', () => {
let lastParentNode;
const parentNodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<NativeText
ref={node => {
lastParentNode = node;
}}>
Some text
</NativeText>,
);
root.render(<NativeText ref={parentNodeRef}>Some text</NativeText>);
});
const parentNode = ensureReadOnlyNode(lastParentNode);
const parentNode = ensureReadOnlyNode(parentNodeRef.current);
const textNode = parentNode.childNodes[0];
expect(textNode.nodeName).toBe('#text');
@@ -82,22 +70,15 @@ describe('ReadOnlyText', () => {
describe('nodeType', () => {
it('returns ReadOnlyNode.TEXT_NODE', () => {
let lastParentNode;
const parentNodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<NativeText
ref={node => {
lastParentNode = node;
}}>
Some text
</NativeText>,
);
root.render(<NativeText ref={parentNodeRef}>Some text</NativeText>);
});
const parentNode = ensureReadOnlyNode(lastParentNode);
const parentNode = ensureReadOnlyNode(parentNodeRef.current);
const textNode = parentNode.childNodes[0];
expect(textNode.nodeType).toBe(ReadOnlyNode.TEXT_NODE);
@@ -106,22 +87,15 @@ describe('ReadOnlyText', () => {
describe('nodeValue / textContent', () => {
it('returns the string data contained in the node', () => {
let lastParentNode;
const parentNodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<NativeText
ref={node => {
lastParentNode = node;
}}>
Some text
</NativeText>,
);
root.render(<NativeText ref={parentNodeRef}>Some text</NativeText>);
});
const parentNode = ensureReadOnlyNode(lastParentNode);
const parentNode = ensureReadOnlyNode(parentNodeRef.current);
const textNode = parentNode.childNodes[0];
expect(textNode.nodeValue).toBe('Some text');
@@ -131,34 +105,27 @@ describe('ReadOnlyText', () => {
describe('traversal', () => {
it('only preserves text nodes when their contents do not change', () => {
let lastParentElement;
let lastChildElementA;
const parentElementRef = React.createRef<HostInstance>();
const childElementARef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<NativeText
key="parent"
ref={element => {
lastParentElement = element;
}}>
<NativeText key="parent" ref={parentElementRef}>
Text A
<NativeText
key="childA"
ref={element => {
lastChildElementA = element;
}}
/>
<NativeText key="childA" ref={childElementARef} />
Text B
</NativeText>,
);
});
const parentElement: ReactNativeElement =
ensureReactNativeElement(lastParentElement);
const childElementA: ReactNativeElement =
ensureReactNativeElement(lastChildElementA);
const parentElement: ReactNativeElement = ensureReactNativeElement(
parentElementRef.current,
);
const childElementA: ReactNativeElement = ensureReactNativeElement(
childElementARef.current,
);
// Get text nodes and refine them as text nodes for Flow
const childTextA = parentElement.childNodes[0];
@@ -183,18 +150,9 @@ describe('ReadOnlyText', () => {
// Change contents of the second text only
Fantom.runTask(() => {
root.render(
<NativeText
key="parent"
ref={element => {
lastParentElement = element;
}}>
<NativeText key="parent" ref={parentElementRef}>
Text A
<NativeText
key="childA"
ref={element => {
lastChildElementA = element;
}}
/>
<NativeText key="childA" ref={childElementARef} />
Text B modified
</NativeText>,
);
@@ -216,22 +174,17 @@ describe('ReadOnlyText', () => {
describe('extends `ReadOnlyCharacterData`', () => {
describe('data / length', () => {
it('returns the string data and its length, respectively', () => {
let lastParentNode;
const parentNodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<NativeText
ref={node => {
lastParentNode = node;
}}>
Some text
</NativeText>,
);
root.render(<NativeText ref={parentNodeRef}>Some text</NativeText>);
});
const parentNode: ReadOnlyNode = ensureReadOnlyNode(lastParentNode);
const parentNode: ReadOnlyNode = ensureReadOnlyNode(
parentNodeRef.current,
);
const textNode = ensureReadOnlyText(parentNode.childNodes[0]);
expect(textNode.data).toBe('Some text');
@@ -241,50 +194,39 @@ describe('ReadOnlyText', () => {
describe('previousElementSibling / nextElementSibling', () => {
it('return updated relative elements', () => {
let lastParentElement;
let lastChildElementA;
let lastChildElementB;
let lastChildElementC;
const parentElementRef = React.createRef<HostInstance>();
const childElementARef = React.createRef<HostInstance>();
const childElementBRef = React.createRef<HostInstance>();
const childElementCRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<NativeText
key="parent"
ref={element => {
lastParentElement = element;
}}>
<NativeText key="parent" ref={parentElementRef}>
Text A
<NativeText
key="childA"
ref={element => {
lastChildElementA = element;
}}
/>
<NativeText key="childA" ref={childElementARef} />
Text B
<NativeText
key="childB"
ref={element => {
lastChildElementB = element;
}}
/>
<NativeText key="childB" ref={childElementBRef} />
Text C
<NativeText
key="childC"
ref={element => {
lastChildElementC = element;
}}
/>
<NativeText key="childC" ref={childElementCRef} />
Text D
</NativeText>,
);
});
const parentElement = ensureReactNativeElement(lastParentElement);
const childElementA = ensureReactNativeElement(lastChildElementA);
const childElementB = ensureReactNativeElement(lastChildElementB);
const childElementC = ensureReactNativeElement(lastChildElementC);
const parentElement = ensureReactNativeElement(
parentElementRef.current,
);
const childElementA = ensureReactNativeElement(
childElementARef.current,
);
const childElementB = ensureReactNativeElement(
childElementBRef.current,
);
const childElementC = ensureReactNativeElement(
childElementCRef.current,
);
// Get text nodes and refine them as text nodes for Flow
const childTextA = parentElement.childNodes[0];
@@ -334,23 +276,21 @@ describe('ReadOnlyText', () => {
describe('substringData', () => {
it('returns a slice of the text content', () => {
let lastParentElement;
const parentElementRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<NativeText
key="parent"
ref={element => {
lastParentElement = element;
}}>
<NativeText key="parent" ref={parentElementRef}>
Text A
</NativeText>,
);
});
const parentElement = ensureReactNativeElement(lastParentElement);
const parentElement = ensureReactNativeElement(
parentElementRef.current,
);
// Get text nodes and refine them as text nodes for Flow
const childTextA = parentElement.childNodes[0];
@@ -13,6 +13,7 @@
import 'react-native/Libraries/Core/InitializeCore';
import type {Root} from '@react-native/fantom';
import type {HostInstance} from 'react-native';
import type IntersectionObserverType from 'react-native/src/private/webapis/intersectionobserver/IntersectionObserver';
import ensureInstance from '../../../__tests__/utilities/ensureInstance';
@@ -27,10 +28,10 @@ declare const IntersectionObserver: Class<IntersectionObserverType>;
setUpIntersectionObserver();
let maybeNode;
const nodeRef = React.createRef<HostInstance>();
let node: ReactNativeElement;
let maybeScrollViewNode;
const scrollViewRef = React.createRef<HostInstance>();
let scrollViewNode: ReactNativeElement;
let observer: IntersectionObserverType;
const VIEWPORT_HEIGHT = 100;
@@ -106,17 +107,10 @@ Fantom.unstable_benchmark
beforeEach: () => {
mockCallback = jest.fn();
Fantom.runTask(() => {
root.render(
<View
style={{width: 100, height: 10}}
ref={receivedNode => {
maybeNode = receivedNode;
}}
/>,
);
root.render(<View style={{width: 100, height: 10}} ref={nodeRef} />);
observer = new IntersectionObserver(mockCallback);
});
node = ensureInstance(maybeNode, ReactNativeElement);
node = ensureInstance(nodeRef.current, ReactNativeElement);
},
afterEach: () => {
expect(mockCallback).toHaveBeenCalledTimes(1);
@@ -137,10 +131,7 @@ Fantom.unstable_benchmark
beforeEach: () => {
Fantom.runTask(() => {
root.render(
<ScrollView
ref={receivedNode => {
maybeScrollViewNode = receivedNode;
}}>
<ScrollView ref={scrollViewRef}>
{renderElementAtYScrollPosition(
VIEWPORT_HEIGHT + 50,
<View style={{width: 100, height: 10}} />,
@@ -149,7 +140,7 @@ Fantom.unstable_benchmark
);
});
scrollViewNode = ensureInstance(
maybeScrollViewNode,
scrollViewRef.current,
ReactNativeElement,
);
},
@@ -167,10 +158,7 @@ Fantom.unstable_benchmark
beforeEach: () => {
Fantom.runTask(() => {
root.render(
<ScrollView
ref={receivedNode => {
maybeScrollViewNode = receivedNode;
}}>
<ScrollView ref={scrollViewRef}>
{renderElementAtYScrollPosition(
-5,
<View style={{width: 100, height: 10}} />,
@@ -179,7 +167,7 @@ Fantom.unstable_benchmark
);
});
scrollViewNode = ensureInstance(
maybeScrollViewNode,
scrollViewRef.current,
ReactNativeElement,
);
},
@@ -199,27 +187,19 @@ Fantom.unstable_benchmark
Fantom.runTask(() => {
root.render(
<ScrollView
ref={receivedNode => {
maybeScrollViewNode = receivedNode;
}}>
<ScrollView ref={scrollViewRef}>
{renderElementAtYScrollPosition(
VIEWPORT_HEIGHT + 50,
<View
ref={receivedNode => {
maybeNode = receivedNode;
}}
style={{width: 100, height: 10}}
/>,
<View ref={nodeRef} style={{width: 100, height: 10}} />,
)}
</ScrollView>,
);
});
scrollViewNode = ensureInstance(
maybeScrollViewNode,
scrollViewRef.current,
ReactNativeElement,
);
node = ensureInstance(maybeNode, ReactNativeElement);
node = ensureInstance(nodeRef.current, ReactNativeElement);
Fantom.runTask(() => {
observer = new IntersectionObserver(mockCallback, {});
observer.observe(node);
@@ -247,27 +227,19 @@ Fantom.unstable_benchmark
Fantom.runTask(() => {
root.render(
<ScrollView
ref={receivedNode => {
maybeScrollViewNode = receivedNode;
}}>
<ScrollView ref={scrollViewRef}>
{renderElementAtYScrollPosition(
-5,
<View
ref={receivedNode => {
maybeNode = receivedNode;
}}
style={{width: 100, height: 10}}
/>,
<View ref={nodeRef} style={{width: 100, height: 10}} />,
)}
</ScrollView>,
);
});
scrollViewNode = ensureInstance(
maybeScrollViewNode,
scrollViewRef.current,
ReactNativeElement,
);
node = ensureInstance(maybeNode, ReactNativeElement);
node = ensureInstance(nodeRef.current, ReactNativeElement);
Fantom.runTask(() => {
observer = new IntersectionObserver(mockCallback, {threshold: 1});
observer.observe(node);
@@ -11,6 +11,7 @@
import 'react-native/Libraries/Core/InitializeCore';
import type {HostInstance} from 'react-native';
import type IntersectionObserverType from 'react-native/src/private/webapis/intersectionobserver/IntersectionObserver';
import ensureInstance from '../../../__tests__/utilities/ensureInstance';
@@ -87,20 +88,14 @@ describe('IntersectionObserver', () => {
});
it('should throw if `root` is provided', () => {
let maybeNode;
const nodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
ref={receivedNode => {
maybeNode = receivedNode;
}}
/>,
);
root.render(<View ref={nodeRef} />);
});
const node = ensureReactNativeElement(maybeNode);
const node = ensureReactNativeElement(nodeRef.current);
expect(() => {
// $FlowExpectedError[prop-missing] root is not even defined in Flow.
@@ -332,23 +327,16 @@ describe('IntersectionObserver', () => {
});
it('should start observing the target when called for the first time (using normalized thresholds)', () => {
let maybeNode;
const nodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot({
viewportWidth: 1000,
viewportHeight: 1000,
});
Fantom.runTask(() => {
root.render(
<View
style={{width: 100, height: 100}}
ref={receivedNode => {
maybeNode = receivedNode;
}}
/>,
);
root.render(<View style={{width: 100, height: 100}} ref={nodeRef} />);
});
const node = ensureReactNativeElement(maybeNode);
const node = ensureReactNativeElement(nodeRef.current);
const intersectionObserverCallback = jest.fn();
@@ -391,20 +379,13 @@ describe('IntersectionObserver', () => {
});
it('should ignore subsequent calls to observe a target already being observed', () => {
let maybeNode;
const nodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
style={{width: 100, height: 100}}
ref={receivedNode => {
maybeNode = receivedNode;
}}
/>,
);
root.render(<View style={{width: 100, height: 100}} ref={nodeRef} />);
});
const node = ensureReactNativeElement(maybeNode);
const node = ensureReactNativeElement(nodeRef.current);
const intersectionObserverCallback = jest.fn();
@@ -436,21 +417,14 @@ describe('IntersectionObserver', () => {
});
it('should ignore disconnected targets', () => {
let maybeNode;
const nodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
style={{width: 100, height: 100}}
ref={receivedNode => {
maybeNode = receivedNode;
}}
/>,
);
root.render(<View style={{width: 100, height: 100}} ref={nodeRef} />);
});
const node = ensureReactNativeElement(maybeNode);
const node = ensureReactNativeElement(nodeRef.current);
Fantom.runTask(() => {
root.render(<></>);
@@ -469,8 +443,8 @@ describe('IntersectionObserver', () => {
});
it('should report completely non-intersecting initial state correctly', () => {
let maybeNode;
let maybeScrollNode;
const nodeRef = React.createRef<HostInstance>();
const scrollNodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot({
viewportWidth: 1000,
@@ -478,21 +452,16 @@ describe('IntersectionObserver', () => {
});
Fantom.runTask(() => {
root.render(
<ScrollView ref={receivedNode => (maybeScrollNode = receivedNode)}>
<View
style={{width: 50, height: 50}}
ref={receivedNode => {
maybeNode = receivedNode;
}}
/>
<ScrollView ref={scrollNodeRef}>
<View style={{width: 50, height: 50}} ref={nodeRef} />
</ScrollView>,
);
});
const scrollNode = ensureReactNativeElement(maybeScrollNode);
const scrollNode = ensureReactNativeElement(scrollNodeRef.current);
// Ensure View is not intersecting with ScrollView
Fantom.scrollTo(scrollNode, {x: 0, y: 200});
const node = ensureReactNativeElement(maybeNode);
const node = ensureReactNativeElement(nodeRef.current);
const intersectionObserverCallback = jest.fn();
@@ -537,8 +506,8 @@ describe('IntersectionObserver', () => {
});
it('should report partial non-intersecting initial state correctly', () => {
let maybeNode;
let maybeScrollNode;
const nodeRef = React.createRef<HostInstance>();
const scrollNodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot({
viewportWidth: 1000,
@@ -547,19 +516,14 @@ describe('IntersectionObserver', () => {
Fantom.runTask(() => {
root.render(
<ScrollView ref={receivedNode => (maybeScrollNode = receivedNode)}>
<View
style={{width: 50, height: 50}}
ref={receivedNode => {
maybeNode = receivedNode;
}}
/>
<ScrollView ref={scrollNodeRef}>
<View style={{width: 50, height: 50}} ref={nodeRef} />
</ScrollView>,
);
});
const scrollNode = ensureReactNativeElement(maybeScrollNode);
const node = ensureReactNativeElement(maybeNode);
const scrollNode = ensureReactNativeElement(scrollNodeRef.current);
const node = ensureReactNativeElement(nodeRef.current);
// Scroll such that View is partially intersecting
Fantom.scrollTo(scrollNode, {x: 0, y: 25});
@@ -606,8 +570,8 @@ describe('IntersectionObserver', () => {
});
it('should report partial intersecting initial state correctly', () => {
let maybeNode;
let maybeScrollNode;
const nodeRef = React.createRef<HostInstance>();
const scrollNodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot({
viewportWidth: 1000,
@@ -615,18 +579,13 @@ describe('IntersectionObserver', () => {
});
Fantom.runTask(() => {
root.render(
<ScrollView ref={receivedNode => (maybeScrollNode = receivedNode)}>
<View
style={{width: 50, height: 50}}
ref={receivedNode => {
maybeNode = receivedNode;
}}
/>
<ScrollView ref={scrollNodeRef}>
<View style={{width: 50, height: 50}} ref={nodeRef} />
</ScrollView>,
);
});
const scrollNode = ensureReactNativeElement(maybeScrollNode);
const node = ensureReactNativeElement(maybeNode);
const scrollNode = ensureReactNativeElement(scrollNodeRef.current);
const node = ensureReactNativeElement(nodeRef.current);
// Scroll such that View is partially intersecting
Fantom.scrollTo(scrollNode, {x: 0, y: 25});
@@ -673,8 +632,8 @@ describe('IntersectionObserver', () => {
});
it('should report subsequent updates correctly', () => {
let maybeNode;
let maybeScrollNode;
const nodeRef = React.createRef<HostInstance>();
const scrollNodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot({
viewportWidth: 1000,
@@ -683,19 +642,14 @@ describe('IntersectionObserver', () => {
Fantom.runTask(() => {
root.render(
<ScrollView ref={receivedNode => (maybeScrollNode = receivedNode)}>
<View
style={{width: 100, height: 100}}
ref={receivedNode => {
maybeNode = receivedNode;
}}
/>
<ScrollView ref={scrollNodeRef}>
<View style={{width: 100, height: 100}} ref={nodeRef} />
</ScrollView>,
);
});
const node = ensureReactNativeElement(maybeNode);
const scrollNode = ensureReactNativeElement(maybeScrollNode);
const node = ensureReactNativeElement(nodeRef.current);
const scrollNode = ensureReactNativeElement(scrollNodeRef.current);
expect(node.isConnected).toBe(true);
@@ -771,7 +725,7 @@ describe('IntersectionObserver', () => {
it('should report updates to the right observers', () => {
let maybeNode1;
let maybeNode2;
let maybeScrollNode;
const scrollNodeRef = React.createRef<HostInstance>();
let observer1: IntersectionObserver;
let observer2: IntersectionObserver;
@@ -782,7 +736,7 @@ describe('IntersectionObserver', () => {
Fantom.runTask(() => {
root.render(
<ScrollView ref={receivedNode => (maybeScrollNode = receivedNode)}>
<ScrollView ref={scrollNodeRef}>
<View
style={{width: 50, height: 50}}
ref={receivedNode => {
@@ -800,7 +754,7 @@ describe('IntersectionObserver', () => {
});
const node1 = ensureReactNativeElement(maybeNode1);
const node2 = ensureReactNativeElement(maybeNode2);
const scrollNode = ensureReactNativeElement(maybeScrollNode);
const scrollNode = ensureReactNativeElement(scrollNodeRef.current);
// Scroll such that node1 is not intersecting and node 2 is intersecting
Fantom.scrollTo(scrollNode, {x: 0, y: 100});
@@ -891,24 +845,17 @@ describe('IntersectionObserver', () => {
describe('rootThreshold', () => {
it('should report partial intersecting initial state correctly', () => {
let maybeNode;
const nodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot({
viewportWidth: 1000,
viewportHeight: 1000,
});
Fantom.runTask(() => {
root.render(
<View
style={{width: 100, height: 100}}
ref={receivedNode => {
maybeNode = receivedNode;
}}
/>,
);
root.render(<View style={{width: 100, height: 100}} ref={nodeRef} />);
});
const node = ensureReactNativeElement(maybeNode);
const node = ensureReactNativeElement(nodeRef.current);
const intersectionObserverCallback = jest.fn();
@@ -953,8 +900,8 @@ describe('IntersectionObserver', () => {
});
it('should report partial non-intersecting initial state correctly', () => {
let maybeNode;
let maybeScrollNode;
const nodeRef = React.createRef<HostInstance>();
const scrollNodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot({
viewportWidth: 1000,
@@ -962,18 +909,13 @@ describe('IntersectionObserver', () => {
});
Fantom.runTask(() => {
root.render(
<ScrollView ref={receivedNode => (maybeScrollNode = receivedNode)}>
<View
style={{width: 50, height: 50}}
ref={receivedNode => {
maybeNode = receivedNode;
}}
/>
<ScrollView ref={scrollNodeRef}>
<View style={{width: 50, height: 50}} ref={nodeRef} />
</ScrollView>,
);
});
const node = ensureReactNativeElement(maybeNode);
const scrollNode = ensureReactNativeElement(maybeScrollNode);
const node = ensureReactNativeElement(nodeRef.current);
const scrollNode = ensureReactNativeElement(scrollNodeRef.current);
Fantom.scrollTo(scrollNode, {x: 0, y: 25});
@@ -1019,8 +961,8 @@ describe('IntersectionObserver', () => {
});
it('should report completely non-intersecting initial state correctly', () => {
let maybeNode;
let maybeScrollNode;
const nodeRef = React.createRef<HostInstance>();
const scrollNodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot({
viewportWidth: 1000,
@@ -1028,18 +970,13 @@ describe('IntersectionObserver', () => {
});
Fantom.runTask(() => {
root.render(
<ScrollView ref={receivedNode => (maybeScrollNode = receivedNode)}>
<View
style={{width: 50, height: 50}}
ref={receivedNode => {
maybeNode = receivedNode;
}}
/>
<ScrollView ref={scrollNodeRef}>
<View style={{width: 50, height: 50}} ref={nodeRef} />
</ScrollView>,
);
});
const node = ensureReactNativeElement(maybeNode);
const scrollNode = ensureReactNativeElement(maybeScrollNode);
const node = ensureReactNativeElement(nodeRef.current);
const scrollNode = ensureReactNativeElement(scrollNodeRef.current);
Fantom.scrollTo(scrollNode, {x: 0, y: 200});
@@ -1085,8 +1022,8 @@ describe('IntersectionObserver', () => {
});
it('should report subsequent updates correctly', () => {
let maybeNode;
let maybeScrollNode;
const nodeRef = React.createRef<HostInstance>();
const scrollNodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot({
viewportWidth: 1000,
@@ -1095,15 +1032,13 @@ describe('IntersectionObserver', () => {
Fantom.runTask(() => {
root.render(
<ScrollView ref={receivedNode => (maybeScrollNode = receivedNode)}>
<ScrollView ref={scrollNodeRef}>
<View
style={{
width: 1000,
height: 1000,
}}
ref={receivedNode => {
maybeNode = receivedNode;
}}
ref={nodeRef}
/>
<View
style={{
@@ -1115,8 +1050,8 @@ describe('IntersectionObserver', () => {
);
});
const node = ensureReactNativeElement(maybeNode);
const scrollNode = ensureReactNativeElement(maybeScrollNode);
const node = ensureReactNativeElement(nodeRef.current);
const scrollNode = ensureReactNativeElement(scrollNodeRef.current);
// Scroll such that target View is not intersecting
Fantom.scrollTo(scrollNode, {x: 0, y: 2000});
@@ -1210,20 +1145,14 @@ describe('IntersectionObserver', () => {
});
it('should ignore the call if `target` was not observed (not fail)', () => {
let maybeNode;
const nodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
ref={receivedNode => {
maybeNode = receivedNode;
}}
/>,
);
root.render(<View ref={nodeRef} />);
});
const node = ensureReactNativeElement(maybeNode);
const node = ensureReactNativeElement(nodeRef.current);
const callback = jest.fn();
Fantom.runTask(() => {
@@ -1235,26 +1164,21 @@ describe('IntersectionObserver', () => {
});
it('should stop observing the target if it was observed', () => {
let maybeNode;
let maybeScrollNode;
const nodeRef = React.createRef<HostInstance>();
const scrollNodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
// View is not intersecting with ScrollView
Fantom.runTask(() => {
root.render(
<ScrollView ref={receivedNode => (maybeScrollNode = receivedNode)}>
<View
style={{width: 100, height: 100}}
ref={receivedNode => {
maybeNode = receivedNode;
}}
/>
<ScrollView ref={scrollNodeRef}>
<View style={{width: 100, height: 100}} ref={nodeRef} />
</ScrollView>,
);
});
const node = ensureReactNativeElement(maybeNode);
const scrollNode = ensureReactNativeElement(maybeScrollNode);
const node = ensureReactNativeElement(nodeRef.current);
const scrollNode = ensureReactNativeElement(scrollNodeRef.current);
Fantom.scrollTo(scrollNode, {x: 0, y: 100});
@@ -1279,12 +1203,7 @@ describe('IntersectionObserver', () => {
Fantom.runTask(() => {
root.render(
<ScrollView>
<View
style={{width: 100, height: 100}}
ref={receivedNode => {
maybeNode = receivedNode;
}}
/>
<View style={{width: 100, height: 100}} ref={nodeRef} />
</ScrollView>,
);
});
@@ -1294,20 +1213,14 @@ describe('IntersectionObserver', () => {
});
it('should stop observing the target if it was observed (detached target after observing)', () => {
let maybeNode;
const nodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
ref={receivedNode => {
maybeNode = receivedNode;
}}
/>,
);
root.render(<View ref={nodeRef} />);
});
const node = ensureReactNativeElement(maybeNode);
const node = ensureReactNativeElement(nodeRef.current);
const callback = jest.fn();
@@ -1333,20 +1246,14 @@ describe('IntersectionObserver', () => {
});
it('should stop observing the target if it was observed (detached target before observing)', () => {
let maybeNode;
const nodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
ref={receivedNode => {
maybeNode = receivedNode;
}}
/>,
);
root.render(<View ref={nodeRef} />);
});
const node = ensureReactNativeElement(maybeNode);
const node = ensureReactNativeElement(nodeRef.current);
Fantom.runTask(() => {
root.render(<></>);
@@ -1359,20 +1266,14 @@ describe('IntersectionObserver', () => {
});
it('should not report the initial state if the target is unobserved before it is delivered', () => {
let maybeNode;
const nodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
ref={receivedNode => {
maybeNode = receivedNode;
}}
/>,
);
root.render(<View ref={nodeRef} />);
});
const node = ensureReactNativeElement(maybeNode);
const node = ensureReactNativeElement(nodeRef.current);
const intersectionObserverCallback = jest.fn();
@@ -1386,27 +1287,22 @@ describe('IntersectionObserver', () => {
});
it('should not report updates if the target is unobserved before they are delivered', () => {
let maybeNode;
let maybeScrollNode;
const nodeRef = React.createRef<HostInstance>();
const scrollNodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<ScrollView
ref={receivedNode => {
maybeScrollNode = receivedNode;
scrollNodeRef.current = receivedNode;
}}>
<View
style={{width: 100, height: 100}}
ref={receivedNode => {
maybeNode = receivedNode;
}}
/>
<View style={{width: 100, height: 100}} ref={nodeRef} />
</ScrollView>,
);
});
const scrollNode = ensureReactNativeElement(maybeScrollNode);
const scrollNode = ensureReactNativeElement(scrollNodeRef.current);
// Scroll such that view is not intersecting with ScrollView
Fantom.scrollTo(scrollNode, {
@@ -1414,7 +1310,7 @@ describe('IntersectionObserver', () => {
y: 100,
});
const node = ensureReactNativeElement(maybeNode);
const node = ensureReactNativeElement(nodeRef.current);
const callback = jest.fn();
@@ -1515,22 +1411,16 @@ describe('IntersectionObserver', () => {
// target was incorrectly cleaned up when a single observer stopped
// observing it.
it('should work with multiple intersection observer instances', () => {
let maybeNode;
const nodeRef = React.createRef<HostInstance>();
let observer1: IntersectionObserver;
let observer2: IntersectionObserver;
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
ref={receivedNode => {
maybeNode = receivedNode;
}}
/>,
);
root.render(<View ref={nodeRef} />);
});
const node = ensureReactNativeElement(maybeNode);
const node = ensureReactNativeElement(nodeRef.current);
Fantom.runTask(() => {
observer1 = new IntersectionObserver(() => {});
@@ -11,6 +11,7 @@
import 'react-native/Libraries/Core/InitializeCore';
import type {HostInstance} from 'react-native';
import type MutationObserverType from 'react-native/src/private/webapis/mutationobserver/MutationObserver';
import type MutationRecordType from 'react-native/src/private/webapis/mutationobserver/MutationRecord';
@@ -72,20 +73,14 @@ describe('MutationObserver', () => {
});
it('should throw if the `childList` option is not provided', () => {
let maybeNode;
const nodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
ref={receivedNode => {
maybeNode = receivedNode;
}}
/>,
);
root.render(<View ref={nodeRef} />);
});
const node = ensureReactNativeElement(maybeNode);
const node = ensureReactNativeElement(nodeRef.current);
expect(() => {
const observer = new MutationObserver(() => {});
@@ -115,20 +110,14 @@ describe('MutationObserver', () => {
});
it('should throw if the `attributes` option is provided', () => {
let maybeNode;
const nodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
ref={receivedNode => {
maybeNode = receivedNode;
}}
/>,
);
root.render(<View ref={nodeRef} />);
});
const node = ensureReactNativeElement(maybeNode);
const node = ensureReactNativeElement(nodeRef.current);
expect(() => {
const observer = new MutationObserver(() => {});
@@ -139,20 +128,14 @@ describe('MutationObserver', () => {
});
it('should throw if the `attributeFilter` option is provided', () => {
let maybeNode;
const nodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
ref={receivedNode => {
maybeNode = receivedNode;
}}
/>,
);
root.render(<View ref={nodeRef} />);
});
const node = ensureReactNativeElement(maybeNode);
const node = ensureReactNativeElement(nodeRef.current);
expect(() => {
const observer = new MutationObserver(() => {});
@@ -163,20 +146,14 @@ describe('MutationObserver', () => {
});
it('should throw if the `attributeOldValue` option is provided', () => {
let maybeNode;
const nodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
ref={receivedNode => {
maybeNode = receivedNode;
}}
/>,
);
root.render(<View ref={nodeRef} />);
});
const node = ensureReactNativeElement(maybeNode);
const node = ensureReactNativeElement(nodeRef.current);
expect(() => {
const observer = new MutationObserver(() => {});
@@ -188,20 +165,14 @@ describe('MutationObserver', () => {
});
it('should throw if the `characterData` option is provided', () => {
let maybeNode;
const nodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
ref={receivedNode => {
maybeNode = receivedNode;
}}
/>,
);
root.render(<View ref={nodeRef} />);
});
const node = ensureReactNativeElement(maybeNode);
const node = ensureReactNativeElement(nodeRef.current);
expect(() => {
const observer = new MutationObserver(() => {});
@@ -212,20 +183,14 @@ describe('MutationObserver', () => {
});
it('should throw if the `characterDataOldValue` option is provided', () => {
let maybeNode;
const nodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
ref={receivedNode => {
maybeNode = receivedNode;
}}
/>,
);
root.render(<View ref={nodeRef} />);
});
const node = ensureReactNativeElement(maybeNode);
const node = ensureReactNativeElement(nodeRef.current);
expect(() => {
const observer = new MutationObserver(() => {});
@@ -236,21 +201,14 @@ describe('MutationObserver', () => {
});
it('should ignore calls to observe disconnected targets', () => {
let maybeNode;
const nodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
key="node1"
ref={receivedNode => {
maybeNode = receivedNode;
}}
/>,
);
root.render(<View key="node1" ref={nodeRef} />);
});
const node = ensureReactNativeElement(maybeNode);
const node = ensureReactNativeElement(nodeRef.current);
Fantom.runTask(() => {
root.render(<></>);
@@ -267,21 +225,14 @@ describe('MutationObserver', () => {
});
it('should report direct children added to and removed from an observed node (childList: true, subtree: false) ', () => {
let maybeNode;
const nodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
key="node1"
ref={receivedNode => {
maybeNode = receivedNode;
}}
/>,
);
root.render(<View key="node1" ref={nodeRef} />);
});
const node = ensureReactNativeElement(maybeNode);
const node = ensureReactNativeElement(nodeRef.current);
const observerCallbackCallArgs = [];
const observerCallback = (...args: $ReadOnlyArray<mixed>) => {
@@ -293,29 +244,20 @@ describe('MutationObserver', () => {
// Does not report anything initially
expect(observerCallbackCallArgs.length).toBe(0);
let maybeChildNode1, maybeChildNode2;
const childNode1Ref = React.createRef<HostInstance>();
const childNode2Ref = React.createRef<HostInstance>();
Fantom.runTask(() => {
root.render(
<View key="node1">
<View
key="node1-1"
ref={receivedChildNode => {
maybeChildNode1 = receivedChildNode;
}}
/>
<View
key="node1-2"
ref={receivedChildNode => {
maybeChildNode2 = receivedChildNode;
}}
/>
<View key="node1-1" ref={childNode1Ref} />
<View key="node1-2" ref={childNode2Ref} />
</View>,
);
});
const childNode1 = ensureReactNativeElement(maybeChildNode1);
const childNode2 = ensureReactNativeElement(maybeChildNode2);
const childNode1 = ensureReactNativeElement(childNode1Ref.current);
const childNode2 = ensureReactNativeElement(childNode2Ref.current);
expect(observerCallbackCallArgs.length).toBe(1);
const firstCall = nullthrows(observerCallbackCallArgs.at(-1));
@@ -365,22 +307,18 @@ describe('MutationObserver', () => {
});
it('should NOT report changes in transitive children when `subtree` is not set to true', () => {
let maybeObservedNode;
const observedNodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
key="node1"
ref={receivedNode => {
maybeObservedNode = receivedNode;
}}>
<View key="node1" ref={observedNodeRef}>
<View key="node1-1" />
</View>,
);
});
const observedNode = ensureReactNativeElement(maybeObservedNode);
const observedNode = ensureReactNativeElement(observedNodeRef.current);
const observerCallback = jest.fn();
const observer = new MutationObserver(observerCallback);
@@ -413,22 +351,18 @@ describe('MutationObserver', () => {
});
it('should report changes in transitive children when `subtree` is set to true', () => {
let maybeNode;
const nodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
key="node1"
ref={receivedNode => {
maybeNode = receivedNode;
}}>
<View key="node1" ref={nodeRef}>
<View key="node1-1" />
</View>,
);
});
const node = ensureReactNativeElement(maybeNode);
const node = ensureReactNativeElement(nodeRef.current);
const observerCallback = jest.fn();
const observer = new MutationObserver(observerCallback);
@@ -437,24 +371,19 @@ describe('MutationObserver', () => {
// Does not report anything initially
expect(observerCallback).not.toHaveBeenCalled();
let maybeNode111;
const node111Ref = React.createRef<HostInstance>();
Fantom.runTask(() => {
root.render(
<View key="node1">
<View key="node1-1">
<View
key="node1-1-1"
ref={receivedGrandchildNode => {
maybeNode111 = receivedGrandchildNode;
}}
/>
<View key="node1-1-1" ref={node111Ref} />
</View>
</View>,
);
});
const node111 = ensureReactNativeElement(maybeNode111);
const node111 = ensureReactNativeElement(node111Ref.current);
expect(observerCallback).toHaveBeenCalledTimes(1);
const firstCall = observerCallback.mock.lastCall;
@@ -481,23 +410,19 @@ describe('MutationObserver', () => {
});
it('should report changes in different parts of the subtree as separate entries (subtree = true)', () => {
let maybeNode;
const nodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
key="node1"
ref={receivedNode => {
maybeNode = receivedNode;
}}>
<View key="node1" ref={nodeRef}>
<View key="node1-1" />
<View key="node1-2" />
</View>,
);
});
const node = ensureReactNativeElement(maybeNode);
const node = ensureReactNativeElement(nodeRef.current);
const observerCallback = jest.fn();
const observer = new MutationObserver(observerCallback);
@@ -506,33 +431,24 @@ describe('MutationObserver', () => {
// Does not report anything initially
expect(observerCallback).not.toHaveBeenCalled();
let maybeNode111, maybeNode121;
const node111Ref = React.createRef<HostInstance>();
const node121Ref = React.createRef<HostInstance>();
Fantom.runTask(() => {
root.render(
<View key="node1">
<View key="node1-1">
<View
key="node1-1-1"
ref={receivedGrandchildNode => {
maybeNode111 = receivedGrandchildNode;
}}
/>
<View key="node1-1-1" ref={node111Ref} />
</View>
<View key="node1-2">
<View
key="node1-2-1"
ref={receivedGrandchildNode => {
maybeNode121 = receivedGrandchildNode;
}}
/>
<View key="node1-2-1" ref={node121Ref} />
</View>
</View>,
);
});
const node111 = ensureReactNativeElement(maybeNode111);
const node121 = ensureReactNativeElement(maybeNode121);
const node111 = ensureReactNativeElement(node111Ref.current);
const node121 = ensureReactNativeElement(node121Ref.current);
expect(observerCallback).toHaveBeenCalledTimes(1);
const firstCall = observerCallback.mock.lastCall;
@@ -566,31 +482,21 @@ describe('MutationObserver', () => {
describe('multiple observers', () => {
it('should report changes to multiple observers observing different subtrees', () => {
let maybeNode1;
let maybeNode2;
const node1Ref = React.createRef<HostInstance>();
const node2Ref = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<>
<View
key="node1"
ref={receivedNode => {
maybeNode1 = receivedNode;
}}
/>
<View
key="node2"
ref={receivedNode => {
maybeNode2 = receivedNode;
}}
/>
<View key="node1" ref={node1Ref} />
<View key="node2" ref={node2Ref} />
</>,
);
});
const node1 = ensureReactNativeElement(maybeNode1);
const node2 = ensureReactNativeElement(maybeNode2);
const node1 = ensureReactNativeElement(node1Ref.current);
const node2 = ensureReactNativeElement(node2Ref.current);
const observerCallback1 = jest.fn();
const observer1 = new MutationObserver(observerCallback1);
@@ -604,34 +510,24 @@ describe('MutationObserver', () => {
expect(observerCallback1).not.toHaveBeenCalled();
expect(observerCallback2).not.toHaveBeenCalled();
let maybeChildNode11;
let maybeChildNode21;
const childNode11Ref = React.createRef<HostInstance>();
const childNode21Ref = React.createRef<HostInstance>();
Fantom.runTask(() => {
root.render(
<>
<View key="node1">
<View
key="node1-1"
ref={receivedNode => {
maybeChildNode11 = receivedNode;
}}
/>
<View key="node1-1" ref={childNode11Ref} />
</View>
<View key="node2">
<View
key="node2-1"
ref={receivedNode => {
maybeChildNode21 = receivedNode;
}}
/>
<View key="node2-1" ref={childNode21Ref} />
</View>
</>,
);
});
const childNode11 = ensureReactNativeElement(maybeChildNode11);
const childNode21 = ensureReactNativeElement(maybeChildNode21);
const childNode11 = ensureReactNativeElement(childNode11Ref.current);
const childNode21 = ensureReactNativeElement(childNode21Ref.current);
expect(observerCallback1).toHaveBeenCalledTimes(1);
const observer1Records1 = ensureMutationRecordArray(
@@ -676,29 +572,20 @@ describe('MutationObserver', () => {
});
it('should report changes to multiple observers observing the same subtree', () => {
let maybeNode1;
let maybeNode2;
const node1Ref = React.createRef<HostInstance>();
const node2Ref = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
key="node1"
ref={receivedNode => {
maybeNode1 = receivedNode;
}}>
<View
key="node1-1"
ref={receivedNode => {
maybeNode2 = receivedNode;
}}
/>
<View key="node1" ref={node1Ref}>
<View key="node1-1" ref={node2Ref} />
</View>,
);
});
const node1 = ensureReactNativeElement(maybeNode1);
const node2 = ensureReactNativeElement(maybeNode2);
const node1 = ensureReactNativeElement(node1Ref.current);
const node2 = ensureReactNativeElement(node2Ref.current);
const observerCallback1 = jest.fn();
const observer1 = new MutationObserver(observerCallback1);
@@ -712,24 +599,19 @@ describe('MutationObserver', () => {
expect(observerCallback1).not.toHaveBeenCalled();
expect(observerCallback2).not.toHaveBeenCalled();
let maybeChildNode111;
const childNode111Ref = React.createRef<HostInstance>();
Fantom.runTask(() => {
root.render(
<View key="node1">
<View key="node1-1">
<View
key="node-1-1-1"
ref={receivedNode => {
maybeChildNode111 = receivedNode;
}}
/>
<View key="node-1-1-1" ref={childNode111Ref} />
</View>
</View>,
);
});
const childNode111 = ensureReactNativeElement(maybeChildNode111);
const childNode111 = ensureReactNativeElement(childNode111Ref.current);
expect(observerCallback1).toHaveBeenCalledTimes(1);
const observer1Records1 = ensureMutationRecordArray(
@@ -776,31 +658,21 @@ describe('MutationObserver', () => {
describe('multiple observed nodes in the same observer', () => {
it('should report changes in disjoint observations', () => {
let maybeNode1;
let maybeNode2;
const node1Ref = React.createRef<HostInstance>();
const node2Ref = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<>
<View
key="node1"
ref={receivedNode => {
maybeNode1 = receivedNode;
}}
/>
<View
key="node2"
ref={receivedNode => {
maybeNode2 = receivedNode;
}}
/>
<View key="node1" ref={node1Ref} />
<View key="node2" ref={node2Ref} />
</>,
);
});
const node1 = ensureReactNativeElement(maybeNode1);
const node2 = ensureReactNativeElement(maybeNode2);
const node1 = ensureReactNativeElement(node1Ref.current);
const node2 = ensureReactNativeElement(node2Ref.current);
const observerCallback = jest.fn();
const observer = new MutationObserver(observerCallback);
@@ -810,34 +682,24 @@ describe('MutationObserver', () => {
// Does not report anything initially
expect(observerCallback).not.toHaveBeenCalled();
let maybeChildNode11;
let maybeChildNode21;
const childNode11Ref = React.createRef<HostInstance>();
const childNode21Ref = React.createRef<HostInstance>();
Fantom.runTask(() => {
root.render(
<>
<View key="node1">
<View
key="node1-1"
ref={receivedNode => {
maybeChildNode11 = receivedNode;
}}
/>
<View key="node1-1" ref={childNode11Ref} />
</View>
<View key="node2">
<View
key="node2-1"
ref={receivedNode => {
maybeChildNode21 = receivedNode;
}}
/>
<View key="node2-1" ref={childNode21Ref} />
</View>
</>,
);
});
const childNode11 = ensureReactNativeElement(maybeChildNode11);
const childNode21 = ensureReactNativeElement(maybeChildNode21);
const childNode11 = ensureReactNativeElement(childNode11Ref.current);
const childNode21 = ensureReactNativeElement(childNode21Ref.current);
expect(observerCallback).toHaveBeenCalledTimes(1);
const records = ensureMutationRecordArray(
@@ -870,29 +732,20 @@ describe('MutationObserver', () => {
});
it('should report changes in joint observations', () => {
let maybeNode1;
let maybeNode11;
const node1Ref = React.createRef<HostInstance>();
const node11Ref = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
key="node1"
ref={receivedNode => {
maybeNode1 = receivedNode;
}}>
<View
key="node1-1"
ref={receivedNode => {
maybeNode11 = receivedNode;
}}
/>
<View key="node1" ref={node1Ref}>
<View key="node1-1" ref={node11Ref} />
</View>,
);
});
const node1 = ensureReactNativeElement(maybeNode1);
const node11 = ensureReactNativeElement(maybeNode11);
const node1 = ensureReactNativeElement(node1Ref.current);
const node11 = ensureReactNativeElement(node11Ref.current);
const observerCallback = jest.fn();
const observer = new MutationObserver(observerCallback);
@@ -902,24 +755,19 @@ describe('MutationObserver', () => {
// Does not report anything initially
expect(observerCallback).not.toHaveBeenCalled();
let maybeChildNode111;
const childNode111Ref = React.createRef<HostInstance>();
Fantom.runTask(() => {
root.render(
<View key="node1">
<View key="node1-1">
<View
key="node1-1-1"
ref={receivedNode => {
maybeChildNode111 = receivedNode;
}}
/>
<View key="node1-1-1" ref={childNode111Ref} />
</View>
</View>,
);
});
const childNode111 = ensureReactNativeElement(maybeChildNode111);
const childNode111 = ensureReactNativeElement(childNode111Ref.current);
expect(observerCallback).toHaveBeenCalledTimes(1);
const records = ensureMutationRecordArray(
@@ -950,21 +798,14 @@ describe('MutationObserver', () => {
describe('disconnect()', () => {
it('should stop observing targets', () => {
let maybeObservedNode;
const observedNodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
key="node1"
ref={receivedNode => {
maybeObservedNode = receivedNode;
}}
/>,
);
root.render(<View key="node1" ref={observedNodeRef} />);
});
const observedNode = ensureReactNativeElement(maybeObservedNode);
const observedNode = ensureReactNativeElement(observedNodeRef.current);
const observerCallback = jest.fn();
const observer = new MutationObserver(observerCallback);
@@ -998,21 +839,14 @@ describe('MutationObserver', () => {
});
it('should correctly unobserve targets that are disconnected after observing', () => {
let maybeObservedNode;
const observedNodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
key="node1"
ref={receivedNode => {
maybeObservedNode = receivedNode;
}}
/>,
);
root.render(<View key="node1" ref={observedNodeRef} />);
});
const observedNode = ensureReactNativeElement(maybeObservedNode);
const observedNode = ensureReactNativeElement(observedNodeRef.current);
const observerCallback = jest.fn();
const observer = new MutationObserver(observerCallback);
@@ -1030,21 +864,14 @@ describe('MutationObserver', () => {
});
it('should correctly unobserve targets that are disconnected before observing', () => {
let maybeObservedNode;
const observedNodeRef = React.createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
key="node1"
ref={receivedNode => {
maybeObservedNode = receivedNode;
}}
/>,
);
root.render(<View key="node1" ref={observedNodeRef} />);
});
const observedNode = ensureReactNativeElement(maybeObservedNode);
const observedNode = ensureReactNativeElement(observedNodeRef.current);
Fantom.runTask(() => {
root.render(<></>);