diff --git a/.circleci/config.yml b/.circleci/config.yml index f1df27eb1..f677b4bd7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -147,6 +147,7 @@ jobs: sync_generated_files: macos: xcode: 13.4.1 + resource_class: macos.m1.medium.gen1 steps: - advanced-checkout/shallow-checkout - install_node_modules @@ -161,6 +162,7 @@ jobs: test_ios: macos: xcode: 13.4.1 + resource_class: macos.m1.medium.gen1 working_directory: ~/project/examples/default environment: INSTABUG_SOURCEMAPS_UPLOAD_DISABLE: true @@ -192,7 +194,7 @@ jobs: e2e_ios: macos: xcode: 13.4.1 - resource_class: macos.x86.medium.gen2 + resource_class: macos.m1.medium.gen1 environment: INSTABUG_SOURCEMAPS_UPLOAD_DISABLE: true steps: @@ -321,6 +323,7 @@ jobs: publish: macos: xcode: 13.4.1 + resource_class: macos.m1.medium.gen1 working_directory: '~' steps: - advanced-checkout/shallow-checkout diff --git a/.gitignore b/.gitignore index f0e0669d2..50fb3439f 100644 --- a/.gitignore +++ b/.gitignore @@ -64,3 +64,6 @@ android/keystores/debug.keystore # Vscode local history .history/ + +# .idea run configurations +/.run/* diff --git a/android/src/main/java/com/instabug/reactlibrary/Constants.java b/android/src/main/java/com/instabug/reactlibrary/Constants.java index f78d3a732..d33bfe767 100644 --- a/android/src/main/java/com/instabug/reactlibrary/Constants.java +++ b/android/src/main/java/com/instabug/reactlibrary/Constants.java @@ -3,6 +3,7 @@ final class Constants { final static String IBG_PRE_INVOCATION_HANDLER = "IBGpreInvocationHandler"; final static String IBG_POST_INVOCATION_HANDLER = "IBGpostInvocationHandler"; + final static String IBG_NETWORK_DIAGNOSTICS_HANDLER = "IBGNetworkDiagnosticsHandler"; final static String IBG_ON_SHOW_SURVEY_HANDLER = "IBGWillShowSurvey"; final static String IBG_ON_DISMISS_SURVEY_HANDLER = "IBGDidDismissSurvey"; diff --git a/android/src/main/java/com/instabug/reactlibrary/RNInstabugReactnativeModule.java b/android/src/main/java/com/instabug/reactlibrary/RNInstabugReactnativeModule.java index 6692a2597..1d9dae15e 100644 --- a/android/src/main/java/com/instabug/reactlibrary/RNInstabugReactnativeModule.java +++ b/android/src/main/java/com/instabug/reactlibrary/RNInstabugReactnativeModule.java @@ -7,6 +7,8 @@ import android.net.Uri; import android.view.View; +import androidx.annotation.NonNull; + import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.Callback; import com.facebook.react.bridge.Promise; @@ -32,6 +34,7 @@ import com.instabug.library.logging.InstabugLog; import com.instabug.library.model.NetworkLog; import com.instabug.library.model.Report; +import com.instabug.library.networkDiagnostics.model.NetworkDiagnosticsCallback; import com.instabug.library.ui.onboarding.WelcomeMessage; import com.instabug.reactlibrary.utils.ArrayUtil; import com.instabug.reactlibrary.utils.EventEmitterModule; @@ -42,6 +45,7 @@ import org.json.JSONTokener; import java.io.File; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; @@ -144,7 +148,11 @@ public void run() { .setLogLevel(parsedLogLevel); if(codePushVersion != null) { - builder.setCodePushVersion(codePushVersion); + if(Instabug.isBuilt()) { + Instabug.setCodePushVersion(codePushVersion); + } else { + builder.setCodePushVersion(codePushVersion); + } } builder.build(); } @@ -1024,6 +1032,39 @@ public void run() { }); } + @ReactMethod + public void setOnNetworkDiagnosticsHandler() { + MainThreadHandler.runOnMainThread(new Runnable() { + @Override + public void run() { + try { + Method method = getMethod(Class.forName("com.instabug.library.Instabug"), "setNetworkDiagnosticsCallback", NetworkDiagnosticsCallback.class); + + if (method != null) { + method.invoke(null, new NetworkDiagnosticsCallback() { + @Override + public void onReady(@NonNull String date, int totalRequestCount, int failureCount) { + try { + WritableMap params = Arguments.createMap(); + params.putString("date", date); + params.putInt("totalRequestCount", totalRequestCount); + params.putInt("failureCount", failureCount); + + sendEvent(Constants.IBG_NETWORK_DIAGNOSTICS_HANDLER, params); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + } catch (ClassNotFoundException | IllegalAccessException | + InvocationTargetException e) { + e.printStackTrace(); + } + } + }); + } + /** * Map between the exported JS constant and the arg key in {@link ArgsRegistry}. * The constant name and the arg key should match to be able to resolve the diff --git a/android/src/test/java/com/instabug/reactlibrary/RNInstabugReactnativeModuleTest.java b/android/src/test/java/com/instabug/reactlibrary/RNInstabugReactnativeModuleTest.java index 148d71d51..60738541a 100644 --- a/android/src/test/java/com/instabug/reactlibrary/RNInstabugReactnativeModuleTest.java +++ b/android/src/test/java/com/instabug/reactlibrary/RNInstabugReactnativeModuleTest.java @@ -9,6 +9,7 @@ import com.facebook.react.bridge.JavaOnlyArray; import com.facebook.react.bridge.JavaOnlyMap; import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.WritableArray; import com.facebook.react.bridge.WritableMap; import com.instabug.library.Feature; @@ -19,7 +20,10 @@ import com.instabug.library.ReproConfigurations; import com.instabug.library.ReproMode; import com.instabug.library.internal.module.InstabugLocale; +import com.instabug.library.networkDiagnostics.model.NetworkDiagnosticsCallback; import com.instabug.library.ui.onboarding.WelcomeMessage; +import com.instabug.reactlibrary.util.GlobalMocks; +import com.instabug.reactlibrary.util.MockReflected; import com.instabug.reactlibrary.utils.MainThreadHandler; import org.junit.After; @@ -37,6 +41,7 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Locale; @@ -45,18 +50,21 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; +import static com.instabug.reactlibrary.util.GlobalMocks.reflected; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mockConstruction; import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; public class RNInstabugReactnativeModuleTest { - private RNInstabugReactnativeModule rnModule = new RNInstabugReactnativeModule(null); + private RNInstabugReactnativeModule rnModule; + private ReactApplicationContext mReactContext = mock(ReactApplicationContext.class); private final static ScheduledExecutorService mainThread = Executors.newSingleThreadScheduledExecutor(); @@ -66,7 +74,9 @@ public class RNInstabugReactnativeModuleTest { private MockedStatic mockInstabug; @Before - public void mockMainThreadHandler() throws Exception { + public void setUp() throws Exception { + rnModule = spy(new RNInstabugReactnativeModule(mReactContext)); + // Mock static functions mockInstabug = mockStatic(Instabug.class); mockLooper = mockStatic(Looper.class); @@ -86,6 +96,9 @@ public Boolean answer(InvocationOnMock invocation) throws Throwable { }; Mockito.doAnswer(handlerPostAnswer).when(MainThreadHandler.class); MainThreadHandler.runOnMainThread(any(Runnable.class)); + + // Set up global mocks + GlobalMocks.setUp(); } @After public void tearDown() { @@ -93,6 +106,9 @@ public void tearDown() { mockLooper.close(); mockMainThreadHandler.close(); mockInstabug.close(); + + // Remove global mocks + GlobalMocks.close(); } /********Instabug*********/ @@ -483,28 +499,17 @@ public void tearDown() { } @Test - public void givenString$reportCurrentViewChange_whenQuery_thenShouldCallNativeApiWithString() throws Exception { - // when + public void testReportCurrentViewChange() { rnModule.reportCurrentViewChange("screen"); - Method privateStringMethod = getMethod(Class.forName("com.instabug.library.Instabug"), "reportCurrentViewChange", String.class); - privateStringMethod.setAccessible(true); - // then - verify(Instabug.class, VerificationModeFactory.times(1)); - privateStringMethod.invoke("reportCurrentViewChange","screen"); + reflected.verify(() -> MockReflected.reportCurrentViewChange("screen"), times(1)); } @Test - public void givenString$reportScreenChange_whenQuery_thenShouldCallNativeApiWithString() throws Exception { - // when + public void testReportScreenChange() { rnModule.reportScreenChange("screen"); - Method privateStringMethod = getMethod(Class.forName("com.instabug.library.Instabug"), "reportScreenChange", Bitmap.class, String.class); - privateStringMethod.setAccessible(true); - - // then - verify(Instabug.class, VerificationModeFactory.times(1)); - privateStringMethod.invoke("reportScreenChange", null,"screen"); + reflected.verify(() -> MockReflected.reportScreenChange(null, "screen"), times(1)); } @Test @@ -554,4 +559,33 @@ public void tearDown() { verify(Instabug.class,times(1)); Instabug.clearAllExperiments(); } + + @Test + public void testSetOnNetworkDiagnosticsHandler() { + String date = new Date().toString(); + int successOrderCount = 2; + int failureCount = 1; + + MockedStatic mockArgument = mockStatic(Arguments.class); + mockArgument.when(Arguments::createMap).thenReturn(new JavaOnlyMap()); + + reflected + .when(() -> MockReflected.setNetworkDiagnosticsCallback(any(NetworkDiagnosticsCallback.class))) + .thenAnswer((InvocationOnMock invocation) -> { + NetworkDiagnosticsCallback callback = invocation.getArgument(0); + callback.onReady(date, successOrderCount, failureCount); + return null; + }); + + rnModule.setOnNetworkDiagnosticsHandler(); + + WritableMap params = new JavaOnlyMap(); + params.putString("date", date); + params.putInt("totalRequestCount", successOrderCount); + params.putInt("failureCount", failureCount); + + verify(rnModule).sendEvent(Constants.IBG_NETWORK_DIAGNOSTICS_HANDLER, params); + + mockArgument.close(); + } } diff --git a/android/src/test/java/com/instabug/reactlibrary/util/GlobalMocks.java b/android/src/test/java/com/instabug/reactlibrary/util/GlobalMocks.java index e4810c405..48b4c3fff 100644 --- a/android/src/test/java/com/instabug/reactlibrary/util/GlobalMocks.java +++ b/android/src/test/java/com/instabug/reactlibrary/util/GlobalMocks.java @@ -1,9 +1,12 @@ package com.instabug.reactlibrary.util; +import static com.instabug.reactlibrary.utils.InstabugUtil.getMethod; import static org.mockito.Mockito.mockStatic; +import android.graphics.Bitmap; import android.util.Log; +import com.instabug.library.networkDiagnostics.model.NetworkDiagnosticsCallback; import com.instabug.reactlibrary.utils.InstabugUtil; import org.mockito.MockedStatic; @@ -37,6 +40,29 @@ public static void setUp() throws NoSuchMethodException { reflection .when(() -> InstabugUtil.getMethod(Class.forName("com.instabug.library.util.InstabugDeprecationLogger"), "setBaseUrl", String.class)) .thenReturn(mSetBaseUrl); + + // setNetworkDiagnosticsCallback mock + Method mSetNetworkDiagnosticsCallback = MockReflected.class.getDeclaredMethod("setNetworkDiagnosticsCallback", NetworkDiagnosticsCallback.class); + mSetNetworkDiagnosticsCallback.setAccessible(true); + reflection + .when(() -> InstabugUtil.getMethod(Class.forName("com.instabug.library.Instabug"), "setNetworkDiagnosticsCallback", NetworkDiagnosticsCallback.class)) + .thenReturn(mSetNetworkDiagnosticsCallback); + + // reportCurrentViewChange mock + Method mReportCurrentViewChange = MockReflected.class.getDeclaredMethod("reportCurrentViewChange", String.class); + mReportCurrentViewChange.setAccessible(true); + + reflection + .when(() -> InstabugUtil.getMethod(Class.forName("com.instabug.library.Instabug"), "reportCurrentViewChange", String.class)) + .thenReturn(mReportCurrentViewChange); + + // reportScreenChange mock + Method mReportScreenChange = MockReflected.class.getDeclaredMethod("reportScreenChange", Bitmap.class, String.class); + mReportScreenChange.setAccessible(true); + + reflection + .when(() -> InstabugUtil.getMethod(Class.forName("com.instabug.library.Instabug"), "reportScreenChange", Bitmap.class, String.class)) + .thenReturn(mReportScreenChange); } public static void close() { diff --git a/android/src/test/java/com/instabug/reactlibrary/util/MockReflected.java b/android/src/test/java/com/instabug/reactlibrary/util/MockReflected.java index bfe886b96..a5a98526d 100644 --- a/android/src/test/java/com/instabug/reactlibrary/util/MockReflected.java +++ b/android/src/test/java/com/instabug/reactlibrary/util/MockReflected.java @@ -1,5 +1,13 @@ package com.instabug.reactlibrary.util; +import static com.instabug.reactlibrary.utils.InstabugUtil.getMethod; + +import android.graphics.Bitmap; + +import com.instabug.library.networkDiagnostics.model.NetworkDiagnosticsCallback; + +import java.lang.reflect.Method; + /** * Includes fake implementations of methods called by reflection. * Used to verify whether or not a private methods was called. @@ -16,4 +24,19 @@ public static void setCurrentPlatform(int platform) {} * Instabug.util.InstabugDeprecationLogger.setBaseUrl */ public static void setBaseUrl(String baseUrl) {} + + /** + * com.instabug.library.Instabug.setNetworkDiagnosticsCallback + */ + public static void setNetworkDiagnosticsCallback(NetworkDiagnosticsCallback callback) {} + + /** + * com.instabug.library.Instabug.reportCurrentViewChange + */ + public static void reportCurrentViewChange(String currentView) {} + + /** + * com.instabug.library.Instabug.reportScreenChange + */ + public static void reportScreenChange(Bitmap screenshot, String screen) {} } diff --git a/examples/default/ios/InstabugTests/InstabugSampleTests.m b/examples/default/ios/InstabugTests/InstabugSampleTests.m index 05e085ee3..3e07682a8 100644 --- a/examples/default/ios/InstabugTests/InstabugSampleTests.m +++ b/examples/default/ios/InstabugTests/InstabugSampleTests.m @@ -13,6 +13,7 @@ #import #import "IBGConstants.h" #import "RNInstabug.h" +#import "Instabug+CP.h" @protocol InstabugCPTestProtocol /** @@ -45,7 +46,7 @@ @implementation InstabugSampleTests - (void)setUp { // Put setup code here. This method is called before the invocation of each test method in the class. - self.instabugBridge = [[InstabugReactBridge alloc] init]; + self.instabugBridge = OCMPartialMock([[InstabugReactBridge alloc] init]); self.mRNInstabug = OCMClassMock([RNInstabug class]); } @@ -408,4 +409,25 @@ - (void)testClearAllExperiments { OCMVerify([mock clearAllExperiments]); } +- (void)testSetOnNetworkDiagnosticsHandler { + id mInstabug = OCMClassMock([Instabug class]); + NSString* date = @"1/2/2024"; + NSInteger totalRequestCount = 10; + NSInteger failureCount = 8; + + NSDictionary *expected = @{ + @"date": date, + @"totalRequestCount": @(totalRequestCount), + @"failureCount": @(failureCount) + }; + + OCMStub([mInstabug setWillSendNetworkDiagnosticsHandler:([OCMArg invokeBlockWithArgs:date, OCMOCK_VALUE(totalRequestCount), OCMOCK_VALUE(failureCount), nil])]); + + OCMStub([self.instabugBridge sendEventWithName:[OCMArg any] body:[OCMArg any]]); + + [self.instabugBridge setOnNetworkDiagnosticsHandler]; + + OCMVerify([self.instabugBridge sendEventWithName:@"IBGNetworkDiagnosticsHandler" body:expected]); +} + @end diff --git a/examples/default/ios/Podfile.lock b/examples/default/ios/Podfile.lock index 45e5f48cf..5cd4fa4f0 100644 --- a/examples/default/ios/Podfile.lock +++ b/examples/default/ios/Podfile.lock @@ -795,4 +795,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: d169b4508f413ff5d69cdf38428960e0828e6282 -COCOAPODS: 1.11.3 +COCOAPODS: 1.12.0 diff --git a/examples/default/src/components/InputField.tsx b/examples/default/src/components/InputField.tsx new file mode 100644 index 000000000..91e789f80 --- /dev/null +++ b/examples/default/src/components/InputField.tsx @@ -0,0 +1,38 @@ +import React, { forwardRef } from 'react'; + +import { KeyboardTypeOptions, StyleSheet, TextInput } from 'react-native'; + +interface InputFieldProps { + placeholder?: string; + value?: string; + onChangeText?: (text: string) => void; + keyboardType?: KeyboardTypeOptions; +} + +export const InputField = forwardRef( + ({ placeholder, value, onChangeText, keyboardType, ...restProps }, ref) => { + return ( + + ); + }, +); + +const styles = StyleSheet.create({ + textInput: { + backgroundColor: 'white', + borderWidth: 1, + borderColor: '#ccc', + paddingVertical: 16, + paddingHorizontal: 24, + fontSize: 16, + borderRadius: 5, + }, +}); diff --git a/examples/default/src/components/NestedView.tsx b/examples/default/src/components/NestedView.tsx new file mode 100644 index 000000000..494fde9f2 --- /dev/null +++ b/examples/default/src/components/NestedView.tsx @@ -0,0 +1,31 @@ +import React from 'react'; + +import { Text } from 'native-base'; +import { StyleSheet, View } from 'react-native'; + +interface NestedViewProps { + children?: React.ReactNode; + depth: number; + breadth?: number; +} + +export const NestedView: React.FC = ({ depth, breadth = 1, children }) => { + if (!depth) { + return <>{children}; + } + return ( + + {depth} + {new Array(breadth).fill(null).map((_, index) => ( + + ))} + + ); +}; + +const styles = StyleSheet.create({ + container: { + borderWidth: 1, + padding: 1, + }, +}); diff --git a/examples/default/src/navigation/HomeStack.tsx b/examples/default/src/navigation/HomeStack.tsx index 360a27444..b3e1b76a4 100644 --- a/examples/default/src/navigation/HomeStack.tsx +++ b/examples/default/src/navigation/HomeStack.tsx @@ -12,6 +12,7 @@ import { UserStepsScreen } from '../screens/user-steps/UserStepsScreen'; import { BasicComponentsScreen } from '../screens/user-steps/BasicComponentsScreen'; import { ScrollViewScreen } from '../screens/user-steps/ScrollViewScreen'; import { FlatListScreen } from '../screens/user-steps/FlatListScreen'; +import { ComplexViewsScreen } from '../screens/user-steps/ComplexViewsScreen'; import { SectionListScreen } from '../screens/user-steps/SectionListScreen'; import { GesturesScreen } from '../screens/user-steps/GesturesScreen'; @@ -26,6 +27,7 @@ export type HomeStackParamList = { BasicComponents: undefined; ScrollView: undefined; FlatList: undefined; + ComplexViews: undefined; SectionList: undefined; Gestures: undefined; }; @@ -63,6 +65,11 @@ export const HomeStackNavigator: React.FC = () => { component={BasicComponentsScreen} options={{ title: 'Basic Components' }} /> + {
- +
diff --git a/examples/default/src/screens/user-steps/ComplexViewsScreen.tsx b/examples/default/src/screens/user-steps/ComplexViewsScreen.tsx new file mode 100644 index 000000000..0035d5775 --- /dev/null +++ b/examples/default/src/screens/user-steps/ComplexViewsScreen.tsx @@ -0,0 +1,47 @@ +import React, { useRef, useState } from 'react'; + +import { Screen } from '../../components/Screen'; +import { Section } from '../../components/Section'; +import { NestedView } from '../../components/NestedView'; +import { Button } from 'react-native'; +import { ScrollView, VStack } from 'native-base'; +import { InputField } from '../../components/InputField'; + +export const ComplexViewsScreen: React.FC = () => { + const initialDepth = 10; + const initialBreadth = 2; + + const depthRef = useRef(initialDepth); + const breadthRef = useRef(initialBreadth); + + const [depth, setDepth] = useState(initialDepth); + const [breadth, setBreadth] = useState(initialBreadth); + + function handleRender() { + setDepth(depthRef.current); + setBreadth(breadthRef.current); + } + + return ( + + +
+ + (depthRef.current = +text)} + /> + (breadthRef.current = +text)} + /> +
+
+
+ ); +}; diff --git a/examples/default/src/screens/user-steps/UserStepsScreen.tsx b/examples/default/src/screens/user-steps/UserStepsScreen.tsx index 219cd5bbd..dc0d26c10 100644 --- a/examples/default/src/screens/user-steps/UserStepsScreen.tsx +++ b/examples/default/src/screens/user-steps/UserStepsScreen.tsx @@ -14,6 +14,7 @@ export const UserStepsScreen: React.FC navigation.navigate('ScrollView')} /> navigation.navigate('FlatList')} /> navigation.navigate('SectionList')} /> + navigation.navigate('ComplexViews')} /> navigation.navigate('Gestures')} /> ); diff --git a/ios/RNInstabug/InstabugReactBridge.h b/ios/RNInstabug/InstabugReactBridge.h index 24baf146a..e2c60ef0c 100644 --- a/ios/RNInstabug/InstabugReactBridge.h +++ b/ios/RNInstabug/InstabugReactBridge.h @@ -112,5 +112,6 @@ - (void)addExperiments:(NSArray *)experiments; - (void)removeExperiments:(NSArray *)experiments; - (void)clearAllExperiments; +- (void)setOnNetworkDiagnosticsHandler; @end diff --git a/ios/RNInstabug/InstabugReactBridge.m b/ios/RNInstabug/InstabugReactBridge.m index ed512fe32..7f6c95ff0 100644 --- a/ios/RNInstabug/InstabugReactBridge.m +++ b/ios/RNInstabug/InstabugReactBridge.m @@ -15,6 +15,7 @@ #import #import #import "RNInstabug.h" +#import "Util/Instabug+CP.h" @interface Instabug (PrivateWillSendAPI) + (void)setWillSendReportHandler_private:(void(^)(IBGReport *report, void(^reportCompletionHandler)(IBGReport *)))willSendReportHandler_private; @@ -23,7 +24,10 @@ + (void)setWillSendReportHandler_private:(void(^)(IBGReport *report, void(^repor @implementation InstabugReactBridge - (NSArray *)supportedEvents { - return @[@"IBGpreSendingHandler"]; + return @[ + @"IBGpreSendingHandler", + @"IBGNetworkDiagnosticsHandler" + ]; } RCT_EXPORT_MODULE(Instabug) @@ -376,6 +380,18 @@ - (dispatch_queue_t)methodQueue { [Instabug clearAllExperiments]; } +RCT_EXPORT_METHOD(setOnNetworkDiagnosticsHandler) { + [Instabug setWillSendNetworkDiagnosticsHandler:^(NSString *date, NSInteger totalRequestCount, NSInteger failureCount) { + NSDictionary *params = @{ + @"date": date, + @"totalRequestCount": @(totalRequestCount), + @"failureCount": @(failureCount) + }; + + [self sendEventWithName:@"IBGNetworkDiagnosticsHandler" body:params]; + }]; +} + - (NSDictionary *)constantsToExport { return ArgsRegistry.getAll; } diff --git a/ios/RNInstabug/Util/Instabug+CP.h b/ios/RNInstabug/Util/Instabug+CP.h index 8666413f0..333142e48 100644 --- a/ios/RNInstabug/Util/Instabug+CP.h +++ b/ios/RNInstabug/Util/Instabug+CP.h @@ -6,6 +6,7 @@ NS_ASSUME_NONNULL_BEGIN @interface Instabug (CP) + (void)setCurrentPlatform:(IBGPlatform)platform; ++ (void)setWillSendNetworkDiagnosticsHandler:(void (^_Nullable)(NSString*, NSInteger, NSInteger))willSendNetworkDiagnosticsHandler; @end diff --git a/src/modules/Instabug.ts b/src/modules/Instabug.ts index cf0debc9a..6ccf9e5d6 100644 --- a/src/modules/Instabug.ts +++ b/src/modules/Instabug.ts @@ -540,6 +540,24 @@ export const clearAllExperiments = () => { NativeInstabug.clearAllExperiments(); }; +export type NetworkDiagnosticsHandler = ( + date: String, + totalRequestCount: number, + failureCount: number, +) => void; + +export const onNetworkDiagnosticsHandler = (handler?: NetworkDiagnosticsHandler) => { + emitter.addListener(NativeEvents.NETWORK_DIAGNOSTICS_HANDLER, (data) => { + const { date, totalRequestCount, failureCount } = data; + + if (handler) { + handler(date, totalRequestCount, failureCount); + } + }); + + NativeInstabug.setOnNetworkDiagnosticsHandler(); +}; + export const componentDidAppearListener = (event: ComponentDidAppearEvent) => { if (_isFirstScreen) { _lastScreen = event.componentName; diff --git a/src/native/NativeInstabug.ts b/src/native/NativeInstabug.ts index b8b1d912f..1699ac6d8 100644 --- a/src/native/NativeInstabug.ts +++ b/src/native/NativeInstabug.ts @@ -103,12 +103,16 @@ export interface InstabugNativeModule extends NativeModule { logInfoToReport(log: string): void; addFileAttachmentWithURLToReport(url: string, filename?: string): void; addFileAttachmentWithDataToReport(data: string, filename?: string): void; + + // Callbacks // + setOnNetworkDiagnosticsHandler(): void; } export const NativeInstabug = NativeModules.Instabug; export enum NativeEvents { PRESENDING_HANDLER = 'IBGpreSendingHandler', + NETWORK_DIAGNOSTICS_HANDLER = 'IBGNetworkDiagnosticsHandler', } export const emitter = new NativeEventEmitter(NativeInstabug); diff --git a/test/mocks/mockInstabug.ts b/test/mocks/mockInstabug.ts index 6353cf64c..0385fe61d 100644 --- a/test/mocks/mockInstabug.ts +++ b/test/mocks/mockInstabug.ts @@ -63,6 +63,7 @@ const mockInstabug: InstabugNativeModule = { addFileAttachmentWithURLToReport: jest.fn(), addFileAttachmentWithDataToReport: jest.fn(), setNetworkLoggingEnabled: jest.fn(), + setOnNetworkDiagnosticsHandler: jest.fn(), }; export default mockInstabug; diff --git a/test/modules/Instabug.spec.ts b/test/modules/Instabug.spec.ts index c8019c1ea..bf191afb9 100644 --- a/test/modules/Instabug.spec.ts +++ b/test/modules/Instabug.spec.ts @@ -720,4 +720,22 @@ describe('Instabug Module', () => { Instabug.clearAllExperiments(); expect(NativeInstabug.clearAllExperiments).toBeCalledTimes(1); }); + + it('onNetworkDiagnosticsHandler should be called with appropriate arguments', () => { + const callback = jest.fn(); + const data = { + date: 'date', + totalRequestCount: 1, + failureCount: 1, + }; + + Instabug.onNetworkDiagnosticsHandler(callback); + + emitter.emit(NativeEvents.NETWORK_DIAGNOSTICS_HANDLER, data); + + expect(NativeInstabug.setOnNetworkDiagnosticsHandler).toBeCalledTimes(1); + expect(emitter.listenerCount(NativeEvents.NETWORK_DIAGNOSTICS_HANDLER)).toBe(1); + expect(callback).toBeCalledTimes(1); + expect(callback).toBeCalledWith(data.date, data.totalRequestCount, data.failureCount); + }); });