mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Make JsiIntegrationPortableTest reusable in other test suites
Summary: Changelog: [Internal] TSIA - useful for the `console` test suite I'm currently writing (D54846940) which would be awkward to fit into `JsiIntegrationTest.cpp`. bypass-github-export-checks Reviewed By: huntie Differential Revision: D54846938 fbshipit-source-id: 9e20bfae7c518b3822da468adf484e51cdc4d0b9
This commit is contained in:
committed by
Facebook GitHub Bot
parent
949296571b
commit
121b26184a
@@ -6,20 +6,8 @@
|
||||
*/
|
||||
|
||||
#include <folly/Format.h>
|
||||
#include <folly/dynamic.h>
|
||||
#include <folly/executors/QueuedImmediateExecutor.h>
|
||||
#include <folly/json.h>
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <jsinspector-modern/HostTarget.h>
|
||||
#include <jsinspector-modern/InspectorInterfaces.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "FollyDynamicMatchers.h"
|
||||
#include "InspectorMocks.h"
|
||||
#include "UniquePtrFactory.h"
|
||||
#include "JsiIntegrationTest.h"
|
||||
#include "engines/JsiIntegrationTestGenericEngineAdapter.h"
|
||||
#include "engines/JsiIntegrationTestHermesEngineAdapter.h"
|
||||
#include "engines/JsiIntegrationTestHermesWithCDPAgentEngineAdapter.h"
|
||||
@@ -29,138 +17,6 @@ using folly::sformat;
|
||||
|
||||
namespace facebook::react::jsinspector_modern {
|
||||
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* A text fixture class for the integration between the modern RN CDP backend
|
||||
* and a JSI engine, mocking out the rest of RN. For simplicity, everything is
|
||||
* single-threaded and "async" work is actually done through a queued immediate
|
||||
* executor ( = run immediately and finish all queued sub-tasks before
|
||||
* returning).
|
||||
*
|
||||
* The main limitation of the simpler threading model is that we can't cover
|
||||
* breakpoints etc - since pausing during JS execution would prevent the test
|
||||
* from making progress. Such functionality is better suited for a full RN+CDP
|
||||
* integration test (using RN's own thread management) as well as for each
|
||||
* engine's unit tests.
|
||||
*
|
||||
* \tparam EngineAdapter An adapter class that implements RuntimeTargetDelegate
|
||||
* for a particular engine, plus exposes access to a RuntimeExecutor (based on
|
||||
* the provided folly::Executor) and the corresponding jsi::Runtime.
|
||||
*/
|
||||
template <typename EngineAdapter>
|
||||
class JsiIntegrationPortableTest : public Test, private HostTargetDelegate {
|
||||
folly::QueuedImmediateExecutor immediateExecutor_;
|
||||
|
||||
protected:
|
||||
JsiIntegrationPortableTest()
|
||||
: inspectorFlagsGuard_{EngineAdapter::getInspectorFlagOverrides()},
|
||||
engineAdapter_{immediateExecutor_} {
|
||||
instance_ = &page_->registerInstance(instanceTargetDelegate_);
|
||||
runtimeTarget_ = &instance_->registerRuntime(
|
||||
engineAdapter_->getRuntimeTargetDelegate(),
|
||||
engineAdapter_->getRuntimeExecutor());
|
||||
}
|
||||
|
||||
~JsiIntegrationPortableTest() override {
|
||||
toPage_.reset();
|
||||
if (runtimeTarget_) {
|
||||
EXPECT_TRUE(instance_);
|
||||
instance_->unregisterRuntime(*runtimeTarget_);
|
||||
runtimeTarget_ = nullptr;
|
||||
}
|
||||
if (instance_) {
|
||||
page_->unregisterInstance(*instance_);
|
||||
instance_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void connect() {
|
||||
ASSERT_FALSE(toPage_) << "Can only connect once in a JSI integration test.";
|
||||
toPage_ = page_->connect(
|
||||
remoteConnections_.make_unique(),
|
||||
{.integrationName = "JsiIntegrationTest"});
|
||||
|
||||
// We'll always get an onDisconnect call when we tear
|
||||
// down the test. Expect it in order to satisfy the strict mock.
|
||||
EXPECT_CALL(*remoteConnections_[0], onDisconnect());
|
||||
}
|
||||
|
||||
void reload() {
|
||||
if (runtimeTarget_) {
|
||||
ASSERT_TRUE(instance_);
|
||||
instance_->unregisterRuntime(*runtimeTarget_);
|
||||
runtimeTarget_ = nullptr;
|
||||
}
|
||||
if (instance_) {
|
||||
page_->unregisterInstance(*instance_);
|
||||
instance_ = nullptr;
|
||||
}
|
||||
// Recreate the engine (e.g. to wipe any state in the inner jsi::Runtime)
|
||||
engineAdapter_.emplace(immediateExecutor_);
|
||||
instance_ = &page_->registerInstance(instanceTargetDelegate_);
|
||||
runtimeTarget_ = &instance_->registerRuntime(
|
||||
engineAdapter_->getRuntimeTargetDelegate(),
|
||||
engineAdapter_->getRuntimeExecutor());
|
||||
}
|
||||
|
||||
MockRemoteConnection& fromPage() {
|
||||
assert(toPage_);
|
||||
return *remoteConnections_[0];
|
||||
}
|
||||
|
||||
VoidExecutor inspectorExecutor_ = [this](auto callback) {
|
||||
immediateExecutor_.add(callback);
|
||||
};
|
||||
|
||||
jsi::Value eval(std::string_view code) {
|
||||
return engineAdapter_->getRuntime().evaluateJavaScript(
|
||||
std::make_shared<jsi::StringBuffer>(std::string(code)), "<eval>");
|
||||
}
|
||||
|
||||
/**
|
||||
* Expect a message matching the provided gmock \c matcher and return a holder
|
||||
* that will eventually contain the parsed JSON payload.
|
||||
*/
|
||||
template <typename Matcher>
|
||||
std::shared_ptr<const std::optional<folly::dynamic>> expectMessageFromPage(
|
||||
Matcher&& matcher) {
|
||||
std::shared_ptr result =
|
||||
std::make_shared<std::optional<folly::dynamic>>(std::nullopt);
|
||||
EXPECT_CALL(fromPage(), onMessage(matcher))
|
||||
.WillOnce(
|
||||
([result](auto message) { *result = folly::parseJson(message); }))
|
||||
.RetiresOnSaturation();
|
||||
return result;
|
||||
}
|
||||
|
||||
std::shared_ptr<HostTarget> page_ =
|
||||
HostTarget::create(*this, inspectorExecutor_);
|
||||
InstanceTarget* instance_{};
|
||||
RuntimeTarget* runtimeTarget_{};
|
||||
|
||||
InspectorFlagOverridesGuard inspectorFlagsGuard_;
|
||||
MockInstanceTargetDelegate instanceTargetDelegate_;
|
||||
std::optional<EngineAdapter> engineAdapter_;
|
||||
|
||||
private:
|
||||
UniquePtrFactory<StrictMock<MockRemoteConnection>> remoteConnections_;
|
||||
|
||||
protected:
|
||||
// NOTE: Needs to be destroyed before page_.
|
||||
std::unique_ptr<ILocalConnection> toPage_;
|
||||
|
||||
private:
|
||||
// HostTargetDelegate methods
|
||||
|
||||
void onReload(const PageReloadRequest& request) override {
|
||||
(void)request;
|
||||
reload();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Some tests are specific to Hermes's CDP capabilities and some are not.
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* 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 <folly/dynamic.h>
|
||||
#include <folly/executors/QueuedImmediateExecutor.h>
|
||||
#include <folly/json.h>
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <jsinspector-modern/HostTarget.h>
|
||||
#include <jsinspector-modern/InspectorInterfaces.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "FollyDynamicMatchers.h"
|
||||
#include "InspectorMocks.h"
|
||||
#include "UniquePtrFactory.h"
|
||||
#include "utils/InspectorFlagOverridesGuard.h"
|
||||
|
||||
namespace facebook::react::jsinspector_modern {
|
||||
|
||||
/**
|
||||
* A text fixture class for the integration between the modern RN CDP backend
|
||||
* and a JSI engine, mocking out the rest of RN. For simplicity, everything is
|
||||
* single-threaded and "async" work is actually done through a queued immediate
|
||||
* executor ( = run immediately and finish all queued sub-tasks before
|
||||
* returning).
|
||||
*
|
||||
* The main limitation of the simpler threading model is that we can't cover
|
||||
* breakpoints etc - since pausing during JS execution would prevent the test
|
||||
* from making progress. Such functionality is better suited for a full RN+CDP
|
||||
* integration test (using RN's own thread management) as well as for each
|
||||
* engine's unit tests.
|
||||
*
|
||||
* \tparam EngineAdapter An adapter class that implements RuntimeTargetDelegate
|
||||
* for a particular engine, plus exposes access to a RuntimeExecutor (based on
|
||||
* the provided folly::Executor) and the corresponding jsi::Runtime.
|
||||
*/
|
||||
template <typename EngineAdapter>
|
||||
class JsiIntegrationPortableTest : public ::testing::Test,
|
||||
private HostTargetDelegate {
|
||||
folly::QueuedImmediateExecutor immediateExecutor_;
|
||||
|
||||
protected:
|
||||
JsiIntegrationPortableTest()
|
||||
: inspectorFlagsGuard_{EngineAdapter::getInspectorFlagOverrides()},
|
||||
engineAdapter_{immediateExecutor_} {
|
||||
instance_ = &page_->registerInstance(instanceTargetDelegate_);
|
||||
runtimeTarget_ = &instance_->registerRuntime(
|
||||
engineAdapter_->getRuntimeTargetDelegate(),
|
||||
engineAdapter_->getRuntimeExecutor());
|
||||
}
|
||||
|
||||
~JsiIntegrationPortableTest() override {
|
||||
toPage_.reset();
|
||||
if (runtimeTarget_) {
|
||||
EXPECT_TRUE(instance_);
|
||||
instance_->unregisterRuntime(*runtimeTarget_);
|
||||
runtimeTarget_ = nullptr;
|
||||
}
|
||||
if (instance_) {
|
||||
page_->unregisterInstance(*instance_);
|
||||
instance_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void connect() {
|
||||
ASSERT_FALSE(toPage_) << "Can only connect once in a JSI integration test.";
|
||||
toPage_ = page_->connect(
|
||||
remoteConnections_.make_unique(),
|
||||
{.integrationName = "JsiIntegrationTest"});
|
||||
|
||||
// We'll always get an onDisconnect call when we tear
|
||||
// down the test. Expect it in order to satisfy the strict mock.
|
||||
EXPECT_CALL(*remoteConnections_[0], onDisconnect());
|
||||
}
|
||||
|
||||
void reload() {
|
||||
if (runtimeTarget_) {
|
||||
ASSERT_TRUE(instance_);
|
||||
instance_->unregisterRuntime(*runtimeTarget_);
|
||||
runtimeTarget_ = nullptr;
|
||||
}
|
||||
if (instance_) {
|
||||
page_->unregisterInstance(*instance_);
|
||||
instance_ = nullptr;
|
||||
}
|
||||
// Recreate the engine (e.g. to wipe any state in the inner jsi::Runtime)
|
||||
engineAdapter_.emplace(immediateExecutor_);
|
||||
instance_ = &page_->registerInstance(instanceTargetDelegate_);
|
||||
runtimeTarget_ = &instance_->registerRuntime(
|
||||
engineAdapter_->getRuntimeTargetDelegate(),
|
||||
engineAdapter_->getRuntimeExecutor());
|
||||
}
|
||||
|
||||
MockRemoteConnection& fromPage() {
|
||||
assert(toPage_);
|
||||
return *remoteConnections_[0];
|
||||
}
|
||||
|
||||
VoidExecutor inspectorExecutor_ = [this](auto callback) {
|
||||
immediateExecutor_.add(callback);
|
||||
};
|
||||
|
||||
jsi::Value eval(std::string_view code) {
|
||||
return engineAdapter_->getRuntime().evaluateJavaScript(
|
||||
std::make_shared<jsi::StringBuffer>(std::string(code)), "<eval>");
|
||||
}
|
||||
|
||||
/**
|
||||
* Expect a message matching the provided gmock \c matcher and return a holder
|
||||
* that will eventually contain the parsed JSON payload.
|
||||
*/
|
||||
template <typename Matcher>
|
||||
std::shared_ptr<const std::optional<folly::dynamic>> expectMessageFromPage(
|
||||
Matcher&& matcher) {
|
||||
std::shared_ptr result =
|
||||
std::make_shared<std::optional<folly::dynamic>>(std::nullopt);
|
||||
EXPECT_CALL(fromPage(), onMessage(matcher))
|
||||
.WillOnce(
|
||||
([result](auto message) { *result = folly::parseJson(message); }))
|
||||
.RetiresOnSaturation();
|
||||
return result;
|
||||
}
|
||||
|
||||
std::shared_ptr<HostTarget> page_ =
|
||||
HostTarget::create(*this, inspectorExecutor_);
|
||||
InstanceTarget* instance_{};
|
||||
RuntimeTarget* runtimeTarget_{};
|
||||
|
||||
InspectorFlagOverridesGuard inspectorFlagsGuard_;
|
||||
MockInstanceTargetDelegate instanceTargetDelegate_;
|
||||
std::optional<EngineAdapter> engineAdapter_;
|
||||
|
||||
private:
|
||||
UniquePtrFactory<::testing::StrictMock<MockRemoteConnection>>
|
||||
remoteConnections_;
|
||||
|
||||
protected:
|
||||
// NOTE: Needs to be destroyed before page_.
|
||||
std::unique_ptr<ILocalConnection> toPage_;
|
||||
|
||||
private:
|
||||
// HostTargetDelegate methods
|
||||
|
||||
void onReload(const PageReloadRequest& request) override {
|
||||
(void)request;
|
||||
reload();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace facebook::react::jsinspector_modern
|
||||
Reference in New Issue
Block a user