Skip to content

Commit

Permalink
Move integration tests to OSS
Browse files Browse the repository at this point in the history
Summary:
Merge the internal `cxxcdp-tester` project into `jsinspector-modern/tests`.

Note: These tests still use RN default feature flags and therefore test against the legacy CDP registry - that's addressed in the next diff.

Changelog: [Internal]

Differential Revision: D53766994
  • Loading branch information
robhogan authored and facebook-github-bot committed Feb 19, 2024
1 parent 3a1e769 commit 52d3290
Show file tree
Hide file tree
Showing 7 changed files with 1,036 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* 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 "FollyDynamicMatchers.h"
#include "ReactInstanceIntegrationTest.h"

#include <glog/logging.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include <jsinspector-modern/InspectorInterfaces.h>

namespace facebook::react::jsinspector_modern {

using namespace testing;

TEST_F(ReactInstanceIntegrationTest, ConsoleLogTest) {
InSequence s;

EXPECT_CALL(getRemoteConnection(), onMessage(_))
.Times(2)
.RetiresOnSaturation();

EXPECT_CALL(
getRemoteConnection(),
onMessage(JsonParsed(AllOf(
AtJsonPtr("/params/args/0/value", Eq("Hello, World!")),
AtJsonPtr("/method", Eq("Runtime.consoleAPICalled"))))));

EXPECT_CALL(getRemoteConnection(), onDisconnect());

send("Runtime.enable");
run("console.log('Hello, World!');");
}

} // namespace facebook::react::jsinspector_modern
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
* 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 "ReactInstanceIntegrationTest.h"
#include "UniquePtrFactory.h"
#include "prelude.js.h"

#include <folly/json.h>
#include <glog/logging.h>
#include <react/runtime/hermes/HermesInstance.h>

namespace facebook::react::jsinspector_modern {

ReactInstanceIntegrationTest::ReactInstanceIntegrationTest()
: runtime(nullptr),
instance(nullptr),
messageQueueThread(std::make_shared<MockMessageQueueThread>()),
errorHandler(std::make_shared<ErrorUtils>()) {}

void ReactInstanceIntegrationTest::SetUp() {
auto mockRegistry = std::make_unique<MockTimerRegistry>();
auto timerManager =
std::make_shared<react::TimerManager>(std::move(mockRegistry));

auto jsErrorHandlingFunc = [](react::MapBuffer error) noexcept {
LOG(INFO) << "Error: \nFile: " << error.getString(react::kFrameFileName)
<< "\nLine: " << error.getInt(react::kFrameLineNumber)
<< "\nColumn: " << error.getInt(react::kFrameColumnNumber)
<< "\nMethod: " << error.getString(react::kFrameMethodName);
};

auto jsRuntimeFactory = std::make_unique<react::HermesInstance>();
std::unique_ptr<react::JSRuntime> runtime_ =
jsRuntimeFactory->createJSRuntime(nullptr, nullptr, messageQueueThread);
jsi::Runtime* jsiRuntime = &runtime_->getRuntime();

// Error handler:
jsiRuntime->global().setProperty(
*jsiRuntime,
"ErrorUtils",
jsi::Object::createFromHostObject(*jsiRuntime, errorHandler));

instance = std::make_unique<react::ReactInstance>(
std::move(runtime_),
messageQueueThread,
timerManager,
std::move(jsErrorHandlingFunc));
timerManager->setRuntimeExecutor(instance->getBufferedRuntimeExecutor());

// JS Environment:
initializeRuntime(preludeJsCode);

// Inspector:
auto& inspector = getInspectorInstance();
auto pages = inspector.getPages();

// We should now have at least a single page once the above runtime has been
// initialized.
assert(pages.size() > 0);
size_t pageId = pages.back().id;

clientToVM_ = inspector.connect(pageId, mockRemoteConnections_.make_unique());
}

void ReactInstanceIntegrationTest::TearDown() {
clientToVM_->disconnect();
}

void ReactInstanceIntegrationTest::initializeRuntime(std::string_view script) {
react::ReactInstance::JSRuntimeFlags flags{
.isProfiling = false,
};
instance->initializeRuntime(flags, [](jsi::Runtime&) {});

messageQueueThread->tick();

std::string init(script);
// JS calls no longer buffered after calling loadScript
instance->loadScript(std::make_unique<react::JSBigStdString>(init), "");

messageQueueThread->flush();
}

void ReactInstanceIntegrationTest::send(
const std::string& method,
const folly::dynamic& params) {
folly::dynamic request = folly::dynamic::object();

request["method"] = method;
request["id"] = id_++;
request["params"] = params;

sendJSONString(folly::toJson(request));
}

void ReactInstanceIntegrationTest::sendJSONString(const std::string& message) {
// The runtime must be initialized and connected to before messaging
clientToVM_->sendMessage(message);
}

jsi::Value ReactInstanceIntegrationTest::run(const std::string& script) {
auto runtimeExecutor = instance->getUnbufferedRuntimeExecutor();
auto ret = jsi::Value::undefined();

runtimeExecutor([script, &ret](jsi::Runtime& rt) {
ret = rt.evaluateJavaScript(
std::make_unique<jsi::StringBuffer>(script), "<test>");
});

messageQueueThread->flush();

while (verbose_ && errorHandler->size() > 0) {
LOG(INFO) << "Error: " << errorHandler->getLastError().getMessage();
}

return ret;
}

bool ReactInstanceIntegrationTest::verbose(bool isVerbose) {
const bool previous = verbose_;
verbose_ = isVerbose;
return previous;
}

} // namespace facebook::react::jsinspector_modern
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* 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/json.h>
#include <gtest/gtest.h>
#include <jsinspector-modern/InspectorInterfaces.h>
#include <memory>

#include "InspectorMocks.h"
#include "UniquePtrFactory.h"
#include "stubs.h"

namespace facebook::react::jsinspector_modern {

class ReactInstanceIntegrationTest : public ::testing::Test {
protected:
ReactInstanceIntegrationTest();
void SetUp() override;
void TearDown() override;

jsi::Value run(const std::string& script);
bool verbose(bool isVerbose);

void send(
const std::string& method,
const folly::dynamic& params = folly::dynamic::object());
void sendJSONString(const std::string& message);

jsi::Runtime* runtime;
std::unique_ptr<react::ReactInstance> instance;
std::shared_ptr<MockMessageQueueThread> messageQueueThread;
std::shared_ptr<ErrorUtils> errorHandler;

MockRemoteConnection& getRemoteConnection() {
return *mockRemoteConnections_[0];
}

private:
void initializeRuntime(std::string_view script);

size_t id_ = 1;
bool verbose_ = false;
UniquePtrFactory<MockRemoteConnection> mockRemoteConnections_;
std::unique_ptr<ILocalConnection> clientToVM_;
};

} // namespace facebook::react::jsinspector_modern
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* 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 "ReactInstanceIntegrationTest.h"

#include <glog/logging.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include <jsinspector-modern/InspectorInterfaces.h>

namespace facebook::react::jsinspector_modern {

using testing::StrEq;

TEST_F(ReactInstanceIntegrationTest, RuntimeEvalTest) {
auto val = run("1 + 2");
EXPECT_EQ(val.asNumber(), 3);
}

} // namespace facebook::react::jsinspector_modern
Loading

0 comments on commit 52d3290

Please sign in to comment.