mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Add basic tests for JsErrorHandler (#35781)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/35781 Changelog: [Internal] Adds basic unit tests for `JsErrorHandler`. The tests contain TODO comments where incorrect behaviour is exposed. Reviewed By: RSNara Differential Revision: D42369492 fbshipit-source-id: 3d984ac90dae295e4b85f3512bff362b121ec97e
This commit is contained in:
committed by
Facebook GitHub Bot
parent
5009ad33a6
commit
68c0b063ed
@@ -1,4 +1,4 @@
|
||||
load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", "CXX", "react_native_xplat_target", "rn_xplat_cxx_library")
|
||||
load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", "CXX", "fb_xplat_cxx_test", "react_native_xplat_target", "rn_xplat_cxx_library")
|
||||
|
||||
# TODO: Expolre merging this module into venice so we don't to load this library seperately
|
||||
rn_xplat_cxx_library(
|
||||
@@ -18,6 +18,7 @@ rn_xplat_cxx_library(
|
||||
"-DLOG_TAG=\"ReactNative\"",
|
||||
"-DWITH_FBSYSTRACE=1",
|
||||
],
|
||||
tests = [":tests"],
|
||||
visibility = [
|
||||
"PUBLIC",
|
||||
],
|
||||
@@ -28,3 +29,23 @@ rn_xplat_cxx_library(
|
||||
react_native_xplat_target("react/renderer/mapbuffer:mapbuffer"),
|
||||
],
|
||||
)
|
||||
|
||||
fb_xplat_cxx_test(
|
||||
name = "tests",
|
||||
srcs = glob(["tests/**/*.cpp"]),
|
||||
headers = glob(["tests/**/*.h"]),
|
||||
compiler_flags = [
|
||||
"-fexceptions",
|
||||
"-frtti",
|
||||
"-std=c++17",
|
||||
"-Wall",
|
||||
],
|
||||
contacts = ["oncall+react_native@xmail.facebook.com"],
|
||||
platforms = (ANDROID, APPLE, CXX),
|
||||
deps = [
|
||||
"//xplat/hermes/API:HermesAPI",
|
||||
"//xplat/third-party/gmock:gtest",
|
||||
react_native_xplat_target("jserrorhandler:jserrorhandler"),
|
||||
react_native_xplat_target("react/renderer/mapbuffer:mapbuffer"),
|
||||
],
|
||||
)
|
||||
|
||||
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
* 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 <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <hermes/API/hermes/hermes.h>
|
||||
#include <jserrorhandler/JsErrorHandler.h>
|
||||
#include <jsi/jsi.h>
|
||||
#include <react/renderer/mapbuffer/MapBuffer.h>
|
||||
#include <react/renderer/mapbuffer/MapBufferBuilder.h>
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
class JsErrorHandlerTest : public testing::Test {
|
||||
void SetUp() override {
|
||||
runtime_ = facebook::hermes::makeHermesRuntime();
|
||||
}
|
||||
|
||||
protected:
|
||||
MapBuffer parseErrorWithStackString(std::string stack, bool isFatal) {
|
||||
std::optional<MapBuffer> result;
|
||||
JsErrorHandler handler{
|
||||
[&](MapBuffer errorMap) -> void { result = std::move(errorMap); }};
|
||||
jsi::JSError error{*runtime_, "test message", stack};
|
||||
handler.handleJsError(error, isFatal);
|
||||
EXPECT_TRUE(result.has_value());
|
||||
return std::move(*result);
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<facebook::hermes::HermesRuntime> runtime_;
|
||||
};
|
||||
|
||||
TEST_F(JsErrorHandlerTest, testSimpleJscSourceStack) {
|
||||
auto errorMap = parseErrorWithStackString(
|
||||
"http://path/to/file.js:47:22\n"
|
||||
"foo@http://path/to/file.js:52:15\n"
|
||||
"bar@http://path/to/file.js:108:23",
|
||||
/* isFatal */ false);
|
||||
|
||||
EXPECT_FALSE(errorMap.getBool(JSErrorHandlerKey::kIsFatal));
|
||||
|
||||
auto frames = errorMap.getMapBufferList(JSErrorHandlerKey::kAllStackFrames);
|
||||
EXPECT_EQ(frames.size(), 3);
|
||||
|
||||
EXPECT_EQ(
|
||||
frames[0].getString(JSErrorHandlerKey::kFrameFileName),
|
||||
"http://path/to/file.js");
|
||||
EXPECT_EQ(frames[0].getInt(JSErrorHandlerKey::kFrameLineNumber), 47);
|
||||
// TODO: This is the wrong column number. JSC's columns are 1-based while ours
|
||||
// are 0-based.
|
||||
EXPECT_EQ(frames[0].getInt(JSErrorHandlerKey::kFrameColumnNumber), 22);
|
||||
EXPECT_EQ(frames[0].getString(JSErrorHandlerKey::kFrameMethodName), "");
|
||||
|
||||
EXPECT_EQ(
|
||||
frames[1].getString(JSErrorHandlerKey::kFrameFileName),
|
||||
"http://path/to/file.js");
|
||||
EXPECT_EQ(frames[1].getInt(JSErrorHandlerKey::kFrameLineNumber), 52);
|
||||
// TODO: This is the wrong column number. JSC's columns are 1-based while ours
|
||||
// are 0-based.
|
||||
EXPECT_EQ(frames[1].getInt(JSErrorHandlerKey::kFrameColumnNumber), 15);
|
||||
EXPECT_EQ(frames[1].getString(JSErrorHandlerKey::kFrameMethodName), "foo");
|
||||
|
||||
EXPECT_EQ(
|
||||
frames[2].getString(JSErrorHandlerKey::kFrameFileName),
|
||||
"http://path/to/file.js");
|
||||
EXPECT_EQ(frames[2].getInt(JSErrorHandlerKey::kFrameLineNumber), 108);
|
||||
// TODO: This is the wrong column number. JSC's columns are 1-based while ours
|
||||
// are 0-based.
|
||||
EXPECT_EQ(frames[2].getInt(JSErrorHandlerKey::kFrameColumnNumber), 23);
|
||||
EXPECT_EQ(frames[2].getString(JSErrorHandlerKey::kFrameMethodName), "bar");
|
||||
}
|
||||
|
||||
TEST_F(JsErrorHandlerTest, testSimpleHermesBytecodeStack) {
|
||||
auto errorMap = parseErrorWithStackString(
|
||||
" at global (address at unknown:1:9)\n"
|
||||
" at foo$bar (address at /js/foo.hbc:10:1234)",
|
||||
/* isFatal */ false);
|
||||
|
||||
EXPECT_FALSE(errorMap.getBool(JSErrorHandlerKey::kIsFatal));
|
||||
|
||||
auto frames = errorMap.getMapBufferList(JSErrorHandlerKey::kAllStackFrames);
|
||||
EXPECT_EQ(frames.size(), 2);
|
||||
|
||||
// TODO: This is the wrong source URL.
|
||||
EXPECT_EQ(
|
||||
frames[0].getString(JSErrorHandlerKey::kFrameFileName),
|
||||
"address at unknown");
|
||||
EXPECT_EQ(frames[0].getInt(JSErrorHandlerKey::kFrameLineNumber), 1);
|
||||
EXPECT_EQ(frames[0].getInt(JSErrorHandlerKey::kFrameColumnNumber), 9);
|
||||
EXPECT_EQ(frames[0].getString(JSErrorHandlerKey::kFrameMethodName), "global");
|
||||
|
||||
// TODO: This is the wrong source URL.
|
||||
EXPECT_EQ(
|
||||
frames[1].getString(JSErrorHandlerKey::kFrameFileName),
|
||||
"address at /js/foo.hbc");
|
||||
EXPECT_EQ(frames[1].getInt(JSErrorHandlerKey::kFrameLineNumber), 10);
|
||||
EXPECT_EQ(frames[1].getInt(JSErrorHandlerKey::kFrameColumnNumber), 1234);
|
||||
EXPECT_EQ(
|
||||
frames[1].getString(JSErrorHandlerKey::kFrameMethodName), "foo$bar");
|
||||
}
|
||||
|
||||
TEST_F(JsErrorHandlerTest, testSimpleHermesSourceStack) {
|
||||
auto errorMap = parseErrorWithStackString(
|
||||
" at global (unknown:1:9)\n"
|
||||
" at foo$bar (/js/foo.js:10:1234)",
|
||||
/* isFatal */ false);
|
||||
|
||||
EXPECT_FALSE(errorMap.getBool(JSErrorHandlerKey::kIsFatal));
|
||||
|
||||
auto frames = errorMap.getMapBufferList(JSErrorHandlerKey::kAllStackFrames);
|
||||
EXPECT_EQ(frames.size(), 2);
|
||||
|
||||
EXPECT_EQ(frames[0].getString(JSErrorHandlerKey::kFrameFileName), "unknown");
|
||||
EXPECT_EQ(frames[0].getInt(JSErrorHandlerKey::kFrameLineNumber), 1);
|
||||
// TODO: This is the wrong column number. Hermes's columns are 1-based (for
|
||||
// non-bytecode locations) while ours are 0-based.
|
||||
EXPECT_EQ(frames[0].getInt(JSErrorHandlerKey::kFrameColumnNumber), 9);
|
||||
EXPECT_EQ(frames[0].getString(JSErrorHandlerKey::kFrameMethodName), "global");
|
||||
|
||||
EXPECT_EQ(
|
||||
frames[1].getString(JSErrorHandlerKey::kFrameFileName), "/js/foo.js");
|
||||
EXPECT_EQ(frames[1].getInt(JSErrorHandlerKey::kFrameLineNumber), 10);
|
||||
// TODO: This is the wrong column number. Hermes's columns are 1-based (for
|
||||
// non-bytecode locations) while ours are 0-based.
|
||||
EXPECT_EQ(frames[1].getInt(JSErrorHandlerKey::kFrameColumnNumber), 1234);
|
||||
EXPECT_EQ(
|
||||
frames[1].getString(JSErrorHandlerKey::kFrameMethodName), "foo$bar");
|
||||
}
|
||||
|
||||
TEST_F(JsErrorHandlerTest, testHermesSourceStackWithSkippedFrames) {
|
||||
auto errorMap = parseErrorWithStackString(
|
||||
" at global (unknown:1:9)\n"
|
||||
" ... skipping 50 frames\n"
|
||||
" at foo$bar (/js/foo.js:10:1234)",
|
||||
/* isFatal */ false);
|
||||
|
||||
EXPECT_FALSE(errorMap.getBool(JSErrorHandlerKey::kIsFatal));
|
||||
|
||||
auto frames = errorMap.getMapBufferList(JSErrorHandlerKey::kAllStackFrames);
|
||||
EXPECT_EQ(frames.size(), 2);
|
||||
|
||||
EXPECT_EQ(frames[0].getString(JSErrorHandlerKey::kFrameFileName), "unknown");
|
||||
EXPECT_EQ(frames[0].getInt(JSErrorHandlerKey::kFrameLineNumber), 1);
|
||||
// TODO: This is the wrong column number. Hermes's columns are 1-based (for
|
||||
// non-bytecode locations) while ours are 0-based.
|
||||
EXPECT_EQ(frames[0].getInt(JSErrorHandlerKey::kFrameColumnNumber), 9);
|
||||
EXPECT_EQ(frames[0].getString(JSErrorHandlerKey::kFrameMethodName), "global");
|
||||
|
||||
EXPECT_EQ(
|
||||
frames[1].getString(JSErrorHandlerKey::kFrameFileName), "/js/foo.js");
|
||||
EXPECT_EQ(frames[1].getInt(JSErrorHandlerKey::kFrameLineNumber), 10);
|
||||
// TODO: This is the wrong column number. Hermes's columns are 1-based (for
|
||||
// non-bytecode locations) while ours are 0-based.
|
||||
EXPECT_EQ(frames[1].getInt(JSErrorHandlerKey::kFrameColumnNumber), 1234);
|
||||
EXPECT_EQ(
|
||||
frames[1].getString(JSErrorHandlerKey::kFrameMethodName), "foo$bar");
|
||||
}
|
||||
|
||||
TEST_F(JsErrorHandlerTest, testHermesSourceStackWithNativeFrame) {
|
||||
auto errorMap = parseErrorWithStackString(
|
||||
" at global (unknown:1:9)\n"
|
||||
" at apply (native)\n"
|
||||
" at foo$bar (/js/foo.js:10:1234)",
|
||||
/* isFatal */ false);
|
||||
|
||||
EXPECT_FALSE(errorMap.getBool(JSErrorHandlerKey::kIsFatal));
|
||||
|
||||
auto frames = errorMap.getMapBufferList(JSErrorHandlerKey::kAllStackFrames);
|
||||
EXPECT_EQ(frames.size(), 2);
|
||||
|
||||
EXPECT_EQ(frames[0].getString(JSErrorHandlerKey::kFrameFileName), "unknown");
|
||||
EXPECT_EQ(frames[0].getInt(JSErrorHandlerKey::kFrameLineNumber), 1);
|
||||
// TODO: This is the wrong column number. Hermes's columns are 1-based (for
|
||||
// non-bytecode locations) while ours are 0-based.
|
||||
EXPECT_EQ(frames[0].getInt(JSErrorHandlerKey::kFrameColumnNumber), 9);
|
||||
EXPECT_EQ(frames[0].getString(JSErrorHandlerKey::kFrameMethodName), "global");
|
||||
|
||||
EXPECT_EQ(
|
||||
frames[1].getString(JSErrorHandlerKey::kFrameFileName), "/js/foo.js");
|
||||
EXPECT_EQ(frames[1].getInt(JSErrorHandlerKey::kFrameLineNumber), 10);
|
||||
// TODO: This is the wrong column number. Hermes's columns are 1-based (for
|
||||
// non-bytecode locations) while ours are 0-based.
|
||||
EXPECT_EQ(frames[1].getInt(JSErrorHandlerKey::kFrameColumnNumber), 1234);
|
||||
EXPECT_EQ(
|
||||
frames[1].getString(JSErrorHandlerKey::kFrameMethodName), "foo$bar");
|
||||
}
|
||||
|
||||
TEST_F(JsErrorHandlerTest, testJsxSourceStackWithEval) {
|
||||
auto errorMap = parseErrorWithStackString(
|
||||
"eval code\n"
|
||||
"eval@[native code]\n"
|
||||
"foo@http://path/to/file.js:58:21\n"
|
||||
"bar@http://path/to/file.js:109:91",
|
||||
/* isFatal */ false);
|
||||
|
||||
EXPECT_FALSE(errorMap.getBool(JSErrorHandlerKey::kIsFatal));
|
||||
|
||||
auto frames = errorMap.getMapBufferList(JSErrorHandlerKey::kAllStackFrames);
|
||||
EXPECT_EQ(frames.size(), 2);
|
||||
|
||||
EXPECT_EQ(
|
||||
frames[0].getString(JSErrorHandlerKey::kFrameFileName),
|
||||
"http://path/to/file.js");
|
||||
EXPECT_EQ(frames[0].getInt(JSErrorHandlerKey::kFrameLineNumber), 58);
|
||||
// TODO: This is the wrong column number. JSC's columns are 1-based while ours
|
||||
// are 0-based.
|
||||
EXPECT_EQ(frames[0].getInt(JSErrorHandlerKey::kFrameColumnNumber), 21);
|
||||
EXPECT_EQ(frames[0].getString(JSErrorHandlerKey::kFrameMethodName), "foo");
|
||||
|
||||
EXPECT_EQ(
|
||||
frames[1].getString(JSErrorHandlerKey::kFrameFileName),
|
||||
"http://path/to/file.js");
|
||||
EXPECT_EQ(frames[1].getInt(JSErrorHandlerKey::kFrameLineNumber), 109);
|
||||
// TODO: This is the wrong column number. JSC's columns are 1-based while ours
|
||||
// are 0-based.
|
||||
EXPECT_EQ(frames[1].getInt(JSErrorHandlerKey::kFrameColumnNumber), 91);
|
||||
EXPECT_EQ(frames[1].getString(JSErrorHandlerKey::kFrameMethodName), "bar");
|
||||
}
|
||||
} // namespace facebook::react
|
||||
Reference in New Issue
Block a user