diff --git a/ReactCommon/fabric/core/BUCK b/ReactCommon/fabric/core/BUCK index 43e110c7efc..f866fdc5203 100644 --- a/ReactCommon/fabric/core/BUCK +++ b/ReactCommon/fabric/core/BUCK @@ -85,6 +85,7 @@ fb_xplat_cxx_test( deps = [ "fbsource//xplat/folly:molly", "fbsource//xplat/third-party/gmock:gtest", + react_native_xplat_target("fabric/components/view:view"), ":core", ], ) diff --git a/ReactCommon/fabric/core/tests/LayoutableShadowNodeTest.cpp b/ReactCommon/fabric/core/tests/LayoutableShadowNodeTest.cpp new file mode 100644 index 00000000000..fd0978d8ff0 --- /dev/null +++ b/ReactCommon/fabric/core/tests/LayoutableShadowNodeTest.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (c) Facebook, Inc. and its 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 "TestComponent.h" + +using namespace facebook::react; + +class LayoutableShadowNodeTest : public ::testing::Test { + protected: + LayoutableShadowNodeTest() + : eventDispatcher_(std::shared_ptr()), + componentDescriptor_(TestComponentDescriptor({eventDispatcher_})) { + auto familyA = std::make_shared( + ShadowNodeFamilyFragment{ + /* .tag = */ 9, + /* .surfaceId = */ 1, + /* .eventEmitter = */ nullptr, + }, + componentDescriptor_); + + nodeA_ = std::make_shared( + ShadowNodeFragment{ + /* .props = */ std::make_shared(), + /* .children = */ ShadowNode::emptySharedShadowNodeSharedList(), + }, + familyA, + ShadowNodeTraits{}); + + auto familyB = std::make_shared( + ShadowNodeFamilyFragment{ + /* .tag = */ 10, + /* .surfaceId = */ 1, + /* .eventEmitter = */ nullptr, + }, + componentDescriptor_); + + nodeB_ = std::make_shared( + ShadowNodeFragment{ + /* .props = */ std::make_shared(), + /* .children = */ ShadowNode::emptySharedShadowNodeSharedList(), + }, + familyB, + ShadowNodeTraits{}); + + nodeA_->appendChild(nodeB_); + } + + std::shared_ptr eventDispatcher_; + std::shared_ptr nodeA_; + std::shared_ptr nodeB_; + TestComponentDescriptor componentDescriptor_; +}; + +TEST_F(LayoutableShadowNodeTest, relativeLayourMetrics) { + auto layoutMetrics = EmptyLayoutMetrics; + layoutMetrics.frame.origin = {10, 20}; + layoutMetrics.frame.size = {100, 200}; + nodeA_->setLayoutMetrics(layoutMetrics); + nodeB_->setLayoutMetrics(layoutMetrics); + + auto relativeLayoutMetrics = nodeB_->getRelativeLayoutMetrics(*nodeA_, {}); + + // A is a parent to B, A has origin {10, 10}, B has origin {10, 10}. + // B's relative origin to A should be {10, 10}. + // D19447900 has more about the issue. + EXPECT_EQ(relativeLayoutMetrics.frame.origin.x, 10); + EXPECT_EQ(relativeLayoutMetrics.frame.origin.y, 20); +} + +TEST_F(LayoutableShadowNodeTest, relativeLayourMetricsOnClonedNode) { + // B is cloned and mutated. + auto nodeBRevision2 = std::static_pointer_cast( + componentDescriptor_.cloneShadowNode(*nodeB_, ShadowNodeFragment{})); + auto layoutMetrics = EmptyLayoutMetrics; + layoutMetrics.frame.size = {500, 600}; + nodeBRevision2->setLayoutMetrics(layoutMetrics); + nodeA_->replaceChild(*nodeB_, nodeBRevision2); + + // Even if we ask old ShadowNode for its relative layoutMetrics, it needs to + // return correct, new layoutMetrics. D19433873 has more about the issue. + auto newRelativeLayoutMetrics = nodeB_->getRelativeLayoutMetrics(*nodeA_, {}); + EXPECT_EQ(newRelativeLayoutMetrics.frame.size.width, 500); + EXPECT_EQ(newRelativeLayoutMetrics.frame.size.height, 600); +} diff --git a/ReactCommon/fabric/core/tests/TestComponent.h b/ReactCommon/fabric/core/tests/TestComponent.h index f8ea2349d8b..9e0616923d2 100644 --- a/ReactCommon/fabric/core/tests/TestComponent.h +++ b/ReactCommon/fabric/core/tests/TestComponent.h @@ -10,8 +10,9 @@ #include #include +#include +#include #include -#include #include #include #include @@ -39,9 +40,12 @@ class TestLocalData : public LocalData { static const char TestComponentName[] = "Test"; -class TestProps : public Props { +class TestProps : public ViewProps { public: - using Props::Props; + using ViewProps::ViewProps; + + TestProps(const TestProps &sourceProps, const RawProps &rawProps) + : ViewProps(sourceProps, rawProps) {} }; using SharedTestProps = std::shared_ptr; @@ -50,9 +54,14 @@ class TestShadowNode; using SharedTestShadowNode = std::shared_ptr; -class TestShadowNode : public ConcreteShadowNode { +class TestShadowNode + : public ConcreteViewShadowNode { public: - using ConcreteShadowNode::ConcreteShadowNode; + using ConcreteViewShadowNode::ConcreteViewShadowNode; + + bool setLayoutMetrics(LayoutMetrics layoutMetrics) { + return YogaLayoutableShadowNode::setLayoutMetrics(layoutMetrics); + } }; class TestComponentDescriptor