/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #include #include #include #include #include #include #include #include #include #include #include #include #include namespace facebook::react { class OrderIndexTest : public ::testing::Test { protected: ComponentBuilder builder_; std::shared_ptr rootShadowNode_; std::shared_ptr nodeA_; std::shared_ptr nodeB_; std::shared_ptr nodeC_; std::shared_ptr nodeD_; std::shared_ptr currentRootShadowNode_; StubViewTree currentStubViewTree_; OrderIndexTest() : builder_(simpleComponentBuilder()) { auto element = Element() .reference(rootShadowNode_) .tag(1) .children({ Element().tag(2).reference(nodeA_), Element().tag(3).reference(nodeB_), Element().tag(4).reference(nodeC_), Element().tag(5).reference(nodeD_), }); builder_.build(element); mutateViewShadowNodeProps_(nodeA_, [](ViewProps& props) { auto& yogaStyle = props.yogaStyle; yogaStyle.setPositionType(yoga::PositionType::Relative); props.backgroundColor = blackColor(); // to ensure it won't get flattened }); mutateViewShadowNodeProps_(nodeB_, [](ViewProps& props) { auto& yogaStyle = props.yogaStyle; yogaStyle.setPositionType(yoga::PositionType::Relative); props.backgroundColor = blackColor(); // to ensure it won't get flattened }); mutateViewShadowNodeProps_(nodeC_, [](ViewProps& props) { auto& yogaStyle = props.yogaStyle; yogaStyle.setPositionType(yoga::PositionType::Relative); props.backgroundColor = blackColor(); // to ensure it won't get flattened }); mutateViewShadowNodeProps_(nodeD_, [](ViewProps& props) { auto& yogaStyle = props.yogaStyle; yogaStyle.setPositionType(yoga::PositionType::Relative); props.backgroundColor = blackColor(); // to ensure it won't get flattened }); currentRootShadowNode_ = rootShadowNode_; currentRootShadowNode_->layoutIfNeeded(); currentStubViewTree_ = buildStubViewTreeWithoutUsingDifferentiator(*currentRootShadowNode_); } void mutateViewShadowNodeProps_( const std::shared_ptr& node, std::function callback) { rootShadowNode_ = std::static_pointer_cast(rootShadowNode_->cloneTree( node->getFamily(), [&](const ShadowNode& oldShadowNode) { auto viewProps = std::make_shared(); callback(*viewProps); return oldShadowNode.clone(ShadowNodeFragment{viewProps}); })); } void testViewTree_( const std::function& callback) { rootShadowNode_->layoutIfNeeded(); callback(buildStubViewTreeUsingDifferentiator(*rootShadowNode_)); auto mutations = calculateShadowViewMutations(*currentRootShadowNode_, *rootShadowNode_); currentRootShadowNode_ = rootShadowNode_; currentStubViewTree_.mutate(mutations); callback(currentStubViewTree_); } }; TEST_F(OrderIndexTest, defaultOrderIsDocumentOrder) { testViewTree_([this](const StubViewTree& viewTree) { EXPECT_EQ(viewTree.size(), 5); EXPECT_EQ(viewTree.getRootStubView().children.size(), 4); EXPECT_EQ(viewTree.getRootStubView().children.at(0)->tag, nodeA_->getTag()); EXPECT_EQ(viewTree.getRootStubView().children.at(1)->tag, nodeB_->getTag()); EXPECT_EQ(viewTree.getRootStubView().children.at(2)->tag, nodeC_->getTag()); EXPECT_EQ(viewTree.getRootStubView().children.at(3)->tag, nodeD_->getTag()); }); } TEST_F(OrderIndexTest, basicZIndex) { mutateViewShadowNodeProps_( nodeA_, [](ViewProps& props) { props.zIndex = 5; }); mutateViewShadowNodeProps_( nodeB_, [](ViewProps& props) { props.zIndex = 10; }); mutateViewShadowNodeProps_( nodeC_, [](ViewProps& props) { props.zIndex = 1; }); mutateViewShadowNodeProps_( nodeD_, [](ViewProps& props) { props.zIndex = 2; }); testViewTree_([this](const StubViewTree& viewTree) { EXPECT_EQ(viewTree.size(), 5); EXPECT_EQ(viewTree.getRootStubView().children.size(), 4); EXPECT_EQ(viewTree.getRootStubView().children.at(0)->tag, nodeC_->getTag()); EXPECT_EQ(viewTree.getRootStubView().children.at(1)->tag, nodeD_->getTag()); EXPECT_EQ(viewTree.getRootStubView().children.at(2)->tag, nodeA_->getTag()); EXPECT_EQ(viewTree.getRootStubView().children.at(3)->tag, nodeB_->getTag()); }); } TEST_F(OrderIndexTest, negativeZIndex) { mutateViewShadowNodeProps_( nodeA_, [](ViewProps& props) { props.zIndex = 5; }); mutateViewShadowNodeProps_( nodeB_, [](ViewProps& props) { props.zIndex = -10; }); mutateViewShadowNodeProps_( nodeC_, [](ViewProps& props) { props.zIndex = -1; }); mutateViewShadowNodeProps_( nodeD_, [](ViewProps& props) { props.zIndex = 2; }); testViewTree_([this](const StubViewTree& viewTree) { EXPECT_EQ(viewTree.size(), 5); EXPECT_EQ(viewTree.getRootStubView().children.size(), 4); EXPECT_EQ(viewTree.getRootStubView().children.at(0)->tag, nodeB_->getTag()); EXPECT_EQ(viewTree.getRootStubView().children.at(1)->tag, nodeC_->getTag()); EXPECT_EQ(viewTree.getRootStubView().children.at(2)->tag, nodeD_->getTag()); EXPECT_EQ(viewTree.getRootStubView().children.at(3)->tag, nodeA_->getTag()); }); } TEST_F(OrderIndexTest, zeroZIndex) { mutateViewShadowNodeProps_( nodeC_, [](ViewProps& props) { props.zIndex = 0; }); mutateViewShadowNodeProps_( nodeD_, [](ViewProps& props) { props.zIndex = 0; }); testViewTree_([this](const StubViewTree& viewTree) { EXPECT_EQ(viewTree.size(), 5); EXPECT_EQ(viewTree.getRootStubView().children.size(), 4); EXPECT_EQ(viewTree.getRootStubView().children.at(0)->tag, nodeA_->getTag()); EXPECT_EQ(viewTree.getRootStubView().children.at(1)->tag, nodeB_->getTag()); EXPECT_EQ(viewTree.getRootStubView().children.at(2)->tag, nodeC_->getTag()); EXPECT_EQ(viewTree.getRootStubView().children.at(3)->tag, nodeD_->getTag()); }); } TEST_F(OrderIndexTest, staticBehindNonStatic) { mutateViewShadowNodeProps_(nodeB_, [](ViewProps& props) { auto& yogaStyle = props.yogaStyle; yogaStyle.setPositionType(yoga::PositionType::Static); props.backgroundColor = blackColor(); }); mutateViewShadowNodeProps_(nodeD_, [](ViewProps& props) { auto& yogaStyle = props.yogaStyle; yogaStyle.setPositionType(yoga::PositionType::Static); props.backgroundColor = blackColor(); }); testViewTree_([this](const StubViewTree& viewTree) { EXPECT_EQ(viewTree.size(), 5); EXPECT_EQ(viewTree.getRootStubView().children.size(), 4); EXPECT_EQ(viewTree.getRootStubView().children.at(0)->tag, nodeB_->getTag()); EXPECT_EQ(viewTree.getRootStubView().children.at(1)->tag, nodeD_->getTag()); EXPECT_EQ(viewTree.getRootStubView().children.at(2)->tag, nodeA_->getTag()); EXPECT_EQ(viewTree.getRootStubView().children.at(3)->tag, nodeC_->getTag()); }); } TEST_F(OrderIndexTest, zIndexStaticBehindNonStatic) { mutateViewShadowNodeProps_( nodeB_, [](ViewProps& props) { props.zIndex = 5; }); mutateViewShadowNodeProps_( nodeC_, [](ViewProps& props) { props.zIndex = -1; }); mutateViewShadowNodeProps_(nodeD_, [](ViewProps& props) { auto& yogaStyle = props.yogaStyle; yogaStyle.setPositionType(yoga::PositionType::Static); props.backgroundColor = blackColor(); }); testViewTree_([this](const StubViewTree& viewTree) { EXPECT_EQ(viewTree.size(), 5); EXPECT_EQ(viewTree.getRootStubView().children.size(), 4); EXPECT_EQ(viewTree.getRootStubView().children.at(0)->tag, nodeC_->getTag()); EXPECT_EQ(viewTree.getRootStubView().children.at(1)->tag, nodeD_->getTag()); EXPECT_EQ(viewTree.getRootStubView().children.at(2)->tag, nodeA_->getTag()); EXPECT_EQ(viewTree.getRootStubView().children.at(3)->tag, nodeB_->getTag()); }); } TEST_F(OrderIndexTest, staticDoesNotGetZIndex) { mutateViewShadowNodeProps_(nodeB_, [](ViewProps& props) { auto& yogaStyle = props.yogaStyle; yogaStyle.setPositionType(yoga::PositionType::Static); props.backgroundColor = blackColor(); props.zIndex = 5; }); mutateViewShadowNodeProps_(nodeD_, [](ViewProps& props) { auto& yogaStyle = props.yogaStyle; yogaStyle.setPositionType(yoga::PositionType::Static); props.backgroundColor = blackColor(); props.zIndex = -5; }); testViewTree_([this](const StubViewTree& viewTree) { EXPECT_EQ(viewTree.size(), 5); EXPECT_EQ(viewTree.getRootStubView().children.size(), 4); EXPECT_EQ(viewTree.getRootStubView().children.at(0)->tag, nodeB_->getTag()); EXPECT_EQ(viewTree.getRootStubView().children.at(1)->tag, nodeD_->getTag()); EXPECT_EQ(viewTree.getRootStubView().children.at(2)->tag, nodeA_->getTag()); EXPECT_EQ(viewTree.getRootStubView().children.at(3)->tag, nodeC_->getTag()); }); } } // namespace facebook::react