diff --git a/CHANGELOG.md b/CHANGELOG.md index 55cd87389..de6f7cea8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [Unreleased](https://github.com/Instabug/Instabug-React-Native/compare/v15.0.2...dev) + +### Added + +- Add support for App variant. ([#1409](https://github.com/Instabug/Instabug-React-Native/pull/1409)) + ## [15.0.2](https://github.com/Instabug/Instabug-React-Native/compare/v15.2.0...dev) ### Added diff --git a/android/src/main/java/com/instabug/reactlibrary/RNInstabug.java b/android/src/main/java/com/instabug/reactlibrary/RNInstabug.java index 7c0901936..28de7d950 100644 --- a/android/src/main/java/com/instabug/reactlibrary/RNInstabug.java +++ b/android/src/main/java/com/instabug/reactlibrary/RNInstabug.java @@ -59,18 +59,30 @@ public void init( @NonNull Application application, @NonNull String applicationToken, int logLevel, + String codePushVersion, + String appVariant, Boolean ignoreSecureFlag, @NonNull InstabugInvocationEvent... InvocationEvent + + ) { try { setBaseUrlForDeprecationLogs(); setCurrentPlatform(); - Instabug.Builder builder = new Instabug.Builder(application, applicationToken) + Instabug.Builder builder= new Instabug.Builder(application, applicationToken) .setInvocationEvents(InvocationEvent) .setSdkDebugLogsLevel(logLevel); + if(codePushVersion!=null){ + builder.setCodePushVersion(codePushVersion); + } + if(appVariant!=null) + builder.setAppVariant(appVariant); + + + if (ignoreSecureFlag != null) { builder.ignoreFlagSecure(ignoreSecureFlag); } @@ -107,9 +119,11 @@ public void init( public void init( @NonNull Application application, @NonNull String applicationToken, + String codePushVersion, + String appVariant, @NonNull InstabugInvocationEvent... invocationEvent ) { - init(application, applicationToken, LogLevel.ERROR,null, invocationEvent); + init(application, applicationToken, LogLevel.ERROR,codePushVersion,appVariant, null,invocationEvent); } @VisibleForTesting @@ -165,6 +179,11 @@ public static class Builder { * The events that trigger the SDK's user interface. */ private InstabugInvocationEvent[] invocationEvents; + /** + * The App variant name to be used for all reports. + */ + private String appVariant; + private Boolean ignoreFlagSecure; @@ -237,6 +256,16 @@ public Builder setInvocationEvents(InstabugInvocationEvent... invocationEvents) return this; } + /** + * Sets the the current App variant + * + * @param appVariant the current App variant to work with. + */ + public Builder setAppVariant(String appVariant) { + this.appVariant = appVariant; + return this; + } + /** * Builds the Instabug instance with the provided configurations. */ @@ -252,6 +281,9 @@ public void build() { if (codePushVersion != null) { instabugBuilder.setCodePushVersion(codePushVersion); } + if(appVariant!=null){ + instabugBuilder.setAppVariant(appVariant); + } if (ignoreFlagSecure != null) { instabugBuilder.ignoreFlagSecure(ignoreFlagSecure); diff --git a/android/src/main/java/com/instabug/reactlibrary/RNInstabugReactnativeModule.java b/android/src/main/java/com/instabug/reactlibrary/RNInstabugReactnativeModule.java index 21bcf4f44..3118bce46 100644 --- a/android/src/main/java/com/instabug/reactlibrary/RNInstabugReactnativeModule.java +++ b/android/src/main/java/com/instabug/reactlibrary/RNInstabugReactnativeModule.java @@ -149,6 +149,7 @@ public void init( final String logLevel, final boolean useNativeNetworkInterception, @Nullable final String codePushVersion, + @Nullable final String appVariant, final ReadableMap map ) { MainThreadHandler.runOnMainThread(new Runnable() { @@ -178,6 +179,9 @@ public void run() { builder.setCodePushVersion(codePushVersion); } } + if (appVariant != null) { + builder.setAppVariant(appVariant); + } builder.build(); } }); @@ -505,6 +509,8 @@ public void run() { }); } + + /** * Removes user attribute if exists. * @@ -1356,4 +1362,19 @@ public void run() { } }); } + + /** + * Sets current App variant + * + * @param appVariant The app variant name . + */ + @ReactMethod + public void setAppVariant(@NonNull String appVariant) { + try { + Instabug.setAppVariant(appVariant); + + } catch (Exception e) { + e.printStackTrace(); + } + } } diff --git a/android/src/test/java/com/instabug/reactlibrary/RNInstabugReactnativeModuleTest.java b/android/src/test/java/com/instabug/reactlibrary/RNInstabugReactnativeModuleTest.java index f4f6f9bc1..9b46bf854 100644 --- a/android/src/test/java/com/instabug/reactlibrary/RNInstabugReactnativeModuleTest.java +++ b/android/src/test/java/com/instabug/reactlibrary/RNInstabugReactnativeModuleTest.java @@ -631,6 +631,16 @@ public void testRemoveAllFeatureFlags() { mockInstabug.verify(() -> Instabug.removeAllFeatureFlags()); } + @Test + public void testSetAppVariant() { + String appVariant="App-variant"; + // when + rnModule.setAppVariant(appVariant); + + // then + mockInstabug.verify(() -> Instabug.setAppVariant(appVariant)); + } + @Test public void testWillRedirectToStore() { // when @@ -678,7 +688,7 @@ public void testSetNetworkLogBodyDisabled() { mockInstabug.verify(() -> Instabug.setNetworkLogBodyEnabled(false)); } - + @Test public void testEnableAutoMasking(){ diff --git a/android/src/test/java/com/instabug/reactlibrary/RNInstabugTest.java b/android/src/test/java/com/instabug/reactlibrary/RNInstabugTest.java index 625eab1c9..643a1e136 100644 --- a/android/src/test/java/com/instabug/reactlibrary/RNInstabugTest.java +++ b/android/src/test/java/com/instabug/reactlibrary/RNInstabugTest.java @@ -67,7 +67,7 @@ public void testInitWithLogLevel() { when(mock.setInvocationEvents(any())).thenReturn(mock); }); - sut.init(mContext, token, logLevel, true, invocationEvents); + sut.init(mContext, token, logLevel, null, null,true, invocationEvents); Instabug.Builder builder = mInstabugBuilder.constructed().get(0); @@ -89,16 +89,19 @@ public void testInitWithoutLogLevel() { final InstabugInvocationEvent[] invocationEvents = new InstabugInvocationEvent[]{InstabugInvocationEvent.FLOATING_BUTTON}; final String token = "fde...."; final int defaultLogLevel = LogLevel.ERROR; + final String appVariant = "app-variant"; MockedConstruction mInstabugBuilder = mockConstruction( Instabug.Builder.class, (mock, context) -> { when(mock.setSdkDebugLogsLevel(anyInt())).thenReturn(mock); when(mock.setInvocationEvents(any())).thenReturn(mock); + when(mock.setAppVariant(any())).thenReturn(mock); + }); - sut.init(mContext, token, invocationEvents); + sut.init(mContext, token, null, appVariant, invocationEvents); - verify(sut).init(mContext, token, defaultLogLevel, null,invocationEvents); + verify(sut).init(mContext, token, defaultLogLevel, null, appVariant, null,invocationEvents); mInstabugBuilder.close(); } diff --git a/examples/default/ios/InstabugTests/InstabugSampleTests.m b/examples/default/ios/InstabugTests/InstabugSampleTests.m index 34fe9cfe3..7a69a6376 100644 --- a/examples/default/ios/InstabugTests/InstabugSampleTests.m +++ b/examples/default/ios/InstabugTests/InstabugSampleTests.m @@ -69,17 +69,19 @@ - (void)testInit { IBGInvocationEvent floatingButtonInvocationEvent = IBGInvocationEventFloatingButton; NSString *appToken = @"app_token"; NSString *codePushVersion = @"1.0.0(1)"; + NSString *appVariant = @"variant 1"; + NSArray *invocationEvents = [NSArray arrayWithObjects:[NSNumber numberWithInteger:floatingButtonInvocationEvent], nil]; BOOL useNativeNetworkInterception = YES; IBGSDKDebugLogsLevel sdkDebugLogsLevel = IBGSDKDebugLogsLevelDebug; OCMStub([mock setCodePushVersion:codePushVersion]); - [self.instabugBridge init:appToken invocationEvents:invocationEvents debugLogsLevel:sdkDebugLogsLevel useNativeNetworkInterception:useNativeNetworkInterception codePushVersion:codePushVersion - options:nil - ]; + [self.instabugBridge init:appToken invocationEvents:invocationEvents debugLogsLevel:sdkDebugLogsLevel useNativeNetworkInterception:useNativeNetworkInterception codePushVersion:codePushVersion appVariant:appVariant options:nil ]; OCMVerify([mock setCodePushVersion:codePushVersion]); + XCTAssertEqual(Instabug.appVariant, appVariant); + OCMVerify([self.mRNInstabug initWithToken:appToken invocationEvents:floatingButtonInvocationEvent debugLogsLevel:sdkDebugLogsLevel useNativeNetworkInterception:useNativeNetworkInterception]); } @@ -101,6 +103,14 @@ - (void)testSetUserData { OCMVerify([mock setUserData:userData]); } +- (void)testSetAppVariant { + id mock = OCMClassMock([Instabug class]); + NSString *appVariant = @"appVariant"; + + [self.instabugBridge setAppVariant: appVariant]; + XCTAssertEqual(Instabug.appVariant, appVariant); +} + - (void)testSetTrackUserSteps { id mock = OCMClassMock([Instabug class]); BOOL isEnabled = true; diff --git a/examples/default/src/App.tsx b/examples/default/src/App.tsx index ad1c32579..82be996c5 100644 --- a/examples/default/src/App.tsx +++ b/examples/default/src/App.tsx @@ -49,6 +49,7 @@ export const App: React.FC = () => { invocationEvents: [InvocationEvent.floatingButton], debugLogsLevel: LogLevel.verbose, networkInterceptionMode: NetworkInterceptionMode.javascript, + appVariant: 'App variant', }); CrashReporting.setNDKCrashesEnabled(true); diff --git a/ios/RNInstabug/InstabugReactBridge.h b/ios/RNInstabug/InstabugReactBridge.h index 45c075098..bba333536 100644 --- a/ios/RNInstabug/InstabugReactBridge.h +++ b/ios/RNInstabug/InstabugReactBridge.h @@ -26,13 +26,14 @@ - (void)setEnabled:(BOOL)isEnabled; -- (void)init:(NSString *)token invocationEvents:(NSArray *)invocationEventsArray debugLogsLevel:(IBGSDKDebugLogsLevel)sdkDebugLogsLevel useNativeNetworkInterception:(BOOL)useNativeNetworkInterception codePushVersion:(NSString *)codePushVersion -options:(nullable NSDictionary *)options; +- (void)init:(NSString *)token invocationEvents:(NSArray *)invocationEventsArray debugLogsLevel:(IBGSDKDebugLogsLevel)sdkDebugLogsLevel useNativeNetworkInterception:(BOOL)useNativeNetworkInterception codePushVersion:(NSString *)codePushVersion appVariant:(NSString *)appVariant options:(nullable NSDictionary *)options; - (void)setCodePushVersion:(NSString *)version; - (void)setUserData:(NSString *)userData; +- (void)setAppVariant:(NSString *)appVariant; + - (void)setTrackUserSteps:(BOOL)isEnabled; - (void)setSessionProfilerEnabled:(BOOL)sessionProfilerEnabled; diff --git a/ios/RNInstabug/InstabugReactBridge.m b/ios/RNInstabug/InstabugReactBridge.m index 682896515..2291716ad 100644 --- a/ios/RNInstabug/InstabugReactBridge.m +++ b/ios/RNInstabug/InstabugReactBridge.m @@ -42,8 +42,15 @@ - (dispatch_queue_t)methodQueue { debugLogsLevel:(IBGSDKDebugLogsLevel)sdkDebugLogsLevel useNativeNetworkInterception:(BOOL)useNativeNetworkInterception codePushVersion:(NSString *)codePushVersion - options:(nullable NSDictionary *)options - ) { + appVariant:(NSString *)appVariant + options:(nullable NSDictionary *)options + + ) { + + if(appVariant != nil){ + Instabug.appVariant = appVariant; + } + IBGInvocationEvent invocationEvents = 0; for (NSNumber *boxedValue in invocationEventsArray) { @@ -62,6 +69,10 @@ - (dispatch_queue_t)methodQueue { [Instabug setCodePushVersion:version]; } +RCT_EXPORT_METHOD(setAppVariant:(NSString *)appVariant) { + Instabug.appVariant = appVariant; +} + RCT_EXPORT_METHOD(setReproStepsConfig:(IBGUserStepsMode)bugMode :(IBGUserStepsMode)crashMode:(IBGUserStepsMode)sessionReplayMode) { [Instabug setReproStepsFor:IBGIssueTypeBug withMode:bugMode]; [Instabug setReproStepsFor:IBGIssueTypeCrash withMode:crashMode]; diff --git a/src/models/InstabugConfig.ts b/src/models/InstabugConfig.ts index af1d6e841..bc3d5c747 100644 --- a/src/models/InstabugConfig.ts +++ b/src/models/InstabugConfig.ts @@ -24,6 +24,11 @@ export interface InstabugConfig { */ ignoreAndroidSecureFlag?: boolean; + /** + * An optional current App variant to be used for filtering data. + */ + appVariant?: string; + /** * An optional network interception mode, this determines whether network interception * is done in the JavaScript side or in the native Android and iOS SDK side. diff --git a/src/modules/Instabug.ts b/src/modules/Instabug.ts index fd4f17600..757ac2576 100644 --- a/src/modules/Instabug.ts +++ b/src/modules/Instabug.ts @@ -126,6 +126,14 @@ export const init = (config: InstabugConfig) => { }, 1000); }; +/** + * Set Current App Variant. + * @param appVariant the current App variant name + */ +export const setAppVariant = (appVariant: string) => { + NativeInstabug.setAppVariant(appVariant); +}; + /** * Handles app state changes and updates APM network flags if necessary. */ @@ -273,6 +281,7 @@ const initializeNativeInstabug = (config: InstabugConfig) => { shouldEnableNativeInterception && config.networkInterceptionMode === NetworkInterceptionMode.native, config.codePushVersion, + config.appVariant, config.ignoreAndroidSecureFlag != null ? { ignoreAndroidSecureFlag: config.ignoreAndroidSecureFlag, diff --git a/src/native/NativeInstabug.ts b/src/native/NativeInstabug.ts index c9c078f37..f798bf4d2 100644 --- a/src/native/NativeInstabug.ts +++ b/src/native/NativeInstabug.ts @@ -26,6 +26,7 @@ export interface InstabugNativeModule extends NativeModule { debugLogsLevel: LogLevel, useNativeNetworkInterception: boolean, codePushVersion?: string, + appVariant?: string, options?: { ignoreAndroidSecureFlag?: boolean; }, @@ -34,6 +35,7 @@ export interface InstabugNativeModule extends NativeModule { // Misc APIs // setCodePushVersion(version: string): void; + setAppVariant(appVariant: string): void; setIBGLogPrintsToConsole(printsToConsole: boolean): void; setSessionProfilerEnabled(isEnabled: boolean): void; diff --git a/test/mocks/mockInstabug.ts b/test/mocks/mockInstabug.ts index 391a00a38..d3d5206b5 100644 --- a/test/mocks/mockInstabug.ts +++ b/test/mocks/mockInstabug.ts @@ -42,6 +42,7 @@ const mockInstabug: InstabugNativeModule = { clearAllUserAttributes: jest.fn(), showWelcomeMessageWithMode: jest.fn(), setWelcomeMessageMode: jest.fn(), + setAppVariant: jest.fn(), setFileAttachment: jest.fn(), addPrivateView: jest.fn(), removePrivateView: jest.fn(), diff --git a/test/modules/Instabug.spec.ts b/test/modules/Instabug.spec.ts index eeec8e8e4..7ec887f83 100644 --- a/test/modules/Instabug.spec.ts +++ b/test/modules/Instabug.spec.ts @@ -308,6 +308,7 @@ describe('Instabug Module', () => { instabugConfig.debugLogsLevel, usesNativeNetworkInterception, instabugConfig.codePushVersion, + undefined, { ignoreAndroidSecureFlag: instabugConfig.ignoreAndroidSecureFlag }, ); }); @@ -359,6 +360,7 @@ describe('Instabug Module', () => { // usesNativeNetworkInterception should be true when using native interception mode with iOS true, instabugConfig.codePushVersion, + undefined, { ignoreAndroidSecureFlag: instabugConfig.ignoreAndroidSecureFlag }, ); } @@ -960,6 +962,7 @@ describe('Instabug iOS initialization tests', () => { false, // Disable native interception config.codePushVersion, config.ignoreAndroidSecureFlag, + undefined, ); }); @@ -977,6 +980,7 @@ describe('Instabug iOS initialization tests', () => { true, // Enable native interception config.codePushVersion, config.ignoreAndroidSecureFlag, + undefined, ); }); @@ -994,6 +998,7 @@ describe('Instabug iOS initialization tests', () => { false, // Disable native interception config.codePushVersion, config.ignoreAndroidSecureFlag, + undefined, ); }); @@ -1036,6 +1041,7 @@ describe('Instabug Android initialization tests', () => { config.debugLogsLevel, false, // always disable native interception to insure sending network logs to core (Bugs & Crashes). config.codePushVersion, + undefined, { ignoreAndroidSecureFlag: config.ignoreAndroidSecureFlag }, ); }); @@ -1104,4 +1110,21 @@ describe('Instabug Android initialization tests', () => { ); }); }); + + it('should initialize correctly with App variant', async () => { + config.appVariant = 'App Variant'; + await Instabug.init(config); + fakeTimer(() => { + expect(NativeInstabug.setOnFeaturesUpdatedListener).toHaveBeenCalled(); + expect(NativeInstabug.init).toHaveBeenCalledWith( + config.token, + config.invocationEvents, + config.debugLogsLevel, + true, + config.codePushVersion, + config.appVariant, + undefined, + ); + }); + }); });