diff --git a/CHANGELOG.md b/CHANGELOG.md index abda7ed70..360ea32c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## [15.0.2](https://github.com/Instabug/Instabug-React-Native/compare/v15.0.1...v15.0.2) + +- Rollout support for network spans. ([#1427](https://github.com/Instabug/Instabug-React-Native/pull/1427)) + ## [15.0.1](https://github.com/Instabug/Instabug-React-Native/compare/v14.3.0...v15.0.1) ### Added diff --git a/examples/default/src/App.tsx b/examples/default/src/App.tsx index ceef8bc19..ad1c32579 100644 --- a/examples/default/src/App.tsx +++ b/examples/default/src/App.tsx @@ -1,5 +1,5 @@ -import React, { useEffect, useState } from 'react'; -import { ActivityIndicator, StyleSheet } from 'react-native'; +import React, { useEffect } from 'react'; +import { StyleSheet } from 'react-native'; import { GestureHandlerRootView } from 'react-native-gesture-handler'; import { NavigationContainer, useNavigationContainerRef } from '@react-navigation/native'; @@ -40,13 +40,11 @@ export const App: React.FC = () => { const navigationRef = useNavigationContainerRef(); - const [isInstabugInitialized, setIsInstabugInitialized] = useState(false); - - const initializeInstabug = async () => { + const initializeInstabug = () => { try { SessionReplay.setSyncCallback((data) => shouldSyncSession(data)); - await Instabug.init({ + Instabug.init({ token: 'deb1910a7342814af4e4c9210c786f35', invocationEvents: [InvocationEvent.floatingButton], debugLogsLevel: LogLevel.verbose, @@ -55,21 +53,16 @@ export const App: React.FC = () => { CrashReporting.setNDKCrashesEnabled(true); Instabug.setReproStepsConfig({ all: ReproStepsMode.enabled }); - - setIsInstabugInitialized(true); // Set to true after initialization } catch (error) { console.error('Instabug initialization failed:', error); - setIsInstabugInitialized(true); // Proceed even if initialization fails } }; useEffect(() => { - initializeInstabug().then(() => { - NetworkLogger.setNetworkDataObfuscationHandler(async (networkData) => { - networkData.url = `${networkData.url}/JS/Obfuscated`; - return networkData; - }); - // NetworkLogger.setRequestFilterExpression('false'); + initializeInstabug(); + NetworkLogger.setNetworkDataObfuscationHandler(async (networkData) => { + networkData.url = `${networkData.url}/JS/Obfuscated`; + return networkData; }); }); @@ -80,10 +73,6 @@ export const App: React.FC = () => { return unregisterListener; }, [navigationRef]); - if (!isInstabugInitialized) { - return ; - } - return ( diff --git a/ios/RNInstabug/InstabugNetworkLoggerBridge.h b/ios/RNInstabug/InstabugNetworkLoggerBridge.h index 9673f8524..532f21d23 100644 --- a/ios/RNInstabug/InstabugNetworkLoggerBridge.h +++ b/ios/RNInstabug/InstabugNetworkLoggerBridge.h @@ -24,7 +24,7 @@ typedef NS_ENUM(NSInteger, NetworkListenerType) { +------------------------------------------------------------------------+ */ -- (void)isNativeInterceptionEnabled:(RCTPromiseResolveBlock _Nullable )resolve :(RCTPromiseRejectBlock _Nullable )reject; +- (BOOL)isNativeInterceptionEnabled; - (void) registerNetworkLogsListener:(NetworkListenerType)listenerType; diff --git a/ios/RNInstabug/InstabugNetworkLoggerBridge.m b/ios/RNInstabug/InstabugNetworkLoggerBridge.m index 16d71c814..2a2ddeb97 100644 --- a/ios/RNInstabug/InstabugNetworkLoggerBridge.m +++ b/ios/RNInstabug/InstabugNetworkLoggerBridge.m @@ -69,9 +69,11 @@ -(void)stopObserving { // Remove upstream listeners, stop unnecessary background tasks } -RCT_EXPORT_METHOD(isNativeInterceptionEnabled:(RCTPromiseResolveBlock)resolve :(RCTPromiseRejectBlock)reject) { - resolve(@(IBGNetworkLogger.isNativeNetworkInterceptionFeatureEnabled)); -} +RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(isNativeInterceptionEnabled) { + return @(IBGNetworkLogger.isNativeNetworkInterceptionFeatureEnabled); +} + + RCT_EXPORT_METHOD(registerNetworkLogsListener: (NetworkListenerType) listenerType) { switch (listenerType) { diff --git a/src/modules/Instabug.ts b/src/modules/Instabug.ts index f7d582e70..79ec492a5 100644 --- a/src/modules/Instabug.ts +++ b/src/modules/Instabug.ts @@ -84,13 +84,13 @@ function reportCurrentViewForAndroid(screenName: string | null) { * Should be called in constructor of the AppRegistry component * @param config SDK configurations. See {@link InstabugConfig} for more info. */ -export const init = async (config: InstabugConfig) => { +export const init = (config: InstabugConfig) => { if (Platform.OS === 'android') { // Add android feature flags listener for android registerFeatureFlagsListener(); addOnFeatureUpdatedListener(config); } else { - isNativeInterceptionFeatureEnabled = await NativeNetworkLogger.isNativeInterceptionEnabled(); + isNativeInterceptionFeatureEnabled = NativeNetworkLogger.isNativeInterceptionEnabled(); // Add app state listener to handle background/foreground transitions addAppStateListener(async (nextAppState) => handleAppStateChange(nextAppState, config)); @@ -133,7 +133,6 @@ const handleAppStateChange = async (nextAppState: AppStateStatus, config: Instab // Checks if the app has come to the foreground if (['inactive', 'background'].includes(_currentAppState) && nextAppState === 'active') { const isUpdated = await fetchApmNetworkFlags(); - if (isUpdated) { refreshAPMNetworkConfigs(config); } @@ -147,8 +146,7 @@ const handleAppStateChange = async (nextAppState: AppStateStatus, config: Instab */ const fetchApmNetworkFlags = async () => { let isUpdated = false; - const newNativeInterceptionFeatureEnabled = - await NativeNetworkLogger.isNativeInterceptionEnabled(); + const newNativeInterceptionFeatureEnabled = NativeNetworkLogger.isNativeInterceptionEnabled(); if (isNativeInterceptionFeatureEnabled !== newNativeInterceptionFeatureEnabled) { isNativeInterceptionFeatureEnabled = newNativeInterceptionFeatureEnabled; isUpdated = true; diff --git a/src/native/NativeNetworkLogger.ts b/src/native/NativeNetworkLogger.ts index 4162a0fbf..c38f11873 100644 --- a/src/native/NativeNetworkLogger.ts +++ b/src/native/NativeNetworkLogger.ts @@ -8,7 +8,7 @@ export enum NetworkListenerType { } export interface NetworkLoggerNativeModule extends NativeModule { - isNativeInterceptionEnabled(): Promise; + isNativeInterceptionEnabled(): boolean; registerNetworkLogsListener(type?: NetworkListenerType): void; diff --git a/test/modules/Instabug.spec.ts b/test/modules/Instabug.spec.ts index f6e36d8e4..d3d53e461 100644 --- a/test/modules/Instabug.spec.ts +++ b/test/modules/Instabug.spec.ts @@ -69,8 +69,8 @@ describe('Instabug Module', () => { expect(NativeInstabug.reportScreenChange).toBeCalledWith(screenName); }); - it("componentDidAppearListener shouldn't call the native method reportScreenChange if first screen", async () => { - await Instabug.init({ + it("componentDidAppearListener shouldn't call the native method reportScreenChange if first screen", () => { + Instabug.init({ token: 'some-token', invocationEvents: [InvocationEvent.none], }); @@ -81,7 +81,7 @@ describe('Instabug Module', () => { componentType: 'Component', }); - await waitForExpect(() => { + waitForExpect(() => { // Only first screen should be reported expect(NativeInstabug.reportScreenChange).toBeCalledTimes(1); expect(NativeInstabug.reportScreenChange).toBeCalledWith('Initial Screen'); @@ -89,6 +89,11 @@ describe('Instabug Module', () => { }); it("componentDidAppearListener shouldn't call the native method reportScreenChange twice if same screen", (done) => { + Instabug.init({ + token: 'some-token', + invocationEvents: [InvocationEvent.none], + }); + Array(5).forEach(() => { Instabug.componentDidAppearListener({ componentId: '1', @@ -107,7 +112,7 @@ describe('Instabug Module', () => { // 2. Second+ calls: // The screen name is the same as _lastScreen (stored in 1st call) // so it doesn't report a screen change - expect(NativeInstabug.reportScreenChange).not.toBeCalled(); + expect(NativeInstabug.reportScreenChange).toBeCalledTimes(1); done(); }, 1500); }); @@ -283,7 +288,7 @@ describe('Instabug Module', () => { expect(onStateChangeMock).toHaveBeenCalledWith(mockNavigationContainerRef.getRootState()); }); - it('should call the native method init', async () => { + it('should call the native method init', () => { const instabugConfig = { token: 'some-token', invocationEvents: [InvocationEvent.floatingButton, InvocationEvent.shake], @@ -292,7 +297,7 @@ describe('Instabug Module', () => { }; const usesNativeNetworkInterception = false; - await Instabug.init(instabugConfig); + Instabug.init(instabugConfig); expect(NetworkLogger.setEnabled).toBeCalledWith(true); expect(NativeInstabug.init).toBeCalledTimes(1); @@ -314,7 +319,7 @@ describe('Instabug Module', () => { expect(NativeInstabug.setCodePushVersion).toBeCalledWith(codePushVersion); }); - it('init should disable JavaScript interceptor when using native interception mode', async () => { + it('init should disable JavaScript interceptor when using native interception mode', () => { const instabugConfig = { token: 'some-token', invocationEvents: [InvocationEvent.floatingButton, InvocationEvent.shake], @@ -324,12 +329,10 @@ describe('Instabug Module', () => { }; // Stubbing Network feature flags - jest - .spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled') - .mockReturnValue(Promise.resolve(true)); + jest.spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled').mockReturnValue(true); jest.spyOn(NativeNetworkLogger, 'hasAPMNetworkPlugin').mockReturnValue(Promise.resolve(true)); - await Instabug.init(instabugConfig); + Instabug.init(instabugConfig); if (Platform.OS === 'android') { expect(NetworkLogger.setEnabled).not.toBeCalled(); @@ -900,7 +903,7 @@ describe('Instabug Module', () => { expect(NativeInstabug.willRedirectToStore).toBeCalledTimes(1); }); - it('should register feature flag listener', async () => { + it('should register feature flag listener', () => { const callback = jest.fn(); Instabug._registerFeatureFlagsChangeListener(callback); @@ -939,10 +942,10 @@ describe('Instabug iOS initialization tests', () => { jest.advanceTimersByTime(1000); }); - it('should initialize correctly with javascript interception mode', async () => { + it('should initialize correctly with javascript interception mode', () => { config.networkInterceptionMode = NetworkInterceptionMode.javascript; - await Instabug.init(config); + Instabug.init(config); expect(NativeNetworkLogger.isNativeInterceptionEnabled).toHaveBeenCalled(); expect(NetworkLogger.setEnabled).toHaveBeenCalledWith(true); @@ -955,12 +958,10 @@ describe('Instabug iOS initialization tests', () => { ); }); - it('should initialize correctly with native interception mode when [isNativeInterceptionEnabled] == ture', async () => { - jest - .spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled') - .mockReturnValue(Promise.resolve(true)); + it('should initialize correctly with native interception mode when [isNativeInterceptionEnabled] == ture', () => { + jest.spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled').mockReturnValue(true); - await Instabug.init(config); + Instabug.init(config); expect(NativeNetworkLogger.isNativeInterceptionEnabled).toHaveBeenCalled(); expect(NetworkLogger.setEnabled).toHaveBeenCalledWith(false); @@ -973,12 +974,10 @@ describe('Instabug iOS initialization tests', () => { ); }); - it('should disable native interception mode when user sets networkInterceptionMode to native and [isNativeInterceptionEnabled] == false', async () => { - jest - .spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled') - .mockReturnValue(Promise.resolve(false)); + it('should disable native interception mode when user sets networkInterceptionMode to native and [isNativeInterceptionEnabled] == false', () => { + jest.spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled').mockReturnValue(false); - await Instabug.init(config); + Instabug.init(config); expect(NativeNetworkLogger.isNativeInterceptionEnabled).toHaveBeenCalled(); expect(NetworkLogger.setEnabled).toHaveBeenCalled(); @@ -991,13 +990,11 @@ describe('Instabug iOS initialization tests', () => { ); }); - it('should display error message when user sets networkInterceptionMode to native and [isNativeInterceptionEnabled] == false', async () => { - jest - .spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled') - .mockReturnValue(Promise.resolve(false)); + it('should display error message when user sets networkInterceptionMode to native and [isNativeInterceptionEnabled] == false', () => { + jest.spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled').mockReturnValue(false); const logSpy = jest.spyOn(global.console, 'error'); - await Instabug.init(config); + Instabug.init(config); expect(logSpy).toBeCalledTimes(1); expect(logSpy).toBeCalledWith( @@ -1020,9 +1017,9 @@ describe('Instabug Android initialization tests', () => { }; }); - it('should initialize correctly with native interception enabled', async () => { + it('should initialize correctly with native interception enabled', () => { config.networkInterceptionMode = NetworkInterceptionMode.native; - await Instabug.init(config); + Instabug.init(config); fakeTimer(() => { expect(NativeInstabug.setOnFeaturesUpdatedListener).toHaveBeenCalled(); expect(NetworkLogger.setEnabled).toHaveBeenCalledWith(true); @@ -1036,14 +1033,12 @@ describe('Instabug Android initialization tests', () => { }); }); - it('should show warning message when networkInterceptionMode == javascript and user added APM plugin', async () => { - jest - .spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled') - .mockReturnValue(Promise.resolve(true)); + it('should show warning message when networkInterceptionMode == javascript and user added APM plugin', () => { + jest.spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled').mockReturnValue(true); jest.spyOn(NativeNetworkLogger, 'hasAPMNetworkPlugin').mockReturnValue(Promise.resolve(true)); const logSpy = jest.spyOn(global.console, 'warn'); - await Instabug.init(config); + Instabug.init(config); fakeTimer(() => { expect(logSpy).toBeCalledTimes(1); expect(logSpy).toBeCalledWith( @@ -1052,16 +1047,14 @@ describe('Instabug Android initialization tests', () => { }); }); - it('should show error message when networkInterceptionMode == native and user did not add APM plugin', async () => { + it('should show error message when networkInterceptionMode == native and user did not add APM plugin', () => { config.networkInterceptionMode = NetworkInterceptionMode.native; - jest - .spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled') - .mockReturnValue(Promise.resolve(true)); + jest.spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled').mockReturnValue(true); jest.spyOn(NativeNetworkLogger, 'hasAPMNetworkPlugin').mockReturnValue(Promise.resolve(false)); const logSpy = jest.spyOn(global.console, 'error'); - await Instabug.init(config); + Instabug.init(config); fakeTimer(() => { expect(logSpy).toBeCalledTimes(1); @@ -1071,16 +1064,14 @@ describe('Instabug Android initialization tests', () => { }); }); - it('should show error message when networkInterceptionMode == native and user did not add APM plugin and the isNativeInterceptionEnabled is disabled', async () => { + it('should show error message when networkInterceptionMode == native and user did not add APM plugin and the isNativeInterceptionEnabled is disabled', () => { config.networkInterceptionMode = NetworkInterceptionMode.native; - jest - .spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled') - .mockReturnValue(Promise.resolve(false)); + jest.spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled').mockReturnValue(false); jest.spyOn(NativeNetworkLogger, 'hasAPMNetworkPlugin').mockReturnValue(Promise.resolve(false)); const logSpy = jest.spyOn(global.console, 'error'); - await Instabug.init(config); + Instabug.init(config); fakeTimer(() => { expect(logSpy).toBeCalledTimes(1); @@ -1090,15 +1081,13 @@ describe('Instabug Android initialization tests', () => { }); }); - it('should show error message when networkInterceptionMode == native and the isNativeInterceptionEnabled is disabled', async () => { + it('should show error message when networkInterceptionMode == native and the isNativeInterceptionEnabled is disabled', () => { config.networkInterceptionMode = NetworkInterceptionMode.native; - jest - .spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled') - .mockReturnValue(Promise.resolve(false)); + jest.spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled').mockReturnValue(false); jest.spyOn(NativeNetworkLogger, 'hasAPMNetworkPlugin').mockReturnValue(Promise.resolve(true)); const logSpy = jest.spyOn(global.console, 'error'); - await Instabug.init(config); + Instabug.init(config); fakeTimer(() => { expect(logSpy).toBeCalledTimes(1); diff --git a/test/utils/InstabugUtils.spec.ts b/test/utils/InstabugUtils.spec.ts index 11a5c8d1a..49ce13c58 100644 --- a/test/utils/InstabugUtils.spec.ts +++ b/test/utils/InstabugUtils.spec.ts @@ -273,11 +273,9 @@ describe('reportNetworkLog', () => { it('reportNetworkLog should send network logs to native with the correct parameters on Android', async () => { Platform.OS = 'android'; - jest - .spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled') - .mockReturnValue(Promise.resolve(false)); + jest.spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled').mockReturnValue(false); jest.spyOn(NativeNetworkLogger, 'hasAPMNetworkPlugin').mockReturnValue(Promise.resolve(false)); - await Instabug.init({ token: '', invocationEvents: [InvocationEvent.none] }); + Instabug.init({ token: '', invocationEvents: [InvocationEvent.none] }); const requestHeaders = JSON.stringify(network.requestHeaders); const responseHeaders = JSON.stringify(network.responseHeaders);