Refactor existing native module into a general purpose native module for Fantom test specific methods (#51133)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/51133

Changelog: [internal]

Having a single native module with all the test-specific functionality that we need in native in Fantom is just more convenient.

Reviewed By: rshest, huntie

Differential Revision: D73997209

fbshipit-source-id: 5d3aa69a2c799166a1351fbff3e80e4396cec9c6
This commit is contained in:
Rubén Norte
2025-05-07 04:16:41 -07:00
committed by Facebook GitHub Bot
parent 12627f10b3
commit 759652b09f
8 changed files with 168 additions and 113 deletions
@@ -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', () => {
@@ -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 <cxxreact/TraceSection.h>
#include <react/featureflags/ReactNativeFeatureFlags.h>
#include <react/renderer/components/scrollview/ScrollViewShadowNode.h>
#include <react/renderer/core/ShadowNode.h>
#include <react/renderer/uimanager/UIManagerBinding.h>
#include <react/renderer/uimanager/UIManagerCommitHook.h>
#include <react/renderer/uimanager/primitives.h>
#include "Plugins.h"
std::shared_ptr<facebook::react::TurboModule>
NativeFantomForcedCloneCommitHookModuleProvider(
std::shared_ptr<facebook::react::CallInvoker> jsInvoker) {
return std::make_shared<facebook::react::NativeFantomForcedCloneCommitHook>(
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<ShadowNode::ListOfShared>(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<RootShadowNode>(
std::const_pointer_cast<ShadowNode>(result));
}
static UIManager& getUIManagerFromRuntime(jsi::Runtime& runtime) {
return UIManagerBinding::getBinding(runtime)->getUIManager();
}
NativeFantomForcedCloneCommitHook::NativeFantomForcedCloneCommitHook(
std::shared_ptr<CallInvoker> jsInvoker)
: NativeFantomForcedCloneCommitHookCxxSpec(std::move(jsInvoker)),
fantomForcedCloneCommitHook_(
std::make_shared<FantomForcedCloneCommitHook>()) {}
void NativeFantomForcedCloneCommitHook::setup(jsi::Runtime& runtime) {
auto& uiManager = getUIManagerFromRuntime(runtime);
uiManager.registerCommitHook(*fantomForcedCloneCommitHook_);
}
} // namespace facebook::react
@@ -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 <react/renderer/uimanager/UIManager.h>
#include <react/renderer/uimanager/UIManagerBinding.h>
#include "internal/FantomForcedCloneCommitHook.h"
#include "Plugins.h"
std::shared_ptr<facebook::react::TurboModule>
NativeFantomTestSpecificMethodsModuleProvider(
std::shared_ptr<facebook::react::CallInvoker> jsInvoker) {
return std::make_shared<facebook::react::NativeFantomTestSpecificMethods>(
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<CallInvoker> jsInvoker)
: NativeFantomTestSpecificMethodsCxxSpec(std::move(jsInvoker)),
fantomForcedCloneCommitHook_(
std::make_shared<FantomForcedCloneCommitHook>()) {}
void NativeFantomTestSpecificMethods::registerForcedCloneCommitHook(
jsi::Runtime& runtime) {
auto& uiManager = getUIManagerFromRuntime(runtime);
uiManager.registerCommitHook(*fantomForcedCloneCommitHook_);
}
} // namespace facebook::react
@@ -8,20 +8,19 @@
#pragma once
#include <FBReactNativeSpec/FBReactNativeSpecJSI.h>
#include <react/renderer/uimanager/UIManager.h>
namespace facebook::react {
struct FantomForcedCloneCommitHook;
class NativeFantomForcedCloneCommitHook
: public NativeFantomForcedCloneCommitHookCxxSpec<
NativeFantomForcedCloneCommitHook> {
class NativeFantomTestSpecificMethods
: public NativeFantomTestSpecificMethodsCxxSpec<
NativeFantomTestSpecificMethods> {
public:
explicit NativeFantomForcedCloneCommitHook(
explicit NativeFantomTestSpecificMethods(
std::shared_ptr<CallInvoker> jsInvoker);
void setup(jsi::Runtime& runtime);
void registerForcedCloneCommitHook(jsi::Runtime& runtime);
private:
std::shared_ptr<FantomForcedCloneCommitHook> fantomForcedCloneCommitHook_{};
@@ -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 <react/renderer/uimanager/UIManagerBinding.h>
#include <react/renderer/uimanager/primitives.h>
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<ShadowNode::ListOfShared>(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<RootShadowNode>(
std::const_pointer_cast<ShadowNode>(result));
}
} // namespace facebook::react
@@ -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 <react/renderer/core/ShadowNode.h>
#include <react/renderer/uimanager/UIManager.h>
#include <react/renderer/uimanager/UIManagerCommitHook.h>
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
@@ -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<Spec>(
'NativeFantomForcedCloneCommitHookCxx',
): Spec);
@@ -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<Spec>(
'NativeFantomTestSpecificMethodsCxx',
): Spec);