diff --git a/packages/react-native/Libraries/ReactNative/__tests__/State-ForcedCloneCommitHook-itest.js b/packages/react-native/Libraries/ReactNative/__tests__/State-ForcedCloneCommitHook-itest.js index 35985de655c..db6e13d70ea 100644 --- a/packages/react-native/Libraries/ReactNative/__tests__/State-ForcedCloneCommitHook-itest.js +++ b/packages/react-native/Libraries/ReactNative/__tests__/State-ForcedCloneCommitHook-itest.js @@ -18,10 +18,10 @@ import ensureInstance from '../../../src/private/__tests__/utilities/ensureInsta import * as Fantom from '@react-native/fantom'; import * as React from 'react'; import {ScrollView, View} from 'react-native'; -import NativeFantomForcedCloneCommitHook from 'react-native/src/private/testing/fantom/specs/NativeFantomForcedCloneCommitHook'; +import NativeFantomTestSpecificMethods from 'react-native/src/private/testing/fantom/specs/NativeFantomTestSpecificMethods'; import ReactNativeElement from 'react-native/src/private/webapis/dom/nodes/ReactNativeElement'; -NativeFantomForcedCloneCommitHook.setup(); +NativeFantomTestSpecificMethods.registerForcedCloneCommitHook(); describe('ScrollViewShadowNode', () => { it('maintains state after commit hook processing', () => { diff --git a/packages/react-native/ReactCommon/react/nativemodule/fantomforcedclonecommithook/NativeFantomForcedCloneCommitHook.cpp b/packages/react-native/ReactCommon/react/nativemodule/fantomforcedclonecommithook/NativeFantomForcedCloneCommitHook.cpp deleted file mode 100644 index ed4afe29fad..00000000000 --- a/packages/react-native/ReactCommon/react/nativemodule/fantomforcedclonecommithook/NativeFantomForcedCloneCommitHook.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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 "NativeFantomForcedCloneCommitHook.h" -#include -#include -#include -#include -#include -#include -#include - -#include "Plugins.h" - -std::shared_ptr -NativeFantomForcedCloneCommitHookModuleProvider( - std::shared_ptr jsInvoker) { - return std::make_shared( - std::move(jsInvoker)); -} - -namespace facebook::react { - -struct FantomForcedCloneCommitHook : public UIManagerCommitHook { - void commitHookWasRegistered( - const UIManager& /*uiManager*/) noexcept override {} - void commitHookWasUnregistered( - const UIManager& /*uiManager*/) noexcept override {} - RootShadowNode::Unshared shadowTreeWillCommit( - const ShadowTree& shadowTree, - const RootShadowNode::Shared& oldRootShadowNode, - const RootShadowNode::Unshared& newRootShadowNode) noexcept override; -}; - -ShadowNode::Shared findAndClone(const ShadowNode::Shared& node) { - if (node->getProps()->nativeId == "to-be-cloned-in-the-commit-hook") { - return node->clone({}); - } - - auto children = node->getChildren(); - for (int i = 0; i < children.size(); i++) { - auto& child = children[i]; - auto maybeClone = findAndClone(child); - if (maybeClone != child) { - children[i] = maybeClone; - return node->clone( - {ShadowNodeFragment::propsPlaceholder(), - std::make_shared(children)}); - } - } - - return node; -} - -RootShadowNode::Unshared FantomForcedCloneCommitHook::shadowTreeWillCommit( - const ShadowTree& /*shadowTree*/, - const RootShadowNode::Shared& /*oldRootShadowNode*/, - const RootShadowNode::Unshared& newRootShadowNode) noexcept { - auto result = findAndClone(newRootShadowNode); - - return std::static_pointer_cast( - std::const_pointer_cast(result)); -} - -static UIManager& getUIManagerFromRuntime(jsi::Runtime& runtime) { - return UIManagerBinding::getBinding(runtime)->getUIManager(); -} - -NativeFantomForcedCloneCommitHook::NativeFantomForcedCloneCommitHook( - std::shared_ptr jsInvoker) - : NativeFantomForcedCloneCommitHookCxxSpec(std::move(jsInvoker)), - fantomForcedCloneCommitHook_( - std::make_shared()) {} - -void NativeFantomForcedCloneCommitHook::setup(jsi::Runtime& runtime) { - auto& uiManager = getUIManagerFromRuntime(runtime); - uiManager.registerCommitHook(*fantomForcedCloneCommitHook_); -} - -} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/nativemodule/fantomtestspecificmethods/NativeFantomTestSpecificMethods.cpp b/packages/react-native/ReactCommon/react/nativemodule/fantomtestspecificmethods/NativeFantomTestSpecificMethods.cpp new file mode 100644 index 00000000000..d88166c948c --- /dev/null +++ b/packages/react-native/ReactCommon/react/nativemodule/fantomtestspecificmethods/NativeFantomTestSpecificMethods.cpp @@ -0,0 +1,46 @@ +/* + * 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 "NativeFantomTestSpecificMethods.h" +#include +#include + +#include "internal/FantomForcedCloneCommitHook.h" + +#include "Plugins.h" + +std::shared_ptr +NativeFantomTestSpecificMethodsModuleProvider( + std::shared_ptr jsInvoker) { + return std::make_shared( + std::move(jsInvoker)); +} + +namespace { + +facebook::react::UIManager& getUIManagerFromRuntime( + facebook::jsi::Runtime& runtime) { + return facebook::react::UIManagerBinding::getBinding(runtime)->getUIManager(); +} + +} // namespace + +namespace facebook::react { + +NativeFantomTestSpecificMethods::NativeFantomTestSpecificMethods( + std::shared_ptr jsInvoker) + : NativeFantomTestSpecificMethodsCxxSpec(std::move(jsInvoker)), + fantomForcedCloneCommitHook_( + std::make_shared()) {} + +void NativeFantomTestSpecificMethods::registerForcedCloneCommitHook( + jsi::Runtime& runtime) { + auto& uiManager = getUIManagerFromRuntime(runtime); + uiManager.registerCommitHook(*fantomForcedCloneCommitHook_); +} + +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/nativemodule/fantomforcedclonecommithook/NativeFantomForcedCloneCommitHook.h b/packages/react-native/ReactCommon/react/nativemodule/fantomtestspecificmethods/NativeFantomTestSpecificMethods.h similarity index 64% rename from packages/react-native/ReactCommon/react/nativemodule/fantomforcedclonecommithook/NativeFantomForcedCloneCommitHook.h rename to packages/react-native/ReactCommon/react/nativemodule/fantomtestspecificmethods/NativeFantomTestSpecificMethods.h index 9644e5ef765..8aebaacc7a6 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/fantomforcedclonecommithook/NativeFantomForcedCloneCommitHook.h +++ b/packages/react-native/ReactCommon/react/nativemodule/fantomtestspecificmethods/NativeFantomTestSpecificMethods.h @@ -8,20 +8,19 @@ #pragma once #include -#include namespace facebook::react { struct FantomForcedCloneCommitHook; -class NativeFantomForcedCloneCommitHook - : public NativeFantomForcedCloneCommitHookCxxSpec< - NativeFantomForcedCloneCommitHook> { +class NativeFantomTestSpecificMethods + : public NativeFantomTestSpecificMethodsCxxSpec< + NativeFantomTestSpecificMethods> { public: - explicit NativeFantomForcedCloneCommitHook( + explicit NativeFantomTestSpecificMethods( std::shared_ptr jsInvoker); - void setup(jsi::Runtime& runtime); + void registerForcedCloneCommitHook(jsi::Runtime& runtime); private: std::shared_ptr fantomForcedCloneCommitHook_{}; diff --git a/packages/react-native/ReactCommon/react/nativemodule/fantomtestspecificmethods/internal/FantomForcedCloneCommitHook.cpp b/packages/react-native/ReactCommon/react/nativemodule/fantomtestspecificmethods/internal/FantomForcedCloneCommitHook.cpp new file mode 100644 index 00000000000..fb331d9335d --- /dev/null +++ b/packages/react-native/ReactCommon/react/nativemodule/fantomtestspecificmethods/internal/FantomForcedCloneCommitHook.cpp @@ -0,0 +1,56 @@ +/* + * 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 "FantomForcedCloneCommitHook.h" +#include +#include + +namespace { + +using namespace facebook::react; + +ShadowNode::Shared findAndClone(const ShadowNode::Shared& node) { + if (node->getProps()->nativeId == "to-be-cloned-in-the-commit-hook") { + return node->clone({}); + } + + auto children = node->getChildren(); + for (int i = 0; i < children.size(); i++) { + auto& child = children[i]; + auto maybeClone = findAndClone(child); + if (maybeClone != child) { + children[i] = maybeClone; + return node->clone( + {ShadowNodeFragment::propsPlaceholder(), + std::make_shared(children)}); + } + } + + return node; +} + +} // namespace + +namespace facebook::react { + +void FantomForcedCloneCommitHook::commitHookWasRegistered( + const UIManager& /*uiManager*/) noexcept {} + +void FantomForcedCloneCommitHook::commitHookWasUnregistered( + const UIManager& /*uiManager*/) noexcept {} + +RootShadowNode::Unshared FantomForcedCloneCommitHook::shadowTreeWillCommit( + const ShadowTree& /*shadowTree*/, + const RootShadowNode::Shared& /*oldRootShadowNode*/, + const RootShadowNode::Unshared& newRootShadowNode) noexcept { + auto result = findAndClone(newRootShadowNode); + + return std::static_pointer_cast( + std::const_pointer_cast(result)); +} + +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/nativemodule/fantomtestspecificmethods/internal/FantomForcedCloneCommitHook.h b/packages/react-native/ReactCommon/react/nativemodule/fantomtestspecificmethods/internal/FantomForcedCloneCommitHook.h new file mode 100644 index 00000000000..5eea56e0a4d --- /dev/null +++ b/packages/react-native/ReactCommon/react/nativemodule/fantomtestspecificmethods/internal/FantomForcedCloneCommitHook.h @@ -0,0 +1,29 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include + +namespace facebook::react { + +struct FantomForcedCloneCommitHook : public UIManagerCommitHook { + void commitHookWasRegistered( + const UIManager& /*uiManager*/) noexcept override; + + void commitHookWasUnregistered( + const UIManager& /*uiManager*/) noexcept override; + + RootShadowNode::Unshared shadowTreeWillCommit( + const ShadowTree& shadowTree, + const RootShadowNode::Shared& oldRootShadowNode, + const RootShadowNode::Unshared& newRootShadowNode) noexcept override; +}; + +} // namespace facebook::react diff --git a/packages/react-native/src/private/testing/fantom/specs/NativeFantomForcedCloneCommitHook.js b/packages/react-native/src/private/testing/fantom/specs/NativeFantomForcedCloneCommitHook.js deleted file mode 100644 index bc8da85b91f..00000000000 --- a/packages/react-native/src/private/testing/fantom/specs/NativeFantomForcedCloneCommitHook.js +++ /dev/null @@ -1,21 +0,0 @@ -/** - * 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. - * - * @flow strict - * @format - */ - -import type {TurboModule} from '../../../../../Libraries/TurboModule/RCTExport'; - -import * as TurboModuleRegistry from '../../../../../Libraries/TurboModule/TurboModuleRegistry'; - -export interface Spec extends TurboModule { - +setup: () => void; -} - -export default (TurboModuleRegistry.getEnforcing( - 'NativeFantomForcedCloneCommitHookCxx', -): Spec); diff --git a/packages/react-native/src/private/testing/fantom/specs/NativeFantomTestSpecificMethods.js b/packages/react-native/src/private/testing/fantom/specs/NativeFantomTestSpecificMethods.js new file mode 100644 index 00000000000..92e14552fce --- /dev/null +++ b/packages/react-native/src/private/testing/fantom/specs/NativeFantomTestSpecificMethods.js @@ -0,0 +1,30 @@ +/** + * 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. + * + * @flow strict + * @format + */ + +import type {TurboModule} from '../../../../../Libraries/TurboModule/RCTExport'; + +import * as TurboModuleRegistry from '../../../../../Libraries/TurboModule/TurboModuleRegistry'; + +/** + * This native module provides test-specific helpers that run native code + * that isn't provided by React Native and cannot be specified in JavaScript + * (e.g.: to test native hooks that don't have a consumer in any built-in APIs, + * or call into methods that host platforms would generally call into). + * + * Feel free to add more methods here as needed by your tests, but make sure + * that this is the only way to test the behavior. + */ +export interface Spec extends TurboModule { + +registerForcedCloneCommitHook: () => void; +} + +export default (TurboModuleRegistry.getEnforcing( + 'NativeFantomTestSpecificMethodsCxx', +): Spec);