Skip to content

Commit 51091d4

Browse files
sammy-SCfacebook-github-bot
authored andcommitted
add a view culling test case when for reparenting a culled grand (#50894)
Summary: Pull Request resolved: #50894 changelog: [internal] adding more tests to cover all branches of `calculateShadowViewMutationsFlattener`. calculateShadowViewMutationsFlattener is over 400 lines of code and covers quite a few edge cases. I plan to cover every branch with a test to make it easier to refactor Differentiator in the future. Reviewed By: rubennorte Differential Revision: D73543444 fbshipit-source-id: b0b22aba4b9cc4718edd2a6c4535993be437ed9f
1 parent d8fe0d2 commit 51091d4

File tree

2 files changed

+164
-2
lines changed

2 files changed

+164
-2
lines changed

packages/react-native/Libraries/Components/ScrollView/__tests__/ScrollView-viewCulling-itest.js

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1561,4 +1561,168 @@ describe('reparenting', () => {
15611561
'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: "grandchild"}',
15621562
]);
15631563
});
1564+
1565+
test('parent-child switching from flattened-unflattened to unflattened-flattened and grandchild is culled', () => {
1566+
const root = Fantom.createRoot({viewportWidth: 100, viewportHeight: 100});
1567+
1568+
// First render unflattened view container with flattened child that has a culled grandchild.
1569+
Fantom.runTask(() => {
1570+
root.render(
1571+
<ScrollView
1572+
style={{height: 100, width: 100}}
1573+
contentOffset={{x: 0, y: 60}}>
1574+
<View
1575+
style={{
1576+
marginTop: 100,
1577+
}}>
1578+
<View
1579+
style={{
1580+
marginTop: 50,
1581+
opacity: 0,
1582+
}}>
1583+
<View
1584+
nativeID={'grandchild'}
1585+
style={{height: 10, width: 10, marginTop: 11}}
1586+
/>
1587+
</View>
1588+
</View>
1589+
</ScrollView>,
1590+
);
1591+
});
1592+
1593+
// Note that `grandchild` is not mounted.
1594+
expect(root.takeMountingManagerLogs()).toEqual([
1595+
'Update {type: "RootView", nativeID: (root)}',
1596+
'Create {type: "ScrollView", nativeID: (N/A)}',
1597+
'Create {type: "View", nativeID: (N/A)}',
1598+
'Create {type: "View", nativeID: (N/A)}',
1599+
'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}',
1600+
'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}',
1601+
'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}',
1602+
]);
1603+
1604+
let maybeNode = null;
1605+
1606+
// Now change unflattened view container to flattened and change its child to be unflattened.
1607+
Fantom.runTask(() => {
1608+
root.render(
1609+
<ScrollView
1610+
style={{height: 100, width: 100}}
1611+
ref={node => {
1612+
maybeNode = node;
1613+
}}
1614+
contentOffset={{x: 0, y: 60}}>
1615+
<View
1616+
style={{
1617+
marginTop: 100,
1618+
opacity: 0,
1619+
}}>
1620+
<View
1621+
style={{
1622+
marginTop: 50,
1623+
}}>
1624+
<View
1625+
nativeID={'grandchild'}
1626+
style={{height: 10, width: 10, marginTop: 11}}
1627+
/>
1628+
</View>
1629+
</View>
1630+
</ScrollView>,
1631+
);
1632+
});
1633+
1634+
// Note that `grandchild` is not mounted.
1635+
expect(root.takeMountingManagerLogs()).toEqual([
1636+
'Remove {type: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}',
1637+
'Delete {type: "View", nativeID: (N/A)}',
1638+
'Create {type: "View", nativeID: (N/A)}',
1639+
'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}',
1640+
]);
1641+
1642+
const element = ensureInstance(maybeNode, ReactNativeElement);
1643+
1644+
// Scroll to reveal grandchild.
1645+
Fantom.scrollTo(element, {
1646+
x: 0,
1647+
y: 70,
1648+
});
1649+
1650+
expect(root.takeMountingManagerLogs()).toEqual([
1651+
'Update {type: "ScrollView", nativeID: (N/A)}',
1652+
'Create {type: "View", nativeID: "grandchild"}',
1653+
'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: "grandchild"}',
1654+
]);
1655+
});
1656+
1657+
test('parent-child switching from flattened-unflattened to unflattened-flattened', () => {
1658+
const root = Fantom.createRoot({viewportWidth: 100, viewportHeight: 100});
1659+
1660+
// First create a view hierarchy where parent is flattened but child is not.
1661+
// `grandchild` is not culled.
1662+
Fantom.runTask(() => {
1663+
root.render(
1664+
<ScrollView
1665+
style={{height: 100, width: 100}}
1666+
contentOffset={{x: 0, y: 60}}>
1667+
<View
1668+
style={{
1669+
marginTop: 100,
1670+
}}>
1671+
<View
1672+
style={{
1673+
marginTop: 50,
1674+
opacity: 0,
1675+
}}>
1676+
<View nativeID={'grandchild'} style={{height: 10, width: 10}} />
1677+
</View>
1678+
</View>
1679+
</ScrollView>,
1680+
);
1681+
});
1682+
1683+
expect(root.takeMountingManagerLogs()).toEqual([
1684+
'Update {type: "RootView", nativeID: (root)}',
1685+
'Create {type: "ScrollView", nativeID: (N/A)}',
1686+
'Create {type: "View", nativeID: (N/A)}',
1687+
'Create {type: "View", nativeID: (N/A)}',
1688+
'Create {type: "View", nativeID: "grandchild"}',
1689+
'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: "grandchild"}',
1690+
'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}',
1691+
'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}',
1692+
'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}',
1693+
]);
1694+
1695+
// Now switch parent to be unflattened and child to be flattened.
1696+
// `grandchild` remains visible.
1697+
Fantom.runTask(() => {
1698+
root.render(
1699+
<ScrollView
1700+
style={{height: 100, width: 100}}
1701+
contentOffset={{x: 0, y: 60}}>
1702+
<View
1703+
style={{
1704+
marginTop: 100,
1705+
opacity: 0,
1706+
}}>
1707+
<View
1708+
style={{
1709+
marginTop: 50,
1710+
}}>
1711+
<View nativeID={'grandchild'} style={{height: 10, width: 10}} />
1712+
</View>
1713+
</View>
1714+
</ScrollView>,
1715+
);
1716+
});
1717+
1718+
expect(root.takeMountingManagerLogs()).toEqual([
1719+
'Update {type: "View", nativeID: "grandchild"}',
1720+
'Remove {type: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}',
1721+
'Remove {type: "View", parentNativeID: (N/A), index: 0, nativeID: "grandchild"}',
1722+
'Delete {type: "View", nativeID: (N/A)}',
1723+
'Create {type: "View", nativeID: (N/A)}',
1724+
'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}',
1725+
'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: "grandchild"}',
1726+
]);
1727+
});
15641728
});

packages/react-native/ReactCommon/react/renderer/mounting/Differentiator.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -710,8 +710,6 @@ static void calculateShadowViewMutationsFlattener(
710710
// Flatten old tree into new list
711711
// At the end of this loop we still want to know which of these
712712
// children are visited, so we reuse the `newRemainingPairs` map.
713-
// TODO(T217775046): Find a test case for this branch of view
714-
// flattening + culling.
715713
calculateShadowViewMutationsFlattener(
716714
scope,
717715
ReparentMode::Flatten,

0 commit comments

Comments
 (0)