Files
react-native/ReactCommon/react/renderer/mounting/tests/StateReconciliationTest.cpp
T
Joshua Gross 175b1ea636 Pass PropsParserContext to prop parsing layer
Summary: Changelog: [internal]

Reviewed By: mdvacca

Differential Revision: D29921232

fbshipit-source-id: ba045f545b564aedf1b287045a0e75428de30a0f
2021-07-28 20:18:20 -07:00

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);
}