mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
175b1ea636
Summary: Changelog: [internal] Reviewed By: mdvacca Differential Revision: D29921232 fbshipit-source-id: ba045f545b564aedf1b287045a0e75428de30a0f
181 lines
5.9 KiB
C++
181 lines
5.9 KiB
C++
/*
|
|
* 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 <memory>
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
|
|
#include <react/renderer/components/view/ViewComponentDescriptor.h>
|
|
#include <react/renderer/core/PropsParserContext.h>
|
|
#include <react/renderer/element/ComponentBuilder.h>
|
|
#include <react/renderer/element/Element.h>
|
|
#include <react/renderer/mounting/MountingCoordinator.h>
|
|
#include <react/renderer/mounting/ShadowTree.h>
|
|
#include <react/renderer/mounting/ShadowTreeDelegate.h>
|
|
|
|
#include <react/renderer/element/testUtils.h>
|
|
|
|
using namespace facebook::react;
|
|
|
|
class DummyShadowTreeDelegate : public ShadowTreeDelegate {
|
|
public:
|
|
virtual RootShadowNode::Unshared shadowTreeWillCommit(
|
|
ShadowTree const &shadowTree,
|
|
RootShadowNode::Shared const &oldRootShadowNode,
|
|
RootShadowNode::Unshared const &newRootShadowNode) const override {
|
|
return newRootShadowNode;
|
|
};
|
|
|
|
virtual void shadowTreeDidFinishTransaction(
|
|
ShadowTree const &shadowTree,
|
|
MountingCoordinator::Shared const &mountingCoordinator) const override{};
|
|
};
|
|
|
|
inline ShadowNode const *findDescendantNode(
|
|
ShadowNode const &shadowNode,
|
|
ShadowNodeFamily const &family) {
|
|
ShadowNode const *result = nullptr;
|
|
shadowNode.cloneTree(family, [&](ShadowNode const &oldShadowNode) {
|
|
result = &oldShadowNode;
|
|
return oldShadowNode.clone({});
|
|
});
|
|
return result;
|
|
}
|
|
|
|
inline ShadowNode const *findDescendantNode(
|
|
ShadowTree const &shadowTree,
|
|
ShadowNodeFamily const &family) {
|
|
return findDescendantNode(
|
|
*shadowTree.getCurrentRevision().rootShadowNode, family);
|
|
}
|
|
|
|
TEST(StateReconciliationTest, testStateReconciliation) {
|
|
auto builder = simpleComponentBuilder();
|
|
|
|
auto shadowNodeA = std::shared_ptr<RootShadowNode>{};
|
|
auto shadowNodeAA = std::shared_ptr<ViewShadowNode>{};
|
|
auto shadowNodeAB = std::shared_ptr<ScrollViewShadowNode>{};
|
|
auto shadowNodeABA = std::shared_ptr<ViewShadowNode>{};
|
|
auto shadowNodeABB = std::shared_ptr<ViewShadowNode>{};
|
|
auto shadowNodeABC = std::shared_ptr<ViewShadowNode>{};
|
|
|
|
// clang-format off
|
|
auto element =
|
|
Element<RootShadowNode>()
|
|
.reference(shadowNodeA)
|
|
.finalize([](RootShadowNode &shadowNode){
|
|
shadowNode.sealRecursive();
|
|
})
|
|
.children({
|
|
Element<ViewShadowNode>()
|
|
.reference(shadowNodeAA),
|
|
Element<ScrollViewShadowNode>()
|
|
.reference(shadowNodeAB)
|
|
.children({
|
|
Element<ViewShadowNode>()
|
|
.children({
|
|
Element<ViewShadowNode>()
|
|
.reference(shadowNodeABA),
|
|
Element<ViewShadowNode>()
|
|
.reference(shadowNodeABB),
|
|
Element<ViewShadowNode>()
|
|
.reference(shadowNodeABC)
|
|
})
|
|
})
|
|
});
|
|
// clang-format on
|
|
|
|
ContextContainer contextContainer{};
|
|
|
|
auto shadowNode = builder.build(element);
|
|
|
|
auto rootShadowNodeState1 = shadowNode->ShadowNode::clone({});
|
|
|
|
auto &scrollViewComponentDescriptor = shadowNodeAB->getComponentDescriptor();
|
|
auto &family = shadowNodeAB->getFamily();
|
|
auto state1 = shadowNodeAB->getState();
|
|
auto shadowTreeDelegate = DummyShadowTreeDelegate{};
|
|
ShadowTree shadowTree{
|
|
SurfaceId{11},
|
|
LayoutConstraints{},
|
|
LayoutContext{},
|
|
shadowTreeDelegate,
|
|
contextContainer};
|
|
|
|
shadowTree.commit(
|
|
[&](RootShadowNode const &oldRootShadowNode) {
|
|
return std::static_pointer_cast<RootShadowNode>(rootShadowNodeState1);
|
|
},
|
|
{true});
|
|
|
|
EXPECT_EQ(state1->getMostRecentState(), state1);
|
|
|
|
EXPECT_EQ(
|
|
findDescendantNode(*rootShadowNodeState1, family)->getState(), state1);
|
|
|
|
auto state2 = scrollViewComponentDescriptor.createState(
|
|
family, std::make_shared<ScrollViewState const>());
|
|
|
|
auto rootShadowNodeState2 =
|
|
shadowNode->cloneTree(family, [&](ShadowNode const &oldShadowNode) {
|
|
return oldShadowNode.clone(
|
|
{ShadowNodeFragment::propsPlaceholder(),
|
|
ShadowNodeFragment::childrenPlaceholder(),
|
|
state2});
|
|
});
|
|
|
|
EXPECT_EQ(
|
|
findDescendantNode(*rootShadowNodeState2, family)->getState(), state2);
|
|
|
|
shadowTree.commit(
|
|
[&](RootShadowNode const &oldRootShadowNode) {
|
|
return std::static_pointer_cast<RootShadowNode>(rootShadowNodeState2);
|
|
},
|
|
{true});
|
|
|
|
EXPECT_EQ(state1->getMostRecentState(), state2);
|
|
EXPECT_EQ(state2->getMostRecentState(), state2);
|
|
|
|
auto state3 = scrollViewComponentDescriptor.createState(
|
|
family, std::make_shared<ScrollViewState const>());
|
|
|
|
auto rootShadowNodeState3 = rootShadowNodeState2->cloneTree(
|
|
family, [&](ShadowNode const &oldShadowNode) {
|
|
return oldShadowNode.clone(
|
|
{ShadowNodeFragment::propsPlaceholder(),
|
|
ShadowNodeFragment::childrenPlaceholder(),
|
|
state3});
|
|
});
|
|
|
|
EXPECT_EQ(
|
|
findDescendantNode(*rootShadowNodeState3, family)->getState(), state3);
|
|
|
|
shadowTree.commit(
|
|
[&](RootShadowNode const &oldRootShadowNode) {
|
|
return std::static_pointer_cast<RootShadowNode>(rootShadowNodeState3);
|
|
},
|
|
{true});
|
|
|
|
EXPECT_EQ(findDescendantNode(shadowTree, family)->getState(), state3);
|
|
|
|
EXPECT_EQ(state1->getMostRecentState(), state3);
|
|
EXPECT_EQ(state2->getMostRecentState(), state3);
|
|
EXPECT_EQ(state3->getMostRecentState(), state3);
|
|
|
|
// This is the core part of the whole test.
|
|
// Here we commit the old tree but we expect that the state associated with
|
|
// the node will stay the same (newer that the old tree has).
|
|
shadowTree.commit(
|
|
[&](RootShadowNode const &oldRootShadowNode) {
|
|
return std::static_pointer_cast<RootShadowNode>(rootShadowNodeState2);
|
|
},
|
|
{true});
|
|
|
|
EXPECT_EQ(findDescendantNode(shadowTree, family)->getState(), state3);
|
|
}
|