Skip to content

Commit

Permalink
feat(native): Set current screen on native scope (#3927)
Browse files Browse the repository at this point in the history
  • Loading branch information
krystofwoldrich authored Jul 3, 2024
1 parent 5290b95 commit 8a28af8
Show file tree
Hide file tree
Showing 11 changed files with 271 additions and 89 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
### Features

- Improve touch event component info if annotated with [`@sentry/babel-plugin-component-annotate`](https://www.npmjs.com/package/@sentry/babel-plugin-component-annotate) ([#3899](https://github.com/getsentry/sentry-react-native/pull/3899))
- Set `currentScreen` on native scope ([#3927](https://github.com/getsentry/sentry-react-native/pull/3927))

### Fixes

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package io.sentry.rnsentryandroidtester

import com.facebook.react.bridge.JavaOnlyMap
import io.sentry.react.RNSentryBreadcrumb
import junit.framework.TestCase.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4

@RunWith(JUnit4::class)
class RNSentryBreadcrumbTest {

@Test
fun nullForMissingCategory() {
val map = JavaOnlyMap.of()
val actual = RNSentryBreadcrumb.getCurrentScreenFrom(map)
assertEquals(null, actual)
}


@Test
fun nullForNonNavigationCategory() {
val map = JavaOnlyMap.of(
"category", "unknown"
)
val actual = RNSentryBreadcrumb.getCurrentScreenFrom(map)
assertEquals(null, actual)
}


@Test
fun nullForMissingData() {
val map = JavaOnlyMap.of(
"category", "navigation"
)
val actual = RNSentryBreadcrumb.getCurrentScreenFrom(map)
assertEquals(null, actual)
}


@Test
fun nullForNonStringDataToKey() {
val map = JavaOnlyMap.of(
"category", "unknown",
"data", mapOf(
"to" to 123,
),
)
val actual = RNSentryBreadcrumb.getCurrentScreenFrom(map)
assertEquals(null, actual)
}

@Test
fun screenNameForValidNavigationBreadcrumb() {
val map = JavaOnlyMap.of(
"category", "navigation",
"data", JavaOnlyMap.of(
"to", "newScreen",
),
)
val actual = RNSentryBreadcrumb.getCurrentScreenFrom(map)
assert(actual is String)
assertEquals("newScreen", actual)
}

}
18 changes: 14 additions & 4 deletions RNSentryCocoaTester/RNSentryCocoaTester.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
330F308C2C0F3840002A0D4E /* RNSentryBreadcrumbTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 330F308B2C0F3840002A0D4E /* RNSentryBreadcrumbTests.m */; };
3360843D2C340C76008CC412 /* RNSentryBreadcrumbTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3360843C2C340C76008CC412 /* RNSentryBreadcrumbTests.swift */; };
33958C692BFCF12600AD1FB6 /* RNSentryOnDrawReporterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 33958C682BFCF12600AD1FB6 /* RNSentryOnDrawReporterTests.m */; };
33AFDFED2B8D14B300AAB120 /* RNSentryFramesTrackerListenerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 33AFDFEC2B8D14B300AAB120 /* RNSentryFramesTrackerListenerTests.m */; };
33AFDFF12B8D15E500AAB120 /* RNSentryDependencyContainerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 33AFDFF02B8D15E500AAB120 /* RNSentryDependencyContainerTests.m */; };
Expand All @@ -17,8 +17,9 @@

/* Begin PBXFileReference section */
1482D5685A340AB93348A43D /* Pods-RNSentryCocoaTesterTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RNSentryCocoaTesterTests.release.xcconfig"; path = "Target Support Files/Pods-RNSentryCocoaTesterTests/Pods-RNSentryCocoaTesterTests.release.xcconfig"; sourceTree = "<group>"; };
330F308B2C0F3840002A0D4E /* RNSentryBreadcrumbTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNSentryBreadcrumbTests.m; sourceTree = "<group>"; };
330F308D2C0F385A002A0D4E /* RNSentryBreadcrumb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSentryBreadcrumb.h; path = ../ios/RNSentryBreadcrumb.h; sourceTree = "<group>"; };
3360843B2C340C75008CC412 /* RNSentryCocoaTesterTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RNSentryCocoaTesterTests-Bridging-Header.h"; sourceTree = "<group>"; };
3360843C2C340C76008CC412 /* RNSentryBreadcrumbTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNSentryBreadcrumbTests.swift; sourceTree = "<group>"; };
3360898D29524164007C7730 /* RNSentryCocoaTesterTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RNSentryCocoaTesterTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
338739072A7D7D2800950DDD /* RNSentryTests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNSentryTests.h; sourceTree = "<group>"; };
33958C672BFCEF5A00AD1FB6 /* RNSentryOnDrawReporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSentryOnDrawReporter.h; path = ../ios/RNSentryOnDrawReporter.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -83,7 +84,8 @@
33AFDFF02B8D15E500AAB120 /* RNSentryDependencyContainerTests.m */,
33AFDFF22B8D15F600AAB120 /* RNSentryDependencyContainerTests.h */,
33958C682BFCF12600AD1FB6 /* RNSentryOnDrawReporterTests.m */,
330F308B2C0F3840002A0D4E /* RNSentryBreadcrumbTests.m */,
3360843C2C340C76008CC412 /* RNSentryBreadcrumbTests.swift */,
3360843B2C340C75008CC412 /* RNSentryCocoaTesterTests-Bridging-Header.h */,
);
path = RNSentryCocoaTesterTests;
sourceTree = "<group>";
Expand Down Expand Up @@ -138,6 +140,7 @@
TargetAttributes = {
3360898C29524164007C7730 = {
CreatedOnToolsVersion = 14.2;
LastSwiftMigration = 1540;
};
};
};
Expand Down Expand Up @@ -209,7 +212,7 @@
33AFDFF12B8D15E500AAB120 /* RNSentryDependencyContainerTests.m in Sources */,
33F58AD02977037D008F60EA /* RNSentryTests.mm in Sources */,
33958C692BFCF12600AD1FB6 /* RNSentryOnDrawReporterTests.m in Sources */,
330F308C2C0F3840002A0D4E /* RNSentryBreadcrumbTests.m in Sources */,
3360843D2C340C76008CC412 /* RNSentryBreadcrumbTests.swift in Sources */,
33AFDFED2B8D14B300AAB120 /* RNSentryFramesTrackerListenerTests.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -333,6 +336,7 @@
isa = XCBuildConfiguration;
baseConfigurationReference = E2321E7CFA55AB617247098E /* Pods-RNSentryCocoaTesterTests.debug.xcconfig */;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
Expand Down Expand Up @@ -387,6 +391,9 @@
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_EMIT_LOC_STRINGS = NO;
SWIFT_OBJC_BRIDGING_HEADER = "RNSentryCocoaTesterTests/RNSentryCocoaTesterTests-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
};
name = Debug;
Expand All @@ -395,6 +402,7 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 1482D5685A340AB93348A43D /* Pods-RNSentryCocoaTesterTests.release.xcconfig */;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
Expand Down Expand Up @@ -449,6 +457,8 @@
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_EMIT_LOC_STRINGS = NO;
SWIFT_OBJC_BRIDGING_HEADER = "RNSentryCocoaTesterTests/RNSentryCocoaTesterTests-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
};
name = Release;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import XCTest
import Sentry

class RNSentryBreadcrumbTests: XCTestCase {

func testGeneratesSentryBreadcrumbFromNSDictionary() {
let actualCrumb = RNSentryBreadcrumb.from([
"level": "error",
"category": "testCategory",
"type": "testType",
"message": "testMessage",
"data": [
"test": "data"
]
])

XCTAssertEqual(actualCrumb!.level, SentryLevel.error)
XCTAssertEqual(actualCrumb!.category, "testCategory")
XCTAssertEqual(actualCrumb!.type, "testType")
XCTAssertEqual(actualCrumb!.message, "testMessage")
XCTAssertEqual((actualCrumb!.data)!["test"] as! String, "data")
}

func testUsesInfoAsDefaultSentryLevel() {
let actualCrumb = RNSentryBreadcrumb.from([
"message": "testMessage"
])

XCTAssertEqual(actualCrumb!.level, SentryLevel.info)
}

func testNullForMissingCategory() {
let map: [String: Any] = [:]
let actual = RNSentryBreadcrumb.getCurrentScreen(from: map)
XCTAssertNil(actual)
}

func testNullForNonNavigationCategory() {
let map: [String: Any] = ["category": "unknown"]
let actual = RNSentryBreadcrumb.getCurrentScreen(from: map)
XCTAssertNil(actual)
}

func testNullForMissingData() {
let map: [String: Any] = ["category": "navigation"]
let actual = RNSentryBreadcrumb.getCurrentScreen(from: map)
XCTAssertNil(actual)
}

func testNullForNonStringDataToKey() {
let map: [String: Any] = [
"category": "unknown",
"data": ["to": 123]
]
let actual = RNSentryBreadcrumb.getCurrentScreen(from: map)
XCTAssertNil(actual)
}

func testScreenNameForValidNavigationBreadcrumb() {
let map: [String: Any] = [
"category": "navigation",
"data": ["to": "newScreen"]
]
let actual = RNSentryBreadcrumb.getCurrentScreen(from: map)
XCTAssertEqual(actual, "newScreen")
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#import "RNSentryBreadcrumb.h"
87 changes: 87 additions & 0 deletions android/src/main/java/io/sentry/react/RNSentryBreadcrumb.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package io.sentry.react;

import com.facebook.react.bridge.ReadableMap;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Map;

import io.sentry.Breadcrumb;
import io.sentry.SentryLevel;

public class RNSentryBreadcrumb {

@Nullable
public static String getCurrentScreenFrom(ReadableMap from) {
final @Nullable String maybeCategory = from.hasKey("category") ? from.getString("category") : null;
if (maybeCategory == null || !maybeCategory.equals("navigation")) {
return null;
}

final @Nullable ReadableMap maybeData = from.hasKey("data") ? from.getMap("data") : null;
if (maybeData == null) {
return null;
}

try {
// getString might throw if cast to string fails (data.to is not enforced by TS to be a string)
return maybeData.hasKey("to") ? maybeData.getString("to") : null;
} catch (Throwable exception) {
return null;
}
}

@NotNull
public static Breadcrumb fromMap(ReadableMap from) {
final @NotNull Breadcrumb breadcrumb = new Breadcrumb();

if (from.hasKey("message")) {
breadcrumb.setMessage(from.getString("message"));
}

if (from.hasKey("type")) {
breadcrumb.setType(from.getString("type"));
}

if (from.hasKey("category")) {
breadcrumb.setCategory(from.getString("category"));
}

if (from.hasKey("level")) {
switch (from.getString("level")) {
case "fatal":
breadcrumb.setLevel(SentryLevel.FATAL);
break;
case "warning":
breadcrumb.setLevel(SentryLevel.WARNING);
break;
case "debug":
breadcrumb.setLevel(SentryLevel.DEBUG);
break;
case "error":
breadcrumb.setLevel(SentryLevel.ERROR);
break;
case "info":
default:
breadcrumb.setLevel(SentryLevel.INFO);
break;
}
}


if (from.hasKey("data")) {
final ReadableMap data = from.getMap("data");
for (final Map.Entry<String, Object> entry : data.toHashMap().entrySet()) {
final Object value = entry.getValue();
// data is ConcurrentHashMap and can't have null values
if (value != null) {
breadcrumb.setData(entry.getKey(), entry.getValue());
}
}
}

return breadcrumb;
}

}
Loading

0 comments on commit 8a28af8

Please sign in to comment.