add view culling tests when flattetning and deleting a subtree (#50860)

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

changelog: [internal]

Adding a test case verifying branch of code starting in [Differentiator:855](https://github.com/facebook/react-native/blob/main/packages/react-native/ReactCommon/react/renderer/mounting/Differentiator.cpp#L855)

Without using `adjustedOldCullingContext` in the branch, it leads to a crash on [StubViewTree:177](https://github.com/facebook/react-native/blob/main/packages/react-native/ReactCommon/react/renderer/mounting/stubs/StubViewTree.cpp#L177):  trying to remove view that does not exist.

Reviewed By: lenaic

Differential Revision: D73493001

fbshipit-source-id: 4b81a6635decabb5be043b36cbbd764998f2c438
This commit is contained in:
Samuel Susla
2025-04-23 05:01:25 -07:00
committed by Facebook GitHub Bot
parent e0b1b63c3f
commit d40b4c660b
2 changed files with 70 additions and 2 deletions
@@ -1398,3 +1398,73 @@ test('unflattening and creating a subtree that is partially culled', () => {
'Insert {type: "View", parentNativeID: "child", index: 0, nativeID: "grandchild"}',
]);
});
test('flattening and deleting a subtree that is partially culled', () => {
const root = Fantom.createRoot({viewportWidth: 100, viewportHeight: 100});
// First render with a unflattened view container that is visible and a subtree that is partially culled.
Fantom.runTask(() => {
root.render(
<ScrollView
style={{height: 100, width: 100}}
contentOffset={{x: 0, y: 111}}>
<View style={{marginTop: 200, opacity: 0.5}}>
<View
nativeID="child"
style={{
marginTop: 10,
height: 10,
width: 10,
}}>
<View
nativeID="grandchild"
style={{
marginTop: 5,
height: 5,
width: 5,
}}
/>
</View>
</View>
</ScrollView>,
);
});
// All views are mounted, except for the grandchild.
expect(root.takeMountingManagerLogs()).toEqual([
'Update {type: "RootView", nativeID: (root)}',
'Create {type: "ScrollView", nativeID: (N/A)}',
'Create {type: "View", nativeID: (N/A)}',
'Create {type: "View", nativeID: (N/A)}',
'Create {type: "View", nativeID: "child"}',
'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}',
'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}',
'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}',
'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}',
]);
// Now change opacity to the default to flatten the container and delete container's subtree.
Fantom.runTask(() => {
root.render(
<ScrollView
style={{height: 100, width: 100}}
contentOffset={{x: 0, y: 111}}>
<View
style={{
marginTop: 200,
}}
/>
</ScrollView>,
);
});
// Note that the grandchild is not deleted because it was not previously mounted.
expect(root.takeMountingManagerLogs()).toEqual([
'Update {type: "ScrollView", nativeID: (N/A)}',
'Update {type: "View", nativeID: (N/A)}',
'Remove {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}',
'Remove {type: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}',
'Delete {type: "View", nativeID: (N/A)}',
'Delete {type: "View", nativeID: "child"}',
]);
});
@@ -854,8 +854,6 @@ static void calculateShadowViewMutationsFlattener(
if (!treeChildPair.flattened) {
ViewNodePairScope innerScope{};
// TODO(T217775046): Find a test case for this branch of view
// flattening + culling.
calculateShadowViewMutations(
innerScope,
mutationContainer.destructiveDownwardMutations,