From 4e679a22e7b36ed41c6146243de2f4ad36dc7f69 Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Wed, 23 Apr 2025 20:21:49 -0700 Subject: [PATCH] group reparenting tests for view culling together (#50886) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/50886 changelog: [internal] Group tests related to reparenting in "describe" block. Differentiator is two algorithms hidden behind a single interface: regular and reparenting. The tests are structured this way as well where regular tests focus on common scenarios and reparenting section focuses on reparenting and special cases around that. The reparenting implementation is considerably more complex as it handles edge cases that don't happen often. Reviewed By: mdvacca Differential Revision: D73541053 fbshipit-source-id: c3905a0f0117cb1aa6c468e24e6bb982de48545d --- .../__tests__/ScrollView-viewCulling-itest.js | 1300 +++++++++-------- 1 file changed, 651 insertions(+), 649 deletions(-) diff --git a/packages/react-native/Libraries/Components/ScrollView/__tests__/ScrollView-viewCulling-itest.js b/packages/react-native/Libraries/Components/ScrollView/__tests__/ScrollView-viewCulling-itest.js index cafe96b9615..1883c7dc62d 100644 --- a/packages/react-native/Libraries/Components/ScrollView/__tests__/ScrollView-viewCulling-itest.js +++ b/packages/react-native/Libraries/Components/ScrollView/__tests__/ScrollView-viewCulling-itest.js @@ -789,111 +789,6 @@ test('culling when ScrollView parent has transform', () => { ]); }); -test('view flattening with culling', () => { - const root = Fantom.createRoot({viewportWidth: 100, viewportHeight: 100}); - let maybeNode; - - Fantom.runTask(() => { - root.render( - { - maybeNode = node; - }}> - - - - , - ); - }); - - expect(root.takeMountingManagerLogs()).toEqual([ - 'Update {type: "RootView", nativeID: (root)}', - 'Create {type: "ScrollView", nativeID: (N/A)}', - 'Create {type: "View", nativeID: (N/A)}', - 'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}', - 'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}', - ]); - - const element = ensureInstance(maybeNode, ReactNativeElement); - - Fantom.scrollTo(element, { - x: 0, - y: 60, - }); - - expect(root.takeMountingManagerLogs()).toEqual([ - 'Update {type: "ScrollView", nativeID: (N/A)}', - 'Create {type: "View", nativeID: "child"}', - 'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}', - ]); - - // force view to be unflattened. - Fantom.runTask(() => { - root.render( - { - maybeNode = node; - }}> - - - - , - ); - }); - - expect(root.takeMountingManagerLogs()).toEqual([ - 'Update {type: "View", nativeID: "child"}', - 'Remove {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}', - 'Create {type: "View", nativeID: (N/A)}', - 'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}', - 'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}', - ]); - - // force view to be flattened. - Fantom.runTask(() => { - root.render( - { - maybeNode = node; - }}> - - - - , - ); - }); - - expect(root.takeMountingManagerLogs()).toEqual([ - 'Update {type: "View", nativeID: "child"}', - '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)}', - 'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}', - ]); -}); - test('culling inside of Modal', () => { const root = Fantom.createRoot({viewportWidth: 100, viewportHeight: 100}); let maybeNode; @@ -960,603 +855,710 @@ test('culling inside of Modal', () => { ]); }); -test('scroll view parent is unflattened and culled view becomes visible', () => { - const root = Fantom.createRoot({viewportWidth: 100, viewportHeight: 100}); +describe('reparenting', () => { + test('view flattening with culling', () => { + const root = Fantom.createRoot({viewportWidth: 100, viewportHeight: 100}); + let maybeNode; - Fantom.runTask(() => { - root.render( - - - - - , - ); - }); - - expect(root.takeMountingManagerLogs()).toEqual([ - 'Update {type: "RootView", nativeID: (root)}', - 'Create {type: "ScrollView", nativeID: (N/A)}', - 'Create {type: "View", nativeID: (N/A)}', - 'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}', - 'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}', - ]); - - Fantom.runTask(() => { - root.render( - - - - - , - ); - }); - - expect(root.takeMountingManagerLogs()).toEqual([ - 'Update {type: "ScrollView", nativeID: (N/A)}', - 'Remove {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}', - 'Create {type: "View", nativeID: "unflattened"}', - 'Update {type: "View", nativeID: (N/A)}', - 'Create {type: "View", nativeID: "child"}', - 'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}', - 'Insert {type: "View", parentNativeID: (root), index: 0, nativeID: "unflattened"}', - 'Insert {type: "ScrollView", parentNativeID: "unflattened", index: 0, nativeID: (N/A)}', - ]); -}); - -test('scroll view parent is flattened and culled view becomes visible', () => { - const root = Fantom.createRoot({viewportWidth: 100, viewportHeight: 100}); - - Fantom.runTask(() => { - root.render( - - - - - , - ); - }); - - expect(root.takeMountingManagerLogs()).toEqual([ - 'Update {type: "RootView", nativeID: (root)}', - 'Create {type: "View", nativeID: "unflattened"}', - 'Create {type: "ScrollView", nativeID: (N/A)}', - 'Create {type: "View", nativeID: (N/A)}', - 'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}', - 'Insert {type: "ScrollView", parentNativeID: "unflattened", index: 0, nativeID: (N/A)}', - 'Insert {type: "View", parentNativeID: (root), index: 0, nativeID: "unflattened"}', - ]); - - Fantom.runTask(() => { - root.render( - - - - - , - ); - }); - - expect(root.takeMountingManagerLogs()).toEqual([ - 'Update {type: "ScrollView", nativeID: (N/A)}', - 'Remove {type: "ScrollView", parentNativeID: "unflattened", index: 0, nativeID: (N/A)}', - 'Remove {type: "View", parentNativeID: (root), index: 0, nativeID: "unflattened"}', - 'Delete {type: "View", nativeID: "unflattened"}', - 'Update {type: "View", nativeID: (N/A)}', - 'Create {type: "View", nativeID: "child"}', - 'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}', - 'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}', - ]); -}); - -test('scroll view parent is flattened and view becomes culled', () => { - const root = Fantom.createRoot({viewportWidth: 100, viewportHeight: 100}); - - Fantom.runTask(() => { - root.render( - - - - - , - ); - }); - - expect(root.takeMountingManagerLogs()).toEqual([ - 'Update {type: "RootView", nativeID: (root)}', - 'Create {type: "View", nativeID: "unflattened"}', - 'Create {type: "ScrollView", 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: "ScrollView", parentNativeID: "unflattened", index: 0, nativeID: (N/A)}', - 'Insert {type: "View", parentNativeID: (root), index: 0, nativeID: "unflattened"}', - ]); - - Fantom.runTask(() => { - root.render( - - - - - , - ); - }); - - expect(root.takeMountingManagerLogs()).toEqual([ - 'Update {type: "ScrollView", nativeID: (N/A)}', - 'Remove {type: "ScrollView", parentNativeID: "unflattened", index: 0, nativeID: (N/A)}', - 'Remove {type: "View", parentNativeID: (root), index: 0, nativeID: "unflattened"}', - 'Delete {type: "View", nativeID: "unflattened"}', - 'Remove {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}', - 'Delete {type: "View", nativeID: "child"}', - 'Update {type: "View", nativeID: (N/A)}', - 'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}', - ]); -}); - -test('scroll view parent is unflattened and view becomes culled', () => { - const root = Fantom.createRoot({viewportWidth: 100, viewportHeight: 100}); - - Fantom.runTask(() => { - root.render( - - - - - , - ); - }); - - 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: "child"}', - 'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}', - 'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}', - 'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}', - ]); - - Fantom.runTask(() => { - root.render( - - - - - , - ); - }); - - expect(root.takeMountingManagerLogs()).toEqual([ - 'Update {type: "ScrollView", nativeID: (N/A)}', - 'Remove {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}', - 'Create {type: "View", nativeID: "unflattened"}', - 'Remove {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}', - 'Delete {type: "View", nativeID: "child"}', - 'Update {type: "View", nativeID: (N/A)}', - 'Insert {type: "View", parentNativeID: (root), index: 0, nativeID: "unflattened"}', - 'Insert {type: "ScrollView", parentNativeID: "unflattened", index: 0, nativeID: (N/A)}', - ]); -}); - -test('parent-child flattening with culling', () => { - const root = Fantom.createRoot({viewportWidth: 100, viewportHeight: 100}); - - Fantom.runTask(() => { - root.render( - - { + root.render( + { + maybeNode = node; }}> + + + , + ); + }); + + expect(root.takeMountingManagerLogs()).toEqual([ + 'Update {type: "RootView", nativeID: (root)}', + 'Create {type: "ScrollView", nativeID: (N/A)}', + 'Create {type: "View", nativeID: (N/A)}', + 'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}', + 'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}', + ]); + + const element = ensureInstance(maybeNode, ReactNativeElement); + + Fantom.scrollTo(element, { + x: 0, + y: 60, + }); + + expect(root.takeMountingManagerLogs()).toEqual([ + 'Update {type: "ScrollView", nativeID: (N/A)}', + 'Create {type: "View", nativeID: "child"}', + 'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}', + ]); + + // force view to be unflattened. + Fantom.runTask(() => { + root.render( + { + maybeNode = node; + }}> + + + + , + ); + }); + + expect(root.takeMountingManagerLogs()).toEqual([ + 'Update {type: "View", nativeID: "child"}', + 'Remove {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}', + 'Create {type: "View", nativeID: (N/A)}', + 'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}', + 'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}', + ]); + + // force view to be flattened. + Fantom.runTask(() => { + root.render( + { + maybeNode = node; + }}> + + + + , + ); + }); + + expect(root.takeMountingManagerLogs()).toEqual([ + 'Update {type: "View", nativeID: "child"}', + '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)}', + 'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}', + ]); + }); + + test('scroll view parent is unflattened and culled view becomes visible', () => { + const root = Fantom.createRoot({viewportWidth: 100, viewportHeight: 100}); + + Fantom.runTask(() => { + root.render( + + + + + , + ); + }); + + expect(root.takeMountingManagerLogs()).toEqual([ + 'Update {type: "RootView", nativeID: (root)}', + 'Create {type: "ScrollView", nativeID: (N/A)}', + 'Create {type: "View", nativeID: (N/A)}', + 'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}', + 'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}', + ]); + + Fantom.runTask(() => { + root.render( + + + + + , + ); + }); + + expect(root.takeMountingManagerLogs()).toEqual([ + 'Update {type: "ScrollView", nativeID: (N/A)}', + 'Remove {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}', + 'Create {type: "View", nativeID: "unflattened"}', + 'Update {type: "View", nativeID: (N/A)}', + 'Create {type: "View", nativeID: "child"}', + 'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}', + 'Insert {type: "View", parentNativeID: (root), index: 0, nativeID: "unflattened"}', + 'Insert {type: "ScrollView", parentNativeID: "unflattened", index: 0, nativeID: (N/A)}', + ]); + }); + + test('scroll view parent is flattened and culled view becomes visible', () => { + const root = Fantom.createRoot({viewportWidth: 100, viewportHeight: 100}); + + Fantom.runTask(() => { + root.render( + + + + + , + ); + }); + + expect(root.takeMountingManagerLogs()).toEqual([ + 'Update {type: "RootView", nativeID: (root)}', + 'Create {type: "View", nativeID: "unflattened"}', + 'Create {type: "ScrollView", nativeID: (N/A)}', + 'Create {type: "View", nativeID: (N/A)}', + 'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}', + 'Insert {type: "ScrollView", parentNativeID: "unflattened", index: 0, nativeID: (N/A)}', + 'Insert {type: "View", parentNativeID: (root), index: 0, nativeID: "unflattened"}', + ]); + + Fantom.runTask(() => { + root.render( + + + + + , + ); + }); + + expect(root.takeMountingManagerLogs()).toEqual([ + 'Update {type: "ScrollView", nativeID: (N/A)}', + 'Remove {type: "ScrollView", parentNativeID: "unflattened", index: 0, nativeID: (N/A)}', + 'Remove {type: "View", parentNativeID: (root), index: 0, nativeID: "unflattened"}', + 'Delete {type: "View", nativeID: "unflattened"}', + 'Update {type: "View", nativeID: (N/A)}', + 'Create {type: "View", nativeID: "child"}', + 'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}', + 'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}', + ]); + }); + + test('scroll view parent is flattened and view becomes culled', () => { + const root = Fantom.createRoot({viewportWidth: 100, viewportHeight: 100}); + + Fantom.runTask(() => { + root.render( + + + + + , + ); + }); + + expect(root.takeMountingManagerLogs()).toEqual([ + 'Update {type: "RootView", nativeID: (root)}', + 'Create {type: "View", nativeID: "unflattened"}', + 'Create {type: "ScrollView", 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: "ScrollView", parentNativeID: "unflattened", index: 0, nativeID: (N/A)}', + 'Insert {type: "View", parentNativeID: (root), index: 0, nativeID: "unflattened"}', + ]); + + Fantom.runTask(() => { + root.render( + + + + + , + ); + }); + + expect(root.takeMountingManagerLogs()).toEqual([ + 'Update {type: "ScrollView", nativeID: (N/A)}', + 'Remove {type: "ScrollView", parentNativeID: "unflattened", index: 0, nativeID: (N/A)}', + 'Remove {type: "View", parentNativeID: (root), index: 0, nativeID: "unflattened"}', + 'Delete {type: "View", nativeID: "unflattened"}', + 'Remove {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}', + 'Delete {type: "View", nativeID: "child"}', + 'Update {type: "View", nativeID: (N/A)}', + 'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}', + ]); + }); + + test('scroll view parent is unflattened and view becomes culled', () => { + const root = Fantom.createRoot({viewportWidth: 100, viewportHeight: 100}); + + Fantom.runTask(() => { + root.render( + + + + + , + ); + }); + + 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: "child"}', + 'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}', + 'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}', + 'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}', + ]); + + Fantom.runTask(() => { + root.render( + + + + + , + ); + }); + + expect(root.takeMountingManagerLogs()).toEqual([ + 'Update {type: "ScrollView", nativeID: (N/A)}', + 'Remove {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}', + 'Create {type: "View", nativeID: "unflattened"}', + 'Remove {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}', + 'Delete {type: "View", nativeID: "child"}', + 'Update {type: "View", nativeID: (N/A)}', + 'Insert {type: "View", parentNativeID: (root), index: 0, nativeID: "unflattened"}', + 'Insert {type: "ScrollView", parentNativeID: "unflattened", index: 0, nativeID: (N/A)}', + ]); + }); + + test('parent-child flattening with culling', () => { + const root = Fantom.createRoot({viewportWidth: 100, viewportHeight: 100}); + + Fantom.runTask(() => { + root.render( + + + style={{ + marginTop: 50, + opacity: 0, + }}> + + - - , - ); - }); + , + ); + }); - 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: (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: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}', - 'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}', - ]); + 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: (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: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}', + 'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}', + ]); - // force parent-child to be flattened. - Fantom.runTask(() => { - root.render( - - + // force parent-child to be flattened. + Fantom.runTask(() => { + root.render( + + style={{ + marginTop: 50, + }}> + + - - , - ); + , + ); + }); + + expect(root.takeMountingManagerLogs()).toEqual([ + 'Update {type: "View", nativeID: "child"}', + 'Remove {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}', + 'Remove {type: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}', + 'Remove {type: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}', + 'Delete {type: "View", nativeID: (N/A)}', + 'Delete {type: "View", nativeID: (N/A)}', + 'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}', + ]); }); - expect(root.takeMountingManagerLogs()).toEqual([ - 'Update {type: "View", nativeID: "child"}', - 'Remove {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}', - 'Remove {type: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}', - 'Remove {type: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}', - 'Delete {type: "View", nativeID: (N/A)}', - 'Delete {type: "View", nativeID: (N/A)}', - 'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}', - ]); -}); + test('parent-child switching from unflattened-flattened to flattened-unflattened', () => { + const root = Fantom.createRoot({viewportWidth: 100, viewportHeight: 100}); -test('parent-child switching from unflattened-flattened to flattened-unflattened', () => { - const root = Fantom.createRoot({viewportWidth: 100, viewportHeight: 100}); - - Fantom.runTask(() => { - root.render( - - + Fantom.runTask(() => { + root.render( + - - - - , - ); - }); - - 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)}', - ]); - - // force view to be flattened. - Fantom.runTask(() => { - root.render( - - - + style={{ + marginTop: 50, + }}> + + - - , - ); - }); + , + ); + }); - expect(root.takeMountingManagerLogs()).toEqual([ - 'Update {type: "View", nativeID: "child"}', - '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)}', - 'Create {type: "View", nativeID: (N/A)}', - 'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}', - 'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}', - ]); -}); + 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)}', + ]); -test('unflattening and creating a subtree that is partially culled', () => { - const root = Fantom.createRoot({viewportWidth: 100, viewportHeight: 100}); - - // First render with a flattened view container that is visible. - Fantom.runTask(() => { - root.render( - - - , - ); - }); - - expect(root.takeMountingManagerLogs()).toEqual([ - 'Update {type: "RootView", nativeID: (root)}', - 'Create {type: "ScrollView", nativeID: (N/A)}', - 'Create {type: "View", nativeID: (N/A)}', - 'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}', - 'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}', - ]); - - let maybeNode = null; - - // Now update opacity to unflattned the container and add a child that has a culled descendant. - Fantom.runTask(() => { - root.render( - { - maybeNode = node; - }} - contentOffset={{x: 0, y: 111}}> - + // force view to be flattened. + Fantom.runTask(() => { + root.render( + + marginTop: 50, + opacity: 0, + }}> + + - - , - ); + , + ); + }); + + expect(root.takeMountingManagerLogs()).toEqual([ + 'Update {type: "View", nativeID: "child"}', + '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)}', + 'Create {type: "View", nativeID: (N/A)}', + 'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}', + 'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}', + ]); }); - expect(root.takeMountingManagerLogs()).toEqual([ - 'Update {type: "ScrollView", nativeID: (N/A)}', - 'Update {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: (N/A)}', - 'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}', - ]); + test('unflattening and creating a subtree that is partially culled', () => { + const root = Fantom.createRoot({viewportWidth: 100, viewportHeight: 100}); - const element = ensureInstance(maybeNode, ReactNativeElement); + // First render with a flattened view container that is visible. + Fantom.runTask(() => { + root.render( + + + , + ); + }); - // Scroll down to see the grandchild. - Fantom.scrollTo(element, { - x: 0, - y: 115, - }); + expect(root.takeMountingManagerLogs()).toEqual([ + 'Update {type: "RootView", nativeID: (root)}', + 'Create {type: "ScrollView", nativeID: (N/A)}', + 'Create {type: "View", nativeID: (N/A)}', + 'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}', + 'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}', + ]); - expect(root.takeMountingManagerLogs()).toEqual([ - 'Update {type: "ScrollView", nativeID: (N/A)}', - 'Create {type: "View", nativeID: "grandchild"}', - 'Insert {type: "View", parentNativeID: "child", index: 0, nativeID: "grandchild"}', - ]); -}); + let maybeNode = null; -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( - - - - - - - , - ); - }); - - // 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( - - { + root.render( + { + maybeNode = node; }} - /> - , - ); - }); - - // 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"}', - ]); -}); - -test('parent-child switching from unflattened-flattened to flattened-unflattened and grandchild is culled', () => { - const root = Fantom.createRoot({viewportWidth: 100, viewportHeight: 100}); - - // First render unflattened view container with flattened child that has a culled grandchild. - Fantom.runTask(() => { - root.render( - - + contentOffset={{x: 0, y: 111}}> + nativeID="child" + style={{ + marginTop: 10, + height: 10, + width: 10, + }}> + + - - , - ); + , + ); + }); + + expect(root.takeMountingManagerLogs()).toEqual([ + 'Update {type: "ScrollView", nativeID: (N/A)}', + 'Update {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: (N/A)}', + 'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}', + ]); + + const element = ensureInstance(maybeNode, ReactNativeElement); + + // Scroll down to see the grandchild. + Fantom.scrollTo(element, { + x: 0, + y: 115, + }); + + expect(root.takeMountingManagerLogs()).toEqual([ + 'Update {type: "ScrollView", nativeID: (N/A)}', + 'Create {type: "View", nativeID: "grandchild"}', + 'Insert {type: "View", parentNativeID: "child", index: 0, nativeID: "grandchild"}', + ]); }); - // Note that `grandchild` is not mounted. - 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)}', - '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)}', - ]); + test('flattening and deleting a subtree that is partially culled', () => { + const root = Fantom.createRoot({viewportWidth: 100, viewportHeight: 100}); - let maybeNode = null; + // First render with a unflattened view container that is visible and a subtree that is partially culled. + Fantom.runTask(() => { + root.render( + + + + + + + , + ); + }); - // Now change unflattened view container to flattened and change its child to be unflattened. - Fantom.runTask(() => { - root.render( - { - maybeNode = node; - }} - contentOffset={{x: 0, y: 60}}> - + // 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( + + , + ); + }); + + // 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"}', + ]); + }); + + test('parent-child switching from unflattened-flattened to flattened-unflattened and grandchild is culled', () => { + const root = Fantom.createRoot({viewportWidth: 100, viewportHeight: 100}); + + // First render unflattened view container with flattened child that has a culled grandchild. + Fantom.runTask(() => { + root.render( + + + style={{ + marginTop: 50, + }}> + + - - , - ); + , + ); + }); + + // Note that `grandchild` is not mounted. + 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)}', + '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)}', + ]); + + let maybeNode = null; + + // Now change unflattened view container to flattened and change its child to be unflattened. + Fantom.runTask(() => { + root.render( + { + maybeNode = node; + }} + contentOffset={{x: 0, y: 60}}> + + + + + + , + ); + }); + + // Note that `grandchild` is not mounted. + expect(root.takeMountingManagerLogs()).toEqual([ + 'Remove {type: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}', + 'Delete {type: "View", nativeID: (N/A)}', + 'Create {type: "View", nativeID: (N/A)}', + 'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}', + ]); + + const element = ensureInstance(maybeNode, ReactNativeElement); + + // Scroll to reveal grandchild. + Fantom.scrollTo(element, { + x: 0, + y: 70, + }); + + expect(root.takeMountingManagerLogs()).toEqual([ + 'Update {type: "ScrollView", nativeID: (N/A)}', + 'Create {type: "View", nativeID: "grandchild"}', + 'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: "grandchild"}', + ]); }); - - // Note that `grandchild` is not mounted. - expect(root.takeMountingManagerLogs()).toEqual([ - 'Remove {type: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}', - 'Delete {type: "View", nativeID: (N/A)}', - 'Create {type: "View", nativeID: (N/A)}', - 'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}', - ]); - - const element = ensureInstance(maybeNode, ReactNativeElement); - - // Scroll to reveal grandchild. - Fantom.scrollTo(element, { - x: 0, - y: 70, - }); - - expect(root.takeMountingManagerLogs()).toEqual([ - 'Update {type: "ScrollView", nativeID: (N/A)}', - 'Create {type: "View", nativeID: "grandchild"}', - 'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: "grandchild"}', - ]); });