From a35c499d878548b4cef28cfb0e122c418cc5c2b0 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Thu, 4 Jul 2024 17:58:51 +0200 Subject: [PATCH 1/2] fix(replay): Add app lifecycle breadcrumbs conversion tests --- .../RNSentryReplayBreadcrumbConverterTest.kt | 25 +++++++++++++++++ ...SentryReplayBreadcrumbConverterTests.swift | 28 +++++++++++++++++++ .../RNSentryReplayBreadcrumbConverter.java | 8 +++--- ios/RNSentryReplayBreadcrumbConverter.m | 12 +++----- 4 files changed, 61 insertions(+), 12 deletions(-) diff --git a/RNSentryAndroidTester/app/src/test/java/io/sentry/rnsentryandroidtester/RNSentryReplayBreadcrumbConverterTest.kt b/RNSentryAndroidTester/app/src/test/java/io/sentry/rnsentryandroidtester/RNSentryReplayBreadcrumbConverterTest.kt index c6c9b69548..2226254dd6 100644 --- a/RNSentryAndroidTester/app/src/test/java/io/sentry/rnsentryandroidtester/RNSentryReplayBreadcrumbConverterTest.kt +++ b/RNSentryAndroidTester/app/src/test/java/io/sentry/rnsentryandroidtester/RNSentryReplayBreadcrumbConverterTest.kt @@ -2,6 +2,7 @@ package io.sentry.rnsentryandroidtester import io.sentry.Breadcrumb import io.sentry.react.RNSentryReplayBreadcrumbConverter +import io.sentry.rrweb.RRWebBreadcrumbEvent import org.junit.Assert.assertEquals import org.junit.Test import org.junit.runner.RunWith @@ -10,6 +11,30 @@ import org.junit.runners.JUnit4 @RunWith(JUnit4::class) class RNSentryReplayBreadcrumbConverterTest { + @Test + fun testConvertForegroundBreadcrumb() { + val converter = RNSentryReplayBreadcrumbConverter() + val testBreadcrumb = Breadcrumb() + testBreadcrumb.type = "navigation" + testBreadcrumb.category = "app.lifecycle" + testBreadcrumb.setData("state", "foreground"); + val actual = converter.convert(testBreadcrumb) as RRWebBreadcrumbEvent + + assertEquals("app.foreground", actual.category) + } + + @Test + fun testConvertBackgroundBreadcrumb() { + val converter = RNSentryReplayBreadcrumbConverter() + val testBreadcrumb = Breadcrumb() + testBreadcrumb.type = "navigation" + testBreadcrumb.category = "app.lifecycle" + testBreadcrumb.setData("state", "background"); + val actual = converter.convert(testBreadcrumb) as RRWebBreadcrumbEvent + + assertEquals("app.background", actual.category) + } + @Test fun doesNotConvertSentryEventBreadcrumb() { val converter = RNSentryReplayBreadcrumbConverter() diff --git a/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryReplayBreadcrumbConverterTests.swift b/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryReplayBreadcrumbConverterTests.swift index 7654f3ad75..95dddaa3af 100644 --- a/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryReplayBreadcrumbConverterTests.swift +++ b/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryReplayBreadcrumbConverterTests.swift @@ -2,6 +2,34 @@ import XCTest final class RNSentryReplayBreadcrumbConverterTests: XCTestCase { + func testConvertForegroundBreadcrumb() { + let converter = RNSentryReplayBreadcrumbConverter() + let testBreadcrumb = Breadcrumb() + testBreadcrumb.type = "navigation" + testBreadcrumb.category = "app.lifecycle" + testBreadcrumb.data = ["state": "foreground"] + let actual = converter.convert(from: testBreadcrumb) + + XCTAssertNotNil(actual) + let data = actual!.serialize()["data"] as! [String: Any?]; + let payload = data["payload"] as! [String: Any?]; + XCTAssertEqual(payload["category"] as! String, "app.foreground") + } + + func testConvertBackgroundBreadcrumb() { + let converter = RNSentryReplayBreadcrumbConverter() + let testBreadcrumb = Breadcrumb() + testBreadcrumb.type = "navigation" + testBreadcrumb.category = "app.lifecycle" + testBreadcrumb.data = ["state": "background"] + let actual = converter.convert(from: testBreadcrumb) + + XCTAssertNotNil(actual) + let data = actual!.serialize()["data"] as! [String: Any?]; + let payload = data["payload"] as! [String: Any?]; + XCTAssertEqual(payload["category"] as! String, "app.background") + } + func testNotConvertSentryEventBreadcrumb() { let converter = RNSentryReplayBreadcrumbConverter() let testBreadcrumb = Breadcrumb() diff --git a/android/src/main/java/io/sentry/react/RNSentryReplayBreadcrumbConverter.java b/android/src/main/java/io/sentry/react/RNSentryReplayBreadcrumbConverter.java index c402190ade..ede86e4f08 100644 --- a/android/src/main/java/io/sentry/react/RNSentryReplayBreadcrumbConverter.java +++ b/android/src/main/java/io/sentry/react/RNSentryReplayBreadcrumbConverter.java @@ -29,6 +29,10 @@ public RNSentryReplayBreadcrumbConverter() { breadcrumb.getCategory().equals("sentry.transaction")) { return null; } + if (breadcrumb.getCategory().equals("http")) { + // Drop native http breadcrumbs to avoid duplicates + return null; + } if (breadcrumb.getCategory().equals("touch")) { return convertTouchBreadcrumb(breadcrumb); @@ -42,10 +46,6 @@ public RNSentryReplayBreadcrumbConverter() { if (breadcrumb.getCategory().equals("xhr")) { return convertNetworkBreadcrumb(breadcrumb); } - if (breadcrumb.getCategory().equals("http")) { - // Drop native http breadcrumbs to avoid duplicates - return null; - } RRWebEvent nativeBreadcrumb = super.convert(breadcrumb); diff --git a/ios/RNSentryReplayBreadcrumbConverter.m b/ios/RNSentryReplayBreadcrumbConverter.m index 056da5ee0a..251ada8903 100644 --- a/ios/RNSentryReplayBreadcrumbConverter.m +++ b/ios/RNSentryReplayBreadcrumbConverter.m @@ -25,15 +25,11 @@ - (instancetype _Nonnull)init { // Do not add Sentry Event breadcrumbs to replay return nil; } - + if ([breadcrumb.category isEqualToString:@"http"]) { // Drop native network breadcrumbs to avoid duplicates return nil; } - if ([breadcrumb.type isEqualToString:@"navigation"] && ![breadcrumb.category isEqualToString:@"navigation"]) { - // Drop native navigation breadcrumbs to avoid duplicates - return nil; - } if ([breadcrumb.category isEqualToString:@"touch"]) { return [self convertTouch:breadcrumb]; @@ -71,7 +67,7 @@ - (instancetype _Nonnull)init { if (breadcrumb.data == nil) { return nil; } - + NSMutableArray *path = [breadcrumb.data valueForKey:@"path"]; NSString* message = [RNSentryReplayBreadcrumbConverter getTouchPathMessageFrom:path]; @@ -87,7 +83,7 @@ + (NSString* _Nullable) getTouchPathMessageFrom:(NSArray* _Nullable) path { if (path == nil) { return nil; } - + NSInteger pathCount = [path count]; if (pathCount <= 0) { return nil; @@ -129,7 +125,7 @@ + (NSString* _Nullable) getTouchPathMessageFrom:(NSArray* _Nullable) path { [message appendString:@" > "]; } } - + return message; } From 4b22f9a64188b92700477550d7a9e6b0eccbf9f6 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Thu, 4 Jul 2024 18:00:48 +0200 Subject: [PATCH 2/2] add changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b6d284a577..63390c4546 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,10 @@ module.exports = withSentryConfig(getDefaultConfig(__dirname), { annotateReactComponents: true }); ``` +### Fixes + +- Add `app.foreground/background` breadcrumbs to iOS Replays ([#3932](https://github.com/getsentry/sentry-react-native/pull/3932)) + ## 5.25.0-alpha.2 ### Features