From f28d80270164550aecad603c7d05fb901562f067 Mon Sep 17 00:00:00 2001 From: GitHub Date: Wed, 6 Nov 2024 15:42:24 +0000 Subject: [PATCH 1/3] chore: update scripts/update-cocoa.sh to 8.40.0 --- CHANGELOG.md | 6 +++--- packages/core/RNSentry.podspec | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 81aa2effb2..11445713b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,9 +50,9 @@ - Bump Android SDK from v7.15.0 to v7.16.0 ([#4202](https://github.com/getsentry/sentry-react-native/pull/4202)) - [changelog](https://github.com/getsentry/sentry-java/blob/main/CHANGELOG.md#7160) - [diff](https://github.com/getsentry/sentry-java/compare/7.15.0...7.16.0) -- Bump Cocoa SDK from v8.38.0 to v8.39.0 ([#4212](https://github.com/getsentry/sentry-react-native/pull/4212)) - - [changelog](https://github.com/getsentry/sentry-cocoa/blob/main/CHANGELOG.md#8390) - - [diff](https://github.com/getsentry/sentry-cocoa/compare/8.38.0...8.39.0) +- Bump Cocoa SDK from v8.38.0 to v8.40.0 ([#4212](https://github.com/getsentry/sentry-react-native/pull/4212), [#4239](https://github.com/getsentry/sentry-react-native/pull/4239)) + - [changelog](https://github.com/getsentry/sentry-cocoa/blob/main/CHANGELOG.md#8400) + - [diff](https://github.com/getsentry/sentry-cocoa/compare/8.38.0...8.40.0) ## 6.1.0 diff --git a/packages/core/RNSentry.podspec b/packages/core/RNSentry.podspec index 03c1f22d10..257e8c563d 100644 --- a/packages/core/RNSentry.podspec +++ b/packages/core/RNSentry.podspec @@ -37,7 +37,7 @@ Pod::Spec.new do |s| s.compiler_flags = other_cflags - s.dependency 'Sentry/HybridSDK', '8.39.0' + s.dependency 'Sentry/HybridSDK', '8.40.0' if defined? install_modules_dependencies # Default React Native dependencies for 0.71 and above (new and legacy architecture) From 13851a952135f6dddfec3f8994ab633ddecb2139 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Wed, 6 Nov 2024 19:13:41 +0100 Subject: [PATCH 2/3] fix replay redacting and add tests --- .../project.pbxproj | 10 +- ...RNSentryCocoaTesterTests-Bridging-Header.h | 1 + .../RNSentryReplayOptionsTests.swift | 115 ++++++++++++++++++ .../core/RNSentryCocoaTester/RNSentryTests.h | 26 ++++ packages/core/ios/RNSentryReplay.m | 30 ++--- 5 files changed, 159 insertions(+), 23 deletions(-) create mode 100644 packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryReplayOptionsTests.swift create mode 100644 packages/core/RNSentryCocoaTester/RNSentryTests.h diff --git a/packages/core/RNSentryCocoaTester/RNSentryCocoaTester.xcodeproj/project.pbxproj b/packages/core/RNSentryCocoaTester/RNSentryCocoaTester.xcodeproj/project.pbxproj index b1cc2aa6f4..8d96fe625e 100644 --- a/packages/core/RNSentryCocoaTester/RNSentryCocoaTester.xcodeproj/project.pbxproj +++ b/packages/core/RNSentryCocoaTester/RNSentryCocoaTester.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 332D33472CDBDBB600547D76 /* RNSentryReplayOptionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 332D33462CDBDBB600547D76 /* RNSentryReplayOptionsTests.swift */; }; 336084392C32E382008CC412 /* RNSentryReplayBreadcrumbConverterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 336084382C32E382008CC412 /* RNSentryReplayBreadcrumbConverterTests.swift */; }; 33958C692BFCF12600AD1FB6 /* RNSentryOnDrawReporterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 33958C682BFCF12600AD1FB6 /* RNSentryOnDrawReporterTests.m */; }; 33AFDFED2B8D14B300AAB120 /* RNSentryFramesTrackerListenerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 33AFDFEC2B8D14B300AAB120 /* RNSentryFramesTrackerListenerTests.m */; }; @@ -18,11 +19,13 @@ /* 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 = ""; }; 330F308D2C0F385A002A0D4E /* RNSentryBreadcrumb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSentryBreadcrumb.h; path = ../ios/RNSentryBreadcrumb.h; sourceTree = ""; }; + 332D33462CDBDBB600547D76 /* RNSentryReplayOptionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNSentryReplayOptionsTests.swift; sourceTree = ""; }; + 332D33482CDBDC7300547D76 /* RNSentry.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNSentry.h; path = ../ios/RNSentry.h; sourceTree = SOURCE_ROOT; }; 336084382C32E382008CC412 /* RNSentryReplayBreadcrumbConverterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RNSentryReplayBreadcrumbConverterTests.swift; sourceTree = ""; }; 3360843A2C32E3A8008CC412 /* RNSentryReplayBreadcrumbConverter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSentryReplayBreadcrumbConverter.h; path = ../ios/RNSentryReplayBreadcrumbConverter.h; sourceTree = ""; }; 3360843C2C340C76008CC412 /* RNSentryBreadcrumbTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNSentryBreadcrumbTests.swift; sourceTree = ""; }; 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 = ""; }; + 338739072A7D7D2800950DDD /* RNSentryReplay.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNSentryReplay.h; path = ../ios/RNSentryReplay.h; sourceTree = ""; }; 33958C672BFCEF5A00AD1FB6 /* RNSentryOnDrawReporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSentryOnDrawReporter.h; path = ../ios/RNSentryOnDrawReporter.h; sourceTree = ""; }; 33958C682BFCF12600AD1FB6 /* RNSentryOnDrawReporterTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNSentryOnDrawReporterTests.m; sourceTree = ""; }; 33AFDFEC2B8D14B300AAB120 /* RNSentryFramesTrackerListenerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNSentryFramesTrackerListenerTests.m; sourceTree = ""; }; @@ -80,13 +83,13 @@ children = ( 336084382C32E382008CC412 /* RNSentryReplayBreadcrumbConverterTests.swift */, 33F58ACF2977037D008F60EA /* RNSentryTests.mm */, - 338739072A7D7D2800950DDD /* RNSentryTests.h */, 33AFDFEC2B8D14B300AAB120 /* RNSentryFramesTrackerListenerTests.m */, 33AFDFEE2B8D14C200AAB120 /* RNSentryFramesTrackerListenerTests.h */, 33AFDFF02B8D15E500AAB120 /* RNSentryDependencyContainerTests.m */, 33AFDFF22B8D15F600AAB120 /* RNSentryDependencyContainerTests.h */, 33958C682BFCF12600AD1FB6 /* RNSentryOnDrawReporterTests.m */, 3360843C2C340C76008CC412 /* RNSentryBreadcrumbTests.swift */, + 332D33462CDBDBB600547D76 /* RNSentryReplayOptionsTests.swift */, ); path = RNSentryCocoaTesterTests; sourceTree = ""; @@ -94,10 +97,12 @@ 33AFE0122B8F319000AAB120 /* RNSentry */ = { isa = PBXGroup; children = ( + 332D33482CDBDC7300547D76 /* RNSentry.h */, 3360843A2C32E3A8008CC412 /* RNSentryReplayBreadcrumbConverter.h */, 330F308D2C0F385A002A0D4E /* RNSentryBreadcrumb.h */, 33958C672BFCEF5A00AD1FB6 /* RNSentryOnDrawReporter.h */, 33AFE0132B8F31AF00AAB120 /* RNSentryDependencyContainer.h */, + 338739072A7D7D2800950DDD /* RNSentryReplay.h */, ); name = RNSentry; sourceTree = ""; @@ -212,6 +217,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 332D33472CDBDBB600547D76 /* RNSentryReplayOptionsTests.swift in Sources */, 33AFDFF12B8D15E500AAB120 /* RNSentryDependencyContainerTests.m in Sources */, 336084392C32E382008CC412 /* RNSentryReplayBreadcrumbConverterTests.swift in Sources */, 33F58AD02977037D008F60EA /* RNSentryTests.mm in Sources */, diff --git a/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryCocoaTesterTests-Bridging-Header.h b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryCocoaTesterTests-Bridging-Header.h index 6b949b5967..b6c8d70abf 100644 --- a/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryCocoaTesterTests-Bridging-Header.h +++ b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryCocoaTesterTests-Bridging-Header.h @@ -4,3 +4,4 @@ #import "RNSentryBreadcrumb.h" #import "RNSentryReplayBreadcrumbConverter.h" +#import "RNSentryReplay.h" diff --git a/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryReplayOptionsTests.swift b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryReplayOptionsTests.swift new file mode 100644 index 0000000000..66d87694c2 --- /dev/null +++ b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryReplayOptionsTests.swift @@ -0,0 +1,115 @@ +import XCTest +import Sentry + +final class RNSentryReplayOptions: XCTestCase { + + func testOptionsWithoutExperimentalAreIgnored() { + let optionsDict = NSMutableDictionary() + RNSentryReplay.updateOptions(optionsDict) + + XCTAssertEqual(optionsDict.count, 0) + } + + func testExperimentalOptionsWithoutReplaySampleRatesAreRemoved() { + let optionsDict = (["_experiments": [:]] as NSDictionary).mutableCopy() as! NSMutableDictionary + RNSentryReplay.updateOptions(optionsDict) + + XCTAssertEqual(optionsDict.count, 0) + } + + func testExperimentalOptionsWithReplaySessionSampleRateAreUpdated() { + let optionsDict = (["_experiments": [ "replaysSessionSampleRate": 0.75 ]] as NSDictionary).mutableCopy() as! NSMutableDictionary + RNSentryReplay.updateOptions(optionsDict) + + XCTAssertEqual(optionsDict.count, 1) + + let experimental = optionsDict["experimental"] as! [String:Any] + XCTAssertEqual(experimental.count, 1) + + let sessionReplay = experimental["sessionReplay"] as! [String:Any] + + XCTAssertEqual(sessionReplay.count, 5) + XCTAssertEqual(sessionReplay["sessionSampleRate"] as! Double, 0.75) + + XCTAssertNotNil(sessionReplay["errorSampleRate"]) + XCTAssertNotNil(sessionReplay["redactAllImages"]) + XCTAssertNotNil(sessionReplay["redactAllText"]) + XCTAssertNotNil(sessionReplay["maskedViewClasses"]) + } + + func testExperimentalOptionsWithReplayOnErrorSampleRateAreUpdated() { + let optionsDict = (["_experiments": [ "replaysOnErrorSampleRate": 0.75 ]] as NSDictionary).mutableCopy() as! NSMutableDictionary + RNSentryReplay.updateOptions(optionsDict) + + XCTAssertEqual(optionsDict.count, 1) + + let experimental = optionsDict["experimental"] as! [String:Any] + XCTAssertEqual(experimental.count, 1) + + let sessionReplay = experimental["sessionReplay"] as! [String:Any] + XCTAssertEqual(sessionReplay.count, 5) + XCTAssertEqual(sessionReplay["errorSampleRate"] as! Double, 0.75) + + XCTAssertNotNil(sessionReplay["sessionSampleRate"]) + XCTAssertNotNil(sessionReplay["redactAllImages"]) + XCTAssertNotNil(sessionReplay["redactAllText"]) + XCTAssertNotNil(sessionReplay["maskedViewClasses"]) + } + + func testExperimentalOptionsWithReplayOnErrorSampleRateAndMaskAllVectorsAreUpdated() { + let optionsDict = ([ + "_experiments": [ "replaysOnErrorSampleRate": 0.75 ], + "mobileReplayOptions": [ "maskAllVectors": true ] + ] as NSDictionary).mutableCopy() as! NSMutableDictionary + + RNSentryReplay.updateOptions(optionsDict) + + XCTAssertEqual(optionsDict.count, 2) + + let experimental = optionsDict["experimental"] as! [String:Any] + let sessionReplay = experimental["sessionReplay"] as! [String:Any] + + let maskedViewClasses = sessionReplay["maskedViewClasses"] as! [String] + XCTAssertEqual(maskedViewClasses.count, 1) + XCTAssertEqual(maskedViewClasses[0], "RNSVGSvgView") + } + + func testExperimentalOptionsWithReplayOnErrorSampleRateAndMaskAllImagesAreUpdated() { + let optionsDict = ([ + "_experiments": [ "replaysOnErrorSampleRate": 0.75 ], + "mobileReplayOptions": [ "maskAllImages": true ] + ] as NSDictionary).mutableCopy() as! NSMutableDictionary + + RNSentryReplay.updateOptions(optionsDict) + + XCTAssertEqual(optionsDict.count, 2) + + let experimental = optionsDict["experimental"] as! [String:Any] + let sessionReplay = experimental["sessionReplay"] as! [String:Any] + XCTAssertEqual(sessionReplay["redactAllImages"] as! Bool, true) + + let maskedViewClasses = sessionReplay["maskedViewClasses"] as! [String] + XCTAssertEqual(maskedViewClasses.count, 1) + XCTAssertEqual(maskedViewClasses[0], "RCTImageView") + } + + func testExperimentalOptionsWithReplayOnErrorSampleRateAndMaskAllTextAreUpdated() { + let optionsDict = ([ + "dsn": "https://abc@def.ingest.sentry.io/1234567", + "_experiments": [ "replaysOnErrorSampleRate": 0.75 ], + "mobileReplayOptions": [ "maskAllText": true ] + ] as NSDictionary).mutableCopy() as! NSMutableDictionary + + RNSentryReplay.updateOptions(optionsDict) + + let actualOptions = try! Options(dict: optionsDict as! [String: Any]) + + XCTAssertEqual(actualOptions.experimental.sessionReplay.maskAllText, true) + XCTAssertEqual(actualOptions.experimental.sessionReplay.maskedViewClasses.count, 2) + XCTAssertNotNil(actualOptions.experimental.sessionReplay.maskedViewClasses[0]) + XCTAssertNotNil(actualOptions.experimental.sessionReplay.maskedViewClasses[1]) + XCTAssertEqual(ObjectIdentifier(actualOptions.experimental.sessionReplay.maskedViewClasses[0]), ObjectIdentifier(NSClassFromString("RCTTextView")!)) + XCTAssertEqual(ObjectIdentifier(actualOptions.experimental.sessionReplay.maskedViewClasses[1]), ObjectIdentifier(NSClassFromString("RCTParagraphComponentView")!)) + } + +} diff --git a/packages/core/RNSentryCocoaTester/RNSentryTests.h b/packages/core/RNSentryCocoaTester/RNSentryTests.h new file mode 100644 index 0000000000..8c2fddad03 --- /dev/null +++ b/packages/core/RNSentryCocoaTester/RNSentryTests.h @@ -0,0 +1,26 @@ +#import +#import + +@interface +SentrySDK (PrivateTests) +- (nullable SentryOptions *)options; +@end + +@interface SentryBinaryImageInfo : NSObject +@property (nonatomic, strong) NSString *name; +@property (nonatomic) uint64_t address; +@property (nonatomic) uint64_t size; +@end + +@interface SentryBinaryImageCache : NSObject +@property (nonatomic, readonly, class) SentryBinaryImageCache *shared; +- (void)start; +- (void)stop; +- (nullable SentryBinaryImageInfo *)imageByAddress:(const uint64_t)address; +@end + +@interface SentryDependencyContainer : NSObject ++ (instancetype)sharedInstance; +@property (nonatomic, strong) SentryDebugImageProvider *debugImageProvider; +@property (nonatomic, strong) SentryBinaryImageCache *binaryImageCache; +@end diff --git a/packages/core/ios/RNSentryReplay.m b/packages/core/ios/RNSentryReplay.m index 9ef2c4efc0..ca63fb9dde 100644 --- a/packages/core/ios/RNSentryReplay.m +++ b/packages/core/ios/RNSentryReplay.m @@ -30,40 +30,28 @@ + (void)updateOptions:(NSMutableDictionary *)options @"errorSampleRate" : experiments[@"replaysOnErrorSampleRate"] ?: [NSNull null], @"redactAllImages" : replayOptions[@"maskAllImages"] ?: [NSNull null], @"redactAllText" : replayOptions[@"maskAllText"] ?: [NSNull null], + @"maskedViewClasses" : [RNSentryReplay getReplayRNRedactClasses:replayOptions], } } forKey:@"experimental"]; - - [RNSentryReplay addReplayRNRedactClasses:replayOptions]; } -+ (void)addReplayRNRedactClasses:(NSDictionary *_Nullable)replayOptions ++ (NSArray *_Nonnull)getReplayRNRedactClasses:(NSDictionary *_Nullable)replayOptions { NSMutableArray *_Nonnull classesToRedact = [[NSMutableArray alloc] init]; + if ([replayOptions[@"maskAllVectors"] boolValue] == YES) { - Class _Nullable maybeRNSVGViewClass = NSClassFromString(@"RNSVGSvgView"); - if (maybeRNSVGViewClass != nil) { - [classesToRedact addObject:maybeRNSVGViewClass]; - } + [classesToRedact addObject:@"RNSVGSvgView"]; } if ([replayOptions[@"maskAllImages"] boolValue] == YES) { - Class _Nullable maybeRCTImageClass = NSClassFromString(@"RCTImageView"); - if (maybeRCTImageClass != nil) { - [classesToRedact addObject:maybeRCTImageClass]; - } + [classesToRedact addObject:@"RCTImageView"]; } if ([replayOptions[@"maskAllText"] boolValue] == YES) { - Class _Nullable maybeRCTTextClass = NSClassFromString(@"RCTTextView"); - if (maybeRCTTextClass != nil) { - [classesToRedact addObject:maybeRCTTextClass]; - } - Class _Nullable maybeRCTParagraphComponentViewClass - = NSClassFromString(@"RCTParagraphComponentView"); - if (maybeRCTParagraphComponentViewClass != nil) { - [classesToRedact addObject:maybeRCTParagraphComponentViewClass]; - } + [classesToRedact addObject:@"RCTTextView"]; + [classesToRedact addObject:@"RCTParagraphComponentView"]; } - [PrivateSentrySDKOnly addReplayRedactClasses:classesToRedact]; + + return classesToRedact; } + (void)postInit From 3254f9110859b0eb7a1f38d23ff1ba0c326dc8ff Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Thu, 7 Nov 2024 10:58:13 +0100 Subject: [PATCH 3/3] use sentry cocoa options in tests --- .../RNSentryReplayOptionsTests.swift | 110 ++++++++++++------ 1 file changed, 75 insertions(+), 35 deletions(-) diff --git a/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryReplayOptionsTests.swift b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryReplayOptionsTests.swift index 66d87694c2..18a329ebec 100644 --- a/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryReplayOptionsTests.swift +++ b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryReplayOptionsTests.swift @@ -17,54 +17,93 @@ final class RNSentryReplayOptions: XCTestCase { XCTAssertEqual(optionsDict.count, 0) } - func testExperimentalOptionsWithReplaySessionSampleRateAreUpdated() { - let optionsDict = (["_experiments": [ "replaysSessionSampleRate": 0.75 ]] as NSDictionary).mutableCopy() as! NSMutableDictionary + func testReplayOptionsDictContainsAllOptionsKeysWhenSessionSampleRateUsed() { + let optionsDict = ([ + "dsn": "https://abc@def.ingest.sentry.io/1234567", + "_experiments": [ + "replaysSessionSampleRate": 0.75 + ] + ] as NSDictionary).mutableCopy() as! NSMutableDictionary RNSentryReplay.updateOptions(optionsDict) - XCTAssertEqual(optionsDict.count, 1) + let experimental = optionsDict["experimental"] as! [String:Any] + let sessionReplay = experimental["sessionReplay"] as! [String:Any] + + assertAllDefaultReplayOptionsAreNotNil(replayOptions: sessionReplay) + } + + func testReplayOptionsDictContainsAllOptionsKeysWhenErrorSampleRateUsed() { + let optionsDict = ([ + "dsn": "https://abc@def.ingest.sentry.io/1234567", + "_experiments": [ + "replaysOnErrorSampleRate": 0.75 + ] + ] as NSDictionary).mutableCopy() as! NSMutableDictionary + RNSentryReplay.updateOptions(optionsDict) let experimental = optionsDict["experimental"] as! [String:Any] - XCTAssertEqual(experimental.count, 1) + let sessionReplay = experimental["sessionReplay"] as! [String:Any] + + assertAllDefaultReplayOptionsAreNotNil(replayOptions: sessionReplay) + } + func testReplayOptionsDictContainsAllOptionsKeysWhenErrorAndSessionSampleRatesUsed() { + let optionsDict = ([ + "dsn": "https://abc@def.ingest.sentry.io/1234567", + "_experiments": [ + "replaysOnErrorSampleRate": 0.75, + "replaysSessionSampleRate": 0.75 + ] + ] as NSDictionary).mutableCopy() as! NSMutableDictionary + RNSentryReplay.updateOptions(optionsDict) + + let experimental = optionsDict["experimental"] as! [String:Any] let sessionReplay = experimental["sessionReplay"] as! [String:Any] - XCTAssertEqual(sessionReplay.count, 5) - XCTAssertEqual(sessionReplay["sessionSampleRate"] as! Double, 0.75) + assertAllDefaultReplayOptionsAreNotNil(replayOptions: sessionReplay) + } - XCTAssertNotNil(sessionReplay["errorSampleRate"]) - XCTAssertNotNil(sessionReplay["redactAllImages"]) - XCTAssertNotNil(sessionReplay["redactAllText"]) - XCTAssertNotNil(sessionReplay["maskedViewClasses"]) + func assertAllDefaultReplayOptionsAreNotNil(replayOptions: [String: Any]) { + XCTAssertEqual(replayOptions.count, 5) + XCTAssertNotNil(replayOptions["sessionSampleRate"]) + XCTAssertNotNil(replayOptions["errorSampleRate"]) + XCTAssertNotNil(replayOptions["redactAllImages"]) + XCTAssertNotNil(replayOptions["redactAllText"]) + XCTAssertNotNil(replayOptions["maskedViewClasses"]) } - func testExperimentalOptionsWithReplayOnErrorSampleRateAreUpdated() { - let optionsDict = (["_experiments": [ "replaysOnErrorSampleRate": 0.75 ]] as NSDictionary).mutableCopy() as! NSMutableDictionary + func testSessionSampleRate() { + let optionsDict = ([ + "dsn": "https://abc@def.ingest.sentry.io/1234567", + "_experiments": [ "replaysSessionSampleRate": 0.75 ] + ] as NSDictionary).mutableCopy() as! NSMutableDictionary RNSentryReplay.updateOptions(optionsDict) - XCTAssertEqual(optionsDict.count, 1) - - let experimental = optionsDict["experimental"] as! [String:Any] - XCTAssertEqual(experimental.count, 1) + let actualOptions = try! Options(dict: optionsDict as! [String: Any]) + XCTAssertEqual(actualOptions.experimental.sessionReplay.sessionSampleRate, 0.75) + } - let sessionReplay = experimental["sessionReplay"] as! [String:Any] - XCTAssertEqual(sessionReplay.count, 5) - XCTAssertEqual(sessionReplay["errorSampleRate"] as! Double, 0.75) + func testOnErrorSampleRate() { + let optionsDict = ([ + "dsn": "https://abc@def.ingest.sentry.io/1234567", + "_experiments": [ "replaysOnErrorSampleRate": 0.75 ] + ] as NSDictionary).mutableCopy() as! NSMutableDictionary + RNSentryReplay.updateOptions(optionsDict) - XCTAssertNotNil(sessionReplay["sessionSampleRate"]) - XCTAssertNotNil(sessionReplay["redactAllImages"]) - XCTAssertNotNil(sessionReplay["redactAllText"]) - XCTAssertNotNil(sessionReplay["maskedViewClasses"]) + let actualOptions = try! Options(dict: optionsDict as! [String: Any]) + XCTAssertEqual(actualOptions.experimental.sessionReplay.onErrorSampleRate, 0.75) } - func testExperimentalOptionsWithReplayOnErrorSampleRateAndMaskAllVectorsAreUpdated() { + func testMaskAllVectors() { let optionsDict = ([ + "dsn": "https://abc@def.ingest.sentry.io/1234567", "_experiments": [ "replaysOnErrorSampleRate": 0.75 ], "mobileReplayOptions": [ "maskAllVectors": true ] ] as NSDictionary).mutableCopy() as! NSMutableDictionary RNSentryReplay.updateOptions(optionsDict) - XCTAssertEqual(optionsDict.count, 2) + XCTAssertEqual(optionsDict.count, 3) let experimental = optionsDict["experimental"] as! [String:Any] let sessionReplay = experimental["sessionReplay"] as! [String:Any] @@ -72,28 +111,29 @@ final class RNSentryReplayOptions: XCTestCase { let maskedViewClasses = sessionReplay["maskedViewClasses"] as! [String] XCTAssertEqual(maskedViewClasses.count, 1) XCTAssertEqual(maskedViewClasses[0], "RNSVGSvgView") + + let actualOptions = try! Options(dict: optionsDict as! [String: Any]) + XCTAssertEqual(actualOptions.experimental.sessionReplay.maskedViewClasses.count, 0) } - func testExperimentalOptionsWithReplayOnErrorSampleRateAndMaskAllImagesAreUpdated() { + func testMaskAllImages() { let optionsDict = ([ + "dsn": "https://abc@def.ingest.sentry.io/1234567", "_experiments": [ "replaysOnErrorSampleRate": 0.75 ], "mobileReplayOptions": [ "maskAllImages": true ] ] as NSDictionary).mutableCopy() as! NSMutableDictionary RNSentryReplay.updateOptions(optionsDict) - XCTAssertEqual(optionsDict.count, 2) - - let experimental = optionsDict["experimental"] as! [String:Any] - let sessionReplay = experimental["sessionReplay"] as! [String:Any] - XCTAssertEqual(sessionReplay["redactAllImages"] as! Bool, true) + let actualOptions = try! Options(dict: optionsDict as! [String: Any]) - let maskedViewClasses = sessionReplay["maskedViewClasses"] as! [String] - XCTAssertEqual(maskedViewClasses.count, 1) - XCTAssertEqual(maskedViewClasses[0], "RCTImageView") + XCTAssertEqual(actualOptions.experimental.sessionReplay.maskAllImages, true) + XCTAssertEqual(actualOptions.experimental.sessionReplay.maskedViewClasses.count, 1) + XCTAssertNotNil(actualOptions.experimental.sessionReplay.maskedViewClasses[0]) + XCTAssertEqual(ObjectIdentifier(actualOptions.experimental.sessionReplay.maskedViewClasses[0]), ObjectIdentifier(NSClassFromString("RCTImageView")!)) } - func testExperimentalOptionsWithReplayOnErrorSampleRateAndMaskAllTextAreUpdated() { + func testMaskAllText() { let optionsDict = ([ "dsn": "https://abc@def.ingest.sentry.io/1234567", "_experiments": [ "replaysOnErrorSampleRate": 0.75 ],